@@ -1038,9 +1038,131 @@ def less_equal(x1, x2):
1038
1038
def linspace (
1039
1039
start , stop , num = 50 , endpoint = True , retstep = False , dtype = None , axis = 0
1040
1040
):
1041
- raise NotImplementedError (
1042
- "`linspace` is not supported with openvino backend"
1041
+ """Return evenly spaced numbers over a specified interval.
1042
+
1043
+ Supports axis=0 (prepend) and axis=-1 (append). Intermediate axis values are
1044
+ treated as axis=-1.
1045
+
1046
+ If `retstep` is True, also returns the step size between values.
1047
+
1048
+ """
1049
+
1050
+ start = get_ov_output (start )
1051
+ stop = get_ov_output (stop )
1052
+
1053
+ if hasattr (num , "output" ) or isinstance (num , OpenVINOKerasTensor ):
1054
+ num_tensor = get_ov_output (num )
1055
+ try :
1056
+ if num_tensor .get_node ().get_type_name () == "Constant" :
1057
+ num_value = num_tensor .get_node ().get_vector ()[0 ]
1058
+ num = int (num_value )
1059
+ else :
1060
+ raise NotImplementedError (
1061
+ "Dynamic num values not fully supported"
1062
+ )
1063
+ except Exception as e :
1064
+ raise NotImplementedError (
1065
+ "Could not extract num value from tensor"
1066
+ ) from e
1067
+ else :
1068
+ num = int (num )
1069
+
1070
+ if dtype is None :
1071
+ output_type = OPENVINO_DTYPES [config .floatx ()]
1072
+ else :
1073
+ output_type = OPENVINO_DTYPES [dtype ]
1074
+
1075
+ start = ov_opset .convert (start , output_type ).output (0 )
1076
+ stop = ov_opset .convert (stop , output_type ).output (0 )
1077
+
1078
+ if num < 0 :
1079
+ raise ValueError ("Number of samples, `num`, must be non-negative." )
1080
+
1081
+ if num == 0 :
1082
+ empty_shape = ov_opset .constant ([0 ], Type .i32 ).output (0 )
1083
+ result = ov_opset .broadcast (
1084
+ ov_opset .constant (0.0 , output_type ).output (0 ), empty_shape
1085
+ ).output (0 )
1086
+ if retstep :
1087
+ nan_step = ov_opset .constant (np .nan , output_type ).output (0 )
1088
+ return OpenVINOKerasTensor (result ), OpenVINOKerasTensor (nan_step )
1089
+ return OpenVINOKerasTensor (result )
1090
+
1091
+ if num == 1 :
1092
+ result_val = start
1093
+ axis_const = ov_opset .constant ([axis ], Type .i32 ).output (0 )
1094
+ result = ov_opset .unsqueeze (result_val , axis_const ).output (0 )
1095
+ if retstep :
1096
+ if endpoint :
1097
+ step = ov_opset .constant (np .nan , output_type ).output (0 )
1098
+ else :
1099
+ step = ov_opset .subtract (stop , start ).output (0 )
1100
+ return OpenVINOKerasTensor (result ), OpenVINOKerasTensor (step )
1101
+ zero_i32 = ov_opset .constant (0 , Type .i32 ).output (0 )
1102
+ one_i32 = ov_opset .constant (1 , Type .i32 ).output (0 )
1103
+ one_i32_array = ov_opset .constant ([1 ], Type .i32 ).output (0 )
1104
+
1105
+ num_const = ov_opset .constant (num , output_type ).output (0 )
1106
+
1107
+ if endpoint :
1108
+ divisor = ov_opset .subtract (
1109
+ num_const , ov_opset .constant (1 , output_type ).output (0 )
1110
+ ).output (0 )
1111
+ else :
1112
+ divisor = num_const
1113
+
1114
+ step = ov_opset .divide (
1115
+ ov_opset .subtract (stop , start ).output (0 ), divisor
1116
+ ).output (0 )
1117
+
1118
+ indices = ov_opset .range (
1119
+ zero_i32 ,
1120
+ ov_opset .constant (num , Type .i32 ).output (0 ),
1121
+ one_i32 ,
1122
+ output_type ,
1123
+ ).output (0 )
1124
+
1125
+ start_shape = ov_opset .convert (
1126
+ ov_opset .shape_of (start ).output (0 ), Type .i32
1127
+ ).output (0 )
1128
+ indices_shape = ov_opset .convert (
1129
+ ov_opset .shape_of (indices ).output (0 ), Type .i32
1130
+ ).output (0 )
1131
+
1132
+ start_rank = ov_opset .shape_of (start_shape ).output (0 )
1133
+ ones_for_start = ov_opset .broadcast (one_i32 , start_rank ).output (0 )
1134
+
1135
+ if axis == 0 :
1136
+ indices_target_shape = ov_opset .concat (
1137
+ [indices_shape , ones_for_start ], 0
1138
+ ).output (0 )
1139
+ start_target_shape = ov_opset .concat (
1140
+ [one_i32_array , start_shape ], 0
1141
+ ).output (0 )
1142
+ else :
1143
+ indices_target_shape = ov_opset .concat (
1144
+ [ones_for_start , indices_shape ], 0
1145
+ ).output (0 )
1146
+ start_target_shape = ov_opset .concat (
1147
+ [start_shape , one_i32_array ], 0
1148
+ ).output (0 )
1149
+
1150
+ indices_reshaped = ov_opset .reshape (
1151
+ indices , indices_target_shape , False
1152
+ ).output (0 )
1153
+ start_reshaped = ov_opset .reshape (start , start_target_shape , False ).output (
1154
+ 0
1155
+ )
1156
+ step_reshaped = ov_opset .reshape (step , start_target_shape , False ).output (0 )
1157
+
1158
+ scaled_indices = ov_opset .multiply (indices_reshaped , step_reshaped ).output (
1159
+ 0
1043
1160
)
1161
+ result = ov_opset .add (start_reshaped , scaled_indices ).output (0 )
1162
+
1163
+ if retstep :
1164
+ return OpenVINOKerasTensor (result ), OpenVINOKerasTensor (step )
1165
+ return OpenVINOKerasTensor (result )
1044
1166
1045
1167
1046
1168
def log (x ):
@@ -1171,10 +1293,30 @@ def logical_or(x1, x2):
1171
1293
1172
1294
1173
1295
def logspace (start , stop , num = 50 , endpoint = True , base = 10 , dtype = None , axis = 0 ):
1174
- raise NotImplementedError (
1175
- "`logspace` is not supported with openvino backend"
1296
+ linear_samples = linspace (
1297
+ start = start ,
1298
+ stop = stop ,
1299
+ num = num ,
1300
+ endpoint = endpoint ,
1301
+ retstep = False ,
1302
+ dtype = dtype ,
1303
+ axis = axis ,
1176
1304
)
1177
1305
1306
+ if dtype is None :
1307
+ output_type = OPENVINO_DTYPES [config .floatx ()]
1308
+ else :
1309
+ output_type = OPENVINO_DTYPES [dtype ]
1310
+
1311
+ linear_output = get_ov_output (linear_samples )
1312
+ base_tensor = get_ov_output (base )
1313
+
1314
+ base_tensor = ov_opset .convert (base_tensor , output_type ).output (0 )
1315
+
1316
+ result = ov_opset .power (base_tensor , linear_output ).output (0 )
1317
+
1318
+ return OpenVINOKerasTensor (result )
1319
+
1178
1320
1179
1321
def maximum (x1 , x2 ):
1180
1322
x1 = get_ov_output (x1 )
0 commit comments