@@ -186,5 +186,111 @@ TensorPtr randint_strided(
186186 std::uniform_int_distribution<int64_t >(low, high - 1 ));
187187}
188188
189+ TensorPtr arange (
190+ executorch::aten::Scalar start,
191+ executorch::aten::Scalar end,
192+ executorch::aten::Scalar step,
193+ std::vector<executorch::aten::SizesType> sizes,
194+ executorch::aten::ScalarType type,
195+ executorch::aten::TensorShapeDynamism dynamism) {
196+ // Calculate the number of elements in the range
197+ double start_val, end_val, step_val;
198+
199+ if (start.isFloatingPoint ()) {
200+ start_val = start.to <double >();
201+ } else if (start.isIntegral (/* includeBool=*/ false )) {
202+ start_val = static_cast <double >(start.to <int64_t >());
203+ } else {
204+ ET_CHECK_MSG (false , " start must be a number" );
205+ }
206+
207+ if (end.isFloatingPoint ()) {
208+ end_val = end.to <double >();
209+ } else if (end.isIntegral (/* includeBool=*/ false )) {
210+ end_val = static_cast <double >(end.to <int64_t >());
211+ } else {
212+ ET_CHECK_MSG (false , " end must be a number" );
213+ }
214+
215+ if (step.isFloatingPoint ()) {
216+ step_val = step.to <double >();
217+ } else if (step.isIntegral (/* includeBool=*/ false )) {
218+ step_val = static_cast <double >(step.to <int64_t >());
219+ } else {
220+ ET_CHECK_MSG (false , " step must be a number" );
221+ }
222+
223+ ET_CHECK_MSG (step_val != 0 , " step cannot be zero" );
224+
225+ // Calculate the number of elements
226+ int64_t numel =
227+ static_cast <int64_t >(std::ceil ((end_val - start_val) / step_val));
228+ numel = std::max (int64_t (0 ), numel); // Ensure non-negative
229+
230+ // Validate sizes compatibility with numel
231+ if (!sizes.empty ()) {
232+ int64_t negative_one_count = 0 ;
233+ int64_t negative_one_index = -1 ;
234+ int64_t product = 1 ;
235+
236+ // Count -1s and calculate product of positive dimensions
237+ for (size_t i = 0 ; i < sizes.size (); ++i) {
238+ if (sizes[i] == -1 ) {
239+ negative_one_count++;
240+ negative_one_index = static_cast <int64_t >(i);
241+ } else if (sizes[i] <= 0 ) {
242+ ET_CHECK_MSG (false , " sizes must contain positive integers or -1" );
243+ } else {
244+ product *= sizes[i];
245+ }
246+ }
247+
248+ // Check that there's at most one -1
249+ ET_CHECK_MSG (negative_one_count <= 1 , " sizes can contain at most one -1" );
250+
251+ if (negative_one_count == 1 ) {
252+ // Infer the -1 dimension
253+ ET_CHECK_MSG (
254+ numel % product == 0 ,
255+ " numel (%" PRId64
256+ " ) is not divisible by the product of known dimensions (%" PRId64 " )" ,
257+ numel,
258+ product);
259+ int64_t inferred_size = numel / product;
260+ ET_CHECK_MSG (
261+ inferred_size > 0 ,
262+ " inferred dimension size must be positive, got %" PRId64,
263+ inferred_size);
264+ // Update the sizes vector with the inferred dimension
265+ sizes[negative_one_index] = inferred_size;
266+ } else {
267+ // No -1, check exact match
268+ ET_CHECK_MSG (
269+ product == numel,
270+ " product of sizes (%" PRId64 " ) does not match numel (%" PRId64 " )" ,
271+ product,
272+ numel);
273+ }
274+ }
275+
276+ // Create tensor with the provided sizes or default to 1D
277+ std::vector<executorch::aten::SizesType> tensor_sizes = sizes.empty ()
278+ ? std::vector<executorch::aten::SizesType>{static_cast <
279+ executorch::aten::SizesType>(numel)}
280+ : sizes;
281+
282+ auto tensor = empty (tensor_sizes, type, dynamism);
283+
284+ // Fill the tensor with values from start to end with step
285+ ET_SWITCH_REALHBBF16_TYPES (type, nullptr , " arange" , CTYPE, [&] {
286+ CTYPE* data = tensor->mutable_data_ptr <CTYPE>();
287+ for (int64_t i = 0 ; i < numel; ++i) {
288+ data[i] = static_cast <CTYPE>(start_val + i * step_val);
289+ }
290+ });
291+
292+ return tensor;
293+ }
294+
189295} // namespace extension
190296} // namespace executorch
0 commit comments