hypergraphx 0.0.5

A hypergraph library for Rust, based on the Python library of the same name.
Documentation
use crate::algo::floyd_warshall::floyd_warshall;
use crate::prelude::*;
use std::collections::HashMap;

#[test]
fn floyd_warshall_uniform_weight() {
    hypergraph! {
        let mut graph: DirectedHypergraph<_, _> {
            nodes: {
                let a = "a";
                let b = "b";
                let c = "c";
                let d = "d";
                let e = "e";
                let f = "f";
                let g = "g";
                let h = "h";
            };
            edges: {
                // [a, b] = ();
                // [b, c] = ();
                // [c, d] = ();
                // [d, a] = ();
                // [e, f] = ();
                // [b, e] = ();
                // [f, g] = ();
                // [g, h] = ();
                // [h, e] = ();
                ([a] -> [b]) = ();
                ([b] -> [c]) = ();
                ([c] -> [d]) = ();
                ([d] -> [a]) = ();
                ([e] -> [f]) = ();
                ([b] -> [e]) = ();
                ([f] -> [g]) = ();
                ([g] -> [h]) = ();
                ([h] -> [e]) = ();
            };
        }
    }

    // a ----> b ----> e ----> f
    // ^       |       ^       |
    // |       v       |       v
    // d <---- c       h <---- g

    let inf = std::i32::MAX;
    let expected_res: HashMap<(usize, usize), i32> = [
        ((a, a), 0),
        ((a, b), 1),
        ((a, c), 2),
        ((a, d), 3),
        ((a, e), 2),
        ((a, f), 3),
        ((a, g), 4),
        ((a, h), 5),
        ((b, a), 3),
        ((b, b), 0),
        ((b, c), 1),
        ((b, d), 2),
        ((b, e), 1),
        ((b, f), 2),
        ((b, g), 3),
        ((b, h), 4),
        ((c, a), 2),
        ((c, b), 3),
        ((c, c), 0),
        ((c, d), 1),
        ((c, e), 4),
        ((c, f), 5),
        ((c, g), 6),
        ((c, h), 7),
        ((d, a), 1),
        ((d, b), 2),
        ((d, c), 3),
        ((d, d), 0),
        ((d, e), 3),
        ((d, f), 4),
        ((d, g), 5),
        ((d, h), 6),
        ((e, a), inf),
        ((e, b), inf),
        ((e, c), inf),
        ((e, d), inf),
        ((e, e), 0),
        ((e, f), 1),
        ((e, g), 2),
        ((e, h), 3),
        ((f, a), inf),
        ((f, b), inf),
        ((f, c), inf),
        ((f, d), inf),
        ((f, e), 3),
        ((f, f), 0),
        ((f, g), 1),
        ((f, h), 2),
        ((g, a), inf),
        ((g, b), inf),
        ((g, c), inf),
        ((g, d), inf),
        ((g, e), 2),
        ((g, f), 3),
        ((g, g), 0),
        ((g, h), 1),
        ((h, a), inf),
        ((h, b), inf),
        ((h, c), inf),
        ((h, d), inf),
        ((h, e), 1),
        ((h, f), 2),
        ((h, g), 3),
        ((h, h), 0),
    ]
    .iter()
    .cloned()
    .collect();
    let res = floyd_warshall(&graph, |_| 1_i32).unwrap();

    let nodes = [a, b, c, d, e, f, g, h];
    for node1 in &nodes {
        for node2 in &nodes {
            println!(
                "Distance from {} to {}: {}",
                graph.node_weight(*node1).unwrap(),
                graph.node_weight(*node2).unwrap(),
                res.get(&(*node1, *node2)).unwrap()
            );
            assert_eq!(
                res.get(&(*node1, *node2)).unwrap(),
                expected_res.get(&(*node1, *node2)).unwrap()
            );
        }
    }
}

#[test]
fn floyd_warshall_weighted() {
    // let mut graph: Graph<(), (), Directed> = Graph::new();
    // let a = graph.add_node(());
    // let b = graph.add_node(());
    // let c = graph.add_node(());
    // let d = graph.add_node(());

    // graph.extend_with_edges(&[(a, b), (a, c), (a, d), (b, c), (b, d), (c, d)]);

    hypergraph! {
        let mut graph: DirectedHypergraph<_, _> {
            nodes: {
                let a = ();
                let b = ();
                let c = ();
                let d = ();
            };
            edges: {
                ([a] -> [b]) = ();
                ([a] -> [c]) = ();
                ([a] -> [d]) = ();
                ([b] -> [c]) = ();
                ([b] -> [d]) = ();
                ([c] -> [d]) = ();
            };
        }
    }

    let inf = std::i32::MAX;
    let expected_res: HashMap<(usize, usize), i32> = [
        ((a, a), 0),
        ((a, b), 1),
        ((a, c), 3),
        ((a, d), 3),
        ((b, a), inf),
        ((b, b), 0),
        ((b, c), 2),
        ((b, d), 2),
        ((c, a), inf),
        ((c, b), inf),
        ((c, c), 0),
        ((c, d), 2),
        ((d, a), inf),
        ((d, b), inf),
        ((d, c), inf),
        ((d, d), 0),
    ]
    .iter()
    .cloned()
    .collect();

    let weight_map: HashMap<(usize, usize), i32> = [
        ((a, a), 0),
        ((a, b), 1),
        ((a, c), 4),
        ((a, d), 10),
        ((b, b), 0),
        ((b, c), 2),
        ((b, d), 2),
        ((c, c), 0),
        ((c, d), 2),
    ]
    .iter()
    .cloned()
    .collect();

    let res = floyd_warshall(&graph, |edge| {
        if let Some(weight) = weight_map.get(&(
            *graph.source(edge).unwrap().iter().next().unwrap(),
            *graph.target(edge).unwrap().iter().next().unwrap(),
        )) {
            *weight
        } else {
            inf
        }
    })
    .unwrap();

    let nodes = [a, b, c, d];
    for node1 in &nodes {
        for node2 in &nodes {
            assert_eq!(
                res.get(&(*node1, *node2)).unwrap(),
                expected_res.get(&(*node1, *node2)).unwrap()
            );
        }
    }
}

#[test]
fn floyd_warshall_weighted_undirected() {
    // let mut graph: Graph<(), (), Undirected> = Graph::new_undirected();
    // let a = graph.add_node(());
    // let b = graph.add_node(());
    // let c = graph.add_node(());
    // let d = graph.add_node(());

    // graph.extend_with_edges(&[(a, b), (a, c), (a, d), (b, d), (c, b), (c, d)]);

    // let inf = std::i32::MAX;

    hypergraph! {
        let mut graph: UndirectedHypergraph<_, _> {
            nodes: {
                let a = "a";
                let b = "b";
                let c = "c";
                let d = "d";
            };
            edges: {
                [a, b] = ();
                [a, c] = ();
                [a, d] = ();
                [b, d] = ();
                [c, b] = ();
                [c, d] = ();
            };
        }
    }

    let expected_res: HashMap<(usize, usize), i32> = [
        ((a, a), 0),
        ((a, b), 1),
        ((a, c), 3),
        ((a, d), 3),
        ((b, a), 1),
        ((b, b), 0),
        ((b, c), 2),
        ((b, d), 2),
        ((c, a), 3),
        ((c, b), 2),
        ((c, c), 0),
        ((c, d), 2),
        ((d, a), 3),
        ((d, b), 2),
        ((d, c), 2),
        ((d, d), 0),
    ]
    .iter()
    .cloned()
    .collect();
    let inf = std::i32::MAX;

    let weight_map: HashMap<(usize, usize), i32> = [
        ((a, a), 0),
        ((a, b), 1),
        ((a, c), 4),
        ((a, d), 10),
        ((b, b), 0),
        ((b, d), 2),
        ((c, b), 2),
        ((c, c), 0),
        ((c, d), 2),
    ]
    .iter()
    .cloned()
    .collect();

    let res = floyd_warshall(&graph, |edge| {
        let mut v = graph.contained_nodes(edge).unwrap().into_iter();
        let s = v.next().unwrap();
        let t = v.next().unwrap();
        if let Some(weight) = weight_map.get(&(s, t)) {
            *weight
        } else if let Some(weight) = weight_map.get(&(t, s)) {
            *weight
        } else {
            inf
        }
    })
    .unwrap();

    let nodes = [a, b, c, d];
    for node1 in &nodes {
        for node2 in &nodes {
            println!(
                "Distance from {} to {}: {}",
                graph.node_weight(*node1).unwrap(),
                graph.node_weight(*node2).unwrap(),
                res.get(&(*node1, *node2)).unwrap()
            );
            assert_eq!(
                res.get(&(*node1, *node2)).unwrap(),
                expected_res.get(&(*node1, *node2)).unwrap()
            );
        }
    }
}

#[test]
fn floyd_warshall_negative_cycle() {
    // let mut graph: Graph<(), (), Directed> = Graph::new();
    // let a = graph.add_node(());
    // let b = graph.add_node(());
    // let c = graph.add_node(());

    // graph.extend_with_edges(&[(a, b), (b, c), (c, a)]);

    hypergraph! {
        let mut graph: DirectedHypergraph<_, _> {
            nodes: {
                let a = ();
                let b = ();
                let c = ();
            };
            edges: {
                ([a] -> [b]) = ();
                ([b] -> [c]) = ();
                ([c] -> [a]) = ();
            };
        }
    }

    let inf = std::i32::MAX;

    let weight_map: HashMap<(usize, usize), i32> = [
        ((a, a), 0),
        ((a, b), 1),
        ((b, b), 0),
        ((b, c), -3),
        ((c, c), 0),
        ((c, a), 1),
    ]
    .iter()
    .cloned()
    .collect();

    let res = floyd_warshall(&graph, |edge| {
        let src = *graph.source(edge).unwrap().iter().next().unwrap();
        let tgt = *graph.target(edge).unwrap().iter().next().unwrap();
        if let Some(weight) = weight_map.get(&(src, tgt)) {
            *weight
        } else {
            inf
        }
    });

    assert!(res.is_err());
}