hypergraphx 0.0.5

A hypergraph library for Rust, based on the Python library of the same name.
Documentation
//! This is a massive pain.
//! Box<dyn Any>. Sigh. So many problems.
//!
//! The `MultiplexBase` struct is readonly after init, as creating any layers off it borrows it.
//!
//! The alternative is to greatly reduce the functionality of a layer, which is not ideal.
//!
//! Instead, we have the `Multiplex` struct, which robs the autonomy of Layers, but allows the whole
//! graph to be treated as a single entity.
mod aggregated;
mod directive;
pub mod layers;
mod weak_layers;

use std::{hash::Hash, ops::Index, rc::Rc};

pub use layers::{DirectedLayer, Layer, UndirectedLayer};

pub use aggregated::{MultiplexGraph, MultiplexIndex};

pub struct WildcardEdgeType;

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct MultiplexNode<N> {
    weight: N,
    // Can't put edges here because they'd be of too many types.
    // Also we're not indexing into a single edge array.
    // We might put more stuff here, which is why it's a struct.
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct MultiplexBase<N> {
    nodes: Vec<MultiplexNode<N>>,
}

impl<N> Default for MultiplexBase<N> {
    fn default() -> Self {
        Self { nodes: Vec::new() }
    }
}

impl<N> MultiplexBase<N>
where
    N: Clone,
{
    pub fn iter(&self) -> impl Iterator<Item = &MultiplexNode<N>> {
        self.nodes.iter()
    }

    /// Other graphs don't have the `iter_mut` directly, instead only letting you access the weights.
    /// However, MultiplexNode literally only has one field now, and will *never* store any incidence information.
    /// So enjoy.
    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut MultiplexNode<N>> {
        self.nodes.iter_mut()
    }

    pub fn new(weights: impl Iterator<Item = N>) -> Rc<Self> {
        Rc::new(Self {
            nodes: weights.map(|w| MultiplexNode { weight: w }).collect(),
        })
    }

    pub fn len(self: &Rc<Self>) -> usize {
        self.nodes.len()
    }

    pub fn restrict_to<F, L>(
        self: Rc<Self>,
        f: F,
        layers: &Vec<Layer<N, L>>,
    ) -> (Rc<Self>, Vec<Layer<N, L>>)
    where
        F: Fn(usize, &MultiplexNode<N>) -> bool,
        L: Clone,
    {
        let mut node_map = vec![None; self.nodes.len()];
        let new_base = Self {
            nodes: self
                .nodes
                .iter()
                .enumerate()
                .filter(|(i, n)| f(*i, n))
                .enumerate()
                .map(|(i, (j, n))| {
                    node_map[j] = Some(i);
                    n.clone()
                })
                .collect::<Vec<_>>(),
        };

        // let test = Rc::as_ref(&self);

        let new_layers = layers
            .iter()
            .map(|layer| layer.restrict_to(&node_map))
            .collect();

        (Rc::new(new_base), new_layers)
    }

    pub fn get(&self, index: usize) -> Option<&MultiplexNode<N>> {
        self.nodes.get(index)
    }

    pub fn new_directed_layer<E: 'static, L: 'static>(
        self: Rc<Self>,
        weight: L,
    ) -> DirectedLayer<N, L> {
        DirectedLayer::new::<E>(weight, self.clone())
    }

    pub fn new_undirected_layer<E: 'static, L: 'static>(
        self: Rc<Self>,
        weight: L,
    ) -> UndirectedLayer<N, L>
    where
        L: Clone,
    {
        UndirectedLayer::new::<E>(weight, self.clone())
    }

    pub fn aggreggate<L: Clone>(
        self: Rc<Self>,
        layers: Vec<Layer<N, L>>,
    ) -> Option<MultiplexGraph<N, L>> {
        let layers = layers.into_iter().map(|x| x.weaken()).collect();
        Some(MultiplexGraph { base: self, layers })
    }
}

impl<N> Index<usize> for MultiplexBase<N> {
    type Output = MultiplexNode<N>;

    fn index(&self, index: usize) -> &Self::Output {
        &self.nodes[index]
    }
}