use crate::error::{from_kind, ErrorKind, ShapeError};
use crate::slice::SliceArg;
use crate::{Ix, Ixs, Slice, SliceInfoElem};
use crate::shape_builder::Strides;
use num_integer::div_floor;
pub use self::axes::{Axes, AxisDescription};
pub use self::axis::Axis;
pub use self::broadcast::DimMax;
pub use self::conversion::IntoDimension;
pub use self::dim::*;
pub use self::dimension_trait::Dimension;
pub use self::dynindeximpl::IxDynImpl;
pub use self::ndindex::NdIndex;
pub use self::ops::DimAdd;
pub use self::remove_axis::RemoveAxis;
pub(crate) use self::axes::axes_of;
pub(crate) use self::reshape::reshape_dim;
use std::isize;
use std::mem;
#[macro_use]
mod macros;
mod axes;
mod axis;
pub(crate) mod broadcast;
mod conversion;
pub mod dim;
mod dimension_trait;
mod dynindeximpl;
mod ndindex;
mod ops;
mod remove_axis;
pub(crate) mod reshape;
mod sequence;
#[inline(always)]
pub fn stride_offset(n: Ix, stride: Ix) -> isize {
(n as isize) * ((stride as Ixs) as isize)
}
pub fn dim_stride_overlap<D: Dimension>(dim: &D, strides: &D) -> bool {
let order = strides._fastest_varying_stride_order();
let mut sum_prev_offsets = 0;
for &index in order.slice() {
let d = dim[index];
let s = (strides[index] as isize).abs();
match d {
0 => return false,
1 => {}
_ => {
if s <= sum_prev_offsets {
return true;
}
sum_prev_offsets += (d - 1) as isize * s;
}
}
}
false
}
pub fn size_of_shape_checked<D: Dimension>(dim: &D) -> Result<usize, ShapeError> {
let size_nonzero = dim
.slice()
.iter()
.filter(|&&d| d != 0)
.try_fold(1usize, |acc, &d| acc.checked_mul(d))
.ok_or_else(|| from_kind(ErrorKind::Overflow))?;
if size_nonzero > ::std::isize::MAX as usize {
Err(from_kind(ErrorKind::Overflow))
} else {
Ok(dim.size())
}
}
pub(crate) fn can_index_slice_with_strides<A, D: Dimension>(data: &[A], dim: &D,
strides: &Strides<D>)
-> Result<(), ShapeError>
{
if let Strides::Custom(strides) = strides {
can_index_slice(data, dim, strides)
} else {
can_index_slice_not_custom(data.len(), dim)
}
}
pub(crate) fn can_index_slice_not_custom<D: Dimension>(data_len: usize, dim: &D)
-> Result<(), ShapeError>
{
let len = size_of_shape_checked(dim)?;
if len > data_len {
return Err(from_kind(ErrorKind::OutOfBounds));
}
Ok(())
}
pub fn max_abs_offset_check_overflow<A, D>(dim: &D, strides: &D) -> Result<usize, ShapeError>
where
D: Dimension,
{
max_abs_offset_check_overflow_impl(mem::size_of::<A>(), dim, strides)
}
fn max_abs_offset_check_overflow_impl<D>(elem_size: usize, dim: &D, strides: &D)
-> Result<usize, ShapeError>
where
D: Dimension,
{
if dim.ndim() != strides.ndim() {
return Err(from_kind(ErrorKind::IncompatibleLayout));
}
let _ = size_of_shape_checked(dim)?;
let max_offset: usize = izip!(dim.slice(), strides.slice())
.try_fold(0usize, |acc, (&d, &s)| {
let s = s as isize;
let off = d.saturating_sub(1).checked_mul(s.abs() as usize)?;
acc.checked_add(off)
})
.ok_or_else(|| from_kind(ErrorKind::Overflow))?;
if max_offset > isize::MAX as usize {
return Err(from_kind(ErrorKind::Overflow));
}
let max_offset_bytes = max_offset
.checked_mul(elem_size)
.ok_or_else(|| from_kind(ErrorKind::Overflow))?;
if max_offset_bytes > isize::MAX as usize {
return Err(from_kind(ErrorKind::Overflow));
}
Ok(max_offset)
}
pub(crate) fn can_index_slice<A, D: Dimension>(
data: &[A],
dim: &D,
strides: &D,
) -> Result<(), ShapeError> {
let max_offset = max_abs_offset_check_overflow::<A, _>(dim, strides)?;
can_index_slice_impl(max_offset, data.len(), dim, strides)
}
fn can_index_slice_impl<D: Dimension>(
max_offset: usize,
data_len: usize,
dim: &D,
strides: &D,
) -> Result<(), ShapeError> {
let is_empty = dim.slice().iter().any(|&d| d == 0);
if is_empty && max_offset > data_len {
return Err(from_kind(ErrorKind::OutOfBounds));
}
if !is_empty && max_offset >= data_len {
return Err(from_kind(ErrorKind::OutOfBounds));
}
if !is_empty && dim_stride_overlap(dim, strides) {
return Err(from_kind(ErrorKind::Unsupported));
}
Ok(())
}
#[inline]
pub fn stride_offset_checked(dim: &[Ix], strides: &[Ix], index: &[Ix]) -> Option<isize> {
if index.len() != dim.len() {
return None;
}
let mut offset = 0;
for (&d, &i, &s) in izip!(dim, index, strides) {
if i >= d {
return None;
}
offset += stride_offset(i, s);
}
Some(offset)
}
pub fn strides_non_negative<D>(strides: &D) -> Result<(), ShapeError>
where
D: Dimension,
{
for &stride in strides.slice() {
if (stride as isize) < 0 {
return Err(from_kind(ErrorKind::Unsupported));
}
}
Ok(())
}
pub trait DimensionExt {
fn axis(&self, axis: Axis) -> Ix;
fn set_axis(&mut self, axis: Axis, value: Ix);
}
impl<D> DimensionExt for D
where
D: Dimension,
{
#[inline]
fn axis(&self, axis: Axis) -> Ix {
self[axis.index()]
}
#[inline]
fn set_axis(&mut self, axis: Axis, value: Ix) {
self[axis.index()] = value;
}
}
impl DimensionExt for [Ix] {
#[inline]
fn axis(&self, axis: Axis) -> Ix {
self[axis.index()]
}
#[inline]
fn set_axis(&mut self, axis: Axis, value: Ix) {
self[axis.index()] = value;
}
}
pub fn do_collapse_axis<D: Dimension>(
dims: &mut D,
strides: &D,
axis: usize,
index: usize,
) -> isize {
let dim = dims.slice()[axis];
let stride = strides.slice()[axis];
ndassert!(
index < dim,
"collapse_axis: Index {} must be less than axis length {} for \
array with shape {:?}",
index,
dim,
*dims
);
dims.slice_mut()[axis] = 1;
stride_offset(index, stride)
}
#[inline]
pub fn abs_index(len: Ix, index: Ixs) -> Ix {
if index < 0 {
len - (-index as Ix)
} else {
index as Ix
}
}
fn to_abs_slice(axis_len: usize, slice: Slice) -> (usize, usize, isize) {
let Slice { start, end, step } = slice;
let start = abs_index(axis_len, start);
let mut end = abs_index(axis_len, end.unwrap_or(axis_len as isize));
if end < start {
end = start;
}
ndassert!(
start <= axis_len,
"Slice begin {} is past end of axis of length {}",
start,
axis_len,
);
ndassert!(
end <= axis_len,
"Slice end {} is past end of axis of length {}",
end,
axis_len,
);
ndassert!(step != 0, "Slice stride must not be zero");
(start, end, step)
}
pub fn offset_from_low_addr_ptr_to_logical_ptr<D: Dimension>(dim: &D, strides: &D) -> usize {
let offset = izip!(dim.slice(), strides.slice()).fold(0, |_offset, (&d, &s)| {
let s = s as isize;
if s < 0 && d > 1 {
_offset - s * (d as isize - 1)
} else {
_offset
}
});
debug_assert!(offset >= 0);
offset as usize
}
pub fn do_slice(dim: &mut usize, stride: &mut usize, slice: Slice) -> isize {
let (start, end, step) = to_abs_slice(*dim, slice);
let m = end - start;
let s = (*stride) as isize;
let offset = if m == 0 {
0
} else if step < 0 {
stride_offset(end - 1, *stride)
} else {
stride_offset(start, *stride)
};
let abs_step = step.abs() as usize;
*dim = if abs_step == 1 {
m
} else {
let d = m / abs_step;
let r = m % abs_step;
d + if r > 0 { 1 } else { 0 }
};
*stride = if *dim <= 1 { 0 } else { (s * step) as usize };
offset
}
fn extended_gcd(a: isize, b: isize) -> (isize, (isize, isize)) {
if a == 0 {
(b.abs(), (0, b.signum()))
} else if b == 0 {
(a.abs(), (a.signum(), 0))
} else {
let mut r = (a, b);
let mut s = (1, 0);
let mut t = (0, 1);
while r.1 != 0 {
let q = r.0 / r.1;
r = (r.1, r.0 - q * r.1);
s = (s.1, s.0 - q * s.1);
t = (t.1, t.0 - q * t.1);
}
if r.0 > 0 {
(r.0, (s.0, t.0))
} else {
(-r.0, (-s.0, -t.0))
}
}
}
fn solve_linear_diophantine_eq(a: isize, b: isize, c: isize) -> Option<(isize, isize)> {
debug_assert_ne!(a, 0);
debug_assert_ne!(b, 0);
let (g, (u, _)) = extended_gcd(a, b);
if c % g == 0 {
Some((c / g * u, (b / g).abs()))
} else {
None
}
}
fn arith_seq_intersect(
(min1, max1, step1): (isize, isize, isize),
(min2, max2, step2): (isize, isize, isize),
) -> bool {
debug_assert!(max1 >= min1);
debug_assert!(max2 >= min2);
debug_assert_eq!((max1 - min1) % step1, 0);
debug_assert_eq!((max2 - min2) % step2, 0);
if min1 > max2 || min2 > max1 {
false
} else {
let step1 = step1.abs();
let step2 = step2.abs();
if let Some((x0, xd)) = solve_linear_diophantine_eq(-step1, step2, min1 - min2) {
let min = ::std::cmp::max(min1, min2);
let max = ::std::cmp::min(max1, max2);
min1 + step1 * (x0 - xd * div_floor(min - min1 - step1 * x0, -step1 * xd)) <= max
|| min1 + step1 * (x0 + xd * div_floor(max - min1 - step1 * x0, step1 * xd)) >= min
} else {
false
}
}
}
fn slice_min_max(axis_len: usize, slice: Slice) -> Option<(usize, usize)> {
let (start, end, step) = to_abs_slice(axis_len, slice);
if start == end {
None
} else if step > 0 {
Some((start, end - 1 - (end - start - 1) % (step as usize)))
} else {
Some((start + (end - start - 1) % (-step as usize), end - 1))
}
}
pub fn slices_intersect<D: Dimension>(
dim: &D,
indices1: impl SliceArg<D>,
indices2: impl SliceArg<D>,
) -> bool {
debug_assert_eq!(indices1.in_ndim(), indices2.in_ndim());
for (&axis_len, &si1, &si2) in izip!(
dim.slice(),
indices1.as_ref().iter().filter(|si| !si.is_new_axis()),
indices2.as_ref().iter().filter(|si| !si.is_new_axis()),
) {
match (si1, si2) {
(
SliceInfoElem::Slice {
start: start1,
end: end1,
step: step1,
},
SliceInfoElem::Slice {
start: start2,
end: end2,
step: step2,
},
) => {
let (min1, max1) = match slice_min_max(axis_len, Slice::new(start1, end1, step1)) {
Some(m) => m,
None => return false,
};
let (min2, max2) = match slice_min_max(axis_len, Slice::new(start2, end2, step2)) {
Some(m) => m,
None => return false,
};
if !arith_seq_intersect(
(min1 as isize, max1 as isize, step1),
(min2 as isize, max2 as isize, step2),
) {
return false;
}
}
(SliceInfoElem::Slice { start, end, step }, SliceInfoElem::Index(ind))
| (SliceInfoElem::Index(ind), SliceInfoElem::Slice { start, end, step }) => {
let ind = abs_index(axis_len, ind);
let (min, max) = match slice_min_max(axis_len, Slice::new(start, end, step)) {
Some(m) => m,
None => return false,
};
if ind < min || ind > max || (ind - min) % step.abs() as usize != 0 {
return false;
}
}
(SliceInfoElem::Index(ind1), SliceInfoElem::Index(ind2)) => {
let ind1 = abs_index(axis_len, ind1);
let ind2 = abs_index(axis_len, ind2);
if ind1 != ind2 {
return false;
}
}
(SliceInfoElem::NewAxis, _) | (_, SliceInfoElem::NewAxis) => unreachable!(),
}
}
true
}
pub(crate) fn is_layout_c<D: Dimension>(dim: &D, strides: &D) -> bool {
if let Some(1) = D::NDIM {
return strides[0] == 1 || dim[0] <= 1;
}
for &d in dim.slice() {
if d == 0 {
return true;
}
}
let mut contig_stride = 1_isize;
for (&dim, &s) in izip!(dim.slice().iter().rev(), strides.slice().iter().rev()) {
if dim != 1 {
let s = s as isize;
if s != contig_stride {
return false;
}
contig_stride *= dim as isize;
}
}
true
}
pub(crate) fn is_layout_f<D: Dimension>(dim: &D, strides: &D) -> bool {
if let Some(1) = D::NDIM {
return strides[0] == 1 || dim[0] <= 1;
}
for &d in dim.slice() {
if d == 0 {
return true;
}
}
let mut contig_stride = 1_isize;
for (&dim, &s) in izip!(dim.slice(), strides.slice()) {
if dim != 1 {
let s = s as isize;
if s != contig_stride {
return false;
}
contig_stride *= dim as isize;
}
}
true
}
pub fn merge_axes<D>(dim: &mut D, strides: &mut D, take: Axis, into: Axis) -> bool
where
D: Dimension,
{
let into_len = dim.axis(into);
let into_stride = strides.axis(into) as isize;
let take_len = dim.axis(take);
let take_stride = strides.axis(take) as isize;
let merged_len = into_len * take_len;
if take_len <= 1 {
dim.set_axis(into, merged_len);
dim.set_axis(take, if merged_len == 0 { 0 } else { 1 });
true
} else if into_len <= 1 {
strides.set_axis(into, take_stride as usize);
dim.set_axis(into, merged_len);
dim.set_axis(take, if merged_len == 0 { 0 } else { 1 });
true
} else if take_stride == into_len as isize * into_stride {
dim.set_axis(into, merged_len);
dim.set_axis(take, 1);
true
} else {
false
}
}
pub fn move_min_stride_axis_to_last<D>(dim: &mut D, strides: &mut D)
where
D: Dimension,
{
debug_assert_eq!(dim.ndim(), strides.ndim());
match dim.ndim() {
0 | 1 => {}
2 => {
if dim[1] <= 1
|| dim[0] > 1 && (strides[0] as isize).abs() < (strides[1] as isize).abs()
{
dim.slice_mut().swap(0, 1);
strides.slice_mut().swap(0, 1);
}
}
n => {
if let Some(min_stride_axis) = (0..n)
.filter(|&ax| dim[ax] > 1)
.min_by_key(|&ax| (strides[ax] as isize).abs())
{
let last = n - 1;
dim.slice_mut().swap(last, min_stride_axis);
strides.slice_mut().swap(last, min_stride_axis);
}
}
}
}
#[cfg(test)]
mod test {
use super::{
arith_seq_intersect, can_index_slice, can_index_slice_not_custom, extended_gcd,
max_abs_offset_check_overflow, slice_min_max, slices_intersect,
solve_linear_diophantine_eq, IntoDimension,
};
use crate::error::{from_kind, ErrorKind};
use crate::slice::Slice;
use crate::{Dim, Dimension, Ix0, Ix1, Ix2, Ix3, IxDyn, NewAxis};
use num_integer::gcd;
use quickcheck::{quickcheck, TestResult};
#[test]
fn slice_indexing_uncommon_strides() {
let v: alloc::vec::Vec<_> = (0..12).collect();
let dim = (2, 3, 2).into_dimension();
let strides = (1, 2, 6).into_dimension();
assert!(super::can_index_slice(&v, &dim, &strides).is_ok());
let strides = (2, 4, 12).into_dimension();
assert_eq!(
super::can_index_slice(&v, &dim, &strides),
Err(from_kind(ErrorKind::OutOfBounds))
);
}
#[test]
fn overlapping_strides_dim() {
let dim = (2, 3, 2).into_dimension();
let strides = (5, 2, 1).into_dimension();
assert!(super::dim_stride_overlap(&dim, &strides));
let strides = (-5isize as usize, 2, -1isize as usize).into_dimension();
assert!(super::dim_stride_overlap(&dim, &strides));
let strides = (6, 2, 1).into_dimension();
assert!(!super::dim_stride_overlap(&dim, &strides));
let strides = (6, -2isize as usize, 1).into_dimension();
assert!(!super::dim_stride_overlap(&dim, &strides));
let strides = (6, 0, 1).into_dimension();
assert!(super::dim_stride_overlap(&dim, &strides));
let strides = (-6isize as usize, 0, 1).into_dimension();
assert!(super::dim_stride_overlap(&dim, &strides));
let dim = (2, 2).into_dimension();
let strides = (3, 2).into_dimension();
assert!(!super::dim_stride_overlap(&dim, &strides));
let strides = (3, -2isize as usize).into_dimension();
assert!(!super::dim_stride_overlap(&dim, &strides));
}
#[test]
fn max_abs_offset_check_overflow_examples() {
let dim = (1, ::std::isize::MAX as usize, 1).into_dimension();
let strides = (1, 1, 1).into_dimension();
max_abs_offset_check_overflow::<u8, _>(&dim, &strides).unwrap();
let dim = (1, ::std::isize::MAX as usize, 2).into_dimension();
let strides = (1, 1, 1).into_dimension();
max_abs_offset_check_overflow::<u8, _>(&dim, &strides).unwrap_err();
let dim = (0, 2, 2).into_dimension();
let strides = (1, ::std::isize::MAX as usize, 1).into_dimension();
max_abs_offset_check_overflow::<u8, _>(&dim, &strides).unwrap_err();
let dim = (0, 2, 2).into_dimension();
let strides = (1, ::std::isize::MAX as usize / 4, 1).into_dimension();
max_abs_offset_check_overflow::<i32, _>(&dim, &strides).unwrap_err();
}
#[test]
fn can_index_slice_ix0() {
can_index_slice::<i32, _>(&[1], &Ix0(), &Ix0()).unwrap();
can_index_slice::<i32, _>(&[], &Ix0(), &Ix0()).unwrap_err();
}
#[test]
fn can_index_slice_ix1() {
can_index_slice::<i32, _>(&[], &Ix1(0), &Ix1(0)).unwrap();
can_index_slice::<i32, _>(&[], &Ix1(0), &Ix1(1)).unwrap();
can_index_slice::<i32, _>(&[], &Ix1(1), &Ix1(0)).unwrap_err();
can_index_slice::<i32, _>(&[], &Ix1(1), &Ix1(1)).unwrap_err();
can_index_slice::<i32, _>(&[1], &Ix1(1), &Ix1(0)).unwrap();
can_index_slice::<i32, _>(&[1], &Ix1(1), &Ix1(2)).unwrap();
can_index_slice::<i32, _>(&[1], &Ix1(1), &Ix1(-1isize as usize)).unwrap();
can_index_slice::<i32, _>(&[1], &Ix1(2), &Ix1(1)).unwrap_err();
can_index_slice::<i32, _>(&[1, 2], &Ix1(2), &Ix1(0)).unwrap_err();
can_index_slice::<i32, _>(&[1, 2], &Ix1(2), &Ix1(1)).unwrap();
can_index_slice::<i32, _>(&[1, 2], &Ix1(2), &Ix1(-1isize as usize)).unwrap();
}
#[test]
fn can_index_slice_ix2() {
can_index_slice::<i32, _>(&[], &Ix2(0, 0), &Ix2(0, 0)).unwrap();
can_index_slice::<i32, _>(&[], &Ix2(0, 0), &Ix2(2, 1)).unwrap();
can_index_slice::<i32, _>(&[], &Ix2(0, 1), &Ix2(0, 0)).unwrap();
can_index_slice::<i32, _>(&[], &Ix2(0, 1), &Ix2(2, 1)).unwrap();
can_index_slice::<i32, _>(&[], &Ix2(0, 2), &Ix2(0, 0)).unwrap();
can_index_slice::<i32, _>(&[], &Ix2(0, 2), &Ix2(2, 1)).unwrap_err();
can_index_slice::<i32, _>(&[1], &Ix2(1, 2), &Ix2(5, 1)).unwrap_err();
can_index_slice::<i32, _>(&[1, 2], &Ix2(1, 2), &Ix2(5, 1)).unwrap();
can_index_slice::<i32, _>(&[1, 2], &Ix2(1, 2), &Ix2(5, 2)).unwrap_err();
can_index_slice::<i32, _>(&[1, 2, 3, 4, 5], &Ix2(2, 2), &Ix2(3, 1)).unwrap();
can_index_slice::<i32, _>(&[1, 2, 3, 4], &Ix2(2, 2), &Ix2(3, 1)).unwrap_err();
}
#[test]
fn can_index_slice_ix3() {
can_index_slice::<i32, _>(&[], &Ix3(0, 0, 1), &Ix3(2, 1, 3)).unwrap();
can_index_slice::<i32, _>(&[], &Ix3(1, 1, 1), &Ix3(2, 1, 3)).unwrap_err();
can_index_slice::<i32, _>(&[1], &Ix3(1, 1, 1), &Ix3(2, 1, 3)).unwrap();
can_index_slice::<i32, _>(&[1; 11], &Ix3(2, 2, 3), &Ix3(6, 3, 1)).unwrap_err();
can_index_slice::<i32, _>(&[1; 12], &Ix3(2, 2, 3), &Ix3(6, 3, 1)).unwrap();
}
#[test]
fn can_index_slice_zero_size_elem() {
can_index_slice::<(), _>(&[], &Ix1(0), &Ix1(1)).unwrap();
can_index_slice::<(), _>(&[()], &Ix1(1), &Ix1(1)).unwrap();
can_index_slice::<(), _>(&[(), ()], &Ix1(2), &Ix1(1)).unwrap();
can_index_slice::<(), _>(&[], &Ix1(1), &Ix1(1)).unwrap_err();
can_index_slice::<(), _>(&[()], &Ix1(2), &Ix1(1)).unwrap_err();
can_index_slice::<(), _>(&[(), ()], &Ix2(2, 1), &Ix2(1, 0)).unwrap();
can_index_slice::<(), _>(&[], &Ix2(0, 2), &Ix2(0, 0)).unwrap();
can_index_slice::<(), _>(&[], &Ix2(0, 2), &Ix2(2, 1)).unwrap_err();
}
quickcheck! {
fn can_index_slice_not_custom_same_as_can_index_slice(data: alloc::vec::Vec<u8>, dim: alloc::vec::Vec<usize>) -> bool {
let dim = IxDyn(&dim);
let result = can_index_slice_not_custom(data.len(), &dim);
if dim.size_checked().is_none() {
result.is_err()
} else {
result == can_index_slice(&data, &dim, &dim.default_strides()) &&
result == can_index_slice(&data, &dim, &dim.fortran_strides())
}
}
}
quickcheck! {
fn extended_gcd_solves_eq(a: i16, b: i16) -> bool {
let (a, b) = (a as isize, b as isize);
let (g, (x, y)) = extended_gcd(a, b);
a * x + b * y == g
}
fn extended_gcd_correct_gcd(a: i16, b: i16) -> bool {
let (a, b) = (a as isize, b as isize);
let (g, _) = extended_gcd(a, b);
g == gcd(a, b)
}
}
#[test]
fn extended_gcd_zero() {
assert_eq!(extended_gcd(0, 0), (0, (0, 0)));
assert_eq!(extended_gcd(0, 5), (5, (0, 1)));
assert_eq!(extended_gcd(5, 0), (5, (1, 0)));
assert_eq!(extended_gcd(0, -5), (5, (0, -1)));
assert_eq!(extended_gcd(-5, 0), (5, (-1, 0)));
}
quickcheck! {
fn solve_linear_diophantine_eq_solution_existence(
a: i16, b: i16, c: i16
) -> TestResult {
let (a, b, c) = (a as isize, b as isize, c as isize);
if a == 0 || b == 0 {
TestResult::discard()
} else {
TestResult::from_bool(
(c % gcd(a, b) == 0) == solve_linear_diophantine_eq(a, b, c).is_some()
)
}
}
fn solve_linear_diophantine_eq_correct_solution(
a: i8, b: i8, c: i8, t: i8
) -> TestResult {
let (a, b, c, t) = (a as isize, b as isize, c as isize, t as isize);
if a == 0 || b == 0 {
TestResult::discard()
} else {
match solve_linear_diophantine_eq(a, b, c) {
Some((x0, xd)) => {
let x = x0 + xd * t;
let y = (c - a * x) / b;
TestResult::from_bool(a * x + b * y == c)
}
None => TestResult::discard(),
}
}
}
}
quickcheck! {
fn arith_seq_intersect_correct(
first1: i8, len1: i8, step1: i8,
first2: i8, len2: i8, step2: i8
) -> TestResult {
use std::cmp;
let (len1, len2) = (len1 as isize, len2 as isize);
let (first1, step1) = (first1 as isize, step1 as isize);
let (first2, step2) = (first2 as isize, step2 as isize);
if len1 == 0 || len2 == 0 {
return TestResult::discard();
}
let len1 = len1.abs();
let len2 = len2.abs();
let last1 = first1 + step1 * (len1 - 1);
let (min1, max1) = (cmp::min(first1, last1), cmp::max(first1, last1));
let last2 = first2 + step2 * (len2 - 1);
let (min2, max2) = (cmp::min(first2, last2), cmp::max(first2, last2));
let seq1: alloc::vec::Vec<_> = (0..len1)
.map(|n| first1 + step1 * n)
.collect();
let intersects = (0..len2)
.map(|n| first2 + step2 * n)
.any(|elem2| seq1.contains(&elem2));
TestResult::from_bool(
arith_seq_intersect(
(min1, max1, if step1 == 0 { 1 } else { step1 }),
(min2, max2, if step2 == 0 { 1 } else { step2 })
) == intersects
)
}
}
#[test]
fn slice_min_max_empty() {
assert_eq!(slice_min_max(0, Slice::new(0, None, 3)), None);
assert_eq!(slice_min_max(10, Slice::new(1, Some(1), 3)), None);
assert_eq!(slice_min_max(10, Slice::new(-1, Some(-1), 3)), None);
assert_eq!(slice_min_max(10, Slice::new(1, Some(1), -3)), None);
assert_eq!(slice_min_max(10, Slice::new(-1, Some(-1), -3)), None);
}
#[test]
fn slice_min_max_pos_step() {
assert_eq!(slice_min_max(10, Slice::new(1, Some(8), 3)), Some((1, 7)));
assert_eq!(slice_min_max(10, Slice::new(1, Some(9), 3)), Some((1, 7)));
assert_eq!(slice_min_max(10, Slice::new(-9, Some(8), 3)), Some((1, 7)));
assert_eq!(slice_min_max(10, Slice::new(-9, Some(9), 3)), Some((1, 7)));
assert_eq!(slice_min_max(10, Slice::new(1, Some(-2), 3)), Some((1, 7)));
assert_eq!(slice_min_max(10, Slice::new(1, Some(-1), 3)), Some((1, 7)));
assert_eq!(slice_min_max(10, Slice::new(-9, Some(-2), 3)), Some((1, 7)));
assert_eq!(slice_min_max(10, Slice::new(-9, Some(-1), 3)), Some((1, 7)));
assert_eq!(slice_min_max(10, Slice::new(1, None, 3)), Some((1, 7)));
assert_eq!(slice_min_max(10, Slice::new(-9, None, 3)), Some((1, 7)));
assert_eq!(slice_min_max(11, Slice::new(1, None, 3)), Some((1, 10)));
assert_eq!(slice_min_max(11, Slice::new(-10, None, 3)), Some((1, 10)));
}
#[test]
fn slice_min_max_neg_step() {
assert_eq!(slice_min_max(10, Slice::new(1, Some(8), -3)), Some((1, 7)));
assert_eq!(slice_min_max(10, Slice::new(2, Some(8), -3)), Some((4, 7)));
assert_eq!(slice_min_max(10, Slice::new(-9, Some(8), -3)), Some((1, 7)));
assert_eq!(slice_min_max(10, Slice::new(-8, Some(8), -3)), Some((4, 7)));
assert_eq!(slice_min_max(10, Slice::new(1, Some(-2), -3)), Some((1, 7)));
assert_eq!(slice_min_max(10, Slice::new(2, Some(-2), -3)), Some((4, 7)));
assert_eq!(
slice_min_max(10, Slice::new(-9, Some(-2), -3)),
Some((1, 7))
);
assert_eq!(
slice_min_max(10, Slice::new(-8, Some(-2), -3)),
Some((4, 7))
);
assert_eq!(slice_min_max(9, Slice::new(2, None, -3)), Some((2, 8)));
assert_eq!(slice_min_max(9, Slice::new(-7, None, -3)), Some((2, 8)));
assert_eq!(slice_min_max(9, Slice::new(3, None, -3)), Some((5, 8)));
assert_eq!(slice_min_max(9, Slice::new(-6, None, -3)), Some((5, 8)));
}
#[test]
fn slices_intersect_true() {
assert!(slices_intersect(
&Dim([4, 5]),
s![NewAxis, .., NewAxis, ..],
s![.., NewAxis, .., NewAxis]
));
assert!(slices_intersect(
&Dim([4, 5]),
s![NewAxis, 0, ..],
s![0, ..]
));
assert!(slices_intersect(
&Dim([4, 5]),
s![..;2, ..],
s![..;3, NewAxis, ..]
));
assert!(slices_intersect(
&Dim([4, 5]),
s![.., ..;2],
s![.., 1..;3, NewAxis]
));
assert!(slices_intersect(&Dim([4, 10]), s![.., ..;9], s![.., 3..;6]));
}
#[test]
fn slices_intersect_false() {
assert!(!slices_intersect(
&Dim([4, 5]),
s![..;2, ..],
s![NewAxis, 1..;2, ..]
));
assert!(!slices_intersect(
&Dim([4, 5]),
s![..;2, NewAxis, ..],
s![1..;3, ..]
));
assert!(!slices_intersect(
&Dim([4, 5]),
s![.., ..;9],
s![.., 3..;6, NewAxis]
));
}
}