use alloc::vec;
use alloc::vec::Vec;
use alloc::boxed::Box;
use crate::{ MatrixExt, MatrixMutExt };
use crate::access::Observer;
use ::core::ops::Deref;
use ::core::ops::{RangeBounds, RangeInclusive};
pub use crate::req::{ AccessStrategy, TransformStrategy, SwapsDimensions, InPlace };
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Default, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
pub struct Identity;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Default, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
pub struct Transpose;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Default, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
pub struct RotateR;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Default, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
pub struct RotateL;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Default, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
pub struct FlipH;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Default, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
pub struct FlipV;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Default, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
pub struct Reverse;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Default, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
pub struct ShiftFront(pub usize);
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Default, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
pub struct ShiftBack(pub usize);
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Default, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
pub struct Submatrix<Rows: RangeBounds<usize>, Cols: RangeBounds<usize>>(pub Rows, pub Cols);
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Default, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
pub struct Reshape(pub usize, pub usize);
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug)]
pub struct AccessMap<Mapping: MatrixExt>(pub Mapping);
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub type AccessStrategySet = Vec<Box<dyn AccessStrategy<Observer>>>;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Hash, Clone, Copy, Debug)]
pub struct SortBy<T> (pub fn(&T, &T) -> bool);
impl Transpose {
pub fn in_place_square<M: MatrixMutExt>(&self, m: &mut M) {
if !m.is_square() {
panic!("The matrix is not a square matrix.")
}
let dim = m.num_rows(); for i in 0..dim {
for j in 0..i {
m.swap((i, j), (j, i));
}
}
}
pub fn in_place<M: SwapsDimensions + MatrixMutExt>(&self, m: &mut M) {
let r = m.num_rows();
let limit = m.size() - 1;
let mut toreplace;
let mut next ;
let mut cycle_begin;
#[cfg(not(feature = "std"))]
let mut moved: Vec<usize> = vec![];
#[cfg(feature = "std")]
let mut moved: HashSet<usize> = std::collections::HashSet::new();
let mut i = 1;
while i < limit {
cycle_begin = i;
toreplace = i;
loop {
next = (i * r) % limit;
m.swapn(toreplace, next);
#[cfg(not(feature = "std"))]
moved.push(i);
#[cfg(feature = "std")]
moved.insert(i);
i = next;
if i == cycle_begin {
break
}
}
i = 1;
while i < limit && moved.contains(&i) { i += 1 }
}
m.swap_dimensions();
}
}
impl Reverse {
pub fn rev<M: MatrixMutExt>(&self, m: &mut M, range: ::core::ops::Range<usize>) {
let mid = (range.start + range.end) / 2;
for i in range.start..mid {
m.swapn(i, range.end + range.start - i - 1);
}
}
pub fn rev2<M: MatrixMutExt>(&self, m: &mut M, range: ::core::ops::Range<(usize, usize)>) {
let (start, end) = (m.index_from(range.start), m.index_from(range.end));
self.rev(m, start..end);
}
}
impl<Rows: RangeBounds<usize>, Cols: RangeBounds<usize>> Submatrix<Rows, Cols>
{
fn get_range<R: RangeBounds<usize>>(len: usize, r: &R)
-> RangeInclusive<usize> {
use ::core::ops::Bound;
let start = match r.start_bound() {
Bound::Unbounded => 0,
Bound::Excluded(start) => *start + 1,
Bound::Included(start) => *start,
};
if start >= len {
return RangeInclusive::new(1, 0);
}
let end = match r.end_bound() {
Bound::Excluded(&end) if end < len => end.saturating_sub(1),
Bound::Included(&end) if end < len => end,
_ => len.saturating_sub(1),
};
RangeInclusive::new(start, end)
}
}
impl <M: MatrixExt, S: AccessStrategy<M>> AccessStrategy<M> for &S {
#[inline]
fn access(&self, m: &M, i: usize, j: usize) -> Option<(usize, usize)> {
(*self).access(m, i, j)
}
#[inline]
fn nrows(&self, m: &M) -> usize { (*self).nrows(m) }
#[inline]
fn ncols(&self, m: &M) -> usize { (*self).ncols(m) }
}
impl <M: MatrixExt> AccessStrategy<M> for Box<dyn AccessStrategy<M>> {
#[inline]
fn access(&self, m: &M, i: usize, j: usize) -> Option<(usize, usize)> {
self.deref().access(m, i, j)
}
#[inline]
fn nrows(&self, m: &M) -> usize { self.deref().nrows(m) }
#[inline]
fn ncols(&self, m: &M) -> usize { self.deref().ncols(m) }
}
impl <M: MatrixExt> AccessStrategy<M> for &dyn AccessStrategy<M> {
#[inline]
fn access(&self, m: &M, i: usize, j: usize) -> Option<(usize, usize)> {
(*self).access(m, i, j)
}
#[inline]
fn nrows(&self, m: &M) -> usize { (*self).nrows(m) }
#[inline]
fn ncols(&self, m: &M) -> usize { (*self).ncols(m) }
}
impl<M: MatrixExt> AccessStrategy<M> for Identity {
#[inline]
fn access(&self, _m: &M, i: usize, j: usize) -> Option<(usize, usize)> {
Some((i, j))
}
#[inline]
fn nrows(&self, m: &M) -> usize { m.num_rows() }
#[inline]
fn ncols(&self, m: &M) -> usize { m.num_cols() }
}
impl<M: MatrixExt> AccessStrategy<M> for Transpose {
#[inline]
fn access(&self, _m: &M, i: usize, j: usize) -> Option<(usize, usize)> {
Some((j, i))
}
#[inline]
fn nrows(&self, m: &M) -> usize { m.num_cols() }
#[inline]
fn ncols(&self, m: &M) -> usize { m.num_rows() }
}
impl<M: MatrixExt> AccessStrategy<M> for RotateR {
#[inline]
fn access(&self, m: &M, i: usize, j: usize) -> Option<(usize, usize)> {
Some((
m.num_rows().checked_sub(j)?.checked_sub(1)?,
i
))
}
#[inline]
fn nrows(&self, m: &M) -> usize { m.num_cols() }
#[inline]
fn ncols(&self, m: &M) -> usize { m.num_rows() }
}
impl<M: MatrixExt> AccessStrategy<M> for RotateL {
#[inline]
fn access(&self, m: &M, i: usize, j: usize) -> Option<(usize, usize)> {
Some((
j,
m.num_cols().checked_sub(i)?.checked_sub(1)?
))
}
#[inline]
fn nrows(&self, m: &M) -> usize { m.num_cols() }
#[inline]
fn ncols(&self, m: &M) -> usize { m.num_rows() }
}
impl<M: MatrixExt> AccessStrategy<M> for FlipH {
#[inline]
fn access(&self, m: &M, i: usize, j: usize) -> Option<(usize, usize)> {
Some((
i,
m.num_cols().checked_sub(j)?.checked_sub(1)?
))
}
#[inline]
fn nrows(&self, m: &M) -> usize { m.num_rows() }
#[inline]
fn ncols(&self, m: &M) -> usize { m.num_cols() }
}
impl<M: MatrixExt> AccessStrategy<M> for FlipV {
#[inline]
fn access(&self, m: &M, i: usize, j: usize) -> Option<(usize, usize)> {
Some((
m.num_rows().checked_sub(i)?.checked_sub(1)?,
j
))
}
#[inline]
fn nrows(&self, m: &M) -> usize { m.num_rows() }
#[inline]
fn ncols(&self, m: &M) -> usize { m.num_cols() }
}
impl<M: MatrixExt> AccessStrategy<M> for Reverse {
fn access(&self, m: &M, i: usize, j: usize) -> Option<(usize, usize)> {
Some((
m.num_rows().checked_sub(i)?.checked_sub(1)?,
m.num_cols().checked_sub(j)?.checked_sub(1)?
))
}
#[inline]
fn nrows(&self, m: &M) -> usize { m.num_rows() }
#[inline]
fn ncols(&self, m: &M) -> usize { m.num_cols() }
}
impl<M: MatrixExt> AccessStrategy<M> for ShiftBack {
fn access(&self, m: &M, i: usize, j: usize) -> Option<(usize, usize)> {
let mut n = m.checked_index_from((i, j))?;
let len = m.size();
let shift = self.0 % len;
if n >= len {
return None
}
else if n >= len - shift {
n -= len - shift;
}
else {
n += shift;
}
Some(m.subscripts_from(n))
}
#[inline]
fn nrows(&self, m: &M) -> usize { m.num_rows() }
#[inline]
fn ncols(&self, m: &M) -> usize { m.num_cols() }
}
impl<M: MatrixExt> AccessStrategy<M> for ShiftFront {
fn access(&self, m: &M, i: usize, j: usize) -> Option<(usize, usize)> {
let mut n = m.checked_index_from((i, j))?;
let len = m.size();
let shift = self.0 % len;
if n >= len {
return None
}
else if n >= shift {
n -= shift;
}
else {
n += len - shift;
}
Some(m.subscripts_from(n))
}
#[inline]
fn nrows(&self, m: &M) -> usize { m.num_rows() }
#[inline]
fn ncols(&self, m: &M) -> usize { m.num_cols() }
}
impl<M: MatrixExt, Rows: RangeBounds<usize>, Cols: RangeBounds<usize>>
AccessStrategy<M> for Submatrix<Rows, Cols> {
fn access(&self, m: &M, i: usize, j: usize) -> Option<(usize, usize)> {
let rows = Self::get_range(m.num_rows(), &self.0);
let cols = Self::get_range(m.num_cols(), &self.1);
if rows.is_empty() || cols.is_empty() {
return None
}
if rows.contains(&i) && cols.contains(&j) {
return Some((i, j))
}
else {
return None
}
}
fn nrows(&self, m: &M) -> usize {
let rows = Self::get_range(m.num_rows(), &self.0);
if rows.is_empty() { 0 }
else {
rows.end() - rows.start() + 1
}
}
fn ncols(&self, m: &M) -> usize {
let cols = Self::get_range(m.num_cols(), &self.1);
if cols.is_empty() { 0 }
else {
cols.end() - cols.start() + 1
}
}
}
impl<M: MatrixExt> AccessStrategy<M> for Reshape {
#[inline]
fn access(&self, m: &M, i: usize, j: usize) -> Option<(usize, usize)> {
if m.size() != self.0 * self.1 {
panic!("Reshape fails because dimensions provided {:?} does not fit the number of elements of the matrix ({})", self, m.size())
}
if i >= self.0 || j >= self.1 {
None
}
else {
Some(m.subscripts_from(i * self.1 + j))
}
}
#[inline]
fn nrows(&self, _m: &M) -> usize {
self.0
}
#[inline]
fn ncols(&self, _m: &M) -> usize {
self.1
}
}
impl<M: MatrixExt, Mapping: MatrixExt> AccessStrategy<M> for AccessMap<Mapping>
where for <'a> &'a <Mapping as MatrixExt>::Element: Into<&'a usize>
{
#[inline]
fn access(&self, m: &M, i: usize, j: usize) -> Option<(usize, usize)> {
let n = self.0.get(i, j)?.into();
if !m.check_nth(*n) {
panic!("Map index does not match with target matrix element.")
}
m.checked_subscripts_from(*n)
}
#[inline]
fn nrows(&self, _m: &M) -> usize { self.0.num_rows() }
#[inline]
fn ncols(&self, _m: &M) -> usize { self.0.num_cols() }
}
impl <M: MatrixExt> AccessStrategy<M> for AccessStrategySet {
#[inline]
fn access(&self, m: &M, mut i: usize, mut j: usize) -> Option<(usize, usize)> {
let observer = Observer::new(
m.shape(),
);
for strategy in self.iter().rev() {
(i, j) = strategy.deref().access(&observer, i, j)?;
}
Some((i, j))
}
#[inline]
fn nrows(&self, m: &M) -> usize {
let mut observer = Observer::new(
m.shape()
);
for strategy in self.iter().rev() {
observer.update_dimensions(&strategy.deref());
}
observer.num_rows()
}
#[inline]
fn ncols(&self, m: &M) -> usize {
let mut observer = Observer::new(
m.shape()
);
for strategy in self.iter().rev() {
observer.update_dimensions(&strategy.deref());
}
observer.num_cols()
}
}
impl<M, S> InPlace<M> for &S
where
M: MatrixMutExt, S: InPlace<M>
{
#[inline]
fn in_place(&self, m: &mut M) {
(*self).in_place(m)
}
}
impl<M: MatrixMutExt> InPlace<M> for Identity {
#[inline]
fn in_place(&self, _m: &mut M) {}
}
impl<M: SwapsDimensions> InPlace<M> for Transpose {
#[inline]
fn in_place(&self, m: &mut M) {
if m.is_square() {
self.in_place_square(m);
}
else {
self.in_place(m);
}
}
}
impl<M: SwapsDimensions> InPlace<M> for RotateR
where
Transpose: InPlace<M>,
FlipH: InPlace<M>,
{
#[inline]
fn in_place(&self, m: &mut M) {
Transpose.in_place(m);
FlipH.in_place(m);
}
}
impl<M: SwapsDimensions> InPlace<M> for RotateL
where
Transpose: InPlace<M>,
FlipV: InPlace<M>,
{
#[inline]
fn in_place(&self, m: &mut M) {
Transpose.in_place(m);
FlipV.in_place(m);
}
}
impl<M: MatrixMutExt> InPlace<M> for FlipH {
fn in_place(&self, m: &mut M) {
let cols = m.num_cols();
let rows = m.num_rows();
for i in 0..rows {
for j in 0..(cols / 2) {
m.swap((i, j), (i, cols - j - 1));
}
}
}
}
impl<M: MatrixMutExt> InPlace<M> for FlipV {
fn in_place(&self, m: &mut M) {
let cols = m.num_cols();
let rows = m.num_rows();
for i in 0..(rows / 2) {
for j in 0..cols {
m.swap((i, j), (rows - i - 1, j));
}
}
}
}
impl<M: MatrixMutExt> InPlace<M> for Reverse {
#[inline]
fn in_place(&self, m: &mut M) {
Reverse.rev(m, 0..m.size());
}
}
impl<M: MatrixMutExt> InPlace<M> for ShiftBack {
fn in_place(&self, m: &mut M) {
let len = m.size();
let shift = self.0 % len;
if shift == 0 {
return;
}
{
let reverse = Reverse;
reverse.rev(m, 0..len);
reverse.rev(m, len-shift..len);
reverse.rev(m, 0..len-shift);
}
}
}
impl<M: MatrixMutExt> InPlace<M> for ShiftFront {
fn in_place(&self, m: &mut M) {
let len = m.size();
let shift = self.0 % len;
if shift == 0 {
return;
}
{
let reverse = Reverse;
reverse.rev(m, 0..len);
reverse.rev(m, 0..shift);
reverse.rev(m, shift..len);
}
}
}
impl<M: MatrixMutExt> InPlace<M> for SortBy<M::Element> {
fn in_place(&self, m: &mut M) {
let mut im;
let mut min;
let mut cmp;
for i in 0..(m.size() - 1) {
im = i;
min = m.get_nth(i).unwrap();
for j in (i+1)..m.size() {
cmp = m.get_nth(j).unwrap();
if !(self.0)(min, cmp) {
im = j;
min = cmp;
}
}
m.swapn(im, i);
}
}
}
impl<M, S> TransformStrategy<M> for &S
where
M: MatrixExt,
S: TransformStrategy<M>
{
type Output = <S as TransformStrategy<M>>::Output;
#[inline]
fn out_of(&self, m: M) -> Self::Output { (*self).out_of(m) }
}
impl<M: MatrixExt> TransformStrategy<M> for Identity {
type Output = M;
#[inline]
fn out_of(&self, m: M) -> Self::Output { m }
}
impl<M: SwapsDimensions + MatrixMutExt > TransformStrategy<M> for Transpose {
type Output = M;
fn out_of(&self, mut m: M) -> Self::Output {
if m.is_square() {
self.in_place_square(&mut m);
m
}
else {
self.in_place(&mut m);
m
}
}
}
impl<M: MatrixExt> TransformStrategy<M> for RotateR
where
Transpose: TransformStrategy<M>,
<Transpose as TransformStrategy<M>>::Output: MatrixExt,
FlipH: TransformStrategy<<Transpose as TransformStrategy<M>>::Output>
{
type Output = <FlipH as TransformStrategy<<Transpose as TransformStrategy<M>>::Output>>::Output;
#[inline]
fn out_of(&self, m: M) -> Self::Output {
FlipH.out_of(Transpose.out_of(m))
}
}
impl<M: MatrixExt> TransformStrategy<M> for RotateL
where
Transpose: TransformStrategy<M>,
<Transpose as TransformStrategy<M>>::Output: MatrixExt,
FlipV: TransformStrategy<<Transpose as TransformStrategy<M>>::Output>
{
type Output = <FlipV as TransformStrategy<<Transpose as TransformStrategy<M>>::Output>>::Output;
#[inline]
fn out_of(&self, m: M) -> Self::Output {
FlipV.out_of(Transpose.out_of(m))
}
}
impl<M: MatrixMutExt> TransformStrategy<M> for FlipH {
type Output = M;
fn out_of(&self, mut m: M) -> Self::Output {
let cols = m.num_cols();
let rows = m.num_rows();
for i in 0..rows {
for j in 0..(cols / 2) {
m.swap((i, j), (i, cols - j - 1));
}
}
m
}
}
impl<M: MatrixMutExt> TransformStrategy<M> for FlipV {
type Output = M;
fn out_of(&self, mut m: M) -> Self::Output {
let cols = m.num_cols();
let rows = m.num_rows();
for i in 0..(rows / 2) {
for j in 0..cols {
m.swap((i, j), (rows - i - 1, j));
}
}
m
}
}
impl<M: MatrixMutExt> TransformStrategy<M> for Reverse {
type Output = M;
#[inline]
fn out_of(&self, mut m: M) -> Self::Output {
let len = m.size();
Reverse.rev(&mut m, 0..len);
m
}
}
impl<M: MatrixMutExt> TransformStrategy<M> for ShiftBack {
type Output = M;
fn out_of(&self, mut m: M) -> Self::Output {
let len = m.size();
let shift = self.0 % len;
if shift == 0 {
return m
}
{
let reverse = Reverse;
reverse.rev(&mut m, 0..len);
reverse.rev(&mut m, len-shift..len);
reverse.rev(&mut m, 0..len-shift);
}
m
}
}
impl<M: MatrixMutExt> TransformStrategy<M> for ShiftFront {
type Output = M;
fn out_of(&self, mut m: M) -> Self::Output {
let len = m.size();
let shift = self.0 % len;
if shift == 0 {
return m
}
{
let reverse = Reverse;
reverse.rev(&mut m, 0..len);
reverse.rev(&mut m, 0..shift);
reverse.rev(&mut m, shift..len);
}
m
}
}