Skip to content

Commit 9903c4d

Browse files
cycle detection logic with bitmask
1 parent ddfdfd0 commit 9903c4d

File tree

1 file changed

+67
-39
lines changed

1 file changed

+67
-39
lines changed

src/impl_methods.rs

Lines changed: 67 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2538,27 +2538,6 @@ where
25382538
unsafe { self.with_strides_dim(new_strides, new_dim) }
25392539
}
25402540

2541-
/// Transpose the array by reversing axes.
2542-
///
2543-
/// Transposition reverses the order of the axes (dimensions and strides)
2544-
/// while retaining the same data.
2545-
pub fn reversed_axes(mut self) -> ArrayBase<S, D>
2546-
{
2547-
self.layout.dim.slice_mut().reverse();
2548-
self.layout.strides.slice_mut().reverse();
2549-
self
2550-
}
2551-
2552-
/// Reverse the axes of the array in-place.
2553-
///
2554-
/// This does not move any data, it just adjusts the array's dimensions
2555-
/// and strides.
2556-
pub fn reverse_axes(&mut self)
2557-
{
2558-
self.layout.dim.slice_mut().reverse();
2559-
self.layout.strides.slice_mut().reverse();
2560-
}
2561-
25622541
/// Permute the axes in-place.
25632542
///
25642543
/// This does not move any data, it just adjusts the array's dimensions
@@ -2568,10 +2547,38 @@ where
25682547
/// becomes `self`'s *j*-th axis
25692548
///
25702549
/// **Panics** if any of the axes are out of bounds, if an axis is missing,
2571-
/// or if an axis is repeated more than once.
2572-
///
2573-
/// # Examples
2550+
/// or if an axis is repeated more than once.
2551+
///
2552+
/// # About the Cycle Detection
2553+
///
2554+
/// The cycle detection is done using a bitmask to track visited positions.
2555+
///
2556+
/// For example, axes from [0,1,2] to [2, 0, 1]
2557+
/// For axis values [1, 0, 2]:
2558+
/// 1 << 1; // 0b0001 << 1 = 0b0010 (decimal 2)
2559+
/// 1 << 0; // 0b0001 << 0 = 0b0001 (decimal 1)
2560+
/// 1 << 2; // 0b0001 << 2 = 0b0100 (decimal 4)
2561+
///
2562+
/// Each axis gets its own unique bit position in the bitmask:
2563+
/// - Axis 0: bit 0 (rightmost)
2564+
/// - Axis 1: bit 1
2565+
/// - Axis 2: bit 2
2566+
///
2567+
/// The check `(visited & (1 << axis)) != 0` works as follows:
2568+
/// ```no_run
2569+
/// let mut visited = 0; // 0b0000
2570+
/// // Check axis 1
2571+
/// if (visited & (1 << 1)) != 0 { // 0b0000 & 0b0010 = 0b0000
2572+
/// // Not visited yet
2573+
/// }
2574+
/// // Mark axis 1 as visited
2575+
/// visited |= (1 << axis) | (1 << new_axis); /// // Check axis 1 again
2576+
/// if (visited & (1 << 1)) != 0 { // 0b0010 & 0b0010 = 0b0010
2577+
/// // Already visited!
2578+
/// }
2579+
/// ```
25742580
///
2581+
/// # Example
25752582
/// ```rust
25762583
/// use ndarray::{arr2, Array3};
25772584
///
@@ -2597,25 +2604,46 @@ where
25972604
assert_eq!(*count, 1, "each axis must be listed exactly once");
25982605
}
25992606

2600-
// Create temporary arrays for the new dimensions and strides
2601-
let mut new_dim = D::zeros(self.ndim());
2602-
let mut new_strides = D::zeros(self.ndim());
2607+
let dim = self.layout.dim.slice_mut();
2608+
let strides = self.layout.strides.slice_mut();
2609+
let axes = axes.slice();
26032610

2604-
{
2605-
let dim = self.layout.dim.slice();
2606-
let strides = self.layout.strides.slice();
2607-
for (new_axis, &axis) in axes.slice().iter().enumerate() {
2608-
new_dim[new_axis] = dim[axis];
2609-
new_strides[new_axis] = strides[axis];
2611+
let mut visited = 0usize;
2612+
for (new_axis, &axis) in axes.iter().enumerate() {
2613+
if (visited & (1 << axis)) != 0 {
2614+
continue;
26102615
}
2616+
2617+
let temp = dim[axis];
2618+
dim[axis] = dim[new_axis];
2619+
dim[new_axis] = temp;
2620+
2621+
let temp = strides[axis];
2622+
strides[axis] = strides[new_axis];
2623+
strides[new_axis] = temp;
2624+
visited |= (1 << axis) | (1 << new_axis);
26112625
}
2626+
}
2627+
2628+
/// Transpose the array by reversing axes.
2629+
///
2630+
/// Transposition reverses the order of the axes (dimensions and strides)
2631+
/// while retaining the same data.
2632+
pub fn reversed_axes(mut self) -> ArrayBase<S, D>
2633+
{
2634+
self.layout.dim.slice_mut().reverse();
2635+
self.layout.strides.slice_mut().reverse();
2636+
self
2637+
}
26122638

2613-
// Update the dimensions and strides in place
2614-
self.layout.dim.slice_mut().copy_from_slice(new_dim.slice());
2615-
self.layout
2616-
.strides
2617-
.slice_mut()
2618-
.copy_from_slice(new_strides.slice());
2639+
/// Reverse the axes of the array in-place.
2640+
///
2641+
/// This does not move any data, it just adjusts the array's dimensions
2642+
/// and strides.
2643+
pub fn reverse_axes(&mut self)
2644+
{
2645+
self.layout.dim.slice_mut().reverse();
2646+
self.layout.strides.slice_mut().reverse();
26192647
}
26202648
}
26212649

0 commit comments

Comments
 (0)