1use std::borrow::Cow;
2
3use smallvec::{smallvec, SmallVec};
4
5use crate::{
6 constants::DEFAULT_STACK_VEC_LEN,
7 error::Result,
8 ops::{
9 broadcast_arrays, broadcast_to,
10 indexing::{count_non_new_axis_operations, expand_ellipsis_operations},
11 reshape,
12 },
13 utils::{resolve_index_signed_unchecked, VectorArray},
14 with_stream, Array, Stream,
15};
16
17use super::{
18 ArrayIndex, ArrayIndexOp, Guarded, IndexUpdateError, RangeIndex, TryIndexMutOp, UpdateMode,
19};
20
21fn non_null_i32_ptr(values: &[i32]) -> *const i32 {
22 static DUMMY: i32 = 0;
23 values.first().map_or(&DUMMY, |value| value) as *const i32
24}
25
26impl Array {
27 pub(crate) fn slice_update_device(
28 &self,
29 update: &Array,
30 starts: &[i32],
31 ends: &[i32],
32 strides: &[i32],
33 mode: UpdateMode,
34 stream: impl AsRef<Stream>,
35 ) -> std::result::Result<Array, IndexUpdateError> {
36 Array::try_from_op(|res| unsafe {
37 let start = non_null_i32_ptr(starts);
38 let stop = non_null_i32_ptr(ends);
39 let strides_ptr = non_null_i32_ptr(strides);
40 match mode {
41 UpdateMode::Replace => mlx_sys::mlx_slice_update(
42 res,
43 self.as_ptr(),
44 update.as_ptr(),
45 start,
46 starts.len(),
47 stop,
48 ends.len(),
49 strides_ptr,
50 strides.len(),
51 stream.as_ref().as_ptr(),
52 ),
53 UpdateMode::Add => mlx_sys::mlx_slice_update_add(
54 res,
55 self.as_ptr(),
56 update.as_ptr(),
57 start,
58 starts.len(),
59 stop,
60 ends.len(),
61 strides_ptr,
62 strides.len(),
63 stream.as_ref().as_ptr(),
64 ),
65 UpdateMode::Min => mlx_sys::mlx_slice_update_min(
66 res,
67 self.as_ptr(),
68 update.as_ptr(),
69 start,
70 starts.len(),
71 stop,
72 ends.len(),
73 strides_ptr,
74 strides.len(),
75 stream.as_ref().as_ptr(),
76 ),
77 UpdateMode::Max => mlx_sys::mlx_slice_update_max(
78 res,
79 self.as_ptr(),
80 update.as_ptr(),
81 start,
82 starts.len(),
83 stop,
84 ends.len(),
85 strides_ptr,
86 strides.len(),
87 stream.as_ref().as_ptr(),
88 ),
89 UpdateMode::Product => mlx_sys::mlx_slice_update_prod(
90 res,
91 self.as_ptr(),
92 update.as_ptr(),
93 start,
94 starts.len(),
95 stop,
96 ends.len(),
97 strides_ptr,
98 strides.len(),
99 stream.as_ref().as_ptr(),
100 ),
101 }
102 })
103 .map_err(IndexUpdateError::from)
104 }
105}
106
107fn update_slice(
109 src: &Array,
110 operations: &[ArrayIndexOp],
111 update: &Array,
112 mode: UpdateMode,
113 stream: impl AsRef<Stream>,
114) -> std::result::Result<Option<Array>, IndexUpdateError> {
115 let ndim = src.ndim();
116 if ndim == 0 && count_non_new_axis_operations(operations) > 0 {
117 return Ok(None);
118 }
119
120 let mut update = remove_leading_singleton_dimensions(update, &stream)?;
122
123 let mut starts: SmallVec<[i32; DEFAULT_STACK_VEC_LEN]> = smallvec![0; ndim];
125 let mut ends: SmallVec<[i32; DEFAULT_STACK_VEC_LEN]> = SmallVec::from_slice(src.shape());
126 let mut strides: SmallVec<[i32; DEFAULT_STACK_VEC_LEN]> = smallvec![1; ndim];
127
128 if operations.len() == 1 {
130 if let ArrayIndexOp::Slice(range_index) = &operations[0] {
131 let size = src.dim(0);
132 starts[0] = range_index.start(size);
133 ends[0] = range_index.end(size);
134 strides[0] = range_index.stride();
135
136 return Ok(Some(src.slice_update_device(
137 &update, &starts, &ends, &strides, mode, &stream,
138 )?));
139 }
140 }
141
142 if operations.iter().any(|op| op.is_array()) {
144 return Ok(None);
145 }
146
147 let operations = expand_ellipsis_operations(ndim, operations);
149
150 let non_new_axis_operation_count = count_non_new_axis_operations(&operations);
152 if non_new_axis_operation_count == 0 {
153 update = Cow::Owned(with_stream(stream.as_ref(), || {
154 broadcast_to(&update, src.shape())
155 })?);
156 return Ok(Some(src.slice_update_device(
157 &update, &starts, &ends, &strides, mode, &stream,
158 )?));
159 }
160
161 let mut update_reshape: SmallVec<[i32; DEFAULT_STACK_VEC_LEN]> = smallvec![0; ndim];
164 let mut axis = src.ndim() - 1;
165 let mut update_axis = update.ndim() as i32 - 1;
166
167 while axis >= non_new_axis_operation_count {
168 if update_axis >= 0 {
169 update_reshape[axis] = update.dim(update_axis);
170 update_axis -= 1;
171 } else {
172 update_reshape[axis] = 1;
173 }
174 axis -= 1;
175 }
176
177 for item in operations.iter().rev() {
178 use ArrayIndexOp::*;
179
180 match item {
181 TakeIndex { index } => {
182 let size = src.dim(axis as i32);
183 let index = if index.is_negative() {
184 size + index
185 } else {
186 *index
187 };
188 starts[axis] = index;
190 ends[axis] = index.saturating_add(1);
191
192 update_reshape[axis] = 1;
193 axis = axis.saturating_sub(1);
194 }
195 Slice(slice) => {
196 let size = src.dim(axis as i32);
197 starts[axis] = slice.start(size);
199 ends[axis] = slice.end(size);
200 strides[axis] = slice.stride();
201
202 if update_axis >= 0 {
203 update_reshape[axis] = update.dim(update_axis);
204 update_axis = update_axis.saturating_sub(1);
205 } else {
206 update_reshape[axis] = 1;
207 }
208 axis = axis.saturating_sub(1);
209 }
210 ExpandDims => {}
211 Ellipsis | TakeArray { indices: _ } | TakeArrayRef { indices: _ } => {
212 panic!("unexpected item in operations")
213 }
214 }
215 }
216
217 if update.shape() != &update_reshape[..] {
218 update = Cow::Owned(with_stream(stream.as_ref(), || {
219 reshape(update, &update_reshape)
220 })?);
221 }
222
223 Ok(Some(src.slice_update_device(
224 &update, &starts, &ends, &strides, mode, &stream,
225 )?))
226}
227
228fn remove_leading_singleton_dimensions(
230 a: &Array,
231 stream: impl AsRef<Stream>,
232) -> Result<Cow<'_, Array>> {
233 let shape = a.shape();
234 let mut new_shape: Vec<_> = shape.iter().skip_while(|&&dim| dim == 1).cloned().collect();
235 if shape != new_shape {
236 if new_shape.is_empty() {
237 new_shape = vec![1];
238 }
239 Ok(Cow::Owned(with_stream(stream.as_ref(), || {
240 a.reshape(&new_shape)
241 })?))
242 } else {
243 Ok(Cow::Borrowed(a))
244 }
245}
246
247struct ScatterArgs<'a> {
248 indices: SmallVec<[Cow<'a, Array>; DEFAULT_STACK_VEC_LEN]>,
249 update: Array,
250 axes: SmallVec<[i32; DEFAULT_STACK_VEC_LEN]>,
251}
252
253fn scatter_args<'a>(
255 src: &'a Array,
256 operations: &'a [ArrayIndexOp],
257 update: &Array,
258 stream: impl AsRef<Stream>,
259) -> Result<ScatterArgs<'a>> {
260 use ArrayIndexOp::*;
261
262 if operations.len() == 1 {
263 return match &operations[0] {
264 TakeIndex { index } => scatter_args_index(src, *index, update, stream),
265 TakeArray { indices } => {
266 scatter_args_array(src, Cow::Borrowed(indices), update, stream)
267 }
268 TakeArrayRef { indices } => {
269 scatter_args_array(src, Cow::Borrowed(indices), update, stream)
270 }
271 Slice(range_index) => scatter_args_slice(src, range_index, update, stream),
272 ExpandDims => Ok(ScatterArgs {
273 indices: smallvec![],
274 update: with_stream(stream.as_ref(), || broadcast_to(update, src.shape()))?,
275 axes: smallvec![],
276 }),
277 Ellipsis => panic!("Unable to update array with ellipsis argument"),
278 };
279 }
280
281 scatter_args_nd(src, operations, update, stream)
282}
283
284fn scatter_args_index<'a>(
285 src: &'a Array,
286 index: i32,
287 update: &Array,
288 stream: impl AsRef<Stream>,
289) -> Result<ScatterArgs<'a>> {
290 let update = remove_leading_singleton_dimensions(update, &stream)?;
295
296 let mut shape: SmallVec<[i32; DEFAULT_STACK_VEC_LEN]> = SmallVec::from_slice(src.shape());
297 shape[0] = 1;
298
299 Ok(ScatterArgs {
300 indices: smallvec![Cow::Owned(Array::from_int(resolve_index_signed_unchecked(
301 index,
302 src.dim(0)
303 )))],
304 update: with_stream(stream.as_ref(), || broadcast_to(&update, &shape))?,
305 axes: smallvec![0],
306 })
307}
308
309fn scatter_args_array<'a>(
310 src: &'a Array,
311 a: Cow<'a, Array>,
312 update: &Array,
313 stream: impl AsRef<Stream>,
314) -> Result<ScatterArgs<'a>> {
315 let update = remove_leading_singleton_dimensions(update, &stream)?;
319
320 let mut update_shape: SmallVec<[i32; DEFAULT_STACK_VEC_LEN]> = a
322 .shape()
323 .iter()
324 .chain(src.shape().iter().skip(1))
325 .cloned()
326 .collect();
327 let update = with_stream(stream.as_ref(), || broadcast_to(&update, &update_shape))?;
328
329 update_shape.insert(a.ndim(), 1);
330 let update = with_stream(stream.as_ref(), || update.reshape(&update_shape))?;
331
332 Ok(ScatterArgs {
333 indices: smallvec![a],
334 update,
335 axes: smallvec![0],
336 })
337}
338
339fn scatter_args_slice<'a>(
340 src: &'a Array,
341 range_index: &'a RangeIndex,
342 update: &Array,
343 stream: impl AsRef<Stream>,
344) -> Result<ScatterArgs<'a>> {
345 if range_index.is_full() {
349 let update = remove_leading_singleton_dimensions(update, &stream)?;
350
351 return Ok(ScatterArgs {
352 indices: smallvec![],
353 update: with_stream(stream.as_ref(), || broadcast_to(&update, src.shape()))?,
354 axes: smallvec![],
355 });
356 }
357
358 let size = src.dim(0);
359 let start = range_index.start(size);
360 let end = range_index.end(size);
361 let stride = range_index.stride();
362
363 if stride == 1 {
365 let update = remove_leading_singleton_dimensions(update, &stream)?;
366
367 let update_broadcast_shape: SmallVec<[i32; DEFAULT_STACK_VEC_LEN]> = (1..end - start)
369 .chain(src.shape().iter().skip(1).cloned())
370 .collect();
371 let update = with_stream(stream.as_ref(), || {
372 broadcast_to(&update, &update_broadcast_shape)
373 })?;
374
375 let indices = Array::from_slice(&[start], &[1]);
376 Ok(ScatterArgs {
377 indices: smallvec![Cow::Owned(indices)],
378 update,
379 axes: smallvec![0],
380 })
381 } else {
382 let a_vals = strided_range_to_vec(start, end, stride);
384 let a = Array::from_slice(&a_vals, &[a_vals.len() as i32]);
385
386 scatter_args_array(src, Cow::Owned(a), update, stream)
387 }
388}
389
390fn scatter_args_nd<'a>(
391 src: &'a Array,
392 operations: &[ArrayIndexOp],
393 update: &Array,
394 stream: impl AsRef<Stream>,
395) -> Result<ScatterArgs<'a>> {
396 use ArrayIndexOp::*;
397
398 let shape = src.shape();
401
402 let operations = expand_ellipsis_operations(src.ndim(), operations);
403 let update = remove_leading_singleton_dimensions(update, &stream)?;
404
405 let non_new_axis_operation_count = count_non_new_axis_operations(&operations);
407 if non_new_axis_operation_count == 0 {
408 return Ok(ScatterArgs {
409 indices: smallvec![],
410 update: with_stream(stream.as_ref(), || broadcast_to(&update, shape))?,
411 axes: smallvec![],
412 });
413 }
414
415 let mut max_dims = 0;
417 let mut arrays_first = false;
418 let mut count_new_axis: i32 = 0;
419 let mut count_slices: i32 = 0;
420 let mut count_arrays: i32 = 0;
421 let mut count_strided_slices: i32 = 0;
422 let mut count_simple_slices_post: i32 = 0;
423
424 let mut have_array = false;
425 let mut have_non_array = false;
426
427 macro_rules! analyze_indices_take_array {
428 ($indices:ident) => {
429 have_array = true;
430 if have_array && have_non_array {
431 arrays_first = true;
432 }
433 max_dims = $indices.ndim().max(max_dims);
434 count_arrays = count_arrays.saturating_add(1);
435 count_simple_slices_post = 0;
436 };
437 }
438
439 for item in operations.iter() {
440 match item {
441 TakeIndex { index: _ } => {
442 }
444 Slice(range_index) => {
445 have_non_array = have_array;
446 count_slices = count_slices.saturating_add(1);
447 if range_index.stride() != 1 {
448 count_strided_slices = count_strided_slices.saturating_add(1);
449 count_simple_slices_post = 0;
450 } else {
451 count_simple_slices_post = count_simple_slices_post.saturating_add(1);
452 }
453 }
454 TakeArray { indices } => {
455 analyze_indices_take_array!(indices);
456 }
457 TakeArrayRef { indices } => {
458 analyze_indices_take_array!(indices);
459 }
460 ExpandDims => {
461 have_non_array = true;
462 count_new_axis = count_new_axis.saturating_add(1);
463 }
464 Ellipsis => panic!("Unexpected item ellipsis in scatter_args_nd"),
465 }
466 }
467
468 let mut index_dims = (max_dims + count_new_axis as usize + count_slices as usize)
470 .saturating_sub(count_simple_slices_post as usize);
471
472 if index_dims == 0 {
474 index_dims = 1;
475 }
476
477 let mut array_indices: SmallVec<[Array; DEFAULT_STACK_VEC_LEN]> =
479 SmallVec::with_capacity(operations.len());
480 let mut slice_number: i32 = 0;
481 let mut array_number: i32 = 0;
482 let mut axis: i32 = 0;
483
484 let mut update_shape = vec![1; non_new_axis_operation_count];
486 let mut slice_shapes: SmallVec<[i32; DEFAULT_STACK_VEC_LEN]> = SmallVec::new();
487
488 macro_rules! update_shapes_take_array {
489 ($indices:ident) => {
490 let start = if arrays_first {
492 max_dims - $indices.ndim()
493 } else {
494 slice_number as usize + max_dims - $indices.ndim()
496 };
497 let mut new_shape = vec![1; index_dims];
498
499 for j in 0..$indices.ndim() {
500 new_shape[start + j] = $indices.dim(j as i32);
501 }
502
503 array_indices.push(with_stream(stream.as_ref(), || {
504 $indices.reshape(&new_shape)
505 })?);
506 array_number = array_number.saturating_add(1);
507
508 if !arrays_first && array_number == count_arrays {
509 slice_number = slice_number.saturating_add_unsigned(max_dims as u32);
510 }
511
512 update_shape[axis as usize] = 1;
514 axis = axis.saturating_add(1);
515 };
516 }
517
518 for item in operations.iter() {
519 match item {
520 TakeIndex { index } => {
521 let resolved_index = resolve_index_signed_unchecked(*index, src.dim(axis));
522 array_indices.push(Array::from_int(resolved_index));
523 update_shape[axis as usize] = 1;
525 axis = axis.saturating_add(1);
526 }
527 Slice(range_index) => {
528 let size = src.dim(axis);
529 let start = range_index.absolute_start(size);
530 let end = range_index.absolute_end(size);
531 let stride = range_index.stride();
532
533 let mut index_shape = vec![1; index_dims];
534
535 if array_number >= count_arrays && count_strided_slices <= 0 && stride == 1 {
537 let index = with_stream(stream.as_ref(), || {
538 Array::from_int(start).reshape(&index_shape)
539 })?;
540 let slice_shape_entry = end - start;
541 slice_shapes.push(slice_shape_entry);
542 array_indices.push(index);
543
544 update_shape[axis as usize] = slice_shape_entry;
546 } else {
547 let index_vals = strided_range_to_vec(start, end, stride);
549 let index = Array::from_slice(&index_vals, &[index_vals.len() as i32]);
550 let location = if arrays_first {
551 slice_number.saturating_add(max_dims as i32)
552 } else {
553 slice_number
554 };
555 index_shape[location as usize] = index.size() as i32;
556 array_indices.push(with_stream(stream.as_ref(), || {
557 index.reshape(&index_shape)
558 })?);
559
560 slice_number = slice_number.saturating_add(1);
561 count_strided_slices = count_strided_slices.saturating_sub(1);
562
563 update_shape[axis as usize] = 1;
565 }
566
567 axis = axis.saturating_add(1);
568 }
569 TakeArray { indices } => {
570 update_shapes_take_array!(indices);
571 }
572 TakeArrayRef { indices } => {
573 update_shapes_take_array!(indices);
574 }
575 ExpandDims => slice_number = slice_number.saturating_add(1),
576 Ellipsis => panic!("Unexpected item ellipsis in scatter_args_nd"),
577 }
578 }
579
580 let array_indices = with_stream(stream.as_ref(), || broadcast_arrays(&array_indices))?;
582 let update_shape_broadcast: Vec<_> = array_indices[0]
583 .shape()
584 .iter()
585 .chain(slice_shapes.iter())
586 .chain(src.shape().iter().skip(non_new_axis_operation_count))
587 .cloned()
588 .collect();
589 let update = with_stream(stream.as_ref(), || {
590 broadcast_to(&update, &update_shape_broadcast)
591 })?;
592
593 let update_reshape: Vec<_> = array_indices[0]
595 .shape()
596 .iter()
597 .chain(update_shape.iter())
598 .chain(src.shape().iter().skip(non_new_axis_operation_count))
599 .cloned()
600 .collect();
601
602 let update = with_stream(stream.as_ref(), || update.reshape(&update_reshape))?;
603
604 let array_indices_len = array_indices.len();
605
606 let indices = array_indices.into_iter().map(Cow::Owned).collect();
607 Ok(ScatterArgs {
608 indices,
609 update,
610 axes: (0..array_indices_len as i32).collect(),
611 })
612}
613
614fn strided_range_to_vec(start: i32, exclusive_end: i32, stride: i32) -> Vec<i32> {
615 let estimated_capacity = (exclusive_end - start).abs() / stride.abs();
616 let mut vec = Vec::with_capacity(estimated_capacity as usize);
617 let mut current = start;
618
619 if stride.is_negative() {
620 while current > exclusive_end {
621 vec.push(current);
622 current += stride;
623 }
624 } else {
625 while current < exclusive_end {
626 vec.push(current);
627 current += stride;
628 }
629 }
630
631 vec
632}
633
634unsafe fn scatter_device(
635 a: &Array,
636 indices: &[impl AsRef<Array>],
637 updates: &Array,
638 axes: &[i32],
639 mode: UpdateMode,
640 stream: impl AsRef<Stream>,
641) -> std::result::Result<Array, IndexUpdateError> {
642 let indices_vector = VectorArray::try_from_iter(indices.iter())?;
643
644 Array::try_from_op(|res| unsafe {
645 let axes_ptr = non_null_i32_ptr(axes);
646 match mode {
647 UpdateMode::Replace => mlx_sys::mlx_scatter(
648 res,
649 a.as_ptr(),
650 indices_vector.as_ptr(),
651 updates.as_ptr(),
652 axes_ptr,
653 axes.len(),
654 stream.as_ref().as_ptr(),
655 ),
656 UpdateMode::Add => mlx_sys::mlx_scatter_add(
657 res,
658 a.as_ptr(),
659 indices_vector.as_ptr(),
660 updates.as_ptr(),
661 axes_ptr,
662 axes.len(),
663 stream.as_ref().as_ptr(),
664 ),
665 UpdateMode::Min => mlx_sys::mlx_scatter_min(
666 res,
667 a.as_ptr(),
668 indices_vector.as_ptr(),
669 updates.as_ptr(),
670 axes_ptr,
671 axes.len(),
672 stream.as_ref().as_ptr(),
673 ),
674 UpdateMode::Max => mlx_sys::mlx_scatter_max(
675 res,
676 a.as_ptr(),
677 indices_vector.as_ptr(),
678 updates.as_ptr(),
679 axes_ptr,
680 axes.len(),
681 stream.as_ref().as_ptr(),
682 ),
683 UpdateMode::Product => mlx_sys::mlx_scatter_prod(
684 res,
685 a.as_ptr(),
686 indices_vector.as_ptr(),
687 updates.as_ptr(),
688 axes_ptr,
689 axes.len(),
690 stream.as_ref().as_ptr(),
691 ),
692 }
693 })
694 .map_err(IndexUpdateError::from)
695}
696
697fn validate_strides(operations: &[ArrayIndexOp]) -> std::result::Result<(), IndexUpdateError> {
698 let mut axis = 0;
699 for operation in operations {
700 match operation {
701 ArrayIndexOp::Slice(range) => {
702 if range.stride() == 0 {
703 return Err(IndexUpdateError::ZeroStride { axis });
704 }
705 axis += 1;
706 }
707 ArrayIndexOp::TakeIndex { .. }
708 | ArrayIndexOp::TakeArray { .. }
709 | ArrayIndexOp::TakeArrayRef { .. } => axis += 1,
710 ArrayIndexOp::ExpandDims => {}
711 ArrayIndexOp::Ellipsis => unreachable!("ellipsis is expanded before validation"),
712 }
713 }
714 Ok(())
715}
716
717fn validate_index_structure(
718 ndim: usize,
719 operations: &[ArrayIndexOp],
720) -> std::result::Result<(), IndexUpdateError> {
721 let ellipsis_count = operations
722 .iter()
723 .filter(|operation| matches!(operation, ArrayIndexOp::Ellipsis))
724 .count();
725 if ellipsis_count > 1 {
726 return Err(IndexUpdateError::Exception(
727 crate::error::Exception::custom("multiple ellipses are not supported"),
728 ));
729 }
730
731 let source_axes = operations
732 .iter()
733 .filter(|operation| !matches!(operation, ArrayIndexOp::ExpandDims | ArrayIndexOp::Ellipsis))
734 .count();
735 if source_axes > ndim {
736 return Err(IndexUpdateError::Exception(
737 crate::error::Exception::custom(format!(
738 "too many indices for array with {ndim} dimensions"
739 )),
740 ));
741 }
742
743 Ok(())
744}
745
746pub(super) fn try_index_update_operations(
747 source: &Array,
748 operations: &[ArrayIndexOp],
749 update: &Array,
750 mode: UpdateMode,
751) -> std::result::Result<Array, IndexUpdateError> {
752 let stream = Stream::thread_local_or_default();
753 validate_index_structure(source.ndim(), operations)?;
754 let operations = expand_ellipsis_operations(source.ndim(), operations);
755 validate_strides(&operations)?;
756
757 if let Some(result) = update_slice(source, &operations, update, mode, &stream)? {
758 return Ok(result);
759 }
760
761 let ScatterArgs {
762 indices,
763 update,
764 axes,
765 } = scatter_args(source, &operations, update, &stream)?;
766 if indices.is_empty() {
767 return Ok(update);
768 }
769
770 let result = unsafe { scatter_device(source, &indices, &update, &axes, mode, stream)? };
771 drop(indices);
772 Ok(result)
773}
774
775impl Array {
776 fn try_index_mut_device_inner(
777 &mut self,
778 operations: &[ArrayIndexOp],
779 update: &Array,
780 stream: impl AsRef<Stream>,
781 ) -> Result<()> {
782 let result = with_stream(stream.as_ref(), || {
783 try_index_update_operations(self, operations, update, UpdateMode::Replace)
784 })
785 .map_err(|error| match error {
786 IndexUpdateError::ZeroStride { .. } => {
787 crate::error::Exception::custom(error.to_string())
788 }
789 IndexUpdateError::Exception(error) => error,
790 })?;
791 *self = result;
792 Ok(())
793 }
794}
795
796impl<'a, Val> TryIndexMutOp<&'a [ArrayIndexOp<'a>], Val> for Array
797where
798 Val: AsRef<Array>,
799{
800 fn try_index_mut_device(
801 &mut self,
802 i: &'a [ArrayIndexOp<'a>],
803 val: Val,
804 stream: impl AsRef<Stream>,
805 ) -> Result<()> {
806 let update = val.as_ref();
807 self.try_index_mut_device_inner(i, update, stream)
808 }
809}
810
811impl<A, Val> TryIndexMutOp<A, Val> for Array
812where
813 for<'a> A: ArrayIndex<'a>,
814 Val: AsRef<Array>,
815{
816 fn try_index_mut_device(&mut self, i: A, val: Val, stream: impl AsRef<Stream>) -> Result<()> {
817 let operations = [i.index_op()];
818 let update = val.as_ref();
819 self.try_index_mut_device_inner(&operations, update, stream)
820 }
821}
822
823impl<'a, A, Val> TryIndexMutOp<(A,), Val> for Array
824where
825 A: ArrayIndex<'a>,
826 Val: AsRef<Array>,
827{
828 fn try_index_mut_device(
829 &mut self,
830 (i,): (A,),
831 val: Val,
832 stream: impl AsRef<Stream>,
833 ) -> Result<()> {
834 let operations = [i.index_op()];
835 let update = val.as_ref();
836 self.try_index_mut_device_inner(&operations, update, stream)
837 }
838}
839
840impl<'a, 'b, A, B, Val> TryIndexMutOp<(A, B), Val> for Array
841where
842 A: ArrayIndex<'a>,
843 B: ArrayIndex<'b>,
844 Val: AsRef<Array>,
845{
846 fn try_index_mut_device(
847 &mut self,
848 i: (A, B),
849 val: Val,
850 stream: impl AsRef<Stream>,
851 ) -> Result<()> {
852 let operations = [i.0.index_op(), i.1.index_op()];
853 let update = val.as_ref();
854 self.try_index_mut_device_inner(&operations, update, stream)
855 }
856}
857
858impl<'a, 'b, 'c, A, B, C, Val> TryIndexMutOp<(A, B, C), Val> for Array
859where
860 A: ArrayIndex<'a>,
861 B: ArrayIndex<'b>,
862 C: ArrayIndex<'c>,
863 Val: AsRef<Array>,
864{
865 fn try_index_mut_device(
866 &mut self,
867 i: (A, B, C),
868 val: Val,
869 stream: impl AsRef<Stream>,
870 ) -> Result<()> {
871 let operations = [i.0.index_op(), i.1.index_op(), i.2.index_op()];
872 let update = val.as_ref();
873 self.try_index_mut_device_inner(&operations, update, stream)
874 }
875}
876
877impl<'a, 'b, 'c, 'd, A, B, C, D, Val> TryIndexMutOp<(A, B, C, D), Val> for Array
878where
879 A: ArrayIndex<'a>,
880 B: ArrayIndex<'b>,
881 C: ArrayIndex<'c>,
882 D: ArrayIndex<'d>,
883 Val: AsRef<Array>,
884{
885 fn try_index_mut_device(
886 &mut self,
887 i: (A, B, C, D),
888 val: Val,
889 stream: impl AsRef<Stream>,
890 ) -> Result<()> {
891 let operations = [
892 i.0.index_op(),
893 i.1.index_op(),
894 i.2.index_op(),
895 i.3.index_op(),
896 ];
897 let update = val.as_ref();
898 self.try_index_mut_device_inner(&operations, update, stream)
899 }
900}
901
902impl<'a, 'b, 'c, 'd, 'e, A, B, C, D, E, Val> TryIndexMutOp<(A, B, C, D, E), Val> for Array
903where
904 A: ArrayIndex<'a>,
905 B: ArrayIndex<'b>,
906 C: ArrayIndex<'c>,
907 D: ArrayIndex<'d>,
908 E: ArrayIndex<'e>,
909 Val: AsRef<Array>,
910{
911 fn try_index_mut_device(
912 &mut self,
913 i: (A, B, C, D, E),
914 val: Val,
915 stream: impl AsRef<Stream>,
916 ) -> Result<()> {
917 let operations = [
918 i.0.index_op(),
919 i.1.index_op(),
920 i.2.index_op(),
921 i.3.index_op(),
922 i.4.index_op(),
923 ];
924 let update = val.as_ref();
925 self.try_index_mut_device_inner(&operations, update, stream)
926 }
927}
928
929impl<'a, 'b, 'c, 'd, 'e, 'f, A, B, C, D, E, F, Val> TryIndexMutOp<(A, B, C, D, E, F), Val> for Array
930where
931 A: ArrayIndex<'a>,
932 B: ArrayIndex<'b>,
933 C: ArrayIndex<'c>,
934 D: ArrayIndex<'d>,
935 E: ArrayIndex<'e>,
936 F: ArrayIndex<'f>,
937 Val: AsRef<Array>,
938{
939 fn try_index_mut_device(
940 &mut self,
941 i: (A, B, C, D, E, F),
942 val: Val,
943 stream: impl AsRef<Stream>,
944 ) -> Result<()> {
945 let operations = [
946 i.0.index_op(),
947 i.1.index_op(),
948 i.2.index_op(),
949 i.3.index_op(),
950 i.4.index_op(),
951 i.5.index_op(),
952 ];
953 let update = val.as_ref();
954 self.try_index_mut_device_inner(&operations, update, stream)
955 }
956}
957
958impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, A, B, C, D, E, F, G, Val> TryIndexMutOp<(A, B, C, D, E, F, G), Val>
959 for Array
960where
961 A: ArrayIndex<'a>,
962 B: ArrayIndex<'b>,
963 C: ArrayIndex<'c>,
964 D: ArrayIndex<'d>,
965 E: ArrayIndex<'e>,
966 F: ArrayIndex<'f>,
967 G: ArrayIndex<'g>,
968 Val: AsRef<Array>,
969{
970 fn try_index_mut_device(
971 &mut self,
972 i: (A, B, C, D, E, F, G),
973 val: Val,
974 stream: impl AsRef<Stream>,
975 ) -> Result<()> {
976 let operations = [
977 i.0.index_op(),
978 i.1.index_op(),
979 i.2.index_op(),
980 i.3.index_op(),
981 i.4.index_op(),
982 i.5.index_op(),
983 i.6.index_op(),
984 ];
985 let update = val.as_ref();
986 self.try_index_mut_device_inner(&operations, update, stream)
987 }
988}
989
990impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, A, B, C, D, E, F, G, H, Val>
991 TryIndexMutOp<(A, B, C, D, E, F, G, H), Val> for Array
992where
993 A: ArrayIndex<'a>,
994 B: ArrayIndex<'b>,
995 C: ArrayIndex<'c>,
996 D: ArrayIndex<'d>,
997 E: ArrayIndex<'e>,
998 F: ArrayIndex<'f>,
999 G: ArrayIndex<'g>,
1000 H: ArrayIndex<'h>,
1001 Val: AsRef<Array>,
1002{
1003 fn try_index_mut_device(
1004 &mut self,
1005 i: (A, B, C, D, E, F, G, H),
1006 val: Val,
1007 stream: impl AsRef<Stream>,
1008 ) -> Result<()> {
1009 let operations = [
1010 i.0.index_op(),
1011 i.1.index_op(),
1012 i.2.index_op(),
1013 i.3.index_op(),
1014 i.4.index_op(),
1015 i.5.index_op(),
1016 i.6.index_op(),
1017 i.7.index_op(),
1018 ];
1019 let update = val.as_ref();
1020 self.try_index_mut_device_inner(&operations, update, stream)
1021 }
1022}
1023
1024impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, A, B, C, D, E, F, G, H, I, Val>
1025 TryIndexMutOp<(A, B, C, D, E, F, G, H, I), Val> for Array
1026where
1027 A: ArrayIndex<'a>,
1028 B: ArrayIndex<'b>,
1029 C: ArrayIndex<'c>,
1030 D: ArrayIndex<'d>,
1031 E: ArrayIndex<'e>,
1032 F: ArrayIndex<'f>,
1033 G: ArrayIndex<'g>,
1034 H: ArrayIndex<'h>,
1035 I: ArrayIndex<'i>,
1036 Val: AsRef<Array>,
1037{
1038 fn try_index_mut_device(
1039 &mut self,
1040 i: (A, B, C, D, E, F, G, H, I),
1041 val: Val,
1042 stream: impl AsRef<Stream>,
1043 ) -> Result<()> {
1044 let operations = [
1045 i.0.index_op(),
1046 i.1.index_op(),
1047 i.2.index_op(),
1048 i.3.index_op(),
1049 i.4.index_op(),
1050 i.5.index_op(),
1051 i.6.index_op(),
1052 i.7.index_op(),
1053 i.8.index_op(),
1054 ];
1055 let update = val.as_ref();
1056 self.try_index_mut_device_inner(&operations, update, stream)
1057 }
1058}
1059
1060impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, A, B, C, D, E, F, G, H, I, J, Val>
1061 TryIndexMutOp<(A, B, C, D, E, F, G, H, I, J), Val> for Array
1062where
1063 A: ArrayIndex<'a>,
1064 B: ArrayIndex<'b>,
1065 C: ArrayIndex<'c>,
1066 D: ArrayIndex<'d>,
1067 E: ArrayIndex<'e>,
1068 F: ArrayIndex<'f>,
1069 G: ArrayIndex<'g>,
1070 H: ArrayIndex<'h>,
1071 I: ArrayIndex<'i>,
1072 J: ArrayIndex<'j>,
1073 Val: AsRef<Array>,
1074{
1075 fn try_index_mut_device(
1076 &mut self,
1077 i: (A, B, C, D, E, F, G, H, I, J),
1078 val: Val,
1079 stream: impl AsRef<Stream>,
1080 ) -> Result<()> {
1081 let operations = [
1082 i.0.index_op(),
1083 i.1.index_op(),
1084 i.2.index_op(),
1085 i.3.index_op(),
1086 i.4.index_op(),
1087 i.5.index_op(),
1088 i.6.index_op(),
1089 i.7.index_op(),
1090 i.8.index_op(),
1091 i.9.index_op(),
1092 ];
1093 let update = val.as_ref();
1094 self.try_index_mut_device_inner(&operations, update, stream)
1095 }
1096}
1097
1098impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, A, B, C, D, E, F, G, H, I, J, K, Val>
1099 TryIndexMutOp<(A, B, C, D, E, F, G, H, I, J, K), Val> for Array
1100where
1101 A: ArrayIndex<'a>,
1102 B: ArrayIndex<'b>,
1103 C: ArrayIndex<'c>,
1104 D: ArrayIndex<'d>,
1105 E: ArrayIndex<'e>,
1106 F: ArrayIndex<'f>,
1107 G: ArrayIndex<'g>,
1108 H: ArrayIndex<'h>,
1109 I: ArrayIndex<'i>,
1110 J: ArrayIndex<'j>,
1111 K: ArrayIndex<'k>,
1112 Val: AsRef<Array>,
1113{
1114 fn try_index_mut_device(
1115 &mut self,
1116 i: (A, B, C, D, E, F, G, H, I, J, K),
1117 val: Val,
1118 stream: impl AsRef<Stream>,
1119 ) -> Result<()> {
1120 let operations = [
1121 i.0.index_op(),
1122 i.1.index_op(),
1123 i.2.index_op(),
1124 i.3.index_op(),
1125 i.4.index_op(),
1126 i.5.index_op(),
1127 i.6.index_op(),
1128 i.7.index_op(),
1129 i.8.index_op(),
1130 i.9.index_op(),
1131 i.10.index_op(),
1132 ];
1133 let update = val.as_ref();
1134 self.try_index_mut_device_inner(&operations, update, stream)
1135 }
1136}
1137
1138impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'l, A, B, C, D, E, F, G, H, I, J, K, L, Val>
1139 TryIndexMutOp<(A, B, C, D, E, F, G, H, I, J, K, L), Val> for Array
1140where
1141 A: ArrayIndex<'a>,
1142 B: ArrayIndex<'b>,
1143 C: ArrayIndex<'c>,
1144 D: ArrayIndex<'d>,
1145 E: ArrayIndex<'e>,
1146 F: ArrayIndex<'f>,
1147 G: ArrayIndex<'g>,
1148 H: ArrayIndex<'h>,
1149 I: ArrayIndex<'i>,
1150 J: ArrayIndex<'j>,
1151 K: ArrayIndex<'k>,
1152 L: ArrayIndex<'l>,
1153 Val: AsRef<Array>,
1154{
1155 fn try_index_mut_device(
1156 &mut self,
1157 i: (A, B, C, D, E, F, G, H, I, J, K, L),
1158 val: Val,
1159 stream: impl AsRef<Stream>,
1160 ) -> Result<()> {
1161 let operations = [
1162 i.0.index_op(),
1163 i.1.index_op(),
1164 i.2.index_op(),
1165 i.3.index_op(),
1166 i.4.index_op(),
1167 i.5.index_op(),
1168 i.6.index_op(),
1169 i.7.index_op(),
1170 i.8.index_op(),
1171 i.9.index_op(),
1172 i.10.index_op(),
1173 i.11.index_op(),
1174 ];
1175 let update = val.as_ref();
1176 self.try_index_mut_device_inner(&operations, update, stream)
1177 }
1178}
1179
1180impl<
1181 'a,
1182 'b,
1183 'c,
1184 'd,
1185 'e,
1186 'f,
1187 'g,
1188 'h,
1189 'i,
1190 'j,
1191 'k,
1192 'l,
1193 'm,
1194 A,
1195 B,
1196 C,
1197 D,
1198 E,
1199 F,
1200 G,
1201 H,
1202 I,
1203 J,
1204 K,
1205 L,
1206 M,
1207 Val,
1208 > TryIndexMutOp<(A, B, C, D, E, F, G, H, I, J, K, L, M), Val> for Array
1209where
1210 A: ArrayIndex<'a>,
1211 B: ArrayIndex<'b>,
1212 C: ArrayIndex<'c>,
1213 D: ArrayIndex<'d>,
1214 E: ArrayIndex<'e>,
1215 F: ArrayIndex<'f>,
1216 G: ArrayIndex<'g>,
1217 H: ArrayIndex<'h>,
1218 I: ArrayIndex<'i>,
1219 J: ArrayIndex<'j>,
1220 K: ArrayIndex<'k>,
1221 L: ArrayIndex<'l>,
1222 M: ArrayIndex<'m>,
1223 Val: AsRef<Array>,
1224{
1225 fn try_index_mut_device(
1226 &mut self,
1227 i: (A, B, C, D, E, F, G, H, I, J, K, L, M),
1228 val: Val,
1229 stream: impl AsRef<Stream>,
1230 ) -> Result<()> {
1231 let operations = [
1232 i.0.index_op(),
1233 i.1.index_op(),
1234 i.2.index_op(),
1235 i.3.index_op(),
1236 i.4.index_op(),
1237 i.5.index_op(),
1238 i.6.index_op(),
1239 i.7.index_op(),
1240 i.8.index_op(),
1241 i.9.index_op(),
1242 i.10.index_op(),
1243 i.11.index_op(),
1244 i.12.index_op(),
1245 ];
1246 let update = val.as_ref();
1247 self.try_index_mut_device_inner(&operations, update, stream)
1248 }
1249}
1250
1251impl<
1252 'a,
1253 'b,
1254 'c,
1255 'd,
1256 'e,
1257 'f,
1258 'g,
1259 'h,
1260 'i,
1261 'j,
1262 'k,
1263 'l,
1264 'm,
1265 'n,
1266 A,
1267 B,
1268 C,
1269 D,
1270 E,
1271 F,
1272 G,
1273 H,
1274 I,
1275 J,
1276 K,
1277 L,
1278 M,
1279 N,
1280 Val,
1281 > TryIndexMutOp<(A, B, C, D, E, F, G, H, I, J, K, L, M, N), Val> for Array
1282where
1283 A: ArrayIndex<'a>,
1284 B: ArrayIndex<'b>,
1285 C: ArrayIndex<'c>,
1286 D: ArrayIndex<'d>,
1287 E: ArrayIndex<'e>,
1288 F: ArrayIndex<'f>,
1289 G: ArrayIndex<'g>,
1290 H: ArrayIndex<'h>,
1291 I: ArrayIndex<'i>,
1292 J: ArrayIndex<'j>,
1293 K: ArrayIndex<'k>,
1294 L: ArrayIndex<'l>,
1295 M: ArrayIndex<'m>,
1296 N: ArrayIndex<'n>,
1297 Val: AsRef<Array>,
1298{
1299 fn try_index_mut_device(
1300 &mut self,
1301 i: (A, B, C, D, E, F, G, H, I, J, K, L, M, N),
1302 val: Val,
1303 stream: impl AsRef<Stream>,
1304 ) -> Result<()> {
1305 let operations = [
1306 i.0.index_op(),
1307 i.1.index_op(),
1308 i.2.index_op(),
1309 i.3.index_op(),
1310 i.4.index_op(),
1311 i.5.index_op(),
1312 i.6.index_op(),
1313 i.7.index_op(),
1314 i.8.index_op(),
1315 i.9.index_op(),
1316 i.10.index_op(),
1317 i.11.index_op(),
1318 i.12.index_op(),
1319 i.13.index_op(),
1320 ];
1321 let update = val.as_ref();
1322 self.try_index_mut_device_inner(&operations, update, stream)
1323 }
1324}
1325
1326impl<
1327 'a,
1328 'b,
1329 'c,
1330 'd,
1331 'e,
1332 'f,
1333 'g,
1334 'h,
1335 'i,
1336 'j,
1337 'k,
1338 'l,
1339 'm,
1340 'n,
1341 'o,
1342 A,
1343 B,
1344 C,
1345 D,
1346 E,
1347 F,
1348 G,
1349 H,
1350 I,
1351 J,
1352 K,
1353 L,
1354 M,
1355 N,
1356 O,
1357 Val,
1358 > TryIndexMutOp<(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), Val> for Array
1359where
1360 A: ArrayIndex<'a>,
1361 B: ArrayIndex<'b>,
1362 C: ArrayIndex<'c>,
1363 D: ArrayIndex<'d>,
1364 E: ArrayIndex<'e>,
1365 F: ArrayIndex<'f>,
1366 G: ArrayIndex<'g>,
1367 H: ArrayIndex<'h>,
1368 I: ArrayIndex<'i>,
1369 J: ArrayIndex<'j>,
1370 K: ArrayIndex<'k>,
1371 L: ArrayIndex<'l>,
1372 M: ArrayIndex<'m>,
1373 N: ArrayIndex<'n>,
1374 O: ArrayIndex<'o>,
1375 Val: AsRef<Array>,
1376{
1377 fn try_index_mut_device(
1378 &mut self,
1379 i: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O),
1380 val: Val,
1381 stream: impl AsRef<Stream>,
1382 ) -> Result<()> {
1383 let operations = [
1384 i.0.index_op(),
1385 i.1.index_op(),
1386 i.2.index_op(),
1387 i.3.index_op(),
1388 i.4.index_op(),
1389 i.5.index_op(),
1390 i.6.index_op(),
1391 i.7.index_op(),
1392 i.8.index_op(),
1393 i.9.index_op(),
1394 i.10.index_op(),
1395 i.11.index_op(),
1396 i.12.index_op(),
1397 i.13.index_op(),
1398 i.14.index_op(),
1399 ];
1400 let update = val.as_ref();
1401 self.try_index_mut_device_inner(&operations, update, stream)
1402 }
1403}
1404
1405impl<
1406 'a,
1407 'b,
1408 'c,
1409 'd,
1410 'e,
1411 'f,
1412 'g,
1413 'h,
1414 'i,
1415 'j,
1416 'k,
1417 'l,
1418 'm,
1419 'n,
1420 'o,
1421 'p,
1422 A,
1423 B,
1424 C,
1425 D,
1426 E,
1427 F,
1428 G,
1429 H,
1430 I,
1431 J,
1432 K,
1433 L,
1434 M,
1435 N,
1436 O,
1437 P,
1438 Val,
1439 > TryIndexMutOp<(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P), Val> for Array
1440where
1441 A: ArrayIndex<'a>,
1442 B: ArrayIndex<'b>,
1443 C: ArrayIndex<'c>,
1444 D: ArrayIndex<'d>,
1445 E: ArrayIndex<'e>,
1446 F: ArrayIndex<'f>,
1447 G: ArrayIndex<'g>,
1448 H: ArrayIndex<'h>,
1449 I: ArrayIndex<'i>,
1450 J: ArrayIndex<'j>,
1451 K: ArrayIndex<'k>,
1452 L: ArrayIndex<'l>,
1453 M: ArrayIndex<'m>,
1454 N: ArrayIndex<'n>,
1455 O: ArrayIndex<'o>,
1456 P: ArrayIndex<'p>,
1457 Val: AsRef<Array>,
1458{
1459 fn try_index_mut_device(
1460 &mut self,
1461 i: (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P),
1462 val: Val,
1463 stream: impl AsRef<Stream>,
1464 ) -> Result<()> {
1465 let operations = [
1466 i.0.index_op(),
1467 i.1.index_op(),
1468 i.2.index_op(),
1469 i.3.index_op(),
1470 i.4.index_op(),
1471 i.5.index_op(),
1472 i.6.index_op(),
1473 i.7.index_op(),
1474 i.8.index_op(),
1475 i.9.index_op(),
1476 i.10.index_op(),
1477 i.11.index_op(),
1478 i.12.index_op(),
1479 i.13.index_op(),
1480 i.14.index_op(),
1481 i.15.index_op(),
1482 ];
1483 let update = val.as_ref();
1484 self.try_index_mut_device_inner(&operations, update, stream)
1485 }
1486}
1487
1488#[cfg(test)]
1490mod tests {
1491 use crate::{
1492 ops::{indexing::*, ones, zeros},
1493 Array,
1494 };
1495
1496 #[test]
1497 fn test_array_mutate_single_index() {
1498 let mut a = Array::from_iter(0i32..12, &[3, 4]);
1499 let new_value = Array::from_int(77);
1500 a.index_mut(1, new_value);
1501
1502 let expected = Array::from_slice(&[0, 1, 2, 3, 77, 77, 77, 77, 8, 9, 10, 11], &[3, 4]);
1503 assert_array_all_close!(a, expected);
1504 }
1505
1506 #[test]
1507 fn test_array_mutate_broadcast_multi_index() {
1508 let mut a = Array::from_iter(0i32..20, &[2, 2, 5]);
1509
1510 a.index_mut((1, 0), Array::from_int(77));
1512
1513 a.index_mut((0, 0), Array::from_slice(&[55i32, 66, 77, 88, 99], &[5]));
1515
1516 a.index_mut((0, 1, 3), Array::from_int(123));
1518
1519 let expected = Array::from_slice(
1520 &[
1521 55, 66, 77, 88, 99, 5, 6, 7, 123, 9, 77, 77, 77, 77, 77, 15, 16, 17, 18, 19,
1522 ],
1523 &[2, 2, 5],
1524 );
1525 assert_array_all_close!(a, expected);
1526 }
1527
1528 #[test]
1529 fn test_array_mutate_broadcast_slice() {
1530 let mut a = Array::from_iter(0i32..20, &[2, 2, 5]);
1531
1532 a.index_mut((0..1, 1..2, 2..4), Array::from_int(88));
1534
1535 let expected = Array::from_slice(
1536 &[
1537 0, 1, 2, 3, 4, 5, 6, 88, 88, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
1538 ],
1539 &[2, 2, 5],
1540 );
1541 assert_array_all_close!(a, expected);
1542 }
1543
1544 #[test]
1545 fn test_array_mutate_advanced() {
1546 let mut a = Array::from_iter(0i32..35, &[5, 7]);
1547
1548 let i1 = Array::from_slice(&[0, 2, 4], &[3]);
1549 let i2 = Array::from_slice(&[0, 1, 2], &[3]);
1550
1551 a.index_mut((i1, i2), Array::from_slice(&[100, 200, 300], &[3]));
1552
1553 assert_eq!(a.index((0, 0)).item_exact::<i32>(), 100i32);
1554 assert_eq!(a.index((2, 1)).item_exact::<i32>(), 200i32);
1555 assert_eq!(a.index((4, 2)).item_exact::<i32>(), 300i32);
1556 }
1557
1558 #[test]
1559 fn test_full_index_write_single() {
1560 fn check<I>(index: I, expected_sum: i32)
1561 where
1562 for<'a> I: ArrayIndex<'a>,
1563 {
1564 let mut a = Array::from_iter(0..60, &[3, 4, 5]);
1565
1566 a.index_mut(index, Array::from_int(1));
1567 let sum = a.sum(None).unwrap().item_exact::<i32>();
1568 assert_eq!(sum, expected_sum);
1569 }
1570
1571 check(NewAxis, 60);
1576
1577 check(0, 1600);
1579
1580 check(1..3, 230);
1582
1583 let i = Array::from_slice(&[2, 1], &[2]);
1585
1586 check(i, 230);
1588 }
1589
1590 #[test]
1591 fn test_full_index_write_no_array() {
1592 macro_rules! check {
1593 (($( $i:expr ),*), $sum:expr ) => {
1594 {
1595 let mut a = Array::from_iter(0..360, &[2, 3, 4, 5, 3]);
1596
1597 a.index_mut(($($i),*), Array::from_int(1));
1598 let sum = a.sum(None).unwrap().item_exact::<i32>();
1599 assert_eq!(sum, $sum);
1600 }
1601 };
1602 }
1603
1604 check!((Ellipsis, 0), 43320);
1606
1607 check!((0, Ellipsis), 48690);
1609
1610 check!((0, Ellipsis, 0), 59370);
1612
1613 check!((Ellipsis, (..).stride_by(2), ..), 26064);
1615
1616 check!((Ellipsis, NewAxis, (..).stride_by(2), -1), 51696);
1618
1619 check!((.., 2.., 0), 58140);
1621
1622 check!(
1624 (
1625 (..).stride_by(-1),
1626 ..2,
1627 2..,
1628 Ellipsis,
1629 NewAxis,
1630 (..).stride_by(2)
1631 ),
1632 51540
1633 );
1634 }
1635
1636 #[test]
1637 fn test_full_index_write_array() {
1638 macro_rules! check {
1641 (($( $i:expr ),*), $sum:expr ) => {
1642 {
1643 let mut a = Array::from_iter(0..540, &[3, 3, 4, 5, 3]);
1644
1645 a.index_mut(($($i),*), Array::from_int(1));
1646 let sum = a.sum(None).unwrap().item_exact::<i32>();
1647 assert_eq!(sum, $sum);
1648 }
1649 };
1650 }
1651
1652 let i = Array::from_slice(&[2, 1], &[2]);
1654
1655 check!((0, &i), 131310);
1657
1658 check!((Ellipsis, &i, 0), 126378);
1660
1661 check!((&i, 0, Ellipsis), 109710);
1663
1664 check!((&i, Ellipsis, &i), 102450);
1666
1667 check!((&i, Ellipsis, (..).stride_by(2), ..), 68094);
1669
1670 check!((Ellipsis, &i, NewAxis, (..).stride_by(2), -1), 130977);
1672
1673 check!((.., 2.., &i), 115965);
1675
1676 check!(
1678 (
1679 (..).stride_by(-1),
1680 ..2,
1681 i,
1682 2..,
1683 Ellipsis,
1684 NewAxis,
1685 (..).stride_by(2)
1686 ),
1687 128142
1688 );
1689 }
1690
1691 #[test]
1692 fn test_slice_update_with_broadcast() {
1693 let mut xs = zeros::<f32>(&[4, 3, 2]).unwrap();
1694 let x = ones::<f32>(&[4, 2]).unwrap();
1695
1696 let result = xs.try_index_mut((.., 0, ..), x);
1697 assert!(
1698 result.is_ok(),
1699 "Failed to update slice with broadcast: {result:?}"
1700 );
1701 }
1702}