#![forbid(unsafe_code)]
#![warn(missing_docs)]
pub mod cli;
pub(crate) mod combinadic;
pub mod distances;
pub mod io;
pub mod oracle;
pub(crate) mod solver;
mod union_find;
use std::fmt;
pub use distances::{DistanceMatrix, SparseDistanceMatrix};
pub const GIT_HASH: &str = env!("HOLOS_GIT_HASH");
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub const BUILD_PROFILE: &str = env!("HOLOS_BUILD_PROFILE");
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Bar {
pub dim: usize,
pub birth: f64,
pub death: f64,
}
impl Bar {
pub fn is_essential(&self) -> bool {
self.death == f64::INFINITY
}
}
#[derive(Debug, Clone, Default)]
pub struct Diagram {
pub bars: Vec<Bar>,
}
impl Diagram {
pub fn in_dim(&self, dim: usize) -> impl Iterator<Item = &Bar> {
self.bars.iter().filter(move |b| b.dim == dim)
}
pub fn canonicalize(&mut self) {
self.bars.sort_by(|a, b| {
a.dim
.cmp(&b.dim)
.then(a.birth.total_cmp(&b.birth))
.then(a.death.total_cmp(&b.death))
});
}
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct RipsParams {
pub max_dim: usize,
pub threshold: Option<f64>,
pub modulus: u32,
pub use_emergent_pairs: bool,
pub use_apparent_pairs: bool,
pub use_clearing: bool,
}
impl Default for RipsParams {
fn default() -> Self {
Self {
max_dim: 1,
threshold: None,
modulus: 2,
use_emergent_pairs: true,
use_apparent_pairs: true,
use_clearing: true,
}
}
}
impl RipsParams {
pub fn new(max_dim: usize) -> Self {
Self {
max_dim,
..Self::default()
}
}
pub fn with_threshold(mut self, threshold: f64) -> Self {
self.threshold = Some(threshold);
self
}
pub fn with_modulus(mut self, modulus: u32) -> Self {
self.modulus = modulus;
self
}
}
#[derive(Debug, Clone, PartialEq)]
#[allow(missing_docs)]
pub enum Error {
InvalidDistance(String),
InvalidInput(String),
IndexOverflow { n: usize, dim: usize },
Io(String),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::InvalidDistance(msg) => write!(f, "invalid distance: {msg}"),
Error::InvalidInput(msg) => write!(f, "invalid input: {msg}"),
Error::IndexOverflow { n, dim } => write!(
f,
"simplex index space overflows u64 for {n} points in dimension {dim}"
),
Error::Io(msg) => write!(f, "io error: {msg}"),
}
}
}
impl std::error::Error for Error {}
pub type Result<T> = std::result::Result<T, Error>;
pub fn rips_persistence(dist: &DistanceMatrix, params: &RipsParams) -> Result<Diagram> {
solver::compute(dist, params)
}
pub fn rips_persistence_sparse(
dist: &SparseDistanceMatrix,
params: &RipsParams,
) -> Result<Diagram> {
solver::compute(dist, params)
}