use std::collections::HashSet;
use uuid::Uuid;
use crate::structs::EdgeDirection;
use crate::{
structs::{ConstGenBitBasis, EdgeID, EdgeWeight, GeneroEdge, GeneroGraph},
traits::{HgBasis, HyperGraph},
utils::PowerSetBits,
};
#[derive(Debug)]
pub struct StackGraph<const K: usize> {
pub name: String,
graph: GeneroGraph<ConstGenBitBasis<K>>,
}
impl<const K: usize> StackGraph<K> {
pub fn new() -> Self {
StackGraph {
name: "".to_string(),
graph: GeneroGraph::new(),
}
}
pub fn create_edge(
&mut self,
inputs: &[u32],
outputs: &[u32],
weight: EdgeWeight,
direction: EdgeDirection,
) -> u128 {
let mut pb = PowerSetBits { bits: [0; K] };
for input in inputs {
pb.flip_kth_bit(*input);
}
let mut input_basis = pb.to_bit_nodes();
let mut pb = PowerSetBits { bits: [0; K] };
for output in outputs {
pb.flip_kth_bit(*output);
}
let output_basis = pb.to_bit_nodes();
match direction {
EdgeDirection::Directed | EdgeDirection::Symmetric | EdgeDirection::Oriented => {
let e = GeneroEdge::from(input_basis, output_basis, weight, direction);
let id = e.id.clone();
self.graph.add_edge(e);
id.as_u128()
}
EdgeDirection::Loop | EdgeDirection::Undirected => {
input_basis.union_with(&output_basis);
let e = GeneroEdge::from(input_basis, ConstGenBitBasis::new(), weight, direction);
let id = e.id.clone();
self.graph.add_edge(e);
id.as_u128()
}
}
}
pub fn remove_edge(&mut self, edge_id: &u128) {
let id = Uuid::from_u128(*edge_id);
self.graph.remove_edge(&id);
}
pub fn step(&self, start_nodes: &[u32]) -> Vec<(HashSet<u32>, EdgeWeight)> {
let mut pb = PowerSetBits { bits: [0; K] };
for node in start_nodes {
pb.flip_kth_bit(*node);
}
let start_basis = pb.to_bit_nodes();
let out = self.graph.map_basis(&start_basis);
let v = out.to_tuples();
v.into_iter().map(|(b, w)| (b.to_u32(), w)).collect()
}
}
impl<const K: usize> HyperGraph for StackGraph<K> {
type Basis = ConstGenBitBasis<K>;
fn edges(&self) -> Vec<crate::structs::EdgeID> {
self.graph.clone_edges()
}
fn get_outbound_edges(&self, node: &Self::Basis) -> Vec<EdgeID> {
self.graph.get_outbound_edges(node).into_iter().collect()
}
fn query_edges(
&self,
input: &Self::Basis,
output: &Self::Basis,
) -> Vec<crate::structs::EdgeID> {
self.graph.query_edges(input, output)
}
fn query_weight(&self, input: &Self::Basis, output: &Self::Basis) -> EdgeWeight {
self.graph.query_weight(input, output)
}
fn map_basis(&self, input: &Self::Basis) -> Vec<(Self::Basis, EdgeWeight)> {
self.graph.map_basis(input).to_tuples()
}
fn map_vector(
&self,
input: &crate::structs::GeneroVector<Self::Basis>,
) -> crate::structs::GeneroVector<Self::Basis> {
self.graph.map(input)
}
}
mod test {
use crate::{stackgraph::StackGraph, EdgeDirection};
#[test]
fn test_bit_graph_new() {
const n: usize = 80 / 8;
let sg = StackGraph::<n>::new();
println!("sg: {:#?}", sg);
}
#[test]
fn test_directed_edge_creation() {
const n: usize = 80 / 8;
let mut sg = StackGraph::<n>::new();
sg.create_edge(&[0, 1, 2], &[1, 2, 3], 1., EdgeDirection::Symmetric);
println!("sg: {:#?}", sg);
}
#[test]
fn test_step() {
const n: usize = 80 / 8;
let mut sg = StackGraph::<n>::new();
sg.create_edge(&[0, 1, 2], &[1, 2, 3], 1., EdgeDirection::Symmetric);
sg.create_edge(&[0, 1, 2], &[], 1., EdgeDirection::Loop);
println!("sg: {:#?}", sg);
println!("step output: {:#?}", sg.step(&[0, 1, 2]));
}
}