Skip to content

Commit

Permalink
Add distance matrix constructor
Browse files Browse the repository at this point in the history
  • Loading branch information
tomchaplin committed Nov 13, 2024
1 parent 9c4b574 commit 5af98c9
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 3 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "gramag"
version = "0.4.0"
version = "0.4.1"
edition = "2021"
license = "MIT"
description = "Graph Magnitude Homology in Rust, with Python bindings"
Expand Down
1 change: 1 addition & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- [ ] Benchmark phlite vs lophat - why is phlite so much slower?
2 changes: 1 addition & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
sphinx
sphinx-rtd-theme
sphinxcontrib-napoleon
gramag==0.4.0
gramag==0.4.1
26 changes: 26 additions & 0 deletions docs/source/examples/distance_matrix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from gramag import MagGraph, format_rank_table

# Create your graph based on a square distance matrix
# use -1 to denote an infinite distance

# Undirected cycle graph on N nodes
N = 7
distance_matrix = [[min((j - i) % N, (i - j) % N) for j in range(N)] for i in range(N)]

mg = MagGraph.from_distance_matrix(distance_matrix)
# Compute generators of all MC^{(s, t)}_{k, l} for l<=6
mg.populate_paths(l_max=11)

# Reports the ranks of MC^{(s, t)}_{k, l}, summed over (s, t)
rk_gens = mg.rank_generators()

# For each l, in parallel across each (s, t), computes MH^{(s, t)}_{k, l}
# Adds up the rank for each k, l
rk_hom = mg.rank_homology()

# Pretty print
print("Rank of MC:")
print(format_rank_table(rk_gens))

print("Rank of MH:")
print(format_rank_table(rk_hom))
32 changes: 32 additions & 0 deletions docs/source/examples/distance_matrix_2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from gramag import MagGraph, format_rank_table

# Create your graph based on a square distance matrix
# use -1 to denote an infinite distance

# We do a digraph made up of two paths 0 -> 1 -> 2 -> 4 and 0 -> 3 -> 4

distance_matrix = [
[0, 1, 2, 1, 2],
[-1, 0, 1, -1, 2],
[-1, -1, 0, -1, 1],
[-1, -1, -1, 0, 1],
[-1, -1, -1, -1, 0],
]

mg = MagGraph.from_distance_matrix(distance_matrix)
# Compute generators of all MC^{(s, t)}_{k, l} for l<=6
mg.populate_paths(l_max=3)

# Reports the ranks of MC^{(s, t)}_{k, l}, summed over (s, t)
rk_gens = mg.rank_generators()

# For each l, in parallel across each (s, t), computes MH^{(s, t)}_{k, l}
# Adds up the rank for each k, l
rk_hom = mg.rank_homology()

# Pretty print
print("Rank of MC:")
print(format_rank_table(rk_gens))

print("Rank of MH:")
print(format_rank_table(rk_hom))
50 changes: 50 additions & 0 deletions src/bindings.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::{borrow::Borrow, collections::HashMap, iter, sync::Arc};

use dashmap::DashMap;
use rayon::prelude::*;

use lophat::{algorithms::SerialDecomposition, columns::VecColumn};
Expand Down Expand Up @@ -141,6 +142,55 @@ impl MagGraph {
}
}

/// Call this to compute the magnitude homology of a finite quasimetric space.
/// Simply pass in your distance matrix as the first parameter, using ``-1`` to denote an infinite distance.
/// You will get back a |MagGraph|_ (this is a bit of a hack) from which you can compute magnitude homology.
///
/// :param distance_matrix: The distance matrix of your finite quasimetric space.
/// :type distance_matrix: list[list[int]]
/// :return: A |MagGraph|_ object representing the apce.
/// :rtype: MagGraph
///
#[staticmethod]
fn from_distance_matrix(distance_matrix: Vec<Vec<isize>>) -> Self {
// Bit of a hack, we'll set up a line graph on the number of nodes
// and then input our own distance matrix in lieu of running dijkstra

let n_nodes = distance_matrix.len();
for row in &distance_matrix {
if row.len() != n_nodes {
panic!("Not given a square matrix");
}
}

let mut digraph = Graph::<(), ()>::new();
for i in 0..n_nodes {
let new_index = digraph.add_node(());
assert!(new_index.index() == i as usize)
}

let new_distance_matrix = DashMap::new();
for i in 0..n_nodes {
let mut row = HashMap::new();
for j in 0..n_nodes {
if distance_matrix[i][j] != -1 {
let key = NodeIndex::from(j as u32);
row.insert(key, distance_matrix[i][j] as usize);
}
}
let key = NodeIndex::from(i as u32);
new_distance_matrix.insert(key, row);
}

let distance_matrix = Arc::new(DistanceMatrix(new_distance_matrix));

MagGraph {
digraph,
distance_matrix,
path_container: None,
}
}

#[pyo3(signature=(*,k_max=None, l_max=None))]
/// You must call this method before attempting to compute any homology.
///
Expand Down
2 changes: 1 addition & 1 deletion src/distances.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rayon::prelude::*;
use std::{collections::HashMap, ops::Add};

#[derive(Debug)]
pub struct DistanceMatrix<NodeId: Eq + Hash>(DashMap<NodeId, HashMap<NodeId, usize>>);
pub struct DistanceMatrix<NodeId: Eq + Hash>(pub(crate) DashMap<NodeId, HashMap<NodeId, usize>>);

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Distance {
Expand Down

0 comments on commit 5af98c9

Please sign in to comment.