use std::vec::IntoIter;
use std::cmp::Ordering;
use std::fmt::Debug;
use crate::{algebra::{matrices::{query::{MatrixAlgebra, MatrixOracle}, types::transpose::OrderAntiTranspose}, rings::traits::{DivisionRingOperations, RingOperations}, vectors::operations::{Simplify, VectorOperations}}, utilities::{iterators::{general::PeekUnqualified, merge::hit::{hit_bulk_insert, hit_merge_by_predicate}}, order::JudgeOrder}};
use crate::algebra::matrices::operations::combine_rows_and_columns::{LinearCombinationOfRows};
use crate::algebra::vectors::entries::{KeyValGet, KeyValSet};
pub struct RowOfInverseOfUpperTriangularMatrix
< Matrix >
where
Matrix: MatrixAlgebra<
RowEntry: KeyValSet,
>
{
ring_operator: Matrix::RingOperator, matrix: Matrix, next_entry_of_inv: Option< Matrix::RowEntry >, entries_to_eliminate_simplified_heap: LinearCombinationOfRows< Matrix >,
}
impl < Matrix, Index >
Iterator for
RowOfInverseOfUpperTriangularMatrix
< Matrix >
where
Index: PartialEq,
Matrix: MatrixAlgebra<
RowEntry: KeyValSet,
ColumnIndex = Index,
RowIndex = Index,
RingOperator: DivisionRingOperations,
>
{
type Item = Matrix::RowEntry;
fn next( &mut self ) -> Option<Self::Item> {
match self.next_entry_of_inv.take() {
None => None,
Some( return_value ) => {
if let Some( mut entry_to_eliminate ) = self.entries_to_eliminate_simplified_heap.next() {
let mut seed_of_eliminating_iterator = self.matrix.row( &entry_to_eliminate.key() ).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 = seed_of_eliminating_iterator.scale_by( scale_factor.clone(), self.ring_operator.clone() );
hit_bulk_insert( &mut self.entries_to_eliminate_simplified_heap.unsimplified, vec![eliminating_iterator] );
entry_to_eliminate.set_val( scale_factor );
self.next_entry_of_inv = Some( entry_to_eliminate );
}
Some( return_value )
}
}
}
}
impl < Matrix, Index >
PeekUnqualified for
RowOfInverseOfUpperTriangularMatrix<
Matrix,
>
where
Index: PartialEq,
Matrix: MatrixAlgebra<
RowEntry: KeyValSet,
ColumnIndex = Index,
RowIndex = Index,
RingOperator: DivisionRingOperations,
>
{
fn peek_unqualified(&mut self) -> std::option::Option<&<Self as Iterator>::Item> {
match &self.next_entry_of_inv {
None => { None },
Some(x) => { Some( x ) }
}
}
}
pub fn row_of_inverse_of_upper_triangular_matrix <
Matrix,
>
(
row_index: & Matrix::RowIndex,
matrix: Matrix,
)
->
RowOfInverseOfUpperTriangularMatrix<
Matrix,
>
where
Matrix: MatrixAlgebra< RingOperator: DivisionRingOperations >,
Matrix::RowEntry: KeyValSet,
{
let ring_operator = matrix.ring_operator();
let order_operator = matrix.order_operator_for_row_entries();
let mut unscaled_seed_of_entries_to_be_eliminated = matrix.row( &row_index );
let mut diagonal_entry_of_inverse = unscaled_seed_of_entries_to_be_eliminated.next().unwrap();
diagonal_entry_of_inverse.set_val(
ring_operator.invert( diagonal_entry_of_inverse.val() )
);
let scaled_seed_of_tail_to_be_eliminated = unscaled_seed_of_entries_to_be_eliminated.scale_by(
diagonal_entry_of_inverse.val(),
ring_operator.clone(),
);
let entries_to_eliminate_simplified_heap
= Simplify::new(
hit_merge_by_predicate(vec![ scaled_seed_of_tail_to_be_eliminated ], order_operator),
ring_operator.clone(),
);
RowOfInverseOfUpperTriangularMatrix {
ring_operator, matrix, next_entry_of_inv: Some( diagonal_entry_of_inverse ), entries_to_eliminate_simplified_heap,
}
}
pub fn row_of_inverse_of_upper_triangular_matrix_result <
Matrix,
>
(
row_index: Matrix::RowIndex,
matrix: Matrix,
)
->
Result<
RowOfInverseOfUpperTriangularMatrix< Matrix >,
Matrix::RowIndex,
>
where
Matrix: MatrixAlgebra< RingOperator: DivisionRingOperations >,
Matrix::RowEntry: KeyValSet,
{
let ring_operator = matrix.ring_operator();
let order_operator = matrix.order_operator_for_row_entries();
let mut unscaled_seed_of_entries_to_be_eliminated = matrix.row_result( &row_index )?;
let mut diagonal_entry_of_inverse = unscaled_seed_of_entries_to_be_eliminated.next().unwrap();
diagonal_entry_of_inverse.set_val(
ring_operator.invert( diagonal_entry_of_inverse.val() )
);
let scaled_seed_of_tail_to_be_eliminated = unscaled_seed_of_entries_to_be_eliminated.scale_by(
diagonal_entry_of_inverse.val(),
ring_operator.clone(),
);
let entries_to_eliminate_simplified_heap
= Simplify::new(
hit_merge_by_predicate(vec![ scaled_seed_of_tail_to_be_eliminated ], order_operator),
ring_operator.clone(),
);
let row = RowOfInverseOfUpperTriangularMatrix {
ring_operator, matrix, next_entry_of_inv: Some( diagonal_entry_of_inverse ), entries_to_eliminate_simplified_heap,
};
Ok(row)
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct InverseUpperTriangularMatrix
< Matrix, >
{
matrix_to_invert: Matrix, }
impl < Matrix >
InverseUpperTriangularMatrix
< Matrix >
{
pub fn new( matrix_to_invert: Matrix ) -> Self {
InverseUpperTriangularMatrix{ matrix_to_invert }
}
}
impl < Matrix, Index, Entry >
MatrixOracle for
InverseUpperTriangularMatrix
< Matrix >
where
Matrix: Clone + MatrixAlgebra<
RowIndex=Index,
ColumnIndex=Index,
RowEntry=Entry,
ColumnEntry=Entry,
RingOperator: DivisionRingOperations,
>,
Entry: Clone + Debug + PartialEq + KeyValSet < Key = Index, Val = Matrix::Coefficient >,
Index: Clone + Debug + Eq,
{
type Coefficient = Matrix::Coefficient;
type Column = IntoIter< Matrix::RowEntry >; type ColumnEntry = Matrix::RowEntry;
type ColumnIndex = Matrix::RowIndex;
type ColumnReverse = RowOfInverseOfUpperTriangularMatrix< OrderAntiTranspose< Matrix >,
>;
type Row = RowOfInverseOfUpperTriangularMatrix<
Matrix,
>;
type RowEntry = Matrix::RowEntry;
type RowIndex = Matrix::RowIndex;
type RowReverse = IntoIter< Matrix::RowEntry >;
fn has_column_for_index( & self, index: & Self::ColumnIndex) -> bool {
self.matrix_to_invert.has_column_for_index(index)
}
fn has_row_for_index( & self, index: & Self::RowIndex ) -> bool {
self.matrix_to_invert.has_row_for_index(index)
}
fn column( & self, index: & Self::ColumnIndex) -> Self::Column {
let mut vec: Vec<_> = self.column_reverse( index ).collect(); vec.reverse(); vec.into_iter()
}
fn column_reverse( & self, index: & Self::ColumnIndex) -> Self::ColumnReverse {
let antitransopose = OrderAntiTranspose::new( self.matrix_to_invert.clone() );
row_of_inverse_of_upper_triangular_matrix( index,
antitransopose,
)
}
fn row( & self, index: & Self::RowIndex ) -> Self::Row {
row_of_inverse_of_upper_triangular_matrix( index,
self.matrix_to_invert.clone(),
)
}
fn row_reverse( & self, index: & Self::RowIndex ) -> Self::RowReverse {
let mut row: Vec<_> = self.row( index ).collect();
row.reverse();
row.into_iter()
}
fn structural_nonzero_entry(& self, row: & Self::RowIndex, column: & Self::ColumnIndex ) -> Option< Self::Coefficient > {
let row = self.row( row );
let order_operator = self.matrix_to_invert.order_operator_for_row_indices();
for entry in row {
match order_operator.judge_cmp( & entry.key(), column ) {
Ordering::Less => { continue }
Ordering::Equal => { return Some( entry.val() ) }
Ordering::Greater => { return None }
}
}
return None
}
}
impl < Matrix, Index, Entry >
MatrixAlgebra for
InverseUpperTriangularMatrix
< Matrix >
where
Matrix: Clone + MatrixAlgebra<
RowIndex=Index,
ColumnIndex=Index,
RowEntry=Entry,
ColumnEntry=Entry,
RingOperator: DivisionRingOperations,
>,
Entry: Clone + Debug + PartialEq + KeyValSet < Key = Index, Val = Matrix::Coefficient >,
Index: Clone + Debug + Eq,
{
type OrderOperatorForColumnEntries = Matrix::OrderOperatorForColumnEntries;
type OrderOperatorForColumnIndices = Matrix::OrderOperatorForColumnIndices;
type OrderOperatorForRowEntries = Matrix::OrderOperatorForRowEntries;
type OrderOperatorForRowIndices = Matrix::OrderOperatorForRowIndices;
type RingOperator = Matrix::RingOperator;
fn order_operator_for_column_entries( &self ) -> Self::OrderOperatorForColumnEntries {
self.matrix_to_invert.order_operator_for_column_entries()
}
fn order_operator_for_column_indices( &self ) -> Self::OrderOperatorForColumnIndices {
self.matrix_to_invert.order_operator_for_column_indices()
}
fn order_operator_for_row_entries( &self ) -> Self::OrderOperatorForRowEntries {
self.matrix_to_invert.order_operator_for_row_entries()
}
fn order_operator_for_row_indices( &self ) -> Self::OrderOperatorForRowIndices {
self.matrix_to_invert.order_operator_for_row_indices()
}
fn ring_operator( &self ) -> Self::RingOperator {
self.matrix_to_invert.ring_operator()
}
}
#[cfg(test)]
mod doc_test_drafts {
use crate::{algebra::matrices::types::packet::MatrixAlgebraPacket, utilities::order::{OrderOperatorAuto, OrderOperatorByKey}};
#[test]
fn test_inverse_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::invert::InverseUpperTriangularMatrix;
use crate::algebra::matrices::display::print_indexed_rows;
let modulus = 1049;
let ring_operator = PrimeOrderField::new(modulus);
let matrix = VecOfVec::new(
vec![
vec![ (0,1), (1,1), ],
vec![ (1,1), ],
],
).ok().unwrap();
let matrix_packet = MatrixAlgebraPacket::with_default_order(&matrix, ring_operator);
let inverse = InverseUpperTriangularMatrix::new( & matrix_packet, );
let row_indices = vec![ 0, 1 ];
print_indexed_rows( &inverse, row_indices );
}
}
#[cfg(test)]
mod tests {
use super::*;
use itertools::Itertools;
use crate::algebra::matrices::types::vec_of_vec::sorted::VecOfVec;
use crate::algebra::matrices::types::product::ProductMatrix;
use crate::algebra::rings::types::field_prime_order::PrimeOrderField;
use crate::algebra::matrices::query::MatrixOracle;
#[cfg(test)] fn test_inversion_of_input< Coefficient, RingOperator >(
matrix: & VecOfVec< usize, Coefficient, >,
ring_operator: RingOperator,
matrix_size: usize,
)
where Coefficient: Clone + PartialEq + std::fmt::Debug,
RingOperator: DivisionRingOperations< Element = Coefficient > + Clone,
{
use crate::{algebra::matrices::{debug::matrix_order_operators_are_internally_consistent, types::packet::MatrixAlgebraPacket}, utilities::order::{OrderOperatorAuto, OrderOperatorByKey}};
let matrix_packet = MatrixAlgebraPacket{
matrix: & matrix,
ring_operator,
order_operator_for_column_entries: OrderOperatorByKey,
order_operator_for_column_indices: OrderOperatorAuto,
order_operator_for_row_entries: OrderOperatorByKey,
order_operator_for_row_indices: OrderOperatorAuto,
};
let inverse = InverseUpperTriangularMatrix::new( & matrix_packet );
assert!(
crate::algebra::matrices::debug::matrix_oracle_is_internally_consistent(
matrix_packet.clone(),
0..matrix_size, 0..matrix_size, )
);
assert!(
matrix_order_operators_are_internally_consistent(
matrix_packet.clone(),
0..matrix_size,
0..matrix_size,
).is_ok()
);
let product = ProductMatrix::new(
matrix_packet.clone(),
& inverse,
);
let row_vec = | p: usize |
product.row( &p )
.collect_vec();
let one = <RingOperator as crate::algebra::rings::traits::SemiringOperations>::one();
for row_index in 0 .. matrix_size {
assert_eq!( vec![ ( row_index, one.clone() ) ] , row_vec( row_index ) );
}
}
#[test]
fn test_inversion_of_specific_matrices() {
use num::rational::Ratio;
use crate::algebra::rings::types::native::RingOperatorForNativeRustNumberType;
type IntegerType = isize;
let modulus = 1049;
let r = Ratio::new;
let q = Ratio::from_integer;
let ring_operator_q = RingOperatorForNativeRustNumberType::< Ratio<IntegerType> >::new();
let ring_operator_f = RingOperatorForNativeRustNumberType::< f64 >::new();
let ring_operator_p = PrimeOrderField::new(modulus);
let matrix = VecOfVec::new(
vec![
vec![ (0,1.), (1,1.), ],
vec![ (1,1.), ],
],
).ok().unwrap();
test_inversion_of_input( & matrix, ring_operator_f, 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_inversion_of_input( & matrix, 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_inversion_of_input( & matrix, 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_inversion_of_input( & matrix, ring_operator_q, 4 );
let matrix_size = 20;
let matrix = VecOfVec::random_mod_p_upper_unitriangular( matrix_size, modulus );
test_inversion_of_input( & matrix, ring_operator_p, matrix_size );
}
}