Repository: rust-ndarray/ndarray
Pull request #738 (2019-10-02 15:16:36)

Remove alignment restriction on RawArrayView/Mut
This makes `.cast()` safe without a check for alignment.

This might be a breaking change because we [documented](https://docs.rs/ndarray/0.13.0/ndarray/type.RawArrayView.html) that `RawArrayView/Mut` had alignment requirements. I suppose it depends on how that statement could be interpreted. Someone could think that it would mean that, given any `RawArrayView`, it would be safe to call `.deref_into_view()` without ensuring that the pointer was aligned. IMO, though, since we didn't say exactly what the alignment restrictions were, no one should have made that assumption.

bluss: Thanks a lot. Fixed up to use `as` for raw pointer casts, the cast method on raw pointers was a Rust 1.37 or 1.38 feature apparently (and it was a bit earlier on NonNull).

Patch:
diff --git a/Cargo.toml b/Cargo.toml
index 3da63d1d..b0a5ed74 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -46,7 +46,7 @@ rawpointer = { version = "0.2" }
 
 [dev-dependencies]
 defmac = "0.2"
-quickcheck = { version = "0.9", default-features = false }
+quickcheck = { version = "0.8", default-features = false }
 approx = "0.3.2"
 itertools = { version = "0.8.0", default-features = false, features = ["use_std"] }
 
diff --git a/ndarray-rand/Cargo.toml b/ndarray-rand/Cargo.toml
index aa4715fc..ce993623 100644
--- a/ndarray-rand/Cargo.toml
+++ b/ndarray-rand/Cargo.toml
@@ -16,7 +16,6 @@ keywords = ["multidimensional", "matrix", "rand", "ndarray"]
 [dependencies]
 ndarray = { version = "0.13", path = ".." }
 rand_distr = "0.2.1"
-quickcheck = { version = "0.9", default-features = false, optional = true }
 
 [dependencies.rand]
 version = "0.7.0"
@@ -24,7 +23,6 @@ features = ["small_rng"]
 
 [dev-dependencies]
 rand_isaac = "0.2.0"
-quickcheck = { version = "0.9", default-features = false }
 
 [package.metadata.release]
 no-dev-version = true
diff --git a/ndarray-rand/src/lib.rs b/ndarray-rand/src/lib.rs
index 19235237..49511cbe 100644
--- a/ndarray-rand/src/lib.rs
+++ b/ndarray-rand/src/lib.rs
@@ -29,15 +29,12 @@
 //! that the items are not compatible (e.g. that a type doesn't implement a
 //! necessary trait).
 
-use crate::rand::distributions::{Distribution, Uniform};
+use crate::rand::distributions::Distribution;
 use crate::rand::rngs::SmallRng;
-use crate::rand::seq::index;
 use crate::rand::{thread_rng, Rng, SeedableRng};
 
-use ndarray::{Array, Axis, RemoveAxis, ShapeBuilder};
+use ndarray::ShapeBuilder;
 use ndarray::{ArrayBase, DataOwned, Dimension};
-#[cfg(feature = "quickcheck")]
-use quickcheck::{Arbitrary, Gen};
 
 /// [`rand`](https://docs.rs/rand/0.7), re-exported for convenience and version-compatibility.
 pub mod rand {
@@ -62,9 +59,9 @@ pub mod rand_distr {
 /// low-quality random numbers, and reproducibility is not guaranteed. See its
 /// documentation for information. You can select a different RNG with
 /// [`.random_using()`](#tymethod.random_using).
-pub trait RandomExt<S, A, D>
+pub trait RandomExt<S, D>
 where
-    S: DataOwned<Elem = A>,
+    S: DataOwned,
     D: Dimension,
 {
     /// Create an array with shape `dim` with elements drawn from
@@ -119,117 +116,11 @@ where
         IdS: Distribution<S::Elem>,
         R: Rng + ?Sized,
         Sh: ShapeBuilder<Dim = D>;
-
-    /// Sample `n_samples` lanes slicing along `axis` using the default RNG.
-    ///
-    /// If `strategy==SamplingStrategy::WithoutReplacement`, each lane can only be sampled once.
-    /// If `strategy==SamplingStrategy::WithReplacement`, each lane can be sampled multiple times.
-    ///
-    /// ***Panics*** when:
-    /// - creation of the RNG fails;
-    /// - `n_samples` is greater than the length of `axis` (if sampling without replacement);
-    /// - length of `axis` is 0.
-    ///
-    /// ```
-    /// use ndarray::{array, Axis};
-    /// use ndarray_rand::{RandomExt, SamplingStrategy};
-    ///
-    /// # fn main() {
-    /// let a = array![
-    ///     [1., 2., 3.],
-    ///     [4., 5., 6.],
-    ///     [7., 8., 9.],
-    ///     [10., 11., 12.],
-    /// ];
-    /// // Sample 2 rows, without replacement
-    /// let sample_rows = a.sample_axis(Axis(0), 2, SamplingStrategy::WithoutReplacement);
-    /// println!("{:?}", sample_rows);
-    /// // Example Output: (1st and 3rd rows)
-    /// // [
-    /// //  [1., 2., 3.],
-    /// //  [7., 8., 9.]
-    /// // ]
-    /// // Sample 2 columns, with replacement
-    /// let sample_columns = a.sample_axis(Axis(1), 1, SamplingStrategy::WithReplacement);
-    /// println!("{:?}", sample_columns);
-    /// // Example Output: (2nd column, sampled twice)
-    /// // [
-    /// //  [2., 2.],
-    /// //  [5., 5.],
-    /// //  [8., 8.],
-    /// //  [11., 11.]
-    /// // ]
-    /// # }
-    /// ```
-    fn sample_axis(&self, axis: Axis, n_samples: usize, strategy: SamplingStrategy) -> Array<A, D>
-    where
-        A: Copy,
-        D: RemoveAxis;
-
-    /// Sample `n_samples` lanes slicing along `axis` using the specified RNG `rng`.
-    ///
-    /// If `strategy==SamplingStrategy::WithoutReplacement`, each lane can only be sampled once.
-    /// If `strategy==SamplingStrategy::WithReplacement`, each lane can be sampled multiple times.
-    ///
-    /// ***Panics*** when:
-    /// - creation of the RNG fails;
-    /// - `n_samples` is greater than the length of `axis` (if sampling without replacement);
-    /// - length of `axis` is 0.
-    ///
-    /// ```
-    /// use ndarray::{array, Axis};
-    /// use ndarray_rand::{RandomExt, SamplingStrategy};
-    /// use ndarray_rand::rand::SeedableRng;
-    /// use rand_isaac::isaac64::Isaac64Rng;
-    ///
-    /// # fn main() {
-    /// // Get a seeded random number generator for reproducibility (Isaac64 algorithm)
-    /// let seed = 42;
-    /// let mut rng = Isaac64Rng::seed_from_u64(seed);
-    ///
-    /// let a = array![
-    ///     [1., 2., 3.],
-    ///     [4., 5., 6.],
-    ///     [7., 8., 9.],
-    ///     [10., 11., 12.],
-    /// ];
-    /// // Sample 2 rows, without replacement
-    /// let sample_rows = a.sample_axis_using(Axis(0), 2, SamplingStrategy::WithoutReplacement, &mut rng);
-    /// println!("{:?}", sample_rows);
-    /// // Example Output: (1st and 3rd rows)
-    /// // [
-    /// //  [1., 2., 3.],
-    /// //  [7., 8., 9.]
-    /// // ]
-    ///
-    /// // Sample 2 columns, with replacement
-    /// let sample_columns = a.sample_axis_using(Axis(1), 1, SamplingStrategy::WithReplacement, &mut rng);
-    /// println!("{:?}", sample_columns);
-    /// // Example Output: (2nd column, sampled twice)
-    /// // [
-    /// //  [2., 2.],
-    /// //  [5., 5.],
-    /// //  [8., 8.],
-    /// //  [11., 11.]
-    /// // ]
-    /// # }
-    /// ```
-    fn sample_axis_using<R>(
-        &self,
-        axis: Axis,
-        n_samples: usize,
-        strategy: SamplingStrategy,
-        rng: &mut R,
-    ) -> Array<A, D>
-    where
-        R: Rng + ?Sized,
-        A: Copy,
-        D: RemoveAxis;
 }
 
-impl<S, A, D> RandomExt<S, A, D> for ArrayBase<S, D>
+impl<S, D> RandomExt<S, D> for ArrayBase<S, D>
 where
-    S: DataOwned<Elem = A>,
+    S: DataOwned,
     D: Dimension,
 {
     fn random<Sh, IdS>(shape: Sh, dist: IdS) -> ArrayBase<S, D>
@@ -237,7 +128,9 @@ where
         IdS: Distribution<S::Elem>,
         Sh: ShapeBuilder<Dim = D>,
     {
-        Self::random_using(shape, dist, &mut get_rng())
+        let mut rng =
+            SmallRng::from_rng(thread_rng()).expect("create SmallRng from thread_rng failed");
+        Self::random_using(shape, dist, &mut rng)
     }
 
     fn random_using<Sh, IdS, R>(shape: Sh, dist: IdS, rng: &mut R) -> ArrayBase<S, D>
@@ -248,66 +141,6 @@ where
     {
         Self::from_shape_fn(shape, |_| dist.sample(rng))
     }
-
-    fn sample_axis(&self, axis: Axis, n_samples: usize, strategy: SamplingStrategy) -> Array<A, D>
-    where
-        A: Copy,
-        D: RemoveAxis,
-    {
-        self.sample_axis_using(axis, n_samples, strategy, &mut get_rng())
-    }
-
-    fn sample_axis_using<R>(
-        &self,
-        axis: Axis,
-        n_samples: usize,
-        strategy: SamplingStrategy,
-        rng: &mut R,
-    ) -> Array<A, D>
-    where
-        R: Rng + ?Sized,
-        A: Copy,
-        D: RemoveAxis,
-    {
-        let indices: Vec<_> = match strategy {
-            SamplingStrategy::WithReplacement => {
-                let distribution = Uniform::from(0..self.len_of(axis));
-                (0..n_samples).map(|_| distribution.sample(rng)).collect()
-            }
-            SamplingStrategy::WithoutReplacement => {
-                index::sample(rng, self.len_of(axis), n_samples).into_vec()
-            }
-        };
-        self.select(axis, &indices)
-    }
-}
-
-/// Used as parameter in [`sample_axis`] and [`sample_axis_using`] to determine
-/// if lanes from the original array should only be sampled once (*without replacement*) or
-/// multiple times (*with replacement*).
-///
-/// [`sample_axis`]: trait.RandomExt.html#tymethod.sample_axis
-/// [`sample_axis_using`]: trait.RandomExt.html#tymethod.sample_axis_using
-#[derive(Debug, Clone)]
-pub enum SamplingStrategy {
-    WithReplacement,
-    WithoutReplacement,
-}
-
-// `Arbitrary` enables `quickcheck` to generate random `SamplingStrategy` values for testing.
-#[cfg(feature = "quickcheck")]
-impl Arbitrary for SamplingStrategy {
-    fn arbitrary<G: Gen>(g: &mut G) -> Self {
-        if g.gen_bool(0.5) {
-            SamplingStrategy::WithReplacement
-        } else {
-            SamplingStrategy::WithoutReplacement
-        }
-    }
-}
-
-fn get_rng() -> SmallRng {
-    SmallRng::from_rng(thread_rng()).expect("create SmallRng from thread_rng failed")
 }
 
 /// A wrapper type that allows casting f64 distributions to f32
diff --git a/src/aliases.rs b/src/aliases.rs
index f7c71b3d..1c82120a 100644
--- a/src/aliases.rs
+++ b/src/aliases.rs
@@ -3,7 +3,7 @@
 
 use crate::dimension::Dim;
 #[allow(deprecated)]
-use crate::{ArcArray, Array, ArrayView, ArrayViewMut, Ix, IxDynImpl, RcArray};
+use crate::{Array, ArrayView, ArrayViewMut, Ix, IxDynImpl, RcArray};
 
 /// Create a zero-dimensional index
 #[allow(non_snake_case)]
@@ -158,8 +158,3 @@ pub type RcArray1<A> = RcArray<A, Ix1>;
 #[allow(deprecated)]
 #[deprecated(note = "`RcArray` has been renamed to `ArcArray`")]
 pub type RcArray2<A> = RcArray<A, Ix2>;
-
-/// one-dimensional shared ownership array
-pub type ArcArray1<A> = ArcArray<A, Ix1>;
-/// two-dimensional shared ownership array
-pub type ArcArray2<A> = ArcArray<A, Ix2>;
diff --git a/src/free_functions.rs b/src/free_functions.rs
index 8319865d..7e2bb752 100644
--- a/src/free_functions.rs
+++ b/src/free_functions.rs
@@ -9,8 +9,8 @@
 use std::mem::{forget, size_of};
 use std::slice;
 
+use crate::dimension;
 use crate::imp_prelude::*;
-use crate::{dimension, ArcArray1, ArcArray2};
 
 /// Create an [**`Array`**](type.Array.html) with one, two or
 /// three dimensions.
@@ -63,7 +63,7 @@ pub fn arr1<A: Clone>(xs: &[A]) -> Array1<A> {
 }
 
 /// Create a one-dimensional array with elements from `xs`.
-pub fn rcarr1<A: Clone>(xs: &[A]) -> ArcArray1<A> {
+pub fn rcarr1<A: Clone>(xs: &[A]) -> ArcArray<A, Ix1> {
     arr1(xs).into_shared()
 }
 
@@ -289,7 +289,7 @@ where
 
 /// Create a two-dimensional array with elements from `xs`.
 ///
-pub fn rcarr2<A: Clone, V: Clone + FixedInitializer<Elem = A>>(xs: &[V]) -> ArcArray2<A> {
+pub fn rcarr2<A: Clone, V: Clone + FixedInitializer<Elem = A>>(xs: &[V]) -> ArcArray<A, Ix2> {
     arr2(xs).into_shared()
 }
 
diff --git a/src/impl_raw_views.rs b/src/impl_raw_views.rs
index 643753e7..d10c7909 100644
--- a/src/impl_raw_views.rs
+++ b/src/impl_raw_views.rs
@@ -33,8 +33,8 @@ where
     ///
     /// Unsafe because caller is responsible for ensuring all of the following:
     ///
-    /// * `ptr` must be non-null and aligned, and it must be safe to
-    ///   [`.offset()`] `ptr` by zero.
+    /// * `ptr` must be non-null, and it must be safe to [`.offset()`] `ptr` by
+    ///   zero.
     ///
     /// * It must be safe to [`.offset()`] the pointer repeatedly along all
     ///   axes and calculate the `count`s for the `.offset()` calls without
@@ -70,7 +70,6 @@ where
         let strides = shape.strides;
         if cfg!(debug_assertions) {
             assert!(!ptr.is_null(), "The pointer must be non-null.");
-            assert!(is_aligned(ptr), "The pointer must be aligned.");
             dimension::max_abs_offset_check_overflow::<A, _>(&dim, &strides).unwrap();
         }
         RawArrayView::new_(ptr, dim, strides)
@@ -80,9 +79,14 @@ where
     ///
     /// **Warning** from a safety standpoint, this is equivalent to
     /// dereferencing a raw pointer for every element in the array. You must
-    /// ensure that all of the data is valid and choose the correct lifetime.
+    /// ensure that all of the data is valid, ensure that the pointer is
+    /// aligned, and choose the correct lifetime.
     #[inline]
     pub unsafe fn deref_into_view<'a>(self) -> ArrayView<'a, A, D> {
+        debug_assert!(
+            is_aligned(self.ptr.as_ptr()),
+            "The pointer must be aligned."
+        );
         ArrayView::new(self.ptr, self.dim, self.strides)
     }
 
@@ -130,12 +134,6 @@ where
             "size mismatch in raw view cast"
         );
         let ptr = self.ptr.cast::<B>();
-        debug_assert!(
-            is_aligned(ptr.as_ptr()),
-            "alignment mismatch in raw view cast"
-        );
-        /* Alignment checked with debug assertion: alignment could be dynamically correct,
-         * and we don't have a check that compiles out for that. */
         unsafe { RawArrayView::new(ptr, self.dim, self.strides) }
     }
 }
@@ -167,8 +165,8 @@ where
     ///
     /// Unsafe because caller is responsible for ensuring all of the following:
     ///
-    /// * `ptr` must be non-null and aligned, and it must be safe to
-    ///   [`.offset()`] `ptr` by zero.
+    /// * `ptr` must be non-null, and it must be safe to [`.offset()`] `ptr` by
+    ///   zero.
     ///
     /// * It must be safe to [`.offset()`] the pointer repeatedly along all
     ///   axes and calculate the `count`s for the `.offset()` calls without
@@ -204,7 +202,6 @@ where
         let strides = shape.strides;
         if cfg!(debug_assertions) {
             assert!(!ptr.is_null(), "The pointer must be non-null.");
-            assert!(is_aligned(ptr), "The pointer must be aligned.");
             dimension::max_abs_offset_check_overflow::<A, _>(&dim, &strides).unwrap();
         }
         RawArrayViewMut::new_(ptr, dim, strides)
@@ -220,9 +217,14 @@ where
     ///
     /// **Warning** from a safety standpoint, this is equivalent to
     /// dereferencing a raw pointer for every element in the array. You must
-    /// ensure that all of the data is valid and choose the correct lifetime.
+    /// ensure that all of the data is valid, ensure that the pointer is
+    /// aligned, and choose the correct lifetime.
     #[inline]
     pub unsafe fn deref_into_view<'a>(self) -> ArrayView<'a, A, D> {
+        debug_assert!(
+            is_aligned(self.ptr.as_ptr()),
+            "The pointer must be aligned."
+        );
         ArrayView::new(self.ptr, self.dim, self.strides)
     }
 
@@ -230,9 +232,14 @@ where
     ///
     /// **Warning** from a safety standpoint, this is equivalent to
     /// dereferencing a raw pointer for every element in the array. You must
-    /// ensure that all of the data is valid and choose the correct lifetime.
+    /// ensure that all of the data is valid, ensure that the pointer is
+    /// aligned, and choose the correct lifetime.
     #[inline]
     pub unsafe fn deref_into_view_mut<'a>(self) -> ArrayViewMut<'a, A, D> {
+        debug_assert!(
+            is_aligned(self.ptr.as_ptr()),
+            "The pointer must be aligned."
+        );
         ArrayViewMut::new(self.ptr, self.dim, self.strides)
     }
 
@@ -267,12 +274,6 @@ where
             "size mismatch in raw view cast"
         );
         let ptr = self.ptr.cast::<B>();
-        debug_assert!(
-            is_aligned(ptr.as_ptr()),
-            "alignment mismatch in raw view cast"
-        );
-        /* Alignment checked with debug assertion: alignment could be dynamically correct,
-         * and we don't have a check that compiles out for that. */
         unsafe { RawArrayViewMut::new(ptr, self.dim, self.strides) }
     }
 }
diff --git a/src/lib.rs b/src/lib.rs
index a164bee9..35d1e1aa 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1106,10 +1106,12 @@ pub type Ixs = isize;
 //      `dim`, and `strides` must be exclusively borrowed and not aliased by
 //      multiple indices.
 //
-// 2. `ptr` must be non-null and aligned, and it must be safe to [`.offset()`]
-//    `ptr` by zero.
+// 2. If the type of `data` implements `Data`, then `ptr` must be aligned.
 //
-// 3. It must be safe to [`.offset()`] the pointer repeatedly along all axes
+// 3. `ptr` must be non-null, and it must be safe to [`.offset()`] `ptr` by
+//    zero.
+//
+// 4. It must be safe to [`.offset()`] the pointer repeatedly along all axes
 //    and calculate the `count`s for the `.offset()` calls without overflow,
 //    even if the array is empty or the elements are zero-sized.
 //
@@ -1177,13 +1179,13 @@ pub type Ixs = isize;
 //    `.offset()` at all, even by zero bytes, but the implementation of
 //    `Vec<A>` does this, so we can too. See rust-lang/rust#54857 for details.)
 //
-// 4. The product of non-zero axis lengths must not exceed `isize::MAX`. (This
+// 5. The product of non-zero axis lengths must not exceed `isize::MAX`. (This
 //    also implies that the length of any individual axis must not exceed
 //    `isize::MAX`, and an array can contain at most `isize::MAX` elements.)
 //    This constraint makes various calculations easier because they don't have
 //    to worry about overflow and axis lengths can be freely cast to `isize`.
 //
-// Constraints 2–4 are carefully designed such that if they're upheld for the
+// Constraints 2–5 are carefully designed such that if they're upheld for the
 // array, they're also upheld for any subset of axes of the array as well as
 // slices/subviews/reshapes of the array. This is important for iterators that
 // produce subviews (and other similar cases) to be safe without extra (easy to
@@ -1209,8 +1211,8 @@ where
     /// Data buffer / ownership information. (If owned, contains the data
     /// buffer; if borrowed, contains the lifetime and mutability.)
     data: S,
-    /// A non-null and aligned pointer into the buffer held by `data`; may
-    /// point anywhere in its range.
+    /// A non-null pointer into the buffer held by `data`; may point anywhere
+    /// in its range. If `S: Data`, this pointer must be aligned.
     ptr: std::ptr::NonNull<S::Elem>,
     /// The lengths of the axes.
     dim: D,
@@ -1331,7 +1333,7 @@ pub type ArrayViewMut<'a, A, D> = ArrayBase<ViewRepr<&'a mut A>, D>;
 /// conversion into an [`ArrayView`]. The relationship between `RawArrayView`
 /// and [`ArrayView`] is somewhat analogous to the relationship between `*const
 /// T` and `&T`, but `RawArrayView` has additional requirements that `*const T`
-/// does not, such as alignment and non-nullness.
+/// does not, such as non-nullness.
 ///
 /// [`ArrayView`]: type.ArrayView.html
 ///
@@ -1356,8 +1358,7 @@ pub type RawArrayView<A, D> = ArrayBase<RawViewRepr<*const A>, D>;
 /// unsafe conversion into an [`ArrayViewMut`]. The relationship between
 /// `RawArrayViewMut` and [`ArrayViewMut`] is somewhat analogous to the
 /// relationship between `*mut T` and `&mut T`, but `RawArrayViewMut` has
-/// additional requirements that `*mut T` does not, such as alignment and
-/// non-nullness.
+/// additional requirements that `*mut T` does not, such as non-nullness.
 ///
 /// [`ArrayViewMut`]: type.ArrayViewMut.html
 ///


Test patch:
diff --git a/ndarray-rand/tests/tests.rs b/ndarray-rand/tests/tests.rs
index 52de7459..6e64a10b 100644
--- a/ndarray-rand/tests/tests.rs
+++ b/ndarray-rand/tests/tests.rs
@@ -1,9 +1,6 @@
-use ndarray::{Array, Array2, ArrayView1, Axis};
-#[cfg(feature = "quickcheck")]
-use ndarray_rand::rand::{distributions::Distribution, thread_rng};
+use ndarray::Array;
 use ndarray_rand::rand_distr::Uniform;
-use ndarray_rand::{RandomExt, SamplingStrategy};
-use quickcheck::quickcheck;
+use ndarray_rand::RandomExt;
 
 #[test]
 fn test_dim() {
@@ -17,94 +14,3 @@ fn test_dim() {
         }
     }
 }
-
-#[test]
-#[should_panic]
-fn oversampling_without_replacement_should_panic() {
-    let m = 5;
-    let a = Array::random((m, 4), Uniform::new(0., 2.));
-    let _samples = a.sample_axis(Axis(0), m + 1, SamplingStrategy::WithoutReplacement);
-}
-
-quickcheck! {
-    fn oversampling_with_replacement_is_fine(m: usize, n: usize) -> bool {
-        let a = Array::random((m, n), Uniform::new(0., 2.));
-        // Higher than the length of both axes
-        let n_samples = m + n + 1;
-
-        // We don't want to deal with sampling from 0-length axes in this test
-        if m != 0 {
-            if !sampling_works(&a, SamplingStrategy::WithReplacement, Axis(0), n_samples) {
-                return false;
-            }
-        }
-
-        // We don't want to deal with sampling from 0-length axes in this test
-        if n != 0 {
-            if !sampling_works(&a, SamplingStrategy::WithReplacement, Axis(1), n_samples) {
-                return false;
-            }
-        }
-
-        true
-    }
-}
-
-#[cfg(feature = "quickcheck")]
-quickcheck! {
-    fn sampling_behaves_as_expected(m: usize, n: usize, strategy: SamplingStrategy) -> bool {
-        let a = Array::random((m, n), Uniform::new(0., 2.));
-        let mut rng = &mut thread_rng();
-
-        // We don't want to deal with sampling from 0-length axes in this test
-        if m != 0 {
-            let n_row_samples = Uniform::from(1..m+1).sample(&mut rng);
-            if !sampling_works(&a, strategy.clone(), Axis(0), n_row_samples) {
-                return false;
-            }
-        }
-
-        // We don't want to deal with sampling from 0-length axes in this test
-        if n != 0 {
-            let n_col_samples = Uniform::from(1..n+1).sample(&mut rng);
-            if !sampling_works(&a, strategy, Axis(1), n_col_samples) {
-                return false;
-            }
-        }
-
-        true
-    }
-}
-
-fn sampling_works(
-    a: &Array2<f64>,
-    strategy: SamplingStrategy,
-    axis: Axis,
-    n_samples: usize,
-) -> bool {
-    let samples = a.sample_axis(axis, n_samples, strategy);
-    samples
-        .axis_iter(axis)
-        .all(|lane| is_subset(&a, &lane, axis))
-}
-
-// Check if, when sliced along `axis`, there is at least one lane in `a` equal to `b`
-fn is_subset(a: &Array2<f64>, b: &ArrayView1<f64>, axis: Axis) -> bool {
-    a.axis_iter(axis).any(|lane| &lane == b)
-}
-
-#[test]
-#[should_panic]
-fn sampling_without_replacement_from_a_zero_length_axis_should_panic() {
-    let n = 5;
-    let a = Array::random((0, n), Uniform::new(0., 2.));
-    let _samples = a.sample_axis(Axis(0), 1, SamplingStrategy::WithoutReplacement);
-}
-
-#[test]
-#[should_panic]
-fn sampling_with_replacement_from_a_zero_length_axis_should_panic() {
-    let n = 5;
-    let a = Array::random((0, n), Uniform::new(0., 2.));
-    let _samples = a.sample_axis(Axis(0), 1, SamplingStrategy::WithReplacement);
-}
diff --git a/scripts/all-tests.sh b/scripts/all-tests.sh
index 9b41b41d..7925fd91 100755
--- a/scripts/all-tests.sh
+++ b/scripts/all-tests.sh
@@ -13,8 +13,6 @@ cargo test --verbose --no-default-features
 cargo test --release --verbose --no-default-features
 cargo build --verbose --features "$FEATURES"
 cargo test --verbose --features "$FEATURES"
-cargo test --manifest-path=ndarray-rand/Cargo.toml --no-default-features --verbose
-cargo test --manifest-path=ndarray-rand/Cargo.toml --features quickcheck --verbose
 cargo test --manifest-path=serialization-tests/Cargo.toml --verbose
 cargo test --manifest-path=blas-tests/Cargo.toml --verbose
 CARGO_TARGET_DIR=target/ cargo test --manifest-path=numeric-tests/Cargo.toml --verbose
diff --git a/serialization-tests/tests/serialize.rs b/serialization-tests/tests/serialize.rs
index efb3bacd..953f2a43 100644
--- a/serialization-tests/tests/serialize.rs
+++ b/serialization-tests/tests/serialize.rs
@@ -9,7 +9,7 @@ extern crate rmp_serde;
 #[cfg(feature = "ron")]
 extern crate ron;
 
-use ndarray::{arr0, arr1, arr2, s, ArcArray, ArcArray2, ArrayD, IxDyn};
+use ndarray::{arr0, arr1, arr2, s, ArcArray, ArrayD, Ix2, IxDyn};
 
 #[test]
 fn serial_many_dim_serde() {
@@ -98,13 +98,13 @@ fn serial_ixdyn_serde() {
 fn serial_wrong_count_serde() {
     // one element too few
     let text = r##"{"v":1,"dim":[2,3],"data":[3,1,2.2,3.1,4]}"##;
-    let arr = serde_json::from_str::<ArcArray2<f32>>(text);
+    let arr = serde_json::from_str::<ArcArray<f32, Ix2>>(text);
     println!("{:?}", arr);
     assert!(arr.is_err());
 
     // future version
     let text = r##"{"v":200,"dim":[2,3],"data":[3,1,2.2,3.1,4,7]}"##;
-    let arr = serde_json::from_str::<ArcArray2<f32>>(text);
+    let arr = serde_json::from_str::<ArcArray<f32, Ix2>>(text);
     println!("{:?}", arr);
     assert!(arr.is_err());
 }
diff --git a/tests/raw_views.rs b/tests/raw_views.rs
index 09e01aeb..b63e4292 100644
--- a/tests/raw_views.rs
+++ b/tests/raw_views.rs
@@ -2,8 +2,6 @@ use ndarray::prelude::*;
 use ndarray::Zip;
 
 use std::cell::Cell;
-#[cfg(debug_assertions)]
-use std::mem;
 
 #[test]
 fn raw_view_cast_cell() {
@@ -59,28 +57,27 @@ fn raw_view_mut_invalid_size_cast() {
 }
 
 #[test]
-#[cfg(debug_assertions)]
-#[should_panic = "alignment mismatch"]
-fn raw_view_invalid_align_cast() {
-    #[derive(Copy, Clone, Debug)]
-    #[repr(transparent)]
-    struct A([u8; 16]);
-    #[derive(Copy, Clone, Debug)]
-    #[repr(transparent)]
-    struct B([f64; 2]);
-
+fn raw_view_misaligned() {
+    let data: [u16; 2] = [0x0011, 0x2233];
+    let ptr: *const u16 = data.as_ptr();
     unsafe {
-        const LEN: usize = 16;
-        let mut buffer = [0u8; mem::size_of::<A>() * (LEN + 1)];
-        // Take out a slice of buffer as &[A] which is misaligned for B
-        let mut ptr = buffer.as_mut_ptr();
-        if ptr as usize % mem::align_of::<B>() == 0 {
-            ptr = ptr.add(1);
-        }
-
-        let view = RawArrayViewMut::from_shape_ptr(LEN, ptr as *mut A);
+        let misaligned_ptr = (ptr as *const u8).add(1) as *const u16;
+        RawArrayView::from_shape_ptr(1, misaligned_ptr);
+    }
+}
 
-        // misaligned cast - test debug assertion
-        view.cast::<B>();
+#[test]
+#[cfg(debug_assertions)]
+#[should_panic = "The pointer must be aligned."]
+fn raw_view_deref_into_view_misaligned() {
+    fn misaligned_deref(data: &[u16; 2]) -> ArrayView1<'_, u16> {
+        let ptr: *const u16 = data.as_ptr();
+        unsafe {
+            let misaligned_ptr = (ptr as *const u8).add(1) as *const u16;
+            let raw_view = RawArrayView::from_shape_ptr(1, misaligned_ptr);
+            raw_view.deref_into_view()
+        }
     }
+    let data: [u16; 2] = [0x0011, 0x2233];
+    misaligned_deref(&data);
 }