use core::panic;
use std::collections::binary_heap::Iter;
use std::iter::Peekable;
use std::sync::Arc;
use std::hash::Hash;
use std::fmt::Debug;
use std::vec::IntoIter;
use derive_new::new;
use itertools::Itertools;
use num::iter::Range;
use num_traits::Bounded;
use ordered_float::OrderedFloat;
use sprs::vec;
use crate::algebra::chain_complexes::{ChainComplex, FilteredChainComplex};
use crate::algebra::vectors::operations::ChangeEntryType;
use crate::topology::simplicial::simplices::unweighted::{coboundary_entry_for_facet_vertex_pair, Simplex};
use crate::topology::simplicial::simplices::vector::insert_vertex;
use crate::topology::simplicial::simplices::weighted::{WeightedSimplex, OrderOperatorTwistWeightedSimplex};
use crate::algebra::vectors::entries::{KeyValGet, KeyValNew};
use crate::algebra::matrices::operations::umatch::differential::DifferentialUmatch;
use crate::algebra::matrices::operations::MatrixOracleOperations;
use crate::algebra::matrices::query::{MatrixAlgebra, MatrixOracle};
use crate::algebra::rings::traits::DivisionRingOperations;
use crate::algebra::rings::traits::{RingOperations};
use crate::utilities::order::{ is_sorted_strictly, JudgeOrder, MakeNoneMaximum, OrderOperatorAuto, OrderOperatorByKey};
use crate::utilities::iterators::general::{minmax, symmetric_difference_of_ordered_iterators, TwoTypeIterator, IterWrappedArcVec, PeekUnqualified};
type Vertex = u16;
pub fn filtration_value_for_clique< DissimilarityMatrix >(
vertices: & Vec< Vertex >,
dissimilarity_matrix: DissimilarityMatrix
)
-> Result< DissimilarityMatrix::Coefficient, Vec< Vertex >>
where
DissimilarityMatrix: MatrixOracle< ColumnIndex=usize, RowIndex=usize >,
DissimilarityMatrix::Coefficient: Debug + Ord + num_traits::Bounded,
{
if ! is_sorted_strictly(&vertices, & OrderOperatorAuto) {
return Err( vertices.clone() ); }
let mut diam = DissimilarityMatrix::Coefficient::min_value();
let mut a;
let mut b;
for ii in 0..vertices.len() {
a = usize::from( vertices[ii] );
for jj in ii .. vertices.len() {
b = usize::from( vertices[jj] );
match dissimilarity_matrix.structural_nonzero_entry( &a, &b ) {
None => { return Err( vertices.clone() ) } Some( diam_bound ) => {
if diam_bound > diam { diam = diam_bound.clone(); }
}
}
}
}
Ok(diam)
}
pub fn filtered_cliques_in_row_reduction_order< DissimilarityMatrix >(
dimension_max: isize,
dissimilarity_matrix: DissimilarityMatrix,
dissimilarity_matrix_size: usize,
allow_empty_simplex: bool
)
-> Vec< WeightedSimplex< DissimilarityMatrix::Coefficient > >
where DissimilarityMatrix: Clone + MatrixOracle< ColumnIndex=usize, RowIndex=usize >,
DissimilarityMatrix::Coefficient: Ord + Debug + Bounded,
DissimilarityMatrix::RowEntry: KeyValNew, DissimilarityMatrix::Row: Clone,
{
let order_operator = OrderOperatorTwistWeightedSimplex{};
let dissimilarity_matrix_ref = & dissimilarity_matrix;
let vec: Vec<_> = (-1..dimension_max+1).flat_map(|dimension|
{
let mut vec = AgileSimplexIteratorLexicographicOrder::new(
dissimilarity_matrix_ref,
dissimilarity_matrix_size,
dimension, allow_empty_simplex, )
.collect_vec();
vec.sort_by(|x,y| order_operator.judge_cmp(y,x) );
vec
})
.collect();
vec
}
#[derive(Clone,Debug,)]
pub struct VietorisRipsComplex< DissimilarityMatrix, RingOperator >
where
DissimilarityMatrix: MatrixOracle< ColumnIndex=usize, RowIndex=usize, >
{
pub ring_operator: RingOperator, pub dissimilarity_matrix: DissimilarityMatrix,
pub dissimilarity_matrix_size: usize,
pub filtration_ordered_neighbor_lists: Arc< Vec< Arc< Vec< (DissimilarityMatrix::Coefficient, Vertex) >
>>>,
pub allow_empty_simplex: bool, }
impl < DissimilarityMatrix, RingOperator >
VietorisRipsComplex
< DissimilarityMatrix, RingOperator >
where DissimilarityMatrix: MatrixOracle< ColumnIndex=usize, RowIndex=usize, >,
DissimilarityMatrix::Coefficient: Debug + Ord + num_traits::Bounded,
RingOperator: RingOperations,
{
pub fn new(
dissimilarity_matrix: DissimilarityMatrix,
dissimilarity_matrix_size: usize,
ring_operator: RingOperator,
) -> Result< Self, (usize,usize) >
{
let number_of_points = dissimilarity_matrix_size;
let mut filtration_ordered_neighbor_lists = Vec::with_capacity(number_of_points);
for i in 0 .. number_of_points {
let mut min_filtration = MakeNoneMaximum::from_opt(None);
let mut num_neighbors = 0;
for entry in dissimilarity_matrix.row( & i ) {
let n = entry.key();
let f = entry.val();
min_filtration = min_filtration.min( MakeNoneMaximum::from_val(f.clone()) );
num_neighbors += 1;
let entry_n_i = dissimilarity_matrix.structural_nonzero_entry( &n, &i );
if Some( f.clone() ) != entry_n_i {
println!("\n\nError: The dissimilarity matrix passed to the `VietorisRipsComplex` constructor is not symmetric");
println!(" - Entry {:?} equals {:?}", (i,n) , f.clone() );
println!(" - However, entry {:?} equals {:?}.", (n,i), entry_n_i);
println!("\nThis message is generated by OAT.\n\n");
return Err( (i,n) );
}
}
let diagonal_entry = dissimilarity_matrix.structural_nonzero_entry( &i, &i );
if min_filtration != MakeNoneMaximum::from_opt( diagonal_entry.clone() ) {
println!("\n\nError during construction of the `VietorisRipsComplex`: Entry ({:?},{:?}) of the dissimilarity matrix is {:?} but the minimum structural nonzero entry in row {:?} is {:?}. In this case `None` represents a value strictly greater than `Some(x)`, for every filtration value `x`. This indicates that input dissimilarity matrix is invalid.\nThis message is generated by OAT.\n\n",
i,
i,
diagonal_entry,
i,
min_filtration.into_inner()
);
return Err( (i,i) );
}
let mut filtration_ordered_neighbor_list = Vec::with_capacity(num_neighbors);
for entry in dissimilarity_matrix.row( & i ) {
let neighbor = entry.key() as Vertex;
let filtration = entry.val();
filtration_ordered_neighbor_list.push( (filtration, neighbor) );
}
filtration_ordered_neighbor_list.sort();
filtration_ordered_neighbor_lists.push(Arc::new(filtration_ordered_neighbor_list));
}
Ok(
VietorisRipsComplex {
ring_operator,
dissimilarity_matrix,
dissimilarity_matrix_size,
filtration_ordered_neighbor_lists: Arc::new(filtration_ordered_neighbor_lists),
allow_empty_simplex: false,
}
)
}
pub fn filtration_value_for_clique(
& self,
vertices: & Vec< Vertex >
) -> Result< DissimilarityMatrix::Coefficient, Vec< Vertex >>
{
filtration_value_for_clique( vertices, self.dissimilarity_matrix_ref() )
}
pub fn add_filtration_value_to_simplex( &self, vertices: &Vec<Vertex> )
-> Result<
WeightedSimplex< DissimilarityMatrix::Coefficient >,
Vec<Vertex>
>
{
let filtration_value = self.filtration_value_for_clique( vertices )?;
Ok(WeightedSimplex { vertices: vertices.clone(), weight: filtration_value })
}
pub fn dissimilarity_matrix_ref(&self) -> & DissimilarityMatrix { & self.dissimilarity_matrix }
pub fn dissimilarity_matrix_size(&self) -> usize { self.dissimilarity_matrix_size }
pub fn dissimilarity_as_nonegreater( &self, a: Vertex, b: Vertex ) -> MakeNoneMaximum<DissimilarityMatrix::Coefficient>
{ MakeNoneMaximum { opt: self.dissimilarity_matrix.structural_nonzero_entry(& (a as usize), & (b as usize) ) } }
pub fn ring_operator( &self ) -> RingOperator where RingOperator: Clone { self.ring_operator.clone() }
pub fn cliques_in_row_reduction_order( &self, dimension_max: isize )
->
Vec< WeightedSimplex< DissimilarityMatrix::Coefficient > >
where
DissimilarityMatrix::RowEntry: KeyValNew, DissimilarityMatrix::Row: Clone, {
return filtered_cliques_in_row_reduction_order(
dimension_max,
self.dissimilarity_matrix_ref(),
self.dissimilarity_matrix_size,
self.allow_empty_simplex, )
}
pub fn cliques_in_boundary_matrix_order_fixed_dimension( &self, dimension_max: isize )
-> Vec< WeightedSimplex< DissimilarityMatrix::Coefficient > >
where
DissimilarityMatrix::RowEntry: KeyValNew, DissimilarityMatrix::Row: Clone, {
let mut simplices = self.cliques_in_lexicographic_order_fixed_dimension(dimension_max).collect_vec();
simplices.sort_by( |x,y| OrderOperatorTwistWeightedSimplex{}.judge_cmp( x, y ) );
simplices
}
pub fn cliques_in_lexicographic_order_fixed_dimension( &self, dimension: isize )
-> AgileSimplexIteratorLexicographicOrder< & DissimilarityMatrix >
where
DissimilarityMatrix::RowEntry: KeyValNew, DissimilarityMatrix::Row: Clone, {
AgileSimplexIteratorLexicographicOrder::new(
self.dissimilarity_matrix_ref(), self.dissimilarity_matrix_size,
dimension,
self.allow_empty_simplex,
)
}
pub fn factor_from_arc( self, max_homology_dimension: isize )
->
DifferentialUmatch<
Arc< VietorisRipsComplex< DissimilarityMatrix, RingOperator > >,
>
where
RingOperator::Element: Debug + PartialEq,
RingOperator: Clone + DivisionRingOperations,
DissimilarityMatrix: Clone + MatrixOracle< ColumnIndex=usize, RowIndex=usize, >,
DissimilarityMatrix::RowEntry: KeyValNew, DissimilarityMatrix::Row: Clone, DissimilarityMatrix::Coefficient: Copy + Clone + Debug + Ord + Hash + Bounded,
{
let min_homology_dimension = 0;
let arc = Arc::new(self);
DifferentialUmatch::new(
arc,
min_homology_dimension,
max_homology_dimension,
)
}
}
impl < DissimilarityMatrix, RingOperator >
ChainComplex for
Arc<
VietorisRipsComplex
< DissimilarityMatrix, RingOperator >
>
where
DissimilarityMatrix: Clone + MatrixOracle< ColumnIndex=usize, RowIndex=usize >,
DissimilarityMatrix::Coefficient: Copy + Debug + Ord + Bounded,
DissimilarityMatrix::RowEntry: KeyValNew, DissimilarityMatrix::Row: Clone, RingOperator: Clone + RingOperations,
RingOperator::Element: Debug + PartialEq,
{
type BasisVectorIndicesIterable = Vec< WeightedSimplex< DissimilarityMatrix::Coefficient > >;
fn basis_vector_indices_for_dimension( &self, dimension: isize ) -> Self::BasisVectorIndicesIterable {
self.cliques_in_boundary_matrix_order_fixed_dimension( dimension )
}
fn dimension_for_basis_vector_with_index( &self, index: & Self::RowIndex ) -> Result<isize, Self::RowIndex> {
match self.has_row_for_index( index ) {
false => Err( index.clone() ), true => Ok( index.dimension() as isize ), }
}
}
impl < DissimilarityMatrix, RingOperator >
FilteredChainComplex for
Arc<
VietorisRipsComplex
< DissimilarityMatrix, RingOperator >
>
where
DissimilarityMatrix: Clone + MatrixOracle< ColumnIndex=usize, RowIndex=usize >,
DissimilarityMatrix::Coefficient: Copy + Debug + Ord + Bounded,
DissimilarityMatrix::RowEntry: KeyValNew, DissimilarityMatrix::Row: Clone, RingOperator: Clone + RingOperations,
RingOperator::Element: Debug + PartialEq,
{
type FiltrationValue = DissimilarityMatrix::Coefficient;
fn filtration_value_for_basis_vector_with_index(
&self,
index: & Self::RowIndex
) ->
Result<
Self::FiltrationValue,
Self::RowIndex
> {
match self.has_row_for_index( index ) {
false => Err( index.clone() ), true => {
Ok( index.filtration() )
}
}
}
}
#[derive(Clone, Debug)]
pub struct AgileBoundaryIteratorLexicographicOrder
< DissimilarityMatrix, RingOperator >
where
DissimilarityMatrix: MatrixOracle< ColumnIndex=usize, RowIndex=usize >,
RingOperator: RingOperations,
{
pub vietoris_rips_complex: Arc< VietorisRipsComplex< DissimilarityMatrix, RingOperator > >,
pub simplex: WeightedSimplex<DissimilarityMatrix::Coefficient>,
pub removal_location_for_next_facet: Option<usize>,
pub ring_operator: RingOperator,
}
impl< DissimilarityMatrix, RingOperator >
AgileBoundaryIteratorLexicographicOrder
< DissimilarityMatrix, RingOperator >
where DissimilarityMatrix::Coefficient: Copy + Debug + Ord + Bounded,
DissimilarityMatrix::RowEntry: KeyValNew, DissimilarityMatrix::Row: Clone, DissimilarityMatrix: Clone + MatrixOracle< ColumnIndex=usize, RowIndex=usize >,
RingOperator: Clone + RingOperations,
RingOperator::Element: Debug + PartialEq,
{
pub fn new(
vietoris_rips_complex: Arc< VietorisRipsComplex< DissimilarityMatrix, RingOperator > >,
simplex: WeightedSimplex<DissimilarityMatrix::Coefficient>,
allow_empty_simplex: bool,
) -> Self
{
let removal_location_for_next_facet = match simplex.vertices.len() {
0 => {
None
}
1 => {
if allow_empty_simplex {
Some(0)
} else {
None
}
}
_ => {
Some(simplex.vertices.len() - 1)
}
};
let ring_operator = vietoris_rips_complex.ring_operator();
AgileBoundaryIteratorLexicographicOrder {
vietoris_rips_complex,
simplex,
removal_location_for_next_facet,
ring_operator,
}
}
}
impl< DissimilarityMatrix, RingOperator >
Iterator for
AgileBoundaryIteratorLexicographicOrder
< DissimilarityMatrix, RingOperator >
where
DissimilarityMatrix: MatrixOracle<
ColumnIndex = usize,
RowIndex = usize,
Coefficient: Ord + Bounded,
>,
RingOperator: RingOperations,
{
type Item = (
WeightedSimplex
<DissimilarityMatrix::Coefficient>,
RingOperator
::Element
);
fn next( &mut self ) -> Option<Self::Item> {
let removal_location_for_next_facet = self.removal_location_for_next_facet?;
let mut simplex = self.simplex.clone();
simplex.vertices.remove(removal_location_for_next_facet );
simplex.weight = self.vietoris_rips_complex.filtration_value_for_clique(&simplex.vertices).unwrap();
let coeff = self.ring_operator.minus_one_to_power( removal_location_for_next_facet );
match removal_location_for_next_facet {
0 => { self.removal_location_for_next_facet = None; }
_ => { self.removal_location_for_next_facet = Some(removal_location_for_next_facet - 1); }
}
Some((simplex, coeff))
}
}
impl < DissimilarityMatrix, RingOperator >
MatrixOracle for
Arc<
VietorisRipsComplex
< DissimilarityMatrix, RingOperator >
>
where
DissimilarityMatrix::Coefficient: Copy + Debug + Ord + Bounded,
DissimilarityMatrix::RowEntry: KeyValNew, DissimilarityMatrix::Row: Clone, RingOperator: Clone + RingOperations,
RingOperator::Element: Debug + PartialEq,
DissimilarityMatrix: Clone + MatrixOracle< ColumnIndex=usize, RowIndex=usize >,
{
type Coefficient = RingOperator::Element; type RowIndex = WeightedSimplex<DissimilarityMatrix::Coefficient>; type RowEntry = ( Self::RowIndex, Self::Coefficient ); type ColumnIndex = WeightedSimplex<DissimilarityMatrix::Coefficient>; type ColumnEntry = ( Self::RowIndex, Self::Coefficient ); type Row = AgileCoboundaryIteratorFiltrationOrder< DissimilarityMatrix, RingOperator >; type RowReverse = std::vec::IntoIter<(WeightedSimplex<DissimilarityMatrix::Coefficient>, RingOperator::Element)>; type Column = std::vec::IntoIter<(WeightedSimplex<DissimilarityMatrix::Coefficient>, RingOperator::Element)>; type ColumnReverse = std::vec::IntoIter<(WeightedSimplex<DissimilarityMatrix::Coefficient>, RingOperator::Element)>;
fn row( & self, row_index: & Self::RowIndex ) -> Self::Row {
self.row_result(row_index).ok().unwrap()
}
fn row_reverse( & self, index: & Self::RowIndex ) -> Self::RowReverse {
let mut row: Vec<_> = self.row( index ).collect();
(&mut row).reverse();
row.shrink_to_fit();
return row.into_iter()
}
fn row_result( & self, index: & Self::RowIndex ) -> Result< Self::Row, Self::RowIndex > {
let row_result = AgileCoboundaryIteratorFiltrationOrder::new(
index.vertices().clone(),
self.dissimilarity_matrix.clone(),
self.dissimilarity_matrix_size,
self.filtration_ordered_neighbor_lists.clone(),
self.ring_operator(),
);
match row_result {
Ok(row) => Ok(row),
Err(_) => {
Err(index.clone())
}
}
}
fn column( & self, index: & Self::ColumnIndex) -> Self::Column {
let cardinality = index.number_of_vertices();
let iter = AgileBoundaryIteratorLexicographicOrder::new(
self.clone(), index.clone(), self.allow_empty_simplex, );
let mut vec = Vec::with_capacity( cardinality );
vec.extend( iter );
vec.sort_by(|x,y| x.0.cmp(&y.0));
vec.into_iter()
}
fn column_reverse( & self, index: & Self::ColumnIndex) -> Self::ColumnReverse {
let cardinality = index.number_of_vertices();
let iter = AgileBoundaryIteratorLexicographicOrder::new(
self.clone(), index.clone(), self.allow_empty_simplex, );
let mut vec = Vec::with_capacity( cardinality );
vec.extend( iter );
vec.sort_by(|x,y| y.0.cmp(&x.0)); vec.into_iter()
}
fn has_row_for_index( & self, index: & Self::RowIndex ) -> bool {
match self.filtration_value_for_clique( index.vertices() ) {
Err(_) => false, Ok(filtration_value) => {
filtration_value == index.weight
}
}
}
fn has_column_for_index( & self, index: & Self::ColumnIndex) -> bool {
self.has_row_for_index( index )
}
fn structural_nonzero_entry(& self, row: & Self::RowIndex, column: & Self::ColumnIndex ) -> Option< Self::Coefficient > {
if ! self.has_row_for_index(row) {
panic!("Attempted to look up the entry in row {:?}, column {:?} of a Vietoris Rips boundary matrix, but {:?} is either an invalid simplex (not sorted or has a repeat entry) or it is not contained in the complex", row, column, row );
}
if ! self.has_column_for_index(row) {
panic!("Attempted to look up the entry in row {:?}, column {:?} of a Vietoris Rips boundary matrix, but {:?} is either an invalid simplex (not sorted or has a repeat entry) or it is not contained in the complex", row, column, column );
}
if column.number_of_vertices() != row.number_of_vertices() + 1 {
return None
}
let mut symmetric_difference = symmetric_difference_of_ordered_iterators( row.vertices.iter(), column.vertices.iter() );
let first_different_vertex = symmetric_difference.next();
if symmetric_difference.next().is_some() {
return None
}
for (counter, vertex) in column.vertices.iter().enumerate() {
if Some(vertex) == first_different_vertex {
let coefficient = self.ring_operator.minus_one_to_power( counter );
return Some( coefficient )
}
}
panic!("Something went wrong in the calculation of a structural nonzero");
}
}
impl < DissimilarityMatrix, RingOperator >
MatrixAlgebra for
Arc<
VietorisRipsComplex
< DissimilarityMatrix, RingOperator >
>
where
DissimilarityMatrix: Clone + MatrixOracle< ColumnIndex=usize, RowIndex=usize >,
DissimilarityMatrix::Coefficient: Copy + Debug + Ord + Bounded,
DissimilarityMatrix::RowEntry: KeyValNew, DissimilarityMatrix::Row: Clone, RingOperator: Clone + RingOperations,
RingOperator::Element: Debug + PartialEq,
{
type RingOperator = RingOperator;
type OrderOperatorForRowEntries = OrderOperatorByKey;
type OrderOperatorForRowIndices = OrderOperatorAuto;
type OrderOperatorForColumnEntries = OrderOperatorByKey;
type OrderOperatorForColumnIndices = OrderOperatorAuto;
fn ring_operator( &self ) -> Self::RingOperator {
self.ring_operator.clone()
}
fn order_operator_for_row_entries( &self ) -> Self::OrderOperatorForRowEntries {
OrderOperatorByKey::new()
}
fn order_operator_for_row_indices( &self ) -> Self::OrderOperatorForRowIndices {
OrderOperatorAuto::new()
}
fn order_operator_for_column_entries( &self ) -> Self::OrderOperatorForColumnEntries {
OrderOperatorByKey::new()
}
fn order_operator_for_column_indices( &self ) -> Self::OrderOperatorForColumnIndices {
OrderOperatorAuto::new()
}
}
impl < DissimilarityMatrix, RingOperator >
MatrixOracleOperations for
Arc<
VietorisRipsComplex
< DissimilarityMatrix, RingOperator >
>
where
DissimilarityMatrix: Clone + MatrixOracle< ColumnIndex=usize, RowIndex=usize >,
DissimilarityMatrix::Coefficient: Copy + Debug + Ord + Bounded,
DissimilarityMatrix::RowEntry: KeyValNew, DissimilarityMatrix::Row: Clone, RingOperator: Clone + RingOperations,
RingOperator::Element: Debug + PartialEq,
{
fn bottom_entry_for_column( &self, column_index: &<Arc<VietorisRipsComplex<DissimilarityMatrix, RingOperator>> as crate::algebra::matrices::query::MatrixOracle>::ColumnIndex )
-> Option<
<Arc<VietorisRipsComplex<DissimilarityMatrix, RingOperator>> as MatrixOracle>::ColumnEntry
> {
let order_operator = self.order_operator_for_column_entries();
let iter = AgileBoundaryIteratorLexicographicOrder::new(
self.clone(),
column_index.clone(),
false, );
return iter.max_by(|x, y| order_operator.judge_cmp( &x, &y ) );
}
}
#[derive(Clone,PartialEq)]
pub struct SmallCofacetVertexIterator< DissimilarityMatrix >
where
DissimilarityMatrix: MatrixOracle< ColumnIndex=usize, RowIndex=usize >,
DissimilarityMatrix::Coefficient: Ord + Debug + Bounded,
DissimilarityMatrix::RowEntry: KeyValNew, {
pub proveably_exhausted: bool,
pub neighbor_iterators: Vec< DissimilarityMatrix::Row >,
pub facet: Arc< Vec< Vertex > >,
pub facet_filtration: DissimilarityMatrix::Coefficient,
}
impl < DissimilarityMatrix >
SmallCofacetVertexIterator
< DissimilarityMatrix >
where
DissimilarityMatrix: MatrixOracle< ColumnIndex=usize, RowIndex=usize >,
DissimilarityMatrix::Coefficient: Ord + Debug + Bounded,
DissimilarityMatrix::RowEntry: KeyValNew, {
pub fn new(
dissimilarity_matrix: DissimilarityMatrix,
facet: Arc< Vec< Vertex > >,
facet_filtration: DissimilarityMatrix::Coefficient,
) -> Self
{
let proveably_exhausted = facet.is_empty();
let mut neighbor_iterators = Vec::with_capacity(facet.len());
for vertex in facet.iter() {
let row = dissimilarity_matrix.row(& (*vertex as usize ) );
neighbor_iterators.push(row);
}
SmallCofacetVertexIterator {
proveably_exhausted,
neighbor_iterators,
facet,
facet_filtration,
}
}
pub fn next_plausible_candidate_for_kth_facet_vertex( &mut self, k: usize )
-> Option< Vertex >
{
let neighbor_iterator = &mut self.neighbor_iterators[k];
while let Some(entry) = neighbor_iterator.next() {
let neighbor = entry.key() as Vertex;
let filtration = entry.val();
if self.facet.contains(&neighbor) {
continue; }
if filtration > self.facet_filtration {
continue
} else {
return Some( neighbor );
}
}
return None;
}
}
impl < DissimilarityMatrix >
Iterator for
SmallCofacetVertexIterator
< DissimilarityMatrix >
where
DissimilarityMatrix: MatrixOracle< ColumnIndex=usize, RowIndex=usize >,
DissimilarityMatrix::Coefficient: Ord + Debug + Bounded,
DissimilarityMatrix::RowEntry: KeyValNew, {
type Item = Vertex;
fn next( &mut self ) -> Option<Self::Item> {
if self.proveably_exhausted {
return None; }
let mut candidate_neighbor: u16 = self.next_plausible_candidate_for_kth_facet_vertex( 0 )?;
let mut number_of_facet_vertices_checked = 1;
let mut next_facet_vertex_to_check: usize = 0 % self.facet.len();
'outer_loop: loop {
if number_of_facet_vertices_checked == self.facet.len() {
return Some( candidate_neighbor );
}
next_facet_vertex_to_check += 1;
next_facet_vertex_to_check %= self.facet.len();
while let Some( neighbor ) = self.next_plausible_candidate_for_kth_facet_vertex( next_facet_vertex_to_check ) {
if neighbor < candidate_neighbor {
continue
}
if neighbor > candidate_neighbor {
candidate_neighbor = neighbor;
number_of_facet_vertices_checked = 1; continue 'outer_loop;
}
number_of_facet_vertices_checked += 1;
continue 'outer_loop;
}
self.proveably_exhausted = true;
return None;
}
}
}
#[derive(Clone,Debug,PartialEq, Eq)]
pub struct DiagonalEntryIterator< DissimilarityMatrix >
where DissimilarityMatrix: MatrixOracle< ColumnIndex=usize, RowIndex=usize >,
DissimilarityMatrix::Coefficient: Ord + Debug + Bounded,
{
pub row_number_iterator: std::ops::Range<usize>,
pub dissimilarity_matrix: DissimilarityMatrix,
}
impl < DissimilarityMatrix >
DiagonalEntryIterator
< DissimilarityMatrix >
where DissimilarityMatrix: MatrixOracle< ColumnIndex=usize, RowIndex=usize >,
DissimilarityMatrix::Coefficient: Ord + Debug + Bounded,
{
pub fn new( dissimilarity_matrix: DissimilarityMatrix, size: usize ) -> Self {
DiagonalEntryIterator {
row_number_iterator: 0..size,
dissimilarity_matrix,
}
}
}
impl < DissimilarityMatrix >
Iterator for
DiagonalEntryIterator
< DissimilarityMatrix >
where DissimilarityMatrix: MatrixOracle< ColumnIndex=usize, RowIndex=usize >,
DissimilarityMatrix::Coefficient: Ord + Debug + Bounded,
DissimilarityMatrix::RowEntry: KeyValNew,
{
type Item = DissimilarityMatrix::RowEntry;
fn next( &mut self ) -> Option<Self::Item> {
while let Some(row_number) = self.row_number_iterator.next() {
match self.dissimilarity_matrix.structural_nonzero_entry( & row_number, & row_number ) {
None => continue, Some(coefficient) => {
return Some(
DissimilarityMatrix::RowEntry::new( row_number, coefficient )
);
}
}
}
return None;
}
}
#[derive(Clone,Debug)]
pub struct AgileSimplexIteratorLexicographicOrder< DissimilarityMatrix >
where DissimilarityMatrix: MatrixOracle< ColumnIndex=usize, RowIndex=usize >,
DissimilarityMatrix::Coefficient: Ord + Debug + Bounded,
DissimilarityMatrix::RowEntry: KeyValNew, {
pub dissimilarity_matrix: DissimilarityMatrix,
pub neighbor_iterators: Vec<
TwoTypeIterator<
DiagonalEntryIterator< DissimilarityMatrix >,
DissimilarityMatrix::Row,
>
>,
pub face_filtrations: Vec< DissimilarityMatrix::Coefficient >, pub vertices: Vec<Vertex>, pub dimension: isize,
}
impl < DissimilarityMatrix >
AgileSimplexIteratorLexicographicOrder
< DissimilarityMatrix >
where DissimilarityMatrix: Clone + MatrixOracle< ColumnIndex=usize, RowIndex=usize >,
DissimilarityMatrix::Coefficient: Ord + Debug + Bounded,
DissimilarityMatrix::RowEntry: KeyValNew,
{
pub fn new(
dissimilarity_matrix: DissimilarityMatrix,
dissimilarity_matrix_size: usize, dimension: isize,
allow_empty_simplex: bool,
)
->
Self
where
DissimilarityMatrix: MatrixOracle< ColumnIndex=usize, RowIndex=usize >
{
if dimension < 0 {
let neighborhood_iterators = Vec::with_capacity(0);
let face_filtrations = Vec::with_capacity(0);
let mut vertices= match dimension {
-1 => Vec::with_capacity(1),
_ => Vec::with_capacity(0),
};
if ! allow_empty_simplex {
vertices = Vec::with_capacity(0);
}
return AgileSimplexIteratorLexicographicOrder {
dimension,
dissimilarity_matrix,
neighbor_iterators: neighborhood_iterators,
face_filtrations,
vertices,
};
}
let dimension = dimension as usize;
let diagonal_entry_iterator = TwoTypeIterator::Version1(
DiagonalEntryIterator::new( dissimilarity_matrix.clone(), dissimilarity_matrix_size )
);
let mut neighbor_iterators = Vec::with_capacity( dimension + 1 );
neighbor_iterators.push( diagonal_entry_iterator );
let face_filtrations = Vec::with_capacity(dimension+1);
let vertices = Vec::with_capacity(dimension+1);
AgileSimplexIteratorLexicographicOrder {
dimension: dimension as isize,
dissimilarity_matrix,
neighbor_iterators,
face_filtrations,
vertices,
}
}
pub fn last_neighborhood_ordinal( &self ) -> Option<usize> {
match self.neighbor_iterators.len() {
0 => None, n => Some( n - 1 ), }
}
}
impl< DissimilarityMatrix >
Iterator for
AgileSimplexIteratorLexicographicOrder
< DissimilarityMatrix >
where DissimilarityMatrix: Clone + MatrixOracle< ColumnIndex=usize, RowIndex=usize >,
DissimilarityMatrix::Coefficient: Ord + Debug + Bounded,
DissimilarityMatrix::RowEntry: KeyValNew, DissimilarityMatrix::Row: Clone,
{
type Item = WeightedSimplex<DissimilarityMatrix::Coefficient>;
fn next(&mut self) -> Option<Self::Item> {
if self.dimension < 0 {
if self.vertices.capacity() == 0 {
return None;
} else {
if self.vertices.len() > 0 {
panic!("AgileSimplexIteratorLexicographicOrder::next() called on a simplex iterator with dimension < 0, but the vertices list is not empty. This indicates that the simplex iterator was not properly initialized. This error message originates in the oat_rust::topology::simplicial::from::graph_weighted module, in the AgileSimplexIteratorLexicographicOrder struct.");
}
self.vertices.shrink_to(0);
return Some( WeightedSimplex {
vertices: self.vertices.clone(),
weight: DissimilarityMatrix::Coefficient::min_value(),
} );
}
}
'outer_loop: loop {
let last_neighborhood_ordinal = self.last_neighborhood_ordinal()?;
'search_within_neighborhood: while let Some(entry) = ( &mut self.neighbor_iterators[last_neighborhood_ordinal] ).next() { let v = entry.key(); let mut f = entry.val();
if last_neighborhood_ordinal > 1 {
f = f.max(self.face_filtrations[last_neighborhood_ordinal-1].clone());
}
if last_neighborhood_ordinal > 0 {
for vertex in self.vertices[1..last_neighborhood_ordinal].iter().cloned().map(|x| x as usize) {
match self.dissimilarity_matrix.structural_nonzero_entry( &vertex, &v) {
Some(dissimilarity) => {
f = f.max(dissimilarity); },
None => {
continue 'search_within_neighborhood; }
}
}
}
match last_neighborhood_ordinal == self.dimension as usize {
true => {
let mut vertices = self.vertices.clone();
vertices.push(v as u16);
return Some( WeightedSimplex { vertices, weight: f, } );
} false => {
self.vertices.push(v as u16); self.face_filtrations.push(f);
match last_neighborhood_ordinal == 0 {
true => {
let mut new_neighbor_iterator = self.dissimilarity_matrix.row( &v ); while let Some(entry) = new_neighbor_iterator.next() {
if entry.key() == v { break }
}
self.neighbor_iterators.push(
TwoTypeIterator::Version2(
new_neighbor_iterator
)
);
} false => { self.neighbor_iterators.push(
self.neighbor_iterators[last_neighborhood_ordinal].clone()
);
}
}
continue 'outer_loop;
}
}
}
self.neighbor_iterators.pop();
self.face_filtrations.pop();
self.vertices.pop();
}
}
}
#[derive(Clone,Debug,PartialEq, Eq)]
pub struct BigCofacetEdgeIterator
< DissimilarityMatrix >
where
DissimilarityMatrix: MatrixOracle< ColumnIndex=usize, RowIndex=usize >,
{
facet_filtration: DissimilarityMatrix::Coefficient,
facet: Arc<Vec< Vertex >>,
filtration_ordered_neighborhood_lists: Vec<
IterWrappedArcVec<
(
DissimilarityMatrix::Coefficient,
Vertex,
)
>
>,
dissimilarity_matrix: DissimilarityMatrix,
cofacet_edge_identifiers: Vec< MakeNoneMaximum<(DissimilarityMatrix::Coefficient, Vertex)> >,
}
impl < DissimilarityMatrix >
BigCofacetEdgeIterator
< DissimilarityMatrix >
where
DissimilarityMatrix: MatrixOracle< ColumnIndex=usize, RowIndex=usize >,
DissimilarityMatrix::Coefficient: Ord + Copy,
{
fn new(
facet: Arc<Vec<Vertex>>,
dissimilarity_matrix: DissimilarityMatrix,
facet_filtration: DissimilarityMatrix::Coefficient,
all_ambient_filtration_ordered_neighborhood_lists: Arc< Vec< Arc< Vec< (DissimilarityMatrix::Coefficient, Vertex) >
>>>,
) -> Self {
let facet_cardinality = facet.len();
let mut neighbor_lists_filtration_order = Vec::with_capacity( facet_cardinality );
for v in facet.iter() {
neighbor_lists_filtration_order.push(
IterWrappedArcVec::new(
all_ambient_filtration_ordered_neighborhood_lists[ *v as usize ].clone()
)
);
}
let mut initialized_cofacet_iterator = BigCofacetEdgeIterator {
facet_filtration: facet_filtration,
facet,
filtration_ordered_neighborhood_lists: neighbor_lists_filtration_order,
dissimilarity_matrix,
cofacet_edge_identifiers: Vec::new(),
};
let mut cofacet_edge_identifiers: Vec<_> = Vec::with_capacity( facet_cardinality );
for k in 0 .. facet_cardinality {
cofacet_edge_identifiers.push(
MakeNoneMaximum::from_opt(
initialized_cofacet_iterator
.find_next_identifier_for_the_kth_vertex( k )
)
);
}
initialized_cofacet_iterator.cofacet_edge_identifiers = cofacet_edge_identifiers;
return initialized_cofacet_iterator;
}
fn facet_cardinality( &self ) -> usize {
self.facet.len()
}
fn facet_dimension( &self ) -> isize {
( self.facet.len() as isize ) - 1
}
fn edge_is_a_valid_cofacet_identifier(
&self,
k: usize,
neighbor_of_vk: Vertex,
distance_vk_to_neighbor_of_vk: DissimilarityMatrix::Coefficient,
) -> bool {
if distance_vk_to_neighbor_of_vk <= self.facet_filtration {
return false;
}
for ( facet_vertex_ordinal, facet_vertex ) in self.facet.iter().enumerate() {
if *facet_vertex == neighbor_of_vk {
continue;
}
if facet_vertex_ordinal == k { continue } match self.dissimilarity_matrix.structural_nonzero_entry(
& ( neighbor_of_vk as usize),
&( * facet_vertex as usize )
) {
None => {
return false;
}
Some(f) => {
match f.cmp(&distance_vk_to_neighbor_of_vk) {
std::cmp::Ordering::Less => {
continue
}
std::cmp::Ordering::Greater => {
return false;
}
std::cmp::Ordering::Equal => {
if facet_vertex_ordinal < k {
return false;
} else {
continue
}
}
}
}
}
}
return true
}
fn find_next_identifier_for_the_kth_vertex( &mut self, facet_vertex_ordinal:usize ) -> Option< (DissimilarityMatrix::Coefficient, Vertex) >{
let mut replacement_identifier: Option< (DissimilarityMatrix::Coefficient, Vertex) >;
loop {
replacement_identifier = self.filtration_ordered_neighborhood_lists[facet_vertex_ordinal].next();
if let Some( (f, v) ) = replacement_identifier {
if self.edge_is_a_valid_cofacet_identifier(
facet_vertex_ordinal,
v,
f
)
{
break;
} else {
continue;
}
} else {
break;
}
}
replacement_identifier
}
}
impl < DissimilarityMatrix >
Iterator for
BigCofacetEdgeIterator
< DissimilarityMatrix >
where
DissimilarityMatrix: MatrixOracle< ColumnIndex=usize, RowIndex=usize >,
DissimilarityMatrix::Coefficient: Ord + Copy,
{
type Item = (DissimilarityMatrix::Coefficient, Vertex);
fn next(&mut self) -> Option<Self::Item> {
let (facet_vertex_ordinal, _next_identifier_ref) = self.cofacet_edge_identifiers
.iter()
.enumerate()
.min_by_key(
|(_facet_vertex_ordinal, identifier)| {
**identifier
}
)?;
let replacement_identifier = MakeNoneMaximum::from_opt(
self.find_next_identifier_for_the_kth_vertex(
facet_vertex_ordinal
)
);
let selected_identifier = std::mem::replace(
&mut self.cofacet_edge_identifiers[facet_vertex_ordinal], replacement_identifier );
return selected_identifier.into_inner()
}
}
#[derive(Clone)]
pub struct AgileCoboundaryIteratorFiltrationOrder
< DissimilarityMatrix, RingOperator >
where
DissimilarityMatrix: MatrixOracle< ColumnIndex=usize, RowIndex=usize >,
DissimilarityMatrix::Row: Clone,
DissimilarityMatrix::RowEntry: KeyValNew,
DissimilarityMatrix::Coefficient: Ord + Copy + Debug + Bounded,
RingOperator: RingOperations,
{
facet: Arc<Vec<Vertex>>,
facet_filtration: DissimilarityMatrix::Coefficient,
small_cofacet_vertices: Option< SmallCofacetVertexIterator< DissimilarityMatrix > >,
big_cofacet_edge_identifiers: Option< BigCofacetEdgeIterator< DissimilarityMatrix > >,
dissimilarity_matrix: DissimilarityMatrix,
dissimilarity_matrix_size: usize, zero_dimensional_cofacets_opt: Option<
IntoIter<
WeightedSimplex<
DissimilarityMatrix::Coefficient
>
>
>,
all_ambient_filtration_ordered_neighborhood_lists: Arc< Vec< Arc< Vec<
(DissimilarityMatrix::Coefficient, Vertex)
>>
>>,
ring_operator: RingOperator,
}
impl < 'a, DissimilarityMatrix, RingOperator >
AgileCoboundaryIteratorFiltrationOrder
< DissimilarityMatrix, RingOperator >
where
DissimilarityMatrix: Clone + MatrixOracle< ColumnIndex=usize, RowIndex=usize >,
DissimilarityMatrix::Row: Clone,
DissimilarityMatrix::RowEntry: KeyValNew,
DissimilarityMatrix::Coefficient: Ord + Copy + Debug + Bounded,
RingOperator: RingOperations,
{
pub fn new(
facet: Vec<Vertex>,
dissimilarity_matrix: DissimilarityMatrix,
dissimilarity_matrix_size: usize,
all_ambient_filtration_ordered_neighbor_lists: Arc< Vec< Arc< Vec< (DissimilarityMatrix::Coefficient, Vertex) >
>>>,
ring_operator: RingOperator,
) -> Result< Self, Vec<Vertex> > {
let mut exact_facet = Vec::with_capacity( facet.len() + 1 );
exact_facet.extend_from_slice( &facet );
let facet = Arc::new( exact_facet );
let facet_filtration = filtration_value_for_clique(&(*facet), &dissimilarity_matrix)?;
let zero_dimensional_cofacets_opt = match facet.is_empty() {
true => {
let mut cofacets = Vec::new();
for entry in DiagonalEntryIterator::new(
dissimilarity_matrix.clone(),
dissimilarity_matrix_size
){
let vertex = entry.key() as Vertex; let filtration = entry.val(); let simplex = vec![vertex];
let cofacet = WeightedSimplex::new( filtration, simplex );
cofacets.push( cofacet );
}
cofacets.sort(); Some( cofacets.into_iter() )
}
false => None,
};
Ok(
AgileCoboundaryIteratorFiltrationOrder {
facet,
facet_filtration,
dissimilarity_matrix,
dissimilarity_matrix_size,
ring_operator,
small_cofacet_vertices: None,
big_cofacet_edge_identifiers: None,
zero_dimensional_cofacets_opt: zero_dimensional_cofacets_opt,
all_ambient_filtration_ordered_neighborhood_lists: all_ambient_filtration_ordered_neighbor_lists,
}
)
}
pub fn coboundary_entry_for_exogenous_vertex(
& self,
vertex: Vertex,
filtration: DissimilarityMatrix::Coefficient,
) -> ( WeightedSimplex<DissimilarityMatrix::Coefficient>, RingOperator::Element )
where
RingOperator: Clone,
{
let (cofacet_vertices, coefficient) = coboundary_entry_for_facet_vertex_pair(
& self.facet,
vertex,
self.ring_operator.clone(),
).ok().unwrap();
let weighted_simplex = WeightedSimplex {
vertices: cofacet_vertices,
weight: filtration,
};
return ( weighted_simplex, coefficient );
}
}
impl < DissimilarityMatrix, RingOperator >
Iterator for
AgileCoboundaryIteratorFiltrationOrder
< DissimilarityMatrix, RingOperator >
where
DissimilarityMatrix::Coefficient: Clone + Copy + Debug + Ord + Bounded,
DissimilarityMatrix::RowEntry: KeyValNew, DissimilarityMatrix::Row: Clone,
DissimilarityMatrix: Clone + MatrixOracle< ColumnIndex=usize, RowIndex=usize >,
RingOperator: Clone + RingOperations,
{
type Item = (WeightedSimplex<DissimilarityMatrix::Coefficient>, RingOperator::Element);
fn next(&mut self) -> Option<Self::Item> {
if let Some( zero_dimensional_cofacets ) = &mut self.zero_dimensional_cofacets_opt {
return zero_dimensional_cofacets
.next()
.map( |weighted_simplex| {
( weighted_simplex, RingOperator::one() )
})
}
if self.small_cofacet_vertices.is_none() {
self.small_cofacet_vertices = Some(
SmallCofacetVertexIterator::new(
self.dissimilarity_matrix.clone(),
self.facet.clone(),
self.facet_filtration, )
);
}
if let Some( small_cofacet_vertices ) = &mut self.small_cofacet_vertices {
if let Some( neighbor ) = small_cofacet_vertices.next() {
return Some( self.coboundary_entry_for_exogenous_vertex(
neighbor,
self.facet_filtration.clone(), ) );
}
}
if self.big_cofacet_edge_identifiers.is_none() {
self.big_cofacet_edge_identifiers = Some(
BigCofacetEdgeIterator::new(
self.facet.clone(),
self.dissimilarity_matrix.clone(),
self.facet_filtration, self.all_ambient_filtration_ordered_neighborhood_lists.clone()
)
);
}
if let Some( big_cofacet_edge_identifiers ) = &mut self.big_cofacet_edge_identifiers {
if let Some( (cofacet_filtration, vertex) ) = big_cofacet_edge_identifiers.next() {
return Some( self.coboundary_entry_for_exogenous_vertex(
vertex,
cofacet_filtration ) );
}
}
return None
}
}
pub struct AgileCoboundaryIterartorLexicographicOrder
< DissimilarityMatrix, RingOperator >
where
DissimilarityMatrix: MatrixOracle< ColumnIndex=usize, RowIndex=usize, >,
{
pub facet: Vec<Vertex>,
pub facet_filtration: DissimilarityMatrix::Coefficient,
pub dissimilarity_matrix: DissimilarityMatrix,
pub neighbors_of_vertex_0: DissimilarityMatrix::Row,
pub ring_operator: RingOperator,
}
impl < DissimilarityMatrix, RingOperator >
AgileCoboundaryIterartorLexicographicOrder
< DissimilarityMatrix, RingOperator >
where
DissimilarityMatrix: MatrixOracle<
ColumnIndex = usize,
RowIndex = usize,
Coefficient: Ord + Bounded,
>,
{
pub fn new(
facet: Vec<Vertex>,
dissimilarity_matrix: DissimilarityMatrix,
ring_operator: RingOperator,
) -> Result<Self, Vec<Vertex>> {
let facet_filtration = filtration_value_for_clique(&facet, &dissimilarity_matrix)?;
let neighbors_of_vertex_0 = dissimilarity_matrix.row( & (facet[0] as usize) );
return Ok(
AgileCoboundaryIterartorLexicographicOrder {
facet,
facet_filtration,
dissimilarity_matrix,
neighbors_of_vertex_0,
ring_operator,
}
);
}
}
impl< 'a, DissimilarityMatrix, RingOperator >
Iterator for
AgileCoboundaryIterartorLexicographicOrder
< DissimilarityMatrix, RingOperator >
where
DissimilarityMatrix::Coefficient: Debug + Ord,
DissimilarityMatrix: MatrixOracle< ColumnIndex=usize, RowIndex=usize >,
RingOperator: Clone + RingOperations,
{
type Item = (
WeightedSimplex
< DissimilarityMatrix::Coefficient >,
RingOperator
::Element
);
fn next( &mut self ) -> Option<Self::Item> {
'outer_loop: while let Some( neighbor_entry ) = self.neighbors_of_vertex_0.next() {
let neighbor = neighbor_entry.key();
let mut filtration = neighbor_entry.val();
filtration = filtration.max(self.facet_filtration.clone());
if self.facet.contains(& (neighbor as Vertex )) {
continue 'outer_loop; }
for facet_vertex in self.facet[1..].iter().cloned() {
match self.dissimilarity_matrix.structural_nonzero_entry( & (facet_vertex as usize), & neighbor ) {
None => continue 'outer_loop, Some(new_filtration) => filtration = filtration.max(new_filtration),
}
}
let (cofacet, coefficient) = coboundary_entry_for_facet_vertex_pair(
&self.facet,
neighbor as Vertex,
self.ring_operator.clone(),
).ok().unwrap();
let weighted_cofacet = WeightedSimplex {
vertices: cofacet,
weight: filtration,
};
return Some((weighted_cofacet, coefficient));
}
return None; }
}
#[cfg(test)]
mod tests {
use crate::{algebra::matrices::{debug::matrix_oracle_is_internally_consistent, operations::umatch::differential::DifferentialUmatch}, topology::{point_cloud, simplicial::simplices::{self, weighted::WeightedSimplex}}, utilities::order::OrderOperatorAuto};
#[test]
fn check_that_some_basic_functions_run_without_error_small() {
use crate::topology::simplicial::{simplices::weighted::WeightedSimplex, from::graph_weighted::{VietorisRipsComplex}};
use crate::topology::point_cloud::unit_circle;
use crate::algebra::vectors::entries::KeyValGet;
use crate::algebra::rings::types::native::{FieldRational64};
use crate::algebra::matrices::query::MatrixOracle;
use crate::algebra::matrices::operations::umatch::row_major::{Umatch};
use crate::algebra::matrices::types::third_party::IntoCSR;
use crate::utilities::order::{ is_sorted_strictly, OrderOperatorByKeyCustom, OrderOperatorAutoReverse};
use crate::utilities::iterators::general::minmax;
use crate::utilities::distances::{rowwise_distances};
use std::sync::Arc;
use ordered_float::OrderedFloat;
use itertools::Itertools;
let number_of_points = 2;
let min_homology_dimension = 0;
let max_homology_dimension = 2;
let pcloud: Vec<Vec<f64>> = vec![vec![0.], vec![1.]];
let dissimilarity_matrix_data
= rowwise_distances(pcloud.clone())
.into_iter()
.map(|x| x.into_iter().enumerate().collect_vec() )
.collect_vec()
.into_csr( number_of_points, number_of_points );
let dissimilarity_matrix = & dissimilarity_matrix_data;
let dissimilarity_value_min = OrderedFloat(0.0);
let dissimilarity_value_max =
minmax(
(0..number_of_points).map(
|x|
dissimilarity_matrix.row(&x).into_iter().map(
|x|
x.val()
)
)
).unwrap_or( dissimilarity_value_min.clone() );
let ring_operator = FieldRational64::new();
let chain_complex_data = VietorisRipsComplex::new( & dissimilarity_matrix, number_of_points, ring_operator ).ok().unwrap();
let chain_complex = Arc::new(chain_complex_data);
let mut row_index_vec = chain_complex.cliques_in_row_reduction_order(max_homology_dimension);
let mut column_index_vec = chain_complex.cliques_in_row_reduction_order(max_homology_dimension+1);
row_index_vec.reverse();
column_index_vec.reverse();
for simplex in row_index_vec.iter() {
let filtration = chain_complex.filtration_value_for_clique(simplex.vertices()).ok().unwrap();
assert!( filtration == simplex.filtration() );
}
for simplex in column_index_vec.iter() {
let filtration = chain_complex.filtration_value_for_clique(simplex.vertices()).ok().unwrap();
assert!( filtration == simplex.filtration() );
}
assert!(
crate::algebra::matrices::debug::matrix_oracle_is_internally_consistent(
chain_complex.clone(),
row_index_vec.iter().cloned(),
column_index_vec.iter().cloned(),
)
);
let mut row_index_vec_sorted = row_index_vec.clone();
let mut column_index_vec_sorted = column_index_vec.clone();
row_index_vec_sorted.sort();
column_index_vec_sorted.sort();
assert!(
crate::algebra::matrices::debug::matrix_order_operators_are_internally_consistent(
chain_complex.clone(),
row_index_vec_sorted.iter().cloned(),
column_index_vec_sorted.iter().cloned(),
).is_ok()
);
println!("starting umatch");
let umatch = DifferentialUmatch::new(
chain_complex.clone(),
min_homology_dimension,
max_homology_dimension,
);
println!("setting up to unpack");
let return_cycle_representatives = true;
let return_bounding_chains = true;
let _barcode = crate::algebra::chain_complexes::barcode::get_barcode( &umatch, return_cycle_representatives, return_bounding_chains );
println!("getting intervals, reps, bounding chains");
}
#[test]
fn check_that_some_basic_functions_run_without_error() {
use crate::topology::simplicial::{simplices::weighted::WeightedSimplex, from::graph_weighted::{VietorisRipsComplex}};
use crate::topology::point_cloud::unit_circle;
use crate::algebra::vectors::entries::KeyValGet;
use crate::algebra::rings::types::native::{FieldRational64};
use crate::algebra::matrices::query::MatrixOracle;
use crate::algebra::matrices::operations::umatch::row_major::{Umatch};
use crate::algebra::matrices::types::third_party::IntoCSR;
use crate::utilities::order::{ is_sorted_strictly, OrderOperatorByKeyCustom, OrderOperatorAutoReverse};
use crate::utilities::iterators::general::minmax;
use crate::utilities::distances::{rowwise_distances};
use std::sync::Arc;
use ordered_float::OrderedFloat;
use itertools::Itertools;
let number_of_points = 8;
let min_homology_dimension = 0;
let max_homology_dimension = 2;
let pcloud = unit_circle( number_of_points, Some(-1.0 .. 1.0));
let dissimilarity_matrix_data
= rowwise_distances(pcloud.clone())
.into_iter()
.map(|x| x.into_iter().enumerate().collect_vec() )
.collect_vec()
.into_csr( number_of_points, number_of_points );
let dissimilarity_matrix = & dissimilarity_matrix_data;
let ring_operator = FieldRational64::new();
let chain_complex_data = VietorisRipsComplex::new( & dissimilarity_matrix, number_of_points, ring_operator ).ok().unwrap();
let chain_complex = Arc::new(chain_complex_data);
let mut row_index_vec = chain_complex.cliques_in_row_reduction_order(max_homology_dimension);
let mut column_index_vec = chain_complex.cliques_in_row_reduction_order(max_homology_dimension+1);
row_index_vec.reverse();
column_index_vec.reverse();
for simplex in row_index_vec.iter() {
let filtration = chain_complex.filtration_value_for_clique(simplex.vertices()).ok().unwrap();
assert!( filtration == simplex.filtration() );
}
for simplex in column_index_vec.iter() {
let filtration = chain_complex.filtration_value_for_clique(simplex.vertices()).ok().unwrap();
assert!( filtration == simplex.filtration() );
}
assert!(
crate::algebra::matrices::debug::matrix_oracle_is_internally_consistent(
chain_complex.clone(),
row_index_vec.iter().cloned(),
column_index_vec.iter().cloned(),
)
);
let mut row_index_vec_sorted = row_index_vec.clone();
let mut column_index_vec_sorted = column_index_vec.clone();
row_index_vec_sorted.sort();
column_index_vec_sorted.sort();
assert!(
crate::algebra::matrices::debug::matrix_order_operators_are_internally_consistent(
chain_complex.clone(),
row_index_vec_sorted.iter().cloned(),
column_index_vec_sorted.iter().cloned(),
).is_ok()
);
println!("starting umatch");
let iter_row_index = chain_complex.cliques_in_row_reduction_order(max_homology_dimension);
let differential_umatch = DifferentialUmatch::new(
chain_complex.clone(),
min_homology_dimension,
max_homology_dimension,
);
println!("setting up to unpack");
let return_cycle_representatives = true;
let return_bounding_chains = true;
let _barcode = crate::algebra::chain_complexes::barcode::get_barcode(
&differential_umatch,
return_cycle_representatives,
return_bounding_chains,
);
println!("getting intervals, reps, bounding chains");
}
#[test]
fn test_empty_simplex_iter() {
use sprs::CsMatBase;
use ordered_float::OrderedFloat;
use crate::topology::simplicial::from::graph_weighted::AgileSimplexIteratorLexicographicOrder;
use crate::algebra::matrices::query::MatrixOracle;
let dissimilarity_matrix = CsMatBase::new( (2,2), vec![0,1,2], vec![0,1], vec![OrderedFloat(0.0),OrderedFloat(0.0)] );
println!("entry (0,1) = {:?}", (& dissimilarity_matrix).structural_nonzero_entry(&0, &1));
let simplices: Vec<_> = AgileSimplexIteratorLexicographicOrder::new(
& dissimilarity_matrix,
2, 1, false, ).collect();
println!("generated simplices = {:?}", &simplices );
let empty = Vec::< WeightedSimplex<OrderedFloat<f64>> >::new();
assert!( empty.eq( &simplices ) )
}
#[test]
fn test_simplex_iterators () {
use crate::topology::simplicial::from::graph_weighted::{AgileBoundaryIteratorLexicographicOrder, AgileCoboundaryIteratorFiltrationOrder, VietorisRipsComplex};
use crate::topology::simplicial::simplices::weighted::WeightedSimplex;
use crate::algebra::matrices::types::vec_of_vec::sorted::VecOfVec;
use crate::algebra::matrices::query::MatrixOracle;
use crate::algebra::rings::types::native::FieldFloat64;
use ordered_float::OrderedFloat;
use std::sync::Arc;
let ring_operator = FieldFloat64::new();
let dissimilarity_matrix = VecOfVec::from_ragged(
& vec![
vec![OrderedFloat(0.0), OrderedFloat(1.0), OrderedFloat(2.0), OrderedFloat(3.0)],
vec![OrderedFloat(1.0), OrderedFloat(0.0), OrderedFloat(1.0), OrderedFloat(2.0)],
vec![OrderedFloat(2.0), OrderedFloat(1.0), OrderedFloat(0.0), OrderedFloat(1.0)],
vec![OrderedFloat(3.0), OrderedFloat(2.0), OrderedFloat(1.0), OrderedFloat(1.0)],
]
);
let vietoris_rips_complex = Arc::new(
VietorisRipsComplex::new(
& dissimilarity_matrix,
3, ring_operator,
).ok().unwrap()
);
let simplex = WeightedSimplex {
vertices: vec![0, 1, 2],
weight: OrderedFloat(2.0),
};
let boundary = AgileBoundaryIteratorLexicographicOrder::new(
vietoris_rips_complex.clone(),
simplex,
false, );
assert!(
boundary.eq(
vec![
( WeightedSimplex { vertices: vec![0, 1], weight: OrderedFloat(1.0) }, 1.0 ),
( WeightedSimplex { vertices: vec![0, 2], weight: OrderedFloat(2.0) }, -1.0 ),
( WeightedSimplex { vertices: vec![1, 2], weight: OrderedFloat(1.0) }, 1.0 ),
]
)
);
let simplex = WeightedSimplex {
vertices: vec![0, 2],
weight: OrderedFloat(2.0),
};
let coboundary = vietoris_rips_complex.row( & simplex );
assert!(
coboundary.eq(
vec![
( WeightedSimplex { vertices: vec![0, 1, 2], weight: OrderedFloat(2.0) }, -1.0 ),
( WeightedSimplex { vertices: vec![0, 2, 3], weight: OrderedFloat(3.0) }, 1.0 ),
]
)
);
}
}