calc-graph 0.4.2

Efficient calculations on a graph of values
Documentation
extern crate calc_graph;

use std::collections::HashMap;
use std::sync::Arc;
use std::time::{Duration, SystemTime};

use calc_graph::{Calc, Graph, Node, SharedNode, Source};

type BSNode<T> = SharedNode<Box<Calc<Value = T> + Send>>;

fn timed<T>(name: &str, f: impl FnOnce() -> T) -> T {
    let start_time = SystemTime::now();
    let result = f();
    let duration = start_time.elapsed().unwrap_or(Duration::default());
    println!(
        "{} took {}µs",
        name,
        duration.as_secs() as u64 * 1_000_000 + duration.subsec_micros() as u64
    );
    result
}

fn node(
    nodes: &mut HashMap<(u32, u32), BSNode<Arc<[u64; 32]>>>,
    n: u32,
    k: u32,
) -> BSNode<Arc<[u64; 32]>> {
    if let Some(node) = nodes.get(&(n, k)) {
        return node.clone();
    }

    if k == 0 || k >= n {
        return node(nodes, 0, 0);
    }

    assert!(n >= 1, "n = {} k = {}", n, k);
    assert!(k >= 1, "n = {} k = {}", n, k);

    let node = Node::zip_update(
        node(nodes, n - 1, k - 1),
        node(nodes, n - 1, k),
        Arc::new([0; 32]),
        |sum, x, y| {
            let sum = Arc::make_mut(sum);
            for i in 0..32 {
                sum[i] = x[i] + y[i];
            }

            true
        },
    ).boxed()
        .shared();

    nodes.insert((n, k), node.clone());
    node
}

fn setup() -> (
    Node<Source<Arc<[u64; 32]>>>,
    BSNode<Arc<[u64; 32]>>,
    HashMap<(u32, u32), BSNode<Arc<[u64; 32]>>>,
) {
    let graph = Graph::new();
    let n1 = graph.source(Arc::new([1; 32]));
    let mut nodes = HashMap::new();
    nodes.insert((0, 0), n1.clone().boxed().shared());
    (n1, node(&mut nodes, 80, 20), nodes)
}

fn main() {
    setup();

    let (n1, last, nodes) = timed("setup", || setup());

    assert_eq!(1201, nodes.len());
    assert_eq!(3_535_316_142_212_174_320, timed("calc", || last.get())[0]);
    assert_eq!(
        3_535_316_142_212_174_320,
        timed("cached 1", || last.get())[0]
    );

    timed("dirty", || {
        n1.update(|mut prev| {
            *Arc::make_mut(&mut prev) = [2; 32];
            true
        })
    });

    assert_eq!(7_070_632_284_424_348_640, timed("recalc", || last.get())[0]);
    assert_eq!(
        7_070_632_284_424_348_640,
        timed("cached 2", || last.get())[0]
    );
}