pub mod comb;
pub mod construction;
use itertools::Itertools;
use comb::*;
use construction::*;
use num::rational::Ratio;
use ordered_float::OrderedFloat;
use sprs::linalg::ordering::order;
use crate::algebra::matrices::types::product::ProductMatrix;
use crate::algebra::matrices::operations::solve::triangle::{TriangularSolveForColumnVectorReverse, TriangularSolveForRowVector};
use crate::algebra::matrices::operations::MatrixOracleOperations;
use crate::algebra::matrices::types::bimajor::MatrixBimajorData;
use crate::algebra::matrices::types::packet::MatrixAlgebraPacket;
use crate::algebra::vectors::entries::KeyValNew;
use crate::algebra::matrices::operations::transform_entry_wise::{ReindexMatrixColumns, ReindexSquareMatrix};
use crate::algebra::matrices::types::matching::{GeneralizedMatchingMatrixWithSequentialOrder};
use crate::algebra::matrices::types::scalar_diagonal_triangle::SumOfScalarAndStrictlyUpperTriangularMatrices;
use crate::algebra::matrices::types::vec_of_vec::sorted::VecOfVec;
use crate::algebra::matrices::query::{ MatrixAlgebra, MatrixOracle, };
use crate::algebra::matrices::operations::iterate_rows_and_columns::SequenceOfReverseColumns;
use crate::algebra::matrices::operations::combine_rows_and_columns::{LinearCombinationOfColumns, LinearCombinationOfColumnsReverse, LinearCombinationOfRows };
use crate::topology::simplicial::simplices::weighted::WeightedSimplex;
use crate::utilities::functions::evaluate::{ EvaluateFunctionFnMutWrapper };
use crate::utilities::iterators::general::{FilterOutMembers};
use crate::utilities::iterators::merge::hit::{IteratorsMergedInSortedOrder};
use crate::algebra::vectors::entries::{KeyValGet, KeyValPair};
use crate::algebra::rings::traits::{SemiringOperations, DivisionRingOperations};
use crate::utilities::order::{JudgeOrder, OrderOperatorAuto, OrderOperatorByKey, OrderOperatorByKeyCustom, ReverseOrder};
use crate::algebra::vectors::operations::{Scale, Simplify, VectorOperations};
use std::collections::HashMap;
use std::hash::Hash;
use std::fmt::Debug;
use std::iter::Cloned;
use crate::algebra::matrices::operations::solve::echelon::{RowEchelonSolver};
use crate::algebra::matrices::operations::transform_vector_wise::{OnlyColumnIndicesInsideCollection, OnlyColumnIndicesOutsideCollection, OnlyRowIndicesInsideCollection, OnlyRowIndicesOutsideCollection};
use derive_getters::Dissolve;
#[derive(Clone,Debug,Dissolve,Eq,PartialEq)] pub struct Umatch< MatrixToFactor >
where
MatrixToFactor: MatrixAlgebra,
MatrixToFactor::ColumnIndex: Hash, MatrixToFactor::RowIndex: Hash, {
matrix_to_factor: MatrixToFactor,
matching: GeneralizedMatchingMatrixWithSequentialOrder<
MatrixToFactor::ColumnIndex,
MatrixToFactor::RowIndex,
MatrixToFactor::Coefficient
>,
matched_block_of_target_comb_inverse_indexed_by_ordinal_of_matched_row_off_diagonal:
MatrixBimajorData<
VecOfVec< usize, MatrixToFactor::Coefficient >,
VecOfVec< usize, MatrixToFactor::Coefficient >,
>,
}
impl < MatrixToFactor >
Umatch
< MatrixToFactor >
where
MatrixToFactor: MatrixAlgebra,
MatrixToFactor::ColumnIndex: Hash + std::cmp::Eq, MatrixToFactor::RowIndex: Hash + std::cmp::Eq, {
pub fn new
< RowIndicesInReverseOrder > (
matrix_to_factor: MatrixToFactor,
row_indices_in_reverse_order: RowIndicesInReverseOrder,
)
->
Self
where
MatrixToFactor::RingOperator: DivisionRingOperations< Element = MatrixToFactor::Coefficient >,
MatrixToFactor::RowEntry: KeyValPair,
MatrixToFactor::ColumnEntry: KeyValPair,
RowIndicesInReverseOrder: Iterator< Item = MatrixToFactor::RowIndex >,
{
let ( comb_target_inv_off_diag_pivot_block, matching ) : ( VecOfVec<usize, MatrixToFactor::Coefficient>, GeneralizedMatchingMatrixWithSequentialOrder< MatrixToFactor::ColumnIndex, MatrixToFactor::RowIndex, MatrixToFactor::Coefficient > )
= get_pivot_block_of_target_comb_inverse_with_deleted_diagonal(
& matrix_to_factor,
row_indices_in_reverse_order,
);
let comb_target_inv_off_diag_pivot_block
= MatrixBimajorData {
matrix_columns_data: comb_target_inv_off_diag_pivot_block
.transpose_deep( matching.number_of_structural_nonzeros() ) .unwrap(),
matrix_rows_data: comb_target_inv_off_diag_pivot_block,
};
Umatch{
matrix_to_factor,
matching,
matched_block_of_target_comb_inverse_indexed_by_ordinal_of_matched_row_off_diagonal: comb_target_inv_off_diag_pivot_block,
}
}
pub fn new_with_compression
< RowIndicesInReverseOrder, IndexForRowsAndColumns, EntryForRowsAndColumns, Coefficient > (
matrix_to_factor: MatrixToFactor,
row_indices_in_reverse_order: RowIndicesInReverseOrder,
)
->
Umatch< MatrixToFactor, >
where
IndexForRowsAndColumns: Clone + Debug + Eq + Hash, EntryForRowsAndColumns: PartialEq + KeyValPair< Key=IndexForRowsAndColumns, Val=Coefficient >,
MatrixToFactor: MatrixAlgebra<
ColumnIndex= IndexForRowsAndColumns, RowIndex= IndexForRowsAndColumns, RowEntry= EntryForRowsAndColumns,
ColumnEntry= EntryForRowsAndColumns,
RingOperator: DivisionRingOperations< Element = Coefficient >, Coefficient= Coefficient, >
+ MatrixOracleOperations,
RowIndicesInReverseOrder: IntoIterator< Item = MatrixToFactor::RowIndex >,
Coefficient: Clone + Debug + PartialEq,
{
let ( comb_target_inv_off_diag_pivot_block, matching ) :
(
VecOfVec<usize,
MatrixToFactor::Coefficient>,
GeneralizedMatchingMatrixWithSequentialOrder< MatrixToFactor::ColumnIndex,
MatrixToFactor::RowIndex,
MatrixToFactor::Coefficient >
)
= target_comb_inv_off_diag_pivot_block_skipmatched(
& matrix_to_factor,
row_indices_in_reverse_order,
);
let comb_target_inv_off_diag_pivot_block
= MatrixBimajorData {
matrix_columns_data: comb_target_inv_off_diag_pivot_block.transpose_deep( matching.number_of_structural_nonzeros() ).unwrap(), matrix_rows_data: comb_target_inv_off_diag_pivot_block,
};
Umatch{
matrix_to_factor,
matching,
matched_block_of_target_comb_inverse_indexed_by_ordinal_of_matched_row_off_diagonal: comb_target_inv_off_diag_pivot_block,
}
}
pub fn ring_operator( &self ) -> MatrixToFactor::RingOperator {
self.matrix_to_factor.ring_operator()
}
}
impl < MatrixToFactor >
Umatch
< MatrixToFactor >
where
MatrixToFactor: MatrixAlgebra,
MatrixToFactor::RingOperator: DivisionRingOperations,
MatrixToFactor::ColumnIndex: Hash, MatrixToFactor::RowIndex: Hash, MatrixToFactor::RowEntry: KeyValPair,
MatrixToFactor::ColumnEntry: KeyValPair,
{
pub fn rank( &self ) -> usize
{
self.matching.number_of_structural_nonzeros()
}
pub fn order_operator_for_row_entries( &self ) -> MatrixToFactor::OrderOperatorForRowEntries
{ self.matrix_to_factor.order_operator_for_row_entries() }
pub fn order_operator_for_row_entries_reverse( &self ) -> ReverseOrder< MatrixToFactor::OrderOperatorForRowEntries >
{ ReverseOrder::new(self.matrix_to_factor.order_operator_for_row_entries()) }
pub fn order_operator_for_row_indices( &self ) -> MatrixToFactor::OrderOperatorForRowIndices
{ self.matrix_to_factor.order_operator_for_row_indices() }
pub fn order_operator_for_row_indices_reverse( &self ) -> ReverseOrder< MatrixToFactor::OrderOperatorForRowIndices >
{ ReverseOrder::new(self.matrix_to_factor.order_operator_for_row_indices()) }
pub fn order_operator_for_column_entries( &self ) -> MatrixToFactor::OrderOperatorForColumnEntries
{ self.matrix_to_factor.order_operator_for_column_entries() }
pub fn order_operator_for_column_entries_reverse( &self ) -> ReverseOrder< MatrixToFactor::OrderOperatorForColumnEntries >
{ ReverseOrder::new( self.matrix_to_factor.order_operator_for_column_entries() ) }
pub fn order_operator_for_column_indices( &self ) -> MatrixToFactor::OrderOperatorForColumnIndices
{ self.matrix_to_factor.order_operator_for_column_indices() }
pub fn order_operator_for_column_indices_reverse( &self ) -> ReverseOrder< MatrixToFactor::OrderOperatorForColumnIndices >
{ ReverseOrder::new( self.matrix_to_factor.order_operator_for_column_indices() ) }
pub fn matched_row_indices_in_ascending_order( &self ) -> &Vec< MatrixToFactor::RowIndex > {
self.matching.matched_row_indices_in_sequence()
}
pub fn matched_column_indices_in_matched_row_order( &self ) -> &Vec< MatrixToFactor::ColumnIndex > {
self.matching.matched_column_indices_in_sequence()
}
pub fn matched_column_indices_in_ascending_order( &self ) -> Vec< MatrixToFactor::ColumnIndex > {
let mut indices = self.matching.matched_column_indices_in_sequence().clone();
let order_operator = self.matrix_to_factor.order_operator_for_column_indices();
indices.sort_by( |a,b| order_operator.judge_cmp( a, b ) );
indices
}
pub fn target_comb( &self ) -> TargetComb< '_, MatrixToFactor > {
TargetComb{ umatch: self }
}
pub fn target_comb_inverse( &self ) -> TargetCombInverse< '_, MatrixToFactor > {
TargetCombInverse{ umatch: self }
}
pub fn source_comb( &self ) -> SourceComb< '_, MatrixToFactor > {
SourceComb{ umatch: self }
}
pub fn source_comb_inverse( &self ) -> SourceCombInverse< '_, MatrixToFactor > {
SourceCombInverse{ umatch: self }
}
pub fn generalized_matching_matrix_ref( &self ) -> & GeneralizedMatchingMatrixWithSequentialOrder< MatrixToFactor::ColumnIndex, MatrixToFactor::RowIndex, MatrixToFactor::Coefficient > { & self.matching }
pub fn matrix_to_factor_ref( &self ) -> & MatrixToFactor { & self.matrix_to_factor }
pub fn generalized_matching_matrix_ref_packet( &self )
-> MatrixAlgebraPacket<
& GeneralizedMatchingMatrixWithSequentialOrder< MatrixToFactor::ColumnIndex, MatrixToFactor::RowIndex, MatrixToFactor::Coefficient >,
MatrixToFactor::RingOperator,
OrderOperatorByKeyCustom < MatrixToFactor::OrderOperatorForColumnIndices >, MatrixToFactor::OrderOperatorForRowIndices, OrderOperatorByKeyCustom< MatrixToFactor::OrderOperatorForRowIndices >, MatrixToFactor::OrderOperatorForColumnIndices, >
{
MatrixAlgebraPacket{
matrix: self.generalized_matching_matrix_ref(),
ring_operator: self.ring_operator(),
order_operator_for_row_entries: OrderOperatorByKeyCustom::< MatrixToFactor::OrderOperatorForColumnIndices >::new( self.matrix_to_factor.order_operator_for_column_indices()
),
order_operator_for_row_indices: self.matrix_to_factor.order_operator_for_row_indices(),
order_operator_for_column_entries: OrderOperatorByKeyCustom::< MatrixToFactor::OrderOperatorForRowIndices >::new(
self.matrix_to_factor.order_operator_for_row_indices() ),
order_operator_for_column_indices: self.matrix_to_factor.order_operator_for_column_indices(),
}
}
pub fn matrix_to_factor_matched_columns_only( &self ) -> OnlyColumnIndicesInsideCollection< &MatrixToFactor, &HashMap< MatrixToFactor::ColumnIndex, usize >, >
{
OnlyColumnIndicesInsideCollection::new( & self.matrix_to_factor, self.matching.bijection_column_indices_to_ordinals_and_inverse().hashmap_element_to_ordinal() )
}
pub fn matrix_to_factor_matchless_columns_only( &self ) -> OnlyColumnIndicesOutsideCollection< &MatrixToFactor, &HashMap< MatrixToFactor::ColumnIndex, usize >, >
{
OnlyColumnIndicesOutsideCollection::new( & self.matrix_to_factor, self.matching.bijection_column_indices_to_ordinals_and_inverse().hashmap_element_to_ordinal() )
}
pub fn matrix_to_factor_matched_rows_only( &self ) -> OnlyRowIndicesInsideCollection< &MatrixToFactor, &HashMap< MatrixToFactor::RowIndex, usize >, >
{
OnlyRowIndicesInsideCollection::new( & self.matrix_to_factor, self.matching.bijection_row_indices_to_ordinals_and_inverse().hashmap_element_to_ordinal() )
}
pub fn matrix_to_factor_matchless_rows_only( &self ) -> OnlyRowIndicesOutsideCollection< &MatrixToFactor, &HashMap< MatrixToFactor::RowIndex, usize >, >
{
OnlyRowIndicesOutsideCollection::new( & self.matrix_to_factor, self.matching.bijection_row_indices_to_ordinals_and_inverse().hashmap_element_to_ordinal() )
}
pub fn matched_block_of_matrix_to_factor( &self ) ->
OnlyRowIndicesInsideCollection<
OnlyColumnIndicesInsideCollection<
&MatrixToFactor,
&HashMap< MatrixToFactor::ColumnIndex, usize >,
>,
&HashMap< MatrixToFactor::RowIndex, usize >,
>
{
let matched_row_collection = self.matching.bijection_row_indices_to_ordinals_and_inverse().hashmap_element_to_ordinal();
let matched_column_collection = self.matching.bijection_column_indices_to_ordinals_and_inverse().hashmap_element_to_ordinal();
OnlyRowIndicesInsideCollection::new(
OnlyColumnIndicesInsideCollection::new(
& self.matrix_to_factor,
matched_column_collection,
),
matched_row_collection,
)
}
pub fn matched_block_of_target_comb_inverse_indexed_by_ordinal_of_matched_row_off_diagonal_ref( &self )
->
& MatrixBimajorData<
VecOfVec< usize, MatrixToFactor::Coefficient >,
VecOfVec< usize, MatrixToFactor::Coefficient >,
>
{ & self.matched_block_of_target_comb_inverse_indexed_by_ordinal_of_matched_row_off_diagonal }
pub fn matched_block_of_target_comb_inverse_indexed_by_ordinal_of_matched_row< 'a >( &'a self )
->
SumOfScalarAndStrictlyUpperTriangularMatrices<
&'a MatrixBimajorData<
VecOfVec< usize, MatrixToFactor::Coefficient >,
VecOfVec< usize, MatrixToFactor::Coefficient >,
>
>
{
let prepended = SumOfScalarAndStrictlyUpperTriangularMatrices::new(
self.matched_block_of_target_comb_inverse_indexed_by_ordinal_of_matched_row_off_diagonal_ref(),
MatrixToFactor::RingOperator::one()
);
prepended
}
pub fn matched_block_of_target_comb_inverse( &self )
->
MatrixAlgebraPacket<
ReindexSquareMatrix<
SumOfScalarAndStrictlyUpperTriangularMatrices<
& MatrixBimajorData<
VecOfVec< usize, MatrixToFactor::Coefficient >,
VecOfVec< usize, MatrixToFactor::Coefficient >,
>
>,
&Vec< MatrixToFactor::RowIndex >,
&HashMap< MatrixToFactor::RowIndex, usize >,
usize,
MatrixToFactor::RowIndex,
MatrixToFactor::ColumnEntry,
>,
MatrixToFactor::RingOperator,
MatrixToFactor::OrderOperatorForRowEntries,
MatrixToFactor::OrderOperatorForRowIndices,
MatrixToFactor::OrderOperatorForRowEntries,
MatrixToFactor::OrderOperatorForRowIndices,
>
{
let matrix_integer_indexed = self.matched_block_of_target_comb_inverse_indexed_by_ordinal_of_matched_row();
let matrix = ReindexSquareMatrix::new(
matrix_integer_indexed,
self.matching.bijection_row_indices_to_ordinals_and_inverse().vec_elements_in_order(),
self.matching.bijection_row_indices_to_ordinals_and_inverse().hashmap_element_to_ordinal(),
);
MatrixAlgebraPacket {
matrix,
ring_operator: self.ring_operator(),
order_operator_for_row_entries: self.order_operator_for_row_entries(),
order_operator_for_row_indices: self.order_operator_for_row_indices(),
order_operator_for_column_entries: self.order_operator_for_row_entries(),
order_operator_for_column_indices: self.order_operator_for_row_indices(),
}
}
pub fn matched_block_of_target_comb_inverse_or( &self ) ->
MatrixAlgebraPacket<
ReindexMatrixColumns<
SumOfScalarAndStrictlyUpperTriangularMatrices<
& MatrixBimajorData<
VecOfVec< usize, MatrixToFactor::Coefficient >,
VecOfVec< usize, MatrixToFactor::Coefficient >,
>
>,
&Vec< MatrixToFactor::RowIndex >,
&HashMap< MatrixToFactor::RowIndex, usize >,
usize,
MatrixToFactor::RowIndex,
MatrixToFactor::ColumnEntry,
>,
MatrixToFactor::RingOperator,
MatrixToFactor::OrderOperatorForColumnEntries, OrderOperatorAuto, OrderOperatorByKey, MatrixToFactor::OrderOperatorForRowIndices, >
{
let matrix_integer_indexed = self.matched_block_of_target_comb_inverse_indexed_by_ordinal_of_matched_row();
let matrix = ReindexMatrixColumns::new(
matrix_integer_indexed,
self.matching.bijection_row_indices_to_ordinals_and_inverse().vec_elements_in_order(),
self.matching.bijection_row_indices_to_ordinals_and_inverse().hashmap_element_to_ordinal(),
);
MatrixAlgebraPacket {
matrix,
ring_operator: self.ring_operator(),
order_operator_for_row_entries: self.order_operator_for_column_entries(),
order_operator_for_row_indices: OrderOperatorAuto,
order_operator_for_column_entries: OrderOperatorByKey,
order_operator_for_column_indices: self.order_operator_for_row_indices(),
}
}
pub fn matched_blocks_of_target_comb_inverse_times_matrix_to_factor_oc( & self ) ->
ProductMatrix<
MatrixAlgebraPacket< ReindexMatrixColumns<
SumOfScalarAndStrictlyUpperTriangularMatrices<
& MatrixBimajorData<
VecOfVec< usize, MatrixToFactor::Coefficient >,
VecOfVec< usize, MatrixToFactor::Coefficient >,
>
>,
&Vec< MatrixToFactor::RowIndex >, &HashMap< MatrixToFactor::RowIndex, usize >, usize, MatrixToFactor::RowIndex, MatrixToFactor::ColumnEntry, >,
MatrixToFactor::RingOperator,
MatrixToFactor::OrderOperatorForColumnEntries, OrderOperatorAuto, OrderOperatorByKey, MatrixToFactor::OrderOperatorForRowIndices, >,
OnlyRowIndicesInsideCollection< OnlyColumnIndicesInsideCollection<
&MatrixToFactor,
&HashMap< MatrixToFactor::ColumnIndex, usize >,
>,
&HashMap< MatrixToFactor::RowIndex, usize >,
>
>
{
let target_block = self.matched_block_of_target_comb_inverse_or();
let factored_block = self.matched_block_of_matrix_to_factor();
ProductMatrix::new( target_block, factored_block )
}
pub fn target_comb_inverse_times_matrix_to_factor_matched_block( &self )
->
TargetCombInverseTimesMatrixToFactorMatchedBlock< '_, MatrixToFactor >
{
TargetCombInverseTimesMatrixToFactorMatchedBlock{ umatch: self } }
pub fn target_comb_inverse_times_matrix_to_factor_matched_block_with_rows_indexed_by_matched_column_index( &self )
->
TargetCombInverseTimesMatrixToFactorMatchedBlockRowsIndexedByColumnIndex< '_, MatrixToFactor >
{
TargetCombInverseTimesMatrixToFactorMatchedBlockRowsIndexedByColumnIndex{ umatch: self } }
pub fn solve_tx_equals_b< I >( &self, b: I )
->
Result<
TriangularSolveForColumnVectorReverse<
Vec< MatrixToFactor::ColumnEntry >,
TargetComb< MatrixToFactor >,
>,
()
>
where
I: IntoIterator<Item=MatrixToFactor::ColumnEntry>,
{
TriangularSolveForColumnVectorReverse::solve(
b,
self.target_comb(),
)
}
pub fn solve_x_equals_b_times_source_comb_inverse< I >( &self, b: I )
->
LinearCombinationOfRows< SourceCombInverse< MatrixToFactor > >
where
I: IntoIterator<Item=MatrixToFactor::RowEntry>, {
b.multiply_self_as_a_row_vector_with_matrix( self.source_comb_inverse() )
}
pub fn solve_x_equals_b_times_source_comb< I >( &self, b: I )
->
Result<
TriangularSolveForRowVector<
Vec< MatrixToFactor::RowEntry >,
SourceCombInverse< MatrixToFactor >,
>,
()
>
where
I: IntoIterator<Item=MatrixToFactor::RowEntry>,
{
TriangularSolveForRowVector::solve(
b,
self.source_comb_inverse(),
)
}
pub fn solve_dx_equals_b< Vector >( &self, b: Vector )
->
Option< Vec< MatrixToFactor::RowEntry > >
where
Vector: IntoIterator<Item=MatrixToFactor::ColumnEntry>,
{
let matching_inverse = self.generalized_matching_matrix_ref().generalized_inverse(self.ring_operator());
let matching_inverse = MatrixAlgebraPacket{
matrix: matching_inverse,
ring_operator: self.ring_operator(),
order_operator_for_row_entries: OrderOperatorByKeyCustom::new(self.order_operator_for_row_indices()), order_operator_for_row_indices: self.order_operator_for_column_indices(),
order_operator_for_column_entries: OrderOperatorByKeyCustom::new(self.order_operator_for_column_indices()), order_operator_for_column_indices: self.order_operator_for_row_indices(),
};
let comb_target_inverse = self.target_comb_inverse();
let comb_source = self.source_comb();
let tinv_b = comb_target_inverse.multiply_with_column_vector( b ).collect_vec();
for entry in tinv_b.iter() {
if matching_inverse.matrix_ref().lacks_a_match_for_column_index( & entry.key() ) {
return None;
}
}
let minv_tinv_b = matching_inverse.multiply_with_column_vector(tinv_b).collect_vec();
let x = comb_source.multiply_with_column_vector( minv_tinv_b ).collect_vec();
return Some( x )
}
pub fn solve_xd_equals_b< Vector >( &self, b: Vector )
->
Option< Vec< MatrixToFactor::ColumnEntry > >
where
Vector: IntoIterator<Item=MatrixToFactor::RowEntry>,
{
let prod = self.target_comb_inverse()
.multiply_on_the_left_of( self.matrix_to_factor_ref() );
let matching = self.generalized_matching_matrix_ref();
let key_matching = |x| { matching.row_index_for_column_index(&x) };
RowEchelonSolver::solve(
b.into_iter(),
prod,
EvaluateFunctionFnMutWrapper::new( key_matching ),
self.ring_operator(),
self.order_operator_for_row_entries(),
)
.solution() .map(|x| x.multiply_self_as_a_row_vector_with_matrix( self.target_comb_inverse() ).collect_vec() )
}
pub fn kernel< ColumnIndices >( &self, column_indices: ColumnIndices )
->
SequenceOfReverseColumns<
SourceComb
< MatrixToFactor >,
FilterOutMembers
< ColumnIndices::IntoIter, & HashMap< MatrixToFactor::ColumnIndex, usize > >,
>
where
ColumnIndices: IntoIterator< Item = MatrixToFactor::ColumnIndex >,
{
SequenceOfReverseColumns::new(
self.source_comb(),
self.matching.filter_out_matched_column_indices( column_indices )
)
}
pub fn image( &self )
->
SequenceOfReverseColumns<
TargetComb
< MatrixToFactor >,
Cloned< std::slice::Iter< MatrixToFactor::RowIndex > >,
>
{
SequenceOfReverseColumns::new(
self.target_comb(),
self.matching.bijection_row_indices_to_ordinals_and_inverse().vec_elements_in_order().iter().cloned()
)
}
pub fn multiply_xd< Vector, VectorEntry >( & self, v: Vector )
->
LinearCombinationOfRows< MatrixToFactor >
where
Vector: IntoIterator<Item=VectorEntry>,
VectorEntry: KeyValGet < Key = MatrixToFactor::RowIndex, Val = MatrixToFactor::Coefficient >,
{
let matrix = |i| self.matrix_to_factor.row( & i );
v.multiply_matrix_fnmut( matrix, self.ring_operator(), self.order_operator_for_row_entries() )
}
pub fn multiply_dx< Vector, VectorEntry >( &self, v: Vector )
->
LinearCombinationOfColumns< MatrixToFactor >
where
Vector: IntoIterator<Item=VectorEntry>,
VectorEntry: KeyValGet < Key = MatrixToFactor::ColumnIndex, Val = MatrixToFactor::Coefficient >,
{
let matrix = |i| self.matrix_to_factor.column( & i );
v.multiply_matrix_fnmut( matrix, self.ring_operator(), self.order_operator_for_column_entries() )
}
}
impl < MatrixToFactor, EntryForRowsAndColumns, IndexForRowsAndColumns >
Umatch
< MatrixToFactor >
where
MatrixToFactor: MatrixAlgebra + MatrixOracle< RowEntry=EntryForRowsAndColumns, ColumnEntry=EntryForRowsAndColumns, RowIndex=IndexForRowsAndColumns >,
MatrixToFactor::ColumnIndex: Clone + Hash + std::cmp::Eq, MatrixToFactor::RowIndex: Clone + Hash + std::cmp::Eq, MatrixToFactor::RowEntry: KeyValGet < Key = MatrixToFactor::ColumnIndex, Val = MatrixToFactor::Coefficient >,
{
}
#[cfg(test)]
mod doc_test_drafts {
use crate::algebra::{matrices::types::packet::MatrixAlgebraPacket, rings::types::field_prime_order::BooleanField};
#[test]
fn doc_test_umatchrowmajor_comprehensive_tiny() {
use crate::algebra::matrices::operations::umatch::row_major::doc_test_drafts::BooleanField;
use crate::algebra::matrices::types::{vec_of_vec::sorted::VecOfVec};
use crate::algebra::matrices::operations::umatch::row_major::{Umatch};
use crate::algebra::matrices::types::product::ProductMatrix;
use crate::algebra::matrices::query::MatrixOracle;
use itertools::Itertools;
let ring_operator = BooleanField::new();
let num_indices_row = 1;
let num_indices_col = 1;
let matrix_to_factor_data = VecOfVec::new(
vec![
vec![(0,true),],
] ).ok().unwrap();
let matrix_to_factor = MatrixAlgebraPacket::with_default_order_and_boolean_coefficients( & matrix_to_factor_data );
let umatch
= Umatch::new(
matrix_to_factor,
(0..num_indices_row).rev(),
);
let matching = umatch.generalized_matching_matrix_ref();
let comb_target = umatch.target_comb();
let comb_target_inv = umatch.target_comb_inverse();
let comb_source = umatch.source_comb();
let comb_source_inv = umatch.source_comb_inverse();
let comb_target_ref = & comb_target;
let comb_target_inv_ref = & comb_target_inv;
let comb_source_ref = & comb_source;
let comb_source_inv_ref = & comb_source_inv;
let product_source = ProductMatrix::new( comb_source_ref, comb_source_inv_ref );
let product_target = ProductMatrix::new( comb_target_ref, comb_target_inv_ref );
let product_target_comb_inv_times_matrix_to_factor = ProductMatrix::new( comb_target_inv_ref, matrix_to_factor );
let product_target_comb_inv_times_matrix_to_factor_times_source_comb = ProductMatrix::new( product_target_comb_inv_times_matrix_to_factor, comb_source_ref );
for column_index in 0 .. num_indices_col {
assert_eq!(
product_source.row( & column_index ).collect_vec(),
vec![ (column_index, true) ]
)
}
for row_index in 0 .. num_indices_row {
assert_eq!(
product_target.row( &row_index ).collect_vec(),
vec![ (row_index, true) ]
)
}
for row_index in 0 .. num_indices_row {
assert_eq!(
product_target_comb_inv_times_matrix_to_factor_times_source_comb.row( &row_index ).collect_vec(),
matching.row( &row_index ).collect_vec()
)
}
}
#[test]
fn doc_test_umatchrowmajor_comprehensive_tiny_waist() {
use crate::algebra::matrices::operations::umatch::row_major::doc_test_drafts::BooleanField;
use crate::algebra::matrices::types::{vec_of_vec::sorted::VecOfVec};
use crate::algebra::matrices::operations::umatch::row_major::{Umatch};
use crate::algebra::matrices::types::product::ProductMatrix;
use crate::algebra::matrices::query::MatrixOracle;
use itertools::Itertools;
let ring_operator = BooleanField::new();
let num_indices_row = 2;
let num_indices_col = 1;
let matrix_to_factor_data = VecOfVec::new(
vec![
vec![(0,true),],
vec![(0,true),],
] ).ok().unwrap();
let matrix_to_factor = MatrixAlgebraPacket::with_default_order_and_boolean_coefficients( & matrix_to_factor_data );
let umatch
= Umatch::new(
matrix_to_factor,
(0..num_indices_row).rev(),
);
let matching = umatch.generalized_matching_matrix_ref();
let comb_target = umatch.target_comb();
let comb_target_inv = umatch.target_comb_inverse();
let comb_source = umatch.source_comb();
let comb_source_inv = umatch.source_comb_inverse();
let comb_target_ref = & comb_target;
let comb_target_inv_ref = & comb_target_inv;
let comb_source_ref = & comb_source;
let comb_source_inv_ref = & comb_source_inv;
let product_source = ProductMatrix::new( comb_source_ref, comb_source_inv_ref );
let product_target = ProductMatrix::new( comb_target_ref, comb_target_inv_ref );
let product_target_comb_inv_times_matrix_to_factor = ProductMatrix::new( comb_target_inv_ref, matrix_to_factor );
let product_target_comb_inv_times_matrix_to_factor_times_source_comb = ProductMatrix::new( product_target_comb_inv_times_matrix_to_factor, comb_source_ref );
for column_index in 0 .. num_indices_col {
assert_eq!(
product_source.row( & column_index ).collect_vec(),
vec![ (column_index, true) ]
)
}
for row_index in 0 .. num_indices_row {
assert_eq!(
product_target.row( & row_index ).collect_vec(),
vec![ (row_index, true) ]
)
}
for row_index in 0 .. num_indices_row {
assert_eq!(
product_target_comb_inv_times_matrix_to_factor_times_source_comb.row( &row_index ).collect_vec(),
matching.row( & row_index ).collect_vec()
)
}
}
#[test]
fn doc_test_umatchrowmajor_comprehensive_tiny_height() {
use crate::algebra::matrices::operations::umatch::row_major::doc_test_drafts::BooleanField;
use crate::algebra::matrices::types::{vec_of_vec::sorted::VecOfVec};
use crate::algebra::matrices::operations::umatch::row_major::{Umatch};
use crate::algebra::matrices::types::product::ProductMatrix;
use crate::algebra::matrices::query::MatrixOracle;
use itertools::Itertools;
let ring_operator = BooleanField::new();
let num_indices_row = 1;
let num_indices_col = 2;
let matrix_to_factor_data = VecOfVec::new(
vec![
vec![(0,true), (1,true)],
] ).ok().unwrap();
let matrix_to_factor = MatrixAlgebraPacket::with_default_order_and_boolean_coefficients( & matrix_to_factor_data );
let umatch
= Umatch::new(
matrix_to_factor,
(0..num_indices_row).rev(),
);
let matching = umatch.generalized_matching_matrix_ref();
let comb_target = umatch.target_comb();
let comb_target_inv = umatch.target_comb_inverse();
let comb_source = umatch.source_comb();
let comb_source_inv = umatch.source_comb_inverse();
let comb_target_ref = & comb_target;
let comb_target_inv_ref = & comb_target_inv;
let comb_source_ref = & comb_source;
let comb_source_inv_ref = & comb_source_inv;
let product_source = ProductMatrix::new( comb_source_ref, comb_source_inv_ref );
let product_target = ProductMatrix::new( comb_target_ref, comb_target_inv_ref );
let product_target_comb_inv_times_matrix_to_factor = ProductMatrix::new( comb_target_inv_ref, matrix_to_factor );
let product_target_comb_inv_times_matrix_to_factor_times_source_comb = ProductMatrix::new( product_target_comb_inv_times_matrix_to_factor, comb_source_ref );
for column_index in 0 .. num_indices_col {
assert_eq!(
product_source.row( & column_index ).collect_vec(),
vec![ (column_index, true) ]
)
}
for row_index in 0 .. num_indices_row {
assert_eq!(
product_target.row( &row_index ).collect_vec(),
vec![ (row_index, true) ]
)
}
for row_index in 0 .. num_indices_row {
assert_eq!(
product_target_comb_inv_times_matrix_to_factor_times_source_comb.row( &row_index ).collect_vec(),
matching.row( &row_index ).collect_vec()
)
}
}
#[test]
fn doc_test_umatchrowmajor_comprehensive_small() {
use crate::algebra::rings::types::field_prime_order::PrimeOrderField;
use crate::algebra::matrices::types::{vec_of_vec::sorted::VecOfVec};
use crate::algebra::matrices::operations::umatch::row_major::{Umatch};
use crate::algebra::matrices::types::product::ProductMatrix;
use crate::algebra::matrices::query::MatrixOracle;
use itertools::Itertools;
let modulus = 5;
let ring_operator = PrimeOrderField::new( modulus );
let num_indices_row = 2;
let num_indices_col = 3;
let matrix_to_factor_data = VecOfVec::new(
vec![
vec![(0,1), (1,2), (2,3)],
vec![ (2,1)]
] ).ok().unwrap();
let matrix_to_factor = MatrixAlgebraPacket::with_default_order( & matrix_to_factor_data, ring_operator.clone() );
let umatch
= Umatch::new(
matrix_to_factor,
(0..num_indices_row).rev(),
);
let matching = umatch.generalized_matching_matrix_ref();
let comb_target = umatch.target_comb();
let comb_target_inv = umatch.target_comb_inverse();
let comb_source = umatch.source_comb();
let comb_source_inv = umatch.source_comb_inverse();
let comb_target_ref = & comb_target;
let comb_target_inv_ref = & comb_target_inv;
let comb_source_ref = & comb_source;
let comb_source_inv_ref = & comb_source_inv;
let product_source = ProductMatrix::new( comb_source_ref, comb_source_inv_ref );
let product_target = ProductMatrix::new( comb_target_ref, comb_target_inv_ref );
let product_target_comb_inv_times_matrix_to_factor = ProductMatrix::new( comb_target_inv_ref, matrix_to_factor );
let product_target_comb_inv_times_matrix_to_factor_times_source_comb = ProductMatrix::new( product_target_comb_inv_times_matrix_to_factor, comb_source_ref );
for column_index in 0 .. num_indices_col {
assert_eq!(
product_source.row( & column_index ).collect_vec(),
vec![ (column_index, 1) ]
)
}
for row_index in 0 .. num_indices_row {
assert_eq!(
product_target.row( &row_index ).collect_vec(),
vec![ (row_index, 1) ]
)
}
for row_index in 0 .. num_indices_row {
assert_eq!(
product_target_comb_inv_times_matrix_to_factor_times_source_comb.row( &row_index ).collect_vec(),
matching.row( &row_index ).collect_vec()
)
}
}
}
#[cfg(test)]
mod unit_tests {
use itertools::{assert_equal, Itertools};
use crate::algebra::matrices::{debug::{matrix_oracle_is_internally_consistent, matrix_order_operators_are_internally_consistent}, operations::{multiply::multiply_row_vector_with_matrix, MatrixOracleOperations} };
use crate::algebra::matrices::debug::verify_rows_compatible_with_columns;
use crate::algebra::matrices::types::{vec_of_vec::sorted::VecOfVec, packet::MatrixAlgebraPacket};
use crate::algebra::rings::types::field_prime_order::PrimeOrderField;
#[test]
fn test_initial_decomposition() {
use crate::algebra::matrices::operations::umatch::row_major::get_pivot_block_of_target_comb_inverse_with_deleted_diagonal;
use crate::algebra::matrices::types::vec_of_vec::sorted::VecOfVec;
use crate::algebra::rings::types::field_prime_order::PrimeOrderField;
let matrix_to_factor = VecOfVec::new(
vec![
vec![ (0, 1), (1, 1) ],
vec![ (0, 1), (1, 1) ],
vec![ (0, 1), (1, 1) ],
]
).ok().unwrap();
let ring_operator = PrimeOrderField::new(5);
let matrix_to_factor_packet = MatrixAlgebraPacket::with_default_order( & matrix_to_factor, ring_operator);
let row_indices_in_reverse_order = (0..2).rev();
let _target_comb_inv_pivot_block = get_pivot_block_of_target_comb_inverse_with_deleted_diagonal(
& matrix_to_factor_packet,
row_indices_in_reverse_order,
);
println!("{:#?}", & _target_comb_inv_pivot_block.0);
println!("{:#?}", & _target_comb_inv_pivot_block.1);
}
#[test]
fn test_initial_decomposition_another_example() {
use itertools::Itertools;
use crate::algebra::matrices::query::MatrixOracle;
use crate::algebra::matrices::operations::umatch::row_major::get_pivot_block_of_target_comb_inverse_with_deleted_diagonal;
use crate::algebra::matrices::operations::invert::InverseUpperTriangularMatrix;
use crate::algebra::matrices::types::vec_of_vec::sorted::VecOfVec;
use crate::algebra::rings::types::field_prime_order::PrimeOrderField;
use crate::utilities::order::{OrderOperatorByKey};
let matrix_size = 5;
let max_column_index = matrix_size - 1;
let modulus = 7;
let ring_operator = PrimeOrderField::new( modulus );
let matrix_to_factor = VecOfVec::new(
vec![
vec![(0, 1), (1, 2), (4, 0)],
vec![ (1, 1), (2, 0), (4, 1)],
vec![ (2, 1), (3, 0), (4, 0)],
vec![ (3, 1), (4, 0)],
vec![ (4, 1)],
]
).ok().unwrap();
let matrix_to_factor_packet = MatrixAlgebraPacket::with_default_order( &matrix_to_factor, ring_operator.clone() );
let mut flipped_vertically = matrix_to_factor.clone();
flipped_vertically.reverse_the_sequence_of_columns_in_place(max_column_index);
let flipped_vertically_packet = MatrixAlgebraPacket::with_default_order( &flipped_vertically, ring_operator.clone() );
let row_indices_in_reverse_order = (0 .. matrix_size).rev();
let inverse = InverseUpperTriangularMatrix::new( & matrix_to_factor_packet );
let (array_comb, matching) = get_pivot_block_of_target_comb_inverse_with_deleted_diagonal(
& flipped_vertically_packet, row_indices_in_reverse_order,
);
for row_index in 0 .. matrix_size {
let inv_row = inverse.row(&row_index).collect_vec();
let ordinal = matching.ordinal_for_row_index( &row_index ).unwrap();
let comb_off_diag_view = (& array_comb)
.row( &ordinal )
.map( | (x,y)|
( matching.row_index_for_ordinal( x ), y ) );
let mut comb_view = comb_off_diag_view.collect_vec();
comb_view.push( (row_index, 1) );
comb_view.sort();
let product_inv= multiply_row_vector_with_matrix(
inv_row.clone(),
& flipped_vertically_packet,
ring_operator,
OrderOperatorByKey::new()
);
let product_umatch= multiply_row_vector_with_matrix(
comb_view.clone(),
& flipped_vertically_packet,
ring_operator,
OrderOperatorByKey::new()
);
for k in 0 .. matrix_size { println!("{:?}", matrix_to_factor_packet.row(&k).collect_vec() ) }
for k in 0 .. matrix_size { println!("{:?}", flipped_vertically_packet.row(&k) ) }
assert_eq!(comb_view, inv_row);
}
}
#[test]
fn test_initial_decomposition_larger() {
use itertools::Itertools;
use crate::algebra::matrices::operations::umatch::row_major::get_pivot_block_of_target_comb_inverse_with_deleted_diagonal;
use crate::algebra::matrices::operations::invert::InverseUpperTriangularMatrix;
use crate::algebra::matrices::query::MatrixOracle;
use crate::algebra::rings::types::field_prime_order::PrimeOrderField;
use crate::utilities::order::OrderOperatorByKey;
let matrix_size = 10;
let max_column_index = matrix_size - 1;
let modulus = 7;
let ring_operator = PrimeOrderField::new( modulus );
let matrix_to_factor = VecOfVec::random_mod_p_upper_unitriangular( matrix_size, modulus );
let matrix_to_factor_packet = MatrixAlgebraPacket::with_default_order( &matrix_to_factor, ring_operator.clone() );
let mut flipped_vertically = matrix_to_factor.clone();
flipped_vertically.reverse_the_sequence_of_columns_in_place(max_column_index);
let flipped_vertically_packet = MatrixAlgebraPacket::with_default_order( &flipped_vertically, ring_operator.clone() );
let inverse = InverseUpperTriangularMatrix::new( & matrix_to_factor_packet );
let row_indices_in_reverse_order = (0 .. matrix_size).rev();
let (array_comb, matching) = get_pivot_block_of_target_comb_inverse_with_deleted_diagonal(
& flipped_vertically_packet,
row_indices_in_reverse_order,
);
for row_index in 0 .. matrix_size {
let inv_row = inverse.row(&row_index).collect_vec();
let ordinal = matching.ordinal_for_row_index( &row_index ).unwrap();
let comb_off_diag_view = (& array_comb)
.row( & ordinal )
.map( | (x,y)|
( matching.row_index_for_ordinal( x ), y ) );
let mut comb_view = comb_off_diag_view.collect_vec();
comb_view.push( (row_index, 1) );
comb_view.sort();
let product_inv= multiply_row_vector_with_matrix(
inv_row.clone(),
& matrix_to_factor_packet,
ring_operator,
OrderOperatorByKey::new()
);
let product_umatch= multiply_row_vector_with_matrix(
comb_view.clone(),
& matrix_to_factor_packet,
ring_operator,
OrderOperatorByKey::new()
);
for k in 0 .. matrix_size { println!("{:?}", matrix_to_factor_packet.row(&k).collect_vec() ) }
for k in 0 .. matrix_size { println!("{:?}", flipped_vertically_packet.row(&k) ) }
assert_eq!(comb_view, inv_row);
}
}
#[test]
fn test_umatchrowmajor_comprehensive_small() {
use crate::algebra::matrices::operations::umatch::row_major::Umatch;
use crate::algebra::matrices::types::product::ProductMatrix;
use crate::algebra::matrices::query::MatrixOracle;
use crate::algebra::matrices::display::print_indexed_rows;
let num_indices_row = 2;
let num_indices_col = 3;
let modulus = 3;
let ring_operator = PrimeOrderField::new( modulus );
let matrix_to_factor_data = VecOfVec::new(
vec![
vec![(0,1), (1,2), (2,0)],
vec![ (2,0)]
] ).ok().unwrap();
let matrix_to_factor = MatrixAlgebraPacket::with_default_order( & matrix_to_factor_data, ring_operator );
let umatch = Umatch::new(
matrix_to_factor,
(0..num_indices_row).rev(),
);
let matching = umatch.generalized_matching_matrix_ref();
let comb_target = umatch.target_comb();
let comb_target_inv = umatch.target_comb_inverse();
let comb_source = umatch.source_comb();
let comb_source_inv = umatch.source_comb_inverse();
let comb_target_ref = & comb_target;
let comb_target_inv_ref = & comb_target_inv;
let comb_source_ref = & comb_source;
let comb_source_inv_ref = & comb_source_inv;
let product_source = ProductMatrix::new( comb_source_ref, comb_source_inv_ref );
let product_target = ProductMatrix::new( comb_target_ref, comb_target_inv_ref );
let product_target_comb_inv_times_matrix_to_factor = ProductMatrix::new( comb_target_inv_ref, matrix_to_factor );
let product_target_comb_inv_times_matrix_to_factor_times_source_comb = ProductMatrix::new( product_target_comb_inv_times_matrix_to_factor, comb_source_ref );
for column_index in 0 .. num_indices_col {
itertools::assert_equal( product_source.row( & column_index ), std::iter::once( (column_index, 1) ) );
}
for column_index in 0 .. num_indices_col {
assert_eq!(
product_source.row( & column_index ).collect_vec(),
vec![ (column_index, 1) ]
)
}
for row_index in 0 .. num_indices_row {
assert_eq!(
product_target.row( &row_index ).collect_vec(),
vec![ (row_index, 1) ]
)
}
for row_index in 0 .. num_indices_row {
assert_eq!(
product_target_comb_inv_times_matrix_to_factor_times_source_comb.row( &row_index ).collect_vec(),
matching.row( &row_index ).collect_vec()
)
}
for row_index in 0 .. num_indices_row {
assert!( matrix_to_factor.row( & row_index ).is_sorted_by( |x, y| x.0 < y.0 ) );
assert!( comb_target.row( & row_index ).is_sorted_by( |x, y| x.0 < y.0 ) );
assert!( comb_target_inv.row( & row_index ).is_sorted_by( |x, y| x.0 < y.0 ) );
assert!( comb_source.row( & row_index ).is_sorted_by( |x, y| x.0 < y.0 ) );
assert!( comb_source_inv.row( & row_index ).is_sorted_by( |x, y| x.0 < y.0 ) );
}
let comb_target_vec_of_vec_simple
= VecOfVec::from_iterable_of_iterables(
(0..num_indices_row)
.map( |k| comb_target_inv.row(&k) )
).ok().unwrap();
for row_index in 0..num_indices_row {
itertools::assert_equal(
comb_target.column_reverse( & row_index ),
(& comb_target_vec_of_vec_simple).column_reverse( & row_index )
)
}
let comb_target_inv_vec_of_vec_simple
= VecOfVec::from_iterable_of_iterables(
(0..num_indices_row).map( |k| comb_target_inv.row(&k) )
).ok().unwrap();
for row_index in 0..num_indices_row {
assert_equal(
comb_target_inv.column_reverse( & row_index ).collect_vec(),
(& comb_target_inv_vec_of_vec_simple).column_reverse( & row_index ).collect_vec()
)
}
}
#[test]
fn test_umatchrowmajor_comprehensive_overall() {
use crate::algebra::matrices::operations::umatch::row_major::Umatch;
use crate::algebra::matrices::types::product::ProductMatrix;
use crate::algebra::matrices::query::MatrixOracle;
let num_indices_row = 10;
let num_indices_col = 20;
let approximate_density = 0.2;
let modulus = 17;
let allow_nonstructural_zero = true;
let ring_operator = PrimeOrderField::new( modulus );
let matrix_to_factor_data = VecOfVec::random_mod_p_with_density( num_indices_row, num_indices_col, approximate_density, modulus, allow_nonstructural_zero );
let matrix_to_factor = MatrixAlgebraPacket::with_default_order( & matrix_to_factor_data, ring_operator );
let umatch
= Umatch::new(
matrix_to_factor,
(0..num_indices_row).rev(),
);
let matching = umatch.generalized_matching_matrix_ref();
let comb_target = umatch.target_comb();
let comb_target_inv = umatch.target_comb_inverse();
let comb_source = umatch.source_comb();
let comb_source_inv = umatch.source_comb_inverse();
let target_comb_inverse_times_matrix_to_factor_matched_block = umatch.target_comb_inverse_times_matrix_to_factor_matched_block();
let target_comb_inverse_times_matrix_to_factor_matched_block_rows_indexed_by_column_index = umatch.target_comb_inverse_times_matrix_to_factor_matched_block_with_rows_indexed_by_matched_column_index();
let comb_target_ref = & comb_target;
let comb_target_inv_ref = & comb_target_inv;
let comb_source_ref = & comb_source;
let comb_source_inv_ref = & comb_source_inv;
let target_comb_inverse_times_matrix_to_factor_matched_block_ref = & target_comb_inverse_times_matrix_to_factor_matched_block;
let target_comb_inverse_times_matrix_to_factor_matched_block_rows_indexed_by_column_index_ref = & target_comb_inverse_times_matrix_to_factor_matched_block_rows_indexed_by_column_index;
let product_source = ProductMatrix::new( comb_source_ref, comb_source_inv_ref );
let product_target = ProductMatrix::new( comb_target_ref, comb_target_inv_ref );
let product_target_comb_inv_times_matrix_to_factor = ProductMatrix::new( comb_target_inv_ref, matrix_to_factor );
let product_target_comb_inv_times_matrix_to_factor_times_source_comb = ProductMatrix::new( product_target_comb_inv_times_matrix_to_factor, comb_source_ref );
let matched_row_indices = umatch.matched_row_indices_in_ascending_order();
let matched_column_indices = umatch.matched_column_indices_in_ascending_order();
assert!(
matrix_oracle_is_internally_consistent(
target_comb_inverse_times_matrix_to_factor_matched_block_rows_indexed_by_column_index_ref,
matched_column_indices.iter().cloned(), matched_column_indices.iter().cloned(), )
&&
matrix_oracle_is_internally_consistent(
target_comb_inverse_times_matrix_to_factor_matched_block_ref,
matched_row_indices.iter().cloned(), matched_column_indices.iter().cloned(), )
);
assert!(
matrix_oracle_is_internally_consistent(
comb_source_ref,
0..num_indices_col,
0..num_indices_col
)
&&
matrix_oracle_is_internally_consistent(
comb_source_inv_ref,
0..num_indices_col,
0..num_indices_col
)
&&
matrix_oracle_is_internally_consistent(
comb_target_ref,
0..num_indices_row,
0..num_indices_row
)
&&
matrix_oracle_is_internally_consistent(
comb_target_inv_ref,
0..num_indices_row,
0..num_indices_row
)
);
assert!(
matrix_order_operators_are_internally_consistent(
comb_source_ref,
0..num_indices_col,
0..num_indices_col
).is_ok()
&&
matrix_order_operators_are_internally_consistent(
comb_source_inv_ref,
0..num_indices_col,
0..num_indices_col
).is_ok()
&&
matrix_order_operators_are_internally_consistent(
comb_target_ref,
0..num_indices_row,
0..num_indices_row
).is_ok()
&&
matrix_order_operators_are_internally_consistent(
comb_target_inv_ref,
0..num_indices_row,
0..num_indices_row
).is_ok()
);
for column_index in 0 .. num_indices_col {
println!("row: {:?}", column_index );
println!("row {:?}: {:?}", column_index, product_source.row( & column_index ).collect_vec() );
itertools::assert_equal( product_source.row( & column_index ), std::iter::once( (column_index, 1) ) );
}
for column_index in 0 .. num_indices_col {
assert_eq!(
product_source.row( & column_index ).collect_vec(),
vec![ (column_index, 1) ]
)
}
for row_index in 0 .. num_indices_row {
assert_eq!(
product_target.row( & row_index ).collect_vec(),
vec![ (row_index, 1) ]
)
}
for row_index in 0 .. num_indices_row {
assert_eq!(
product_target_comb_inv_times_matrix_to_factor_times_source_comb.row( &row_index ).collect_vec(),
matching.row( & row_index ).collect_vec()
)
}
verify_rows_compatible_with_columns(
target_comb_inverse_times_matrix_to_factor_matched_block_rows_indexed_by_column_index_ref,
umatch.generalized_matching_matrix_ref().bijection_column_indices_to_ordinals_and_inverse().vec_elements_in_order().iter().cloned(),
umatch.generalized_matching_matrix_ref().bijection_column_indices_to_ordinals_and_inverse().vec_elements_in_order().iter().cloned(),
);
for column_index in umatch.generalized_matching_matrix_ref().bijection_column_indices_to_ordinals_and_inverse().vec_elements_in_order().iter().cloned() {
assert!( target_comb_inverse_times_matrix_to_factor_matched_block_rows_indexed_by_column_index_ref.column_reverse( & column_index ).is_sorted_by( |x, y| x.0 > y.0 ) );
}
for column_index in umatch.generalized_matching_matrix_ref().bijection_column_indices_to_ordinals_and_inverse().vec_elements_in_order().iter().cloned() {
assert!( target_comb_inverse_times_matrix_to_factor_matched_block_rows_indexed_by_column_index_ref.row( & column_index ).is_sorted_by( |x, y| x.0 < y.0 ) );
}
assert!(
matrix_oracle_is_internally_consistent(
comb_source_ref,
0..num_indices_col,
0..num_indices_col
)
&&
matrix_oracle_is_internally_consistent(
comb_source_inv_ref,
0..num_indices_col,
0..num_indices_col
)
&&
matrix_oracle_is_internally_consistent(
comb_target_ref,
0..num_indices_row,
0..num_indices_row
)
&&
matrix_oracle_is_internally_consistent(
comb_target_inv_ref,
0..num_indices_row,
0..num_indices_row
)
);
assert!(
matrix_order_operators_are_internally_consistent(
comb_source_ref,
0..num_indices_col,
0..num_indices_col
).is_ok()
&&
matrix_order_operators_are_internally_consistent(
comb_source_inv_ref,
0..num_indices_col,
0..num_indices_col
).is_ok()
&&
matrix_order_operators_are_internally_consistent(
comb_target_ref,
0..num_indices_row,
0..num_indices_row
).is_ok()
&&
matrix_order_operators_are_internally_consistent(
comb_target_inv_ref,
0..num_indices_row,
0..num_indices_row
).is_ok()
);
for column_index in umatch.generalized_matching_matrix_ref().bijection_column_indices_to_ordinals_and_inverse().vec_elements_in_order().iter().cloned() {
assert!( target_comb_inverse_times_matrix_to_factor_matched_block_rows_indexed_by_column_index_ref.column_reverse( & column_index ).next().unwrap().0 == column_index );
}
for row_index in 0 .. num_indices_col {
assert!( matrix_to_factor.column_reverse( & row_index ).is_sorted_by( |x, y| x.0 > y.0 ) );
assert!( comb_target.column_reverse( & row_index ).is_sorted_by( |x, y| x.0 > y.0 ) );
}
let comb_target_vec_of_vec_simple
= VecOfVec::from_iterable_of_iterables(
(0..num_indices_row).map( |k| comb_target.row(&k) )
).ok().unwrap();
for row_index in 0..num_indices_row {
itertools::assert_equal(
comb_target.column_reverse( & row_index ),
(& comb_target_vec_of_vec_simple).column_reverse( & row_index )
)
}
for row_index in 0 .. num_indices_row {
assert!( matrix_to_factor.row( & row_index ).is_sorted_by( |x, y| x.0 < y.0 ) );
assert!( comb_target.row( & row_index ).is_sorted_by( |x, y| x.0 < y.0 ) );
assert!( comb_target_inv.row( & row_index ).is_sorted_by( |x, y| x.0 < y.0 ) );
assert!( comb_source.row( & row_index ).is_sorted_by( |x, y| x.0 < y.0 ) );
assert!( comb_source_inv.row( & row_index ).is_sorted_by( |x, y| x.0 < y.0 ) );
}
}
#[test]
fn test_retreival() {
use crate::algebra::matrices::operations::umatch::row_major::{Umatch, TargetCombInverseTimesMatrixToFactorMatchedBlock};
use crate::algebra::matrices::types::vec_of_vec::sorted::VecOfVec;
use crate::algebra::matrices::query::MatrixOracle;
use crate::algebra::rings::types::field_prime_order::PrimeOrderField;
let matrix_to_factor_data: VecOfVec< usize, usize > =
VecOfVec::new(
vec![
vec![ (0, 1), (1, 1), (2, 2) ],
vec![ (0, 1), (2, 1) ],
vec![ (1, 1), (2, 1) ],
]
).ok().unwrap();
let ring_operator = PrimeOrderField::new( 13 );
let matrix_to_factor_packet = MatrixAlgebraPacket::with_default_order( &matrix_to_factor_data, ring_operator );
let umatch
= Umatch::new(
matrix_to_factor_packet,
(0..3).rev(),
);
let _umatch_ref = & umatch;
let A = TargetCombInverseTimesMatrixToFactorMatchedBlock::new( & umatch );
let comb_source_inv = umatch.source_comb_inverse();
let comb_source_inv_ground_truth
= VecOfVec::new(
vec![
vec![ (0, 1), (2, 1) ],
vec![ (1, 1), (2, 1) ],
vec![ (2, 1 ) ],
]
).ok().unwrap();
let comb_source_inv_ground_truth_ref = & comb_source_inv_ground_truth;
for row_index in 0 .. 3 {
itertools::assert_equal(
comb_source_inv_ground_truth_ref.row( & row_index ),
comb_source_inv.row( &row_index ),
)
}
}
#[test]
fn test_umatchrowmajor_comb_source_small_example() {
use crate::algebra::matrices::operations::umatch::row_major::{Umatch};
use crate::algebra::matrices::types::vec_of_vec::sorted::VecOfVec;
use crate::algebra::matrices::query::MatrixOracle;
use crate::algebra::matrices::types::product::ProductMatrix;
use crate::algebra::rings::types::field_prime_order::PrimeOrderField;
let num_rows = 1; let num_cols = 4; let modulus = 7;
let ring_operator = PrimeOrderField::new( 13 );
let matrix_to_factor_data = VecOfVec::new( vec![ vec![ (2usize, 6usize), (3,1)], ] ).ok().unwrap();
let matrix_to_factor_packet = MatrixAlgebraPacket::with_default_order( &matrix_to_factor_data, ring_operator );
let umatch_root =
Umatch::new(
matrix_to_factor_packet,
(0 .. num_rows).rev(),
);
let comb_source = umatch_root.source_comb();
let comb_source_inv = umatch_root.source_comb_inverse();
let matrix_to_factor_matched_columns_only = umatch_root.matrix_to_factor_matched_columns_only();
let c_times_c_inv =
ProductMatrix::new(
&comb_source,
&comb_source_inv,
);
for column_index in 0 .. num_cols {
itertools::assert_equal( c_times_c_inv.row( & column_index ), std::iter::once( (column_index, 1) ) );
}
}
#[test]
fn test_umatchrowmajor_comb_source() {
use crate::algebra::matrices::operations::umatch::row_major::{Umatch};
use crate::algebra::matrices::types::product::ProductMatrix;
use crate::algebra::matrices::query::MatrixOracle;
use crate::algebra::rings::types::field_prime_order::PrimeOrderField;
let num_rows = 10; let num_cols = 10; let modulus = 7;
let matrix_to_factor_data = VecOfVec::random_mod_p(num_rows, num_cols, modulus);
let ring_operator = PrimeOrderField::new( modulus );
let matrix_to_factor_packet = MatrixAlgebraPacket::with_default_order( &matrix_to_factor_data, ring_operator );
let umatch_root =
Umatch::new(
matrix_to_factor_packet,
(0 .. num_rows).rev(),
);
let comb_source = umatch_root.source_comb();
let comb_source_inv = umatch_root.source_comb_inverse();
let c_times_c_inv =
ProductMatrix::new(
& comb_source,
& comb_source_inv,
);
for column_index in 0 .. num_cols {
itertools::assert_equal( c_times_c_inv.row( & column_index ), std::iter::once( (column_index, 1) ) );
}
}
#[test]
fn doc_test() {
use crate::algebra::matrices::types::{vec_of_vec::sorted::VecOfVec, product::ProductMatrix};
use crate::algebra::matrices::operations::umatch::row_major::Umatch;
use crate::algebra::matrices::debug::product_is_identity_matrix;
use crate::algebra::matrices::display::print_indexed_columns;
use crate::algebra::matrices::query::MatrixOracle;
use crate::algebra::rings::types::field_prime_order::PrimeOrderField;
use itertools::Itertools;
let modulus = 5;
let ring_operator = PrimeOrderField::new( modulus );
let matrix_to_factor_data = VecOfVec::new(
vec![
vec![(0,1), (1,1), (2,1)],
vec![ ],
vec![ (2,1)],
]
).ok().unwrap();
let matrix_to_factor_packet = MatrixAlgebraPacket::with_default_order( &matrix_to_factor_data, ring_operator );
let umatch
= Umatch::new(
matrix_to_factor_packet, (0..3).rev(), );
println!("matrix_major");
umatch.matched_block_of_target_comb_inverse_indexed_by_ordinal_of_matched_row_off_diagonal.matrix_rows_data.print_dense(0);
println!("{:?}", umatch.matched_block_of_target_comb_inverse_indexed_by_ordinal_of_matched_row_off_diagonal.matrix_rows_data.inner_vec_of_vec_ref() );
println!("matrix_minor");
umatch.matched_block_of_target_comb_inverse_indexed_by_ordinal_of_matched_row_off_diagonal.matrix_columns_data.print_dense(0);
println!("{:?}", umatch.matched_block_of_target_comb_inverse_indexed_by_ordinal_of_matched_row_off_diagonal.matrix_columns_data.inner_vec_of_vec_ref() );
println!("number of pairs: {:?}", umatch.matching.number_of_structural_nonzeros() );
println!(
"result of transpose: {:?}",
umatch.matched_block_of_target_comb_inverse_indexed_by_ordinal_of_matched_row_off_diagonal.matrix_rows_data.transpose_deep( umatch.generalized_matching_matrix_ref().number_of_structural_nonzeros() ).unwrap().inner_vec_of_vec_ref()
);
let t = umatch.target_comb(); let tinv = umatch.target_comb_inverse(); let s = umatch.source_comb(); let sinv = umatch.source_comb_inverse(); let m = umatch.generalized_matching_matrix_ref();
println!("\nColumns of the target COMB"); print_indexed_columns( &t, 0..3 );
println!("\nColumns of the source COMB"); print_indexed_columns( &s, 0..3 );
println!("\nColumns of the generalized matching matrix"); print_indexed_columns( &m, 0..3 );
let b = [ (0,1), (2,1) ];
let x = umatch.solve_dx_equals_b( b.clone() ).unwrap();
let dx = umatch.multiply_dx(x).collect_vec();
assert!( dx.eq( & b ) );
product_is_identity_matrix( &s, &sinv, 0..3 );
product_is_identity_matrix( &t, &tinv, 0..3 );
let rinv_d = ProductMatrix::new( &tinv, &matrix_to_factor_packet );
let rinv_d_c = ProductMatrix::new( &rinv_d, &s );
for row_index in 0 .. 3 {
assert_eq!(
rinv_d_c.row( &row_index ).collect_vec(),
m.row( &row_index ).collect_vec()
)
}
}
}
#[cfg(test)]
mod doc_test_solvers {
use crate::algebra::matrices::types::packet::MatrixAlgebraPacket;
#[test]
fn doc_test_solve_dx_equals_b() {
use crate::algebra::matrices::operations::umatch::row_major::Umatch;
use crate::algebra::matrices::types::vec_of_vec::sorted::VecOfVec;
use itertools::Itertools;
let matrix = VecOfVec::new(
vec![
vec![(0,true), (1,true), (2,true)],
vec![ ],
vec![ (2,true)],
]
).ok().unwrap();
let matrix_packet = MatrixAlgebraPacket::with_default_order_and_boolean_coefficients( & matrix );
let umatch
= Umatch::new(
& matrix_packet, (0..3).rev(), );
let b = [ (0,true), (2,true) ];
let x = umatch.solve_dx_equals_b( b ).unwrap();
let dx = umatch.multiply_dx(x);
assert!( dx.eq( b ) );
}
#[test]
fn doc_test_solve_xd_equals_b() {
use crate::algebra::matrices::types::vec_of_vec::sorted::VecOfVec;
use crate::algebra::matrices::operations::umatch::row_major::Umatch;
let d = VecOfVec::new(
vec![
vec![ (0,true), (1,true), ],
vec![ (1,true), (2,true), ],
]
).ok().unwrap();
let d_packet = MatrixAlgebraPacket::with_default_order_and_boolean_coefficients( & d );
let umatch = Umatch::new(
&d_packet,
0..2,
);
let x = umatch.solve_xd_equals_b( vec![ (0,true), (2,true), ] );
assert!( x.is_some() );
assert!( x.unwrap().eq( & vec![ (0,true), (1,true), ] ) );
let x = umatch.solve_xd_equals_b( vec![ (0,true), (1,true), (2,true) ] );
assert!( x.is_none() );
}
#[test]
fn doc_test_solve_xd_equals_b__withfloatcoefficients() {
use crate::algebra::matrices::types::vec_of_vec::sorted::VecOfVec;
use crate::algebra::matrices::operations::umatch::row_major::Umatch;
let d = VecOfVec::new(
vec![
vec![ (0,3.), (1,3.), ],
vec![ (1,3.), (2,3.), ],
]
).ok().unwrap();
let d_packet = MatrixAlgebraPacket::with_default_order_and_f64_coefficients( & d );
let umatch = Umatch::new(
& d_packet,
0..2,
);
let x = umatch.solve_xd_equals_b( vec![ (0,3.), (1,6.), (2,3.), ] );
assert!( x.is_some() );
assert!( x.unwrap().eq( &vec![ (0,1.), (1,1.) ] ) );
let x = umatch.solve_xd_equals_b( vec![ (0,1.), (1,-1.) ] );
assert!( x.is_none() );
}
}