Repository: rust-ndarray/ndarray
Pull request #958 (2021-03-27 13:57:12)

Implement PartialEq for array == &array and &array == array
This adds missing implementations - so that we can compare a == &b and
&a == b where a and b are arrays or array views.

The change to the windows test shows why this is beneficial - no need to
create views from &Array etc just to do a comparison.


Patch:
diff --git a/RELEASES.md b/RELEASES.md
index 8e6e0c22..76782825 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,13 @@
+Version 0.15.1 (not released yet)
+===========================
+
+Enhancements
+------------
+
+- Arrays and views now implement PartialEq so that it's possible to compare
+  arrays with references to arrays and vice versa by [@bluss]
+
+
 Version 0.15.0 (2021-03-25)
 ===========================
 
diff --git a/src/arraytraits.rs b/src/arraytraits.rs
index 52182234..23f99b8f 100644
--- a/src/arraytraits.rs
+++ b/src/arraytraits.rs
@@ -112,6 +112,34 @@ where
     }
 }
 
+/// Return `true` if the array shapes and all elements of `self` and
+/// `rhs` are equal. Return `false` otherwise.
+impl<'a, A, B, S, S2, D> PartialEq<&'a ArrayBase<S2, D>> for ArrayBase<S, D>
+where
+    A: PartialEq<B>,
+    S: Data<Elem = A>,
+    S2: Data<Elem = B>,
+    D: Dimension,
+{
+    fn eq(&self, rhs: &&ArrayBase<S2, D>) -> bool {
+        *self == **rhs
+    }
+}
+
+/// Return `true` if the array shapes and all elements of `self` and
+/// `rhs` are equal. Return `false` otherwise.
+impl<'a, A, B, S, S2, D> PartialEq<ArrayBase<S2, D>> for &'a ArrayBase<S, D>
+where
+    A: PartialEq<B>,
+    S: Data<Elem = A>,
+    S2: Data<Elem = B>,
+    D: Dimension,
+{
+    fn eq(&self, rhs: &ArrayBase<S2, D>) -> bool {
+        **self == *rhs
+    }
+}
+
 impl<S, D> Eq for ArrayBase<S, D>
 where
     D: Dimension,
diff --git a/src/dimension/axes.rs b/src/dimension/axes.rs
index d6f1c728..a678e78c 100644
--- a/src/dimension/axes.rs
+++ b/src/dimension/axes.rs
@@ -1,7 +1,7 @@
 use crate::{Axis, Dimension, Ix, Ixs};
 
 /// Create a new Axes iterator
-pub(crate) fn axes_of<'a, D>(d: &'a D, strides: &'a D) -> Axes<'a, D>
+pub fn axes_of<'a, D>(d: &'a D, strides: &'a D) -> Axes<'a, D>
 where
     D: Dimension,
 {
@@ -15,10 +15,9 @@ where
 
 /// An iterator over the length and stride of each axis of an array.
 ///
-/// This iterator is created from the array method
-/// [`.axes()`](crate::ArrayBase::axes).
+/// See [`.axes()`](../struct.ArrayBase.html#method.axes) for more information.
 ///
-/// Iterator element type is [`AxisDescription`].
+/// Iterator element type is `AxisDescription`.
 ///
 /// # Examples
 ///
@@ -28,14 +27,10 @@ where
 ///
 /// let a = Array3::<f32>::zeros((3, 5, 4));
 ///
-/// // find the largest axis in the array
-/// // check the axis index and its length
-///
 /// let largest_axis = a.axes()
-///                     .max_by_key(|ax| ax.len)
-///                     .unwrap();
-/// assert_eq!(largest_axis.axis, Axis(1));
-/// assert_eq!(largest_axis.len, 5);
+///                     .max_by_key(|ax| ax.len())
+///                     .unwrap().axis();
+/// assert_eq!(largest_axis, Axis(1));
 /// ```
 #[derive(Debug)]
 pub struct Axes<'a, D> {
diff --git a/src/dimension/axis.rs b/src/dimension/axis.rs
index f4625d2d..42a1ee12 100644
--- a/src/dimension/axis.rs
+++ b/src/dimension/axis.rs
@@ -8,21 +8,11 @@
 
 /// An axis index.
 ///
-/// An axis one of an array’s “dimensions”; an *n*-dimensional array has *n*
-/// axes.  Axis *0* is the array’s outermost axis and *n*-1 is the innermost.
+/// An axis one of an array’s “dimensions”; an *n*-dimensional array has *n* axes.
+/// Axis *0* is the array’s outermost axis and *n*-1 is the innermost.
 ///
 /// All array axis arguments use this type to make the code easier to write
 /// correctly and easier to understand.
-/// 
-/// For example: in a method like `index_axis(axis, index)` the code becomes
-/// self-explanatory when it's called like `.index_axis(Axis(1), i)`; it's
-/// evident which integer is the axis number and which is the index.
-///
-/// Note: This type does **not** implement From/Into usize and similar trait
-/// based conversions, because we want to preserve code readability and quality.
-///
-/// `Axis(1)` in itself is a very clear code style and the style that should be
-/// avoided is code like `1.into()`.
 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
 pub struct Axis(pub usize);
 
diff --git a/src/dimension/mod.rs b/src/dimension/mod.rs
index f4f46e76..fb062513 100644
--- a/src/dimension/mod.rs
+++ b/src/dimension/mod.rs
@@ -11,8 +11,7 @@ use crate::slice::SliceArg;
 use crate::{Ix, Ixs, Slice, SliceInfoElem};
 use num_integer::div_floor;
 
-pub use self::axes::{Axes, AxisDescription};
-pub(crate) use self::axes::axes_of;
+pub use self::axes::{axes_of, Axes, AxisDescription};
 pub use self::axis::Axis;
 pub use self::broadcast::DimMax;
 pub use self::conversion::IntoDimension;
diff --git a/src/impl_2d.rs b/src/impl_2d.rs
index 6e2cfa2c..64d4860c 100644
--- a/src/impl_2d.rs
+++ b/src/impl_2d.rs
@@ -118,7 +118,6 @@ where
     /// assert!(!array.is_square());
     /// ```
     pub fn is_square(&self) -> bool {
-        let (m, n) = self.dim();
-        m == n
+        self.nrows() == self.ncols()
     }
 }


Test patch:
diff --git a/tests/windows.rs b/tests/windows.rs
index 87fdf6ec..b0482e4b 100644
--- a/tests/windows.rs
+++ b/tests/windows.rs
@@ -133,7 +133,7 @@ fn test_window_neg_stride() {
 
     itertools::assert_equal(
         array.slice(s![.., ..;-1]).windows((2, 2)),
-        answer.iter().map(|a| a.view())
+        answer.iter()
     );
 
     answer.invert_axis(Axis(0));
@@ -141,7 +141,7 @@ fn test_window_neg_stride() {
 
     itertools::assert_equal(
         array.slice(s![..;-1, ..;-1]).windows((2, 2)),
-        answer.iter().map(|a| a.view())
+        answer.iter()
     );
 
     answer.invert_axis(Axis(1));
@@ -149,6 +149,6 @@ fn test_window_neg_stride() {
 
     itertools::assert_equal(
         array.slice(s![..;-1, ..]).windows((2, 2)),
-        answer.iter().map(|a| a.view())
+        answer.iter()
     );
 }