causasv 0.8.5

Causal feature attribution via Asymmetric Shapley Values (ASV) over DAGs — Rust + Python
Documentation
use std::collections::HashMap;

use crate::error::CausasvError;
use crate::graph::NodeId;

pub(crate) fn mask_to_coalition(mut mask: u64) -> Vec<NodeId> {
    let mut out = Vec::with_capacity(mask.count_ones() as usize);
    while mask != 0 {
        let i = mask.trailing_zeros();
        out.push(NodeId(i));
        mask &= mask - 1; // clear lowest set bit
    }
    out
}

pub(crate) fn vec_to_mask(nodes: &[NodeId]) -> u64 {
    nodes.iter().fold(0u64, |m, &n| m | (1u64 << n.0))
}

pub(crate) fn value_cached<F>(
    cache: &mut HashMap<u64, f64>,
    value_fn: &F,
    mask: u64,
) -> Result<f64, CausasvError>
where
    F: Fn(&[NodeId]) -> Result<f64, CausasvError>,
{
    if let Some(&v) = cache.get(&mask) {
        return Ok(v);
    }
    let coalition = mask_to_coalition(mask);
    let v = value_fn(&coalition)?;
    cache.insert(mask, v);
    Ok(v)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn roundtrip() {
        let nodes = vec![NodeId(0), NodeId(2), NodeId(5)];
        assert_eq!(mask_to_coalition(vec_to_mask(&nodes)), nodes);
    }

    #[test]
    fn empty_mask() {
        assert!(mask_to_coalition(0).is_empty());
    }
}