use derive_getters::Dissolve;
use derive_new::new;
use crate::algebra::matrices::types::transpose::OrderAntiTranspose;
use crate::algebra::matrices::query::{MatrixOracle};
use crate::algebra::rings::traits::DivisionRingOperations;
use crate::algebra::vectors::entries::{KeyValSet, KeyValGet};
use crate::algebra::vectors::operations::{VectorOperations, LinearCombinationSimplified, Scale, Simplify};
use crate::utilities::iterators::merge::hit::{hit_bulk_insert, hit_merge_by_predicate};
use crate::utilities::order::{JudgePartialOrder, ReverseOrder};
use crate::utilities::functions::evaluate::EvaluateFunction;
use crate::utilities::iterators::general::{HeadTail, TwoTypeIterator, RequireStrictAscentWithPanic, TransformIter};
use crate::utilities::iterators::merge::hit::IteratorsMergedInSortedOrder;
pub trait IntoRemainder{
type Remainder;
fn into_remainder( self ) -> Self::Remainder;
}
#[derive(Clone,Copy,Debug)]
pub struct QuotientRemainderOutput< Q, R >{
pub quotient: Q,
pub remainder: R,
}
#[derive(Copy,Debug,new)]
pub struct QuotientRemainderSolver< I >
where I: Iterator + IntoRemainder,
{
solver: I
}
impl < I > QuotientRemainderSolver< I >
where
I: Iterator + IntoRemainder,
I::Remainder: Iterator,
{
pub fn quotient_remainder( mut self ) -> QuotientRemainderOutput< Vec<I::Item>, I::Remainder > {
let mut quotient = Vec::new();
for i in self.solver.by_ref() { quotient.push(i) }
quotient.shrink_to_fit();
let remainder = self.solver.into_remainder();
QuotientRemainderOutput{ quotient, remainder }
}
pub fn remainder( mut self ) -> I::Remainder {
for _ in self.solver.by_ref() {} self.solver.into_remainder() }
pub fn quotient( self ) -> I { self.solver }
pub fn solver( self ) -> I { self.solver }
pub fn solution( self ) -> Option< Vec< I::Item > > {
let mut qr = self.quotient_remainder();
match qr.remainder.next().is_none() {
true => Some( qr.quotient ),
false => None,
}
}
}
impl < I >
Clone for
QuotientRemainderSolver< I >
where I: Clone + Iterator + IntoRemainder,
{
fn clone(&self) -> Self {
QuotientRemainderSolver { solver: self.solver.clone() }
}
}
#[derive(Dissolve)]
pub struct RowEchelonSolverReindexed<
ProblemVector,
MatchingFromColumnIndicesToRowIndices,
Matrix,
RingOperator,
OrderOperator,
>
where
ProblemVector: IntoIterator< Item = Matrix::RowEntry >, MatchingFromColumnIndicesToRowIndices: EvaluateFunction< Matrix::ColumnIndex, Option< Matrix::RowIndex > >,
Matrix: MatrixOracle,
Matrix::RowEntry: KeyValSet,
RingOperator: Clone + DivisionRingOperations< Element = Matrix::Coefficient >,
OrderOperator: Clone + JudgePartialOrder < Matrix::RowEntry >,
{
ring_operator: RingOperator, matrix: Matrix, entries_to_eliminate: HeadTail<
LinearCombinationSimplified<
TwoTypeIterator< Matrix::Row, RequireStrictAscentWithPanic< ProblemVector::IntoIter, OrderOperator >,
>,
RingOperator,
OrderOperator,
>
>,
matching_from_column_index_to_row_index: MatchingFromColumnIndicesToRowIndices,
}
impl <
ProblemVector,
MatchingFromColumnIndicesToRowIndices,
Matrix,
RingOperator,
OrderOperator,
>
RowEchelonSolverReindexed<
ProblemVector,
MatchingFromColumnIndicesToRowIndices,
Matrix,
RingOperator,
OrderOperator,
>
where
ProblemVector: IntoIterator< Item = Matrix::RowEntry >, MatchingFromColumnIndicesToRowIndices: EvaluateFunction< Matrix::ColumnIndex, Option< Matrix::RowIndex > >,
Matrix: MatrixOracle,
Matrix::RowEntry: KeyValSet< Key=Matrix::ColumnIndex, Val=Matrix::Coefficient >,
RingOperator: Clone + DivisionRingOperations< Element = Matrix::Coefficient >,
OrderOperator: Clone + JudgePartialOrder < Matrix::RowEntry >,
{
pub fn solve(
b: ProblemVector,
a: Matrix,
matching_from_column_index_to_row_index: MatchingFromColumnIndicesToRowIndices,
ring_operator: RingOperator,
order_operator: OrderOperator,
)
->
QuotientRemainderSolver<
RowEchelonSolverReindexed<
ProblemVector,
MatchingFromColumnIndicesToRowIndices,
Matrix,
RingOperator,
OrderOperator,
>
>
{
let entries_to_eliminate
= hit_merge_by_predicate(
std::iter::once(
TwoTypeIterator::Version2( b.into_iter().require_strict_ascent_with_panic( order_operator.clone() ) ) .scale_by( ring_operator.minus_one(), ring_operator.clone() )
),
order_operator,
)
.simplify( ring_operator.clone() );
let entries_to_eliminate = HeadTail { head: None, tail: entries_to_eliminate };
QuotientRemainderSolver::new(
RowEchelonSolverReindexed{
ring_operator,
matching_from_column_index_to_row_index,
matrix: a,
entries_to_eliminate,
}
)
}
}
impl <
ProblemVector,
MatchingFromColumnIndicesToRowIndices,
Matrix,
RingOperator,
OrderOperator,
>
IntoRemainder for
RowEchelonSolverReindexed<
ProblemVector,
MatchingFromColumnIndicesToRowIndices,
Matrix,
RingOperator,
OrderOperator,
>
where
ProblemVector: IntoIterator< Item = Matrix::RowEntry >, MatchingFromColumnIndicesToRowIndices: EvaluateFunction< Matrix::ColumnIndex, Option< Matrix::RowIndex > >,
Matrix: MatrixOracle,
Matrix::RowEntry: KeyValSet< Key=Matrix::ColumnIndex, Val=Matrix::Coefficient >,
RingOperator: Clone + DivisionRingOperations< Element = Matrix::Coefficient >,
OrderOperator: Clone + JudgePartialOrder < Matrix::RowEntry >,
{
type Remainder =
HeadTail<
LinearCombinationSimplified<
TwoTypeIterator< < Matrix::Row as IntoIterator >::IntoIter, RequireStrictAscentWithPanic< ProblemVector::IntoIter, OrderOperator >, >,
RingOperator, OrderOperator
>
>;
fn into_remainder( self ) -> Self::Remainder {
self.entries_to_eliminate
}
}
impl <
ProblemVector,
MatchingFromColumnIndicesToRowIndices,
Matrix,
RingOperator,
OrderOperator,
>
Iterator for
RowEchelonSolverReindexed<
ProblemVector,
MatchingFromColumnIndicesToRowIndices,
Matrix,
RingOperator,
OrderOperator,
>
where
ProblemVector: IntoIterator< Item = Matrix::RowEntry >, MatchingFromColumnIndicesToRowIndices: EvaluateFunction< Matrix::ColumnIndex, Option< Matrix::RowIndex > >,
Matrix: MatrixOracle,
Matrix::RowEntry: KeyValSet< Key=Matrix::ColumnIndex, Val=Matrix::Coefficient >,
RingOperator: Clone + DivisionRingOperations< Element = Matrix::Coefficient >,
OrderOperator: Clone + JudgePartialOrder < Matrix::RowEntry >,
{
type Item = Matrix::RowEntry;
fn next( &mut self ) -> Option<Self::Item> {
if let Some( mut entry_to_eliminate ) = self.entries_to_eliminate.next() {
match self.matching_from_column_index_to_row_index.evaluate_function( entry_to_eliminate.key() ) {
None => {
self.entries_to_eliminate.head = Some( entry_to_eliminate );
None
} Some( row_index_of_eliminating_row ) => {
let mut seed_of_eliminating_iterator = self.matrix.row( &row_index_of_eliminating_row ).into_iter();
let eliminating_entry = seed_of_eliminating_iterator.next().unwrap();
let scale_factor = self.ring_operator.negate(
self.ring_operator.divide( entry_to_eliminate.val(), eliminating_entry.val() )
);
let eliminating_iterator
= TwoTypeIterator::Version1( seed_of_eliminating_iterator )
.scale_by( scale_factor.clone(), self.ring_operator.clone() );
hit_bulk_insert( &mut self.entries_to_eliminate.tail.unsimplified, vec![eliminating_iterator] );
entry_to_eliminate.set_val( scale_factor );
Some( entry_to_eliminate ) }
}
} else {
None
}
}
}
impl <
ProblemVector,
MatchingFromColumnIndicesToRowIndices,
Matrix,
RingOperator,
OrderOperator,
>
Clone for
RowEchelonSolverReindexed<
ProblemVector,
MatchingFromColumnIndicesToRowIndices,
Matrix,
RingOperator,
OrderOperator,
>
where
ProblemVector: IntoIterator<
Item = Matrix::RowEntry, IntoIter: Clone
>,
MatchingFromColumnIndicesToRowIndices: Clone + EvaluateFunction< Matrix::ColumnIndex, Option< Matrix::RowIndex > >,
Matrix: Clone + MatrixOracle< Row: Clone >,
Matrix::RowEntry: Clone + KeyValSet,
RingOperator: Clone + DivisionRingOperations< Element = Matrix::Coefficient >,
OrderOperator: Clone + JudgePartialOrder < Matrix::RowEntry >,
{
fn clone(&self) -> Self {
RowEchelonSolverReindexed{
ring_operator: self.ring_operator.clone(),
matrix: self.matrix.clone(),
entries_to_eliminate: self.entries_to_eliminate.clone(),
matching_from_column_index_to_row_index: self.matching_from_column_index_to_row_index.clone(),
}
}
}
#[derive(Dissolve)]
pub struct RowEchelonSolver<
ProblemVector,
MatchingFromColumnIndicesToRowIndices,
Matrix,
RingOperator,
OrderOperator,
>
where
ProblemVector: IntoIterator< Item = Matrix::RowEntry >, MatchingFromColumnIndicesToRowIndices: EvaluateFunction< Matrix::ColumnIndex, Option< Matrix::RowIndex > >,
Matrix: MatrixOracle,
Matrix::RowEntry: KeyValSet< Key=Matrix::ColumnIndex, Val=Matrix::Coefficient >,
RingOperator: DivisionRingOperations< Element = Matrix::Coefficient >,
OrderOperator: JudgePartialOrder < Matrix::RowEntry >,
{
ring_operator: RingOperator, matrix: Matrix, entries_to_eliminate: HeadTail<
LinearCombinationSimplified<
TwoTypeIterator< < Matrix::Row as IntoIterator >::IntoIter, RequireStrictAscentWithPanic< ProblemVector::IntoIter, OrderOperator >,
>,
RingOperator,
OrderOperator,
>
>,
matching_from_column_index_to_row_index: MatchingFromColumnIndicesToRowIndices,
}
impl <
ProblemVector,
MatchingFromColumnIndicesToRowIndices,
Matrix,
RingOperator,
OrderOperator,
>
RowEchelonSolver<
ProblemVector,
MatchingFromColumnIndicesToRowIndices,
Matrix,
RingOperator,
OrderOperator,
>
where
ProblemVector: IntoIterator< Item = Matrix::RowEntry >, MatchingFromColumnIndicesToRowIndices: EvaluateFunction< Matrix::ColumnIndex, Option< Matrix::RowIndex > >,
Matrix: MatrixOracle,
Matrix::ColumnIndex: Clone + PartialEq,
Matrix::RowIndex: Clone,
RingOperator: Clone + DivisionRingOperations< Element = Matrix::Coefficient >,
OrderOperator: Clone + JudgePartialOrder < Matrix::RowEntry >,
Matrix::RowEntry: KeyValSet,
{
pub fn solve(
b: ProblemVector,
a: Matrix,
matching_from_column_index_to_row_index: MatchingFromColumnIndicesToRowIndices,
ring_operator: RingOperator,
order_operator: OrderOperator,
)
->
QuotientRemainderSolver<
RowEchelonSolver<
ProblemVector,
MatchingFromColumnIndicesToRowIndices,
Matrix,
RingOperator,
OrderOperator,
>
>
{
let entries_to_eliminate
= hit_merge_by_predicate(
std::iter::once(
TwoTypeIterator::Version2( b.into_iter().require_strict_ascent_with_panic(order_operator.clone()) ) .scale_by( ring_operator.minus_one(), ring_operator.clone() )
),
order_operator,
)
.simplify( ring_operator.clone() );
let entries_to_eliminate = HeadTail { head: None, tail: entries_to_eliminate };
QuotientRemainderSolver::new(
RowEchelonSolver{
ring_operator,
matching_from_column_index_to_row_index,
matrix: a,
entries_to_eliminate,
}
)
}
}
impl <
ProblemVector,
MatchingFromColumnIndicesToRowIndices,
Matrix,
RingOperator,
OrderOperator,
>
IntoRemainder for
RowEchelonSolver<
ProblemVector,
MatchingFromColumnIndicesToRowIndices,
Matrix,
RingOperator,
OrderOperator,
>
where
ProblemVector: IntoIterator< Item = Matrix::RowEntry >, MatchingFromColumnIndicesToRowIndices: EvaluateFunction< Matrix::ColumnIndex, Option< Matrix::RowIndex > >,
Matrix: MatrixOracle,
Matrix::ColumnIndex: Clone + PartialEq,
RingOperator: Clone + DivisionRingOperations< Element = Matrix::Coefficient >,
Matrix::Coefficient: Clone,
OrderOperator: Clone + JudgePartialOrder < Matrix::RowEntry >,
Matrix::RowEntry: Clone + KeyValSet< Key=Matrix::ColumnIndex, Val=Matrix::Coefficient >,
{
type Remainder =
HeadTail<
LinearCombinationSimplified<
TwoTypeIterator< Matrix::Row, RequireStrictAscentWithPanic< ProblemVector::IntoIter, OrderOperator >, >,
RingOperator,
OrderOperator,
>
>;
fn into_remainder( self ) -> Self::Remainder
{
self.entries_to_eliminate
}
}
impl <
ProblemVector,
MatchingFromColumnIndicesToRowIndices,
Matrix,
RingOperator,
OrderOperator,
>
Iterator for
RowEchelonSolver<
ProblemVector,
MatchingFromColumnIndicesToRowIndices,
Matrix,
RingOperator,
OrderOperator,
>
where
ProblemVector: IntoIterator< Item = Matrix::RowEntry >, MatchingFromColumnIndicesToRowIndices: EvaluateFunction< Matrix::ColumnIndex, Option< Matrix::RowIndex > >,
Matrix: MatrixOracle,
RingOperator: Clone + DivisionRingOperations< Element = Matrix::Coefficient >, OrderOperator: Clone + JudgePartialOrder < Matrix::RowEntry >,
Matrix::RowEntry: KeyValSet< Key=Matrix::ColumnIndex, Val=Matrix::Coefficient >,
{
type Item = (Matrix::RowIndex, Matrix::Coefficient);
fn next( &mut self ) -> Option<Self::Item> {
if let Some( entry_to_eliminate ) = self.entries_to_eliminate.next() {
match self.matching_from_column_index_to_row_index.evaluate_function( entry_to_eliminate.key() ) {
None => {
self.entries_to_eliminate.head = Some( entry_to_eliminate ); None
}, Some( row_index_of_eliminating_row ) => {
let mut seed_of_eliminating_iterator = self.matrix.row( & row_index_of_eliminating_row ).into_iter();
let eliminating_entry = seed_of_eliminating_iterator.next().unwrap();
let scale_factor = self.ring_operator.negate(
self.ring_operator.divide( entry_to_eliminate.val(), eliminating_entry.val() )
);
let eliminating_iterator
= TwoTypeIterator::Version1( seed_of_eliminating_iterator )
.scale_by( scale_factor.clone(), self.ring_operator.clone() );
hit_bulk_insert( &mut self.entries_to_eliminate.tail.unsimplified, vec![eliminating_iterator] );
Some( (row_index_of_eliminating_row, scale_factor) ) }
}
} else {
None
}
}
}
impl <
ProblemVector,
MatchingFromColumnIndicesToRowIndices,
Matrix,
RingOperator,
OrderOperator,
>
Clone for
RowEchelonSolver<
ProblemVector,
MatchingFromColumnIndicesToRowIndices,
Matrix,
RingOperator,
OrderOperator,
>
where
ProblemVector: IntoIterator<
Item = Matrix::RowEntry, IntoIter: Clone,
>,
MatchingFromColumnIndicesToRowIndices: Clone + EvaluateFunction< Matrix::ColumnIndex, Option< Matrix::RowIndex > >,
Matrix: Clone + MatrixOracle,
RingOperator: Clone + DivisionRingOperations< Element = Matrix::Coefficient >,
OrderOperator: Clone + JudgePartialOrder < Matrix::RowEntry >,
Matrix::RowEntry: KeyValSet,
Simplify<IteratorsMergedInSortedOrder<Scale<TwoTypeIterator<Matrix::Row, RequireStrictAscentWithPanic<ProblemVector::IntoIter, OrderOperator>>, RingOperator>, OrderOperator>, RingOperator>: Clone,
{
fn clone(&self) -> Self {
RowEchelonSolver{
ring_operator: self.ring_operator.clone(),
matrix: self.matrix.clone(),
entries_to_eliminate: self.entries_to_eliminate.clone(),
matching_from_column_index_to_row_index: self.matching_from_column_index_to_row_index.clone(),
}
}
}
#[derive(Dissolve)]
pub struct ColumnEchelonSolverReverseReindexed<
ProblemVector,
MatchingFromRowIndicesToColumnIndices,
Matrix,
RingOperator,
OrderOperatorUnreversed,
>
where
ProblemVector: IntoIterator< Item = Matrix::ColumnEntry >, MatchingFromRowIndicesToColumnIndices: EvaluateFunction< Matrix::RowIndex, Option< Matrix::ColumnIndex > >,
Matrix: MatrixOracle,
Matrix::ColumnEntry: KeyValSet < Key=Matrix::RowIndex, Val=Matrix::Coefficient >,
RingOperator: Clone + DivisionRingOperations< Element = Matrix::Coefficient >,
OrderOperatorUnreversed: Clone + JudgePartialOrder < Matrix::ColumnEntry >,
{
antitransposed_solver: RowEchelonSolverReindexed< ProblemVector,
MatchingFromRowIndicesToColumnIndices,
OrderAntiTranspose< Matrix >,
RingOperator,
ReverseOrder< OrderOperatorUnreversed >,
>,
}
impl <
ProblemVector,
MatchingFromRowIndicesToColumnIndices,
Matrix,
RingOperator,
OrderOperatorUnreversed,
>
ColumnEchelonSolverReverseReindexed<
ProblemVector,
MatchingFromRowIndicesToColumnIndices,
Matrix,
RingOperator,
OrderOperatorUnreversed,
>
where
ProblemVector: IntoIterator< Item = Matrix::ColumnEntry >, MatchingFromRowIndicesToColumnIndices: EvaluateFunction< Matrix::RowIndex, Option< Matrix::ColumnIndex > >,
Matrix: MatrixOracle,
Matrix::ColumnEntry: KeyValSet < Key=Matrix::RowIndex, Val=Matrix::Coefficient >,
RingOperator: Clone + DivisionRingOperations< Element = Matrix::Coefficient >,
OrderOperatorUnreversed: Clone + JudgePartialOrder < Matrix::ColumnEntry >,
{
pub fn solve(
b: ProblemVector,
a: Matrix,
matching_from_row_index_to_column_index: MatchingFromRowIndicesToColumnIndices,
ring_operator: RingOperator,
order_operator_unreversed: OrderOperatorUnreversed,
)
->
QuotientRemainderSolver<
ColumnEchelonSolverReverseReindexed<
ProblemVector,
MatchingFromRowIndicesToColumnIndices,
Matrix,
RingOperator,
OrderOperatorUnreversed,
>
>
{
QuotientRemainderSolver::new(
ColumnEchelonSolverReverseReindexed{
antitransposed_solver: RowEchelonSolverReindexed::solve(
b,
OrderAntiTranspose::new( a ),
matching_from_row_index_to_column_index,
ring_operator,
ReverseOrder::new( order_operator_unreversed ),
).quotient()
}
)
}
}
impl <
ProblemVector,
MatchingFromRowIndicesToColumnIndices,
Matrix,
RingOperator,
OrderOperatorUnreversed,
>
IntoRemainder for
ColumnEchelonSolverReverseReindexed<
ProblemVector,
MatchingFromRowIndicesToColumnIndices,
Matrix,
RingOperator,
OrderOperatorUnreversed,
>
where
ProblemVector: IntoIterator< Item = Matrix::ColumnEntry >, MatchingFromRowIndicesToColumnIndices: EvaluateFunction< Matrix::RowIndex, Option< Matrix::ColumnIndex > >,
Matrix: MatrixOracle,
Matrix::ColumnEntry: KeyValSet < Key=Matrix::RowIndex, Val=Matrix::Coefficient >,
RingOperator: Clone + DivisionRingOperations< Element = Matrix::Coefficient >,
OrderOperatorUnreversed: Clone + JudgePartialOrder < Matrix::ColumnEntry >,
{
type Remainder =
HeadTail<
LinearCombinationSimplified<
TwoTypeIterator< < Matrix::ColumnReverse as IntoIterator >::IntoIter, RequireStrictAscentWithPanic< ProblemVector::IntoIter, ReverseOrder< OrderOperatorUnreversed > >, >,
RingOperator, ReverseOrder< OrderOperatorUnreversed >
>
>;
fn into_remainder( self ) -> Self::Remainder
{
self.antitransposed_solver.into_remainder()
}
}
impl <
ProblemVector,
MatchingFromRowIndicesToColumnIndices,
Matrix,
RingOperator,
OrderOperatorUnreversed,
>
Iterator for
ColumnEchelonSolverReverseReindexed<
ProblemVector,
MatchingFromRowIndicesToColumnIndices,
Matrix,
RingOperator,
OrderOperatorUnreversed,
>
where
ProblemVector: IntoIterator< Item = Matrix::ColumnEntry >, MatchingFromRowIndicesToColumnIndices: EvaluateFunction< Matrix::RowIndex, Option< Matrix::ColumnIndex > >,
Matrix: MatrixOracle,
Matrix::ColumnEntry: KeyValSet < Key=Matrix::RowIndex, Val=Matrix::Coefficient >,
RingOperator: Clone + DivisionRingOperations< Element = Matrix::Coefficient >,
OrderOperatorUnreversed: Clone + JudgePartialOrder < Matrix::ColumnEntry >,
{
type Item = Matrix::ColumnEntry;
fn next( &mut self ) -> Option<Self::Item> {
self.antitransposed_solver.next()
}
}
impl <
ProblemVector,
MatchingFromRowIndicesToColumnIndices,
Matrix,
RingOperator,
OrderOperatorUnreversed,
>
Clone for
ColumnEchelonSolverReverseReindexed<
ProblemVector,
MatchingFromRowIndicesToColumnIndices,
Matrix,
RingOperator,
OrderOperatorUnreversed,
>
where
ProblemVector: IntoIterator< Item = Matrix::ColumnEntry >, MatchingFromRowIndicesToColumnIndices: EvaluateFunction< Matrix::RowIndex, Option< Matrix::ColumnIndex > >,
Matrix: MatrixOracle,
Matrix::ColumnEntry: KeyValSet < Key=Matrix::RowIndex, Val=Matrix::Coefficient >,
RingOperator: Clone + DivisionRingOperations< Element = Matrix::Coefficient >,
OrderOperatorUnreversed: Clone + JudgePartialOrder < Matrix::ColumnEntry >,
RowEchelonSolverReindexed<
ProblemVector,
MatchingFromRowIndicesToColumnIndices,
OrderAntiTranspose< Matrix >,
RingOperator,
ReverseOrder< OrderOperatorUnreversed >,
>: Clone,
{
fn clone(&self) -> Self {
ColumnEchelonSolverReverseReindexed{
antitransposed_solver: self.antitransposed_solver.clone()
}
}
}
pub struct ColumnEchelonSolverReverse<
ProblemVector,
MatchingFromRowIndicesToColumnIndices,
Matrix,
RingOperator,
OrderOperator,
>
where
ProblemVector: IntoIterator< Item = Matrix::ColumnEntry >, MatchingFromRowIndicesToColumnIndices: EvaluateFunction< Matrix::RowIndex, Option< Matrix::ColumnIndex > >,
Matrix: MatrixOracle,
Matrix::ColumnEntry: KeyValSet < Key=Matrix::RowIndex, Val=Matrix::Coefficient >,
RingOperator: Clone + DivisionRingOperations< Element = Matrix::Coefficient >,
OrderOperator: Clone + JudgePartialOrder < Matrix::ColumnEntry >,
{
antitransposed_solver: RowEchelonSolver< ProblemVector,
MatchingFromRowIndicesToColumnIndices,
OrderAntiTranspose< Matrix >,
RingOperator,
ReverseOrder< OrderOperator >,
>,
}
impl <
ProblemVector,
MatchingFromRowIndicesToColumnIndices,
Matrix,
RingOperator,
OrderOperator,
>
ColumnEchelonSolverReverse<
ProblemVector,
MatchingFromRowIndicesToColumnIndices,
Matrix,
RingOperator,
OrderOperator,
>
where
ProblemVector: IntoIterator< Item = Matrix::ColumnEntry >, MatchingFromRowIndicesToColumnIndices: EvaluateFunction< Matrix::RowIndex, Option< Matrix::ColumnIndex > >,
Matrix: MatrixOracle,
Matrix::ColumnEntry: KeyValSet < Key=Matrix::RowIndex, Val=Matrix::Coefficient >,
RingOperator: Clone + DivisionRingOperations< Element = Matrix::Coefficient >,
OrderOperator: Clone + JudgePartialOrder < Matrix::ColumnEntry >,
{
pub fn solve(
b: ProblemVector,
a: Matrix,
matching_from_row_index_to_column_index: MatchingFromRowIndicesToColumnIndices,
ring_operator: RingOperator,
order_operator: OrderOperator,
)
->
QuotientRemainderSolver<
ColumnEchelonSolverReverse<
ProblemVector,
MatchingFromRowIndicesToColumnIndices,
Matrix,
RingOperator,
OrderOperator,
>
>
{
QuotientRemainderSolver::new(
ColumnEchelonSolverReverse{
antitransposed_solver: RowEchelonSolver::solve(
b,
OrderAntiTranspose::new( a ),
matching_from_row_index_to_column_index,
ring_operator,
ReverseOrder::new( order_operator ),
).quotient()
}
)
}
}
impl <
ProblemVector,
MatchingFromRowIndicesToColumnIndices,
Matrix,
RingOperator,
OrderOperator,
>
IntoRemainder for
ColumnEchelonSolverReverse<
ProblemVector,
MatchingFromRowIndicesToColumnIndices,
Matrix,
RingOperator,
OrderOperator,
>
where
ProblemVector: IntoIterator< Item = Matrix::ColumnEntry >, MatchingFromRowIndicesToColumnIndices: EvaluateFunction< Matrix::RowIndex, Option< Matrix::ColumnIndex > >,
Matrix: MatrixOracle,
Matrix::ColumnEntry: KeyValSet < Key=Matrix::RowIndex, Val=Matrix::Coefficient >,
RingOperator: Clone + DivisionRingOperations< Element = Matrix::Coefficient >,
OrderOperator: Clone + JudgePartialOrder < Matrix::ColumnEntry >,
{
type Remainder =
HeadTail<
LinearCombinationSimplified<
TwoTypeIterator< < Matrix::ColumnReverse as IntoIterator >::IntoIter, RequireStrictAscentWithPanic< ProblemVector::IntoIter, ReverseOrder< OrderOperator > >, >,
RingOperator, ReverseOrder< OrderOperator >
>
>;
fn into_remainder( self ) -> Self::Remainder
{
self.antitransposed_solver.into_remainder()
}
}
impl <
ProblemVector,
MatchingFromRowIndicesToColumnIndices,
Matrix,
RingOperator,
OrderOperator,
>
Iterator for
ColumnEchelonSolverReverse<
ProblemVector,
MatchingFromRowIndicesToColumnIndices,
Matrix,
RingOperator,
OrderOperator,
>
where
ProblemVector: IntoIterator< Item = Matrix::ColumnEntry >, MatchingFromRowIndicesToColumnIndices: EvaluateFunction< Matrix::RowIndex, Option< Matrix::ColumnIndex > >,
Matrix: MatrixOracle,
Matrix::ColumnEntry: KeyValSet < Key=Matrix::RowIndex, Val=Matrix::Coefficient >,
RingOperator: Clone + DivisionRingOperations< Element = Matrix::Coefficient >,
OrderOperator: Clone + JudgePartialOrder < Matrix::ColumnEntry >,
{
type Item = (Matrix::ColumnIndex, Matrix::Coefficient);
fn next( &mut self ) -> Option<Self::Item> {
self.antitransposed_solver.next()
}
}
impl <
ProblemVector,
MatchingFromRowIndicesToColumnIndices,
Matrix,
RingOperator,
OrderOperator,
>
Clone for
ColumnEchelonSolverReverse<
ProblemVector,
MatchingFromRowIndicesToColumnIndices,
Matrix,
RingOperator,
OrderOperator,
>
where
ProblemVector: IntoIterator< Item = Matrix::ColumnEntry >, MatchingFromRowIndicesToColumnIndices: EvaluateFunction< Matrix::RowIndex, Option< Matrix::ColumnIndex > >,
Matrix: MatrixOracle,
Matrix::ColumnEntry: KeyValSet < Key=Matrix::RowIndex, Val=Matrix::Coefficient >,
RingOperator: Clone + DivisionRingOperations< Element = Matrix::Coefficient >,
OrderOperator: Clone + JudgePartialOrder < Matrix::ColumnEntry >,
RowEchelonSolver< ProblemVector,
MatchingFromRowIndicesToColumnIndices,
OrderAntiTranspose< Matrix >,
RingOperator,
ReverseOrder< OrderOperator >,
>: Clone,
{
fn clone(&self) -> Self {
ColumnEchelonSolverReverse{
antitransposed_solver: self.antitransposed_solver.clone()
}
}
}
#[cfg(test)]
mod doctring_tests {
#[test]
fn doc_test_module() {
use crate::algebra::matrices::types::vec_of_vec::sorted::VecOfVec;
use crate::algebra::matrices::operations::solve::echelon::{RowEchelonSolver, ColumnEchelonSolverReverse};
use crate::algebra::rings::types::field_prime_order::BooleanField;
use crate::algebra::vectors::operations::VectorOperations;
use crate::utilities::functions::evaluate::EvaluateFunctionFnMutWrapper;
use crate::utilities::order::{OrderOperatorByKey};
use itertools::Itertools;
use assert_panic::assert_panic;
let ring_operator = BooleanField::new();
let matrix = VecOfVec::new(
vec![
vec![ ],
vec![ ],
vec![ (0,true), (1,true), (2,true) ],
vec![ (1,true), (2,true) ],
vec![ (2,true) ],
],
).ok().unwrap();
let b = vec![ (0,true), (1,true) ];
let partial_bijection = |x: usize| { if x < 3 { Some(x+2) } else { None } };
let division = RowEchelonSolver::solve(
b.clone(), & matrix, EvaluateFunctionFnMutWrapper::new( partial_bijection ), BooleanField::new(), OrderOperatorByKey::new(), );
let product = division
.quotient()
.multiply_self_as_a_row_vector_with_matrix_custom(
&matrix,
ring_operator,
OrderOperatorByKey::new()
);
assert_eq!( product.collect_vec(), b );
let division = RowEchelonSolver::solve(
b.clone(), & matrix, vec![2,3,4], BooleanField::new(), OrderOperatorByKey::new(), );
let product = division
.clone()
.quotient()
.multiply_self_as_a_row_vector_with_matrix_custom(
&matrix,
ring_operator,
OrderOperatorByKey::new()
);
assert_eq!( product.collect_vec(), b );
assert_eq!( division.clone().solution(), Some( division.clone().quotient().collect_vec() ) );
let c = vec![ (3,true), (2,true) ];
let partial_bijection = |x: usize| { if (2..=4).contains(&x) { Some(x-2) } else { None } };
let division = ColumnEchelonSolverReverse::solve(
c.clone(), & matrix, EvaluateFunctionFnMutWrapper::new( partial_bijection ), BooleanField::new(), OrderOperatorByKey::new(), );
let product = division
.quotient()
.multiply_self_as_a_column_vector_with_matrix_and_return_entries_in_reverse_order_custom(
&matrix,
ring_operator,
OrderOperatorByKey::new()
);
assert_eq!( product.collect_vec(), c );
let d = vec![ (3,true), (2,true), (1,true), (0,true) ];
let partial_bijection = |x: usize| { if (2..=4).contains(&x) { Some(x-2) } else { None } };
let division = ColumnEchelonSolverReverse::solve(
d, & matrix, EvaluateFunctionFnMutWrapper::new( partial_bijection ), BooleanField::new(), OrderOperatorByKey::new(), );
let remainder = division.remainder().collect_vec();
assert!( remainder.eq( &vec![ (1,true), (0,true) ] ) );
let d = vec![ (0,true), (1,true), (2,true), (3,true), ];
let division = RowEchelonSolver::solve(
d, & matrix, vec![2,3,4], BooleanField::new(), OrderOperatorByKey::new(), );
assert!( division.clone().remainder().eq( vec![ (3,true) ] ) );
assert!( division.clone().quotient_remainder().remainder.eq( vec![ (3,true) ] ) );
let d = vec![ (1,true), (0,true), (3,true), (2,true), ];
let division = RowEchelonSolver::solve(
d, & matrix, vec![2,3,4], BooleanField::new(), OrderOperatorByKey::new(), );
assert_panic!( for _ in division.solver() {} );
let d = vec![ (0,true), (1,true), (2,true), (3,true), (4,true), (2,true), ];
let division = RowEchelonSolver::solve(
d, & matrix, vec![2,3,4], BooleanField::new(), OrderOperatorByKey::new(), );
let mut qr = division.quotient_remainder();
assert!( qr.quotient.clone().eq( &vec![ (2,true) ] ) ); assert_eq!( qr.remainder.next(), Some( (3,true) ) ); assert_panic!( for _ in qr.remainder {} );
}
}
#[cfg(test)]
mod tests {
use super::*;
use itertools::Itertools;
use crate::{algebra::matrices::types::vec_of_vec::sorted::VecOfVec, algebra::rings::types::field_prime_order::PrimeOrderField};
#[cfg(test)] fn test_echelon_solve_on_invertible_uppertriangular_matrix< 'a, MatchingFromColumnIndicesToRowIndices, MatchingFromRowIndicesToColumnIndices, Coefficient, RingOperator >(
matrix: & VecOfVec< usize, Coefficient >,
matching_from_column_index_to_row_index: MatchingFromColumnIndicesToRowIndices,
matching_from_row_index_to_column_index: MatchingFromRowIndicesToColumnIndices,
ring_operator: RingOperator,
matrix_size: usize
)
where Coefficient: Clone + PartialEq + Ord + std::fmt::Debug,
RingOperator: DivisionRingOperations< Element = Coefficient > + Clone,
MatchingFromColumnIndicesToRowIndices: Clone + EvaluateFunction< usize, Option< usize > >,
MatchingFromRowIndicesToColumnIndices: Clone + EvaluateFunction< usize, Option< usize > >,
{
use crate::{algebra::matrices::operations::multiply::{multiply_row_vector_with_matrix, multiply_column_vector_with_matrix_and_return_reversed}, utilities::order::OrderOperatorAuto};
for num_nonzeros in [0, 1, 2, 3, matrix_size].iter().map(|x| std::cmp::min(x, &matrix_size) ) {
for vector_support in (0 .. matrix_size).combinations( *num_nonzeros ) {
let mut vec = vector_support
.iter()
.cloned()
.map(|x| ( x, RingOperator::one() ))
.collect_vec();
vec.sort();
let solution_major_with_minor_keys = RowEchelonSolverReindexed::solve(
vec.iter().cloned(),
matrix,
matching_from_column_index_to_row_index.clone(),
ring_operator.clone(),
OrderOperatorAuto,
)
.quotient()
.peekable()
.simplify( ring_operator.clone() );
itertools::assert_equal(
vec.iter().cloned().peekable().simplify( ring_operator.clone() ),
multiply_row_vector_with_matrix(
solution_major_with_minor_keys,
matrix,
ring_operator.clone(),
OrderOperatorAuto
)
);
let solution_major_with_major_keys = RowEchelonSolver::solve(
vec.iter().cloned(),
matrix,
matching_from_column_index_to_row_index.clone(),
ring_operator.clone(),
OrderOperatorAuto,
)
.quotient()
.peekable()
.simplify( ring_operator.clone() );
itertools::assert_equal(
vec.iter().cloned().peekable().simplify( ring_operator.clone() ),
multiply_row_vector_with_matrix(
solution_major_with_major_keys,
matrix,
ring_operator.clone(),
OrderOperatorAuto
)
);
vec.reverse();
let solution_minor_with_minor_keys = ColumnEchelonSolverReverse::solve(
vec.iter().cloned(),
matrix,
matching_from_row_index_to_column_index.clone(),
ring_operator.clone(),
OrderOperatorAuto,
)
.quotient()
.peekable()
.simplify( ring_operator.clone() );
itertools::assert_equal(
vec.iter().cloned().peekable().simplify( ring_operator.clone() ),
multiply_column_vector_with_matrix_and_return_reversed(
solution_minor_with_minor_keys,
matrix,
ring_operator.clone(),
OrderOperatorAuto
)
);
let solution_major_with_major_keys = ColumnEchelonSolverReverseReindexed::solve(
vec.iter().cloned(),
matrix,
matching_from_row_index_to_column_index.clone(),
ring_operator.clone(),
OrderOperatorAuto,
)
.quotient()
.peekable()
.simplify( ring_operator.clone() );
itertools::assert_equal(
vec.iter().cloned().peekable().simplify( ring_operator.clone() ),
multiply_column_vector_with_matrix_and_return_reversed(
solution_major_with_major_keys,
matrix,
ring_operator.clone(),
OrderOperatorAuto
)
);
}
}
}
#[test]
fn test_echelon_solve_on_specific_matrices() {
use num::rational::Ratio;
use crate::algebra::rings::types::native::RingOperatorForNativeRustNumberType;
use crate::utilities::functions::evaluate::EvaluateFunctionFnMutWrapper;
type IntegerType = isize;
let modulus = 1049;
let r = Ratio::new;
let q = Ratio::from_integer;
let matching_column_index_to_row_index_closure = | x: usize | -> Option< usize > { Some( x ) };
let matching_column_index_to_row_index = EvaluateFunctionFnMutWrapper::new( matching_column_index_to_row_index_closure );
let ring_operator_q = RingOperatorForNativeRustNumberType::< Ratio<IntegerType> >::new();
let ring_operator_p = PrimeOrderField::new(modulus);
let matrix = VecOfVec::new(
vec![
vec![ (0,q(1)) ]
],
).ok().unwrap();
test_echelon_solve_on_invertible_uppertriangular_matrix( &matrix, matching_column_index_to_row_index.clone(), matching_column_index_to_row_index.clone(), ring_operator_q, 1 );
let matrix = VecOfVec::new(
vec![
vec![ (0,q(1)), (1,q(1)), ],
vec![ (1,q(1)), ],
],
).ok().unwrap();
test_echelon_solve_on_invertible_uppertriangular_matrix( &matrix, matching_column_index_to_row_index.clone(), matching_column_index_to_row_index.clone(), ring_operator_q, 2 );
let matrix = VecOfVec::new(
vec![
vec![ (0,q(1)), (1,q(-1)), (2,q(3)) ],
vec![ (1,q(-1)), (2,q(4)) ],
vec![ (2,q(5)) ],
],
).ok().unwrap();
test_echelon_solve_on_invertible_uppertriangular_matrix( &matrix, matching_column_index_to_row_index.clone(), matching_column_index_to_row_index.clone(), ring_operator_q, 3 );
let matrix = VecOfVec::new(
vec![
vec![ (0,r(4,1)), (1,r(-6,1)) ],
vec![ (1,r(4,1)), (2,r(-2,1)) ],
vec![ (2,r(7,1)) ],
],
).ok().unwrap();
test_echelon_solve_on_invertible_uppertriangular_matrix( &matrix, matching_column_index_to_row_index.clone(), matching_column_index_to_row_index.clone(), ring_operator_q, 3 );
let matrix = VecOfVec::new(
vec![
vec![ (0,r(2,1)), (1,r(6,1)), (3,r(8,1)), ],
vec![ (1,r(2,1)), (2,r(9,1)), ],
vec![ (2,r(2,1)), (3,r(-4,1)), ],
vec![ (3,r(4,1)), ],
],
).ok().unwrap();
test_echelon_solve_on_invertible_uppertriangular_matrix( &matrix, matching_column_index_to_row_index.clone(), matching_column_index_to_row_index.clone(), ring_operator_q, 4 );
use rand::Rng; let matrix_size = 20;
let mut rng = rand::thread_rng(); let mut vec_of_vec = vec![];
for row_index in 0 .. matrix_size {
let coefficient_leading = rng.gen_range( 1 .. modulus );
let mut new_vec = vec![ (row_index, coefficient_leading) ]; for q in row_index+1 .. matrix_size { let coefficient = rng.gen_range( 0 .. modulus );
let flag = rng.gen_range(0usize .. 3usize);
if flag == 0 { new_vec.push( ( q, 0 ) ) }
else if flag == 1 { new_vec.push( ( q, coefficient ) ) }
else { continue }
}
vec_of_vec.push( new_vec ); }
let matrix = VecOfVec::new(vec_of_vec).ok().unwrap(); test_echelon_solve_on_invertible_uppertriangular_matrix( &matrix, matching_column_index_to_row_index.clone(), matching_column_index_to_row_index, ring_operator_p, matrix_size );
}
}