use std::{
collections::{HashMap, HashSet},
hash::Hash,
};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::traits::HgBasis;
use super::{
generic_edge::{EdgeDirection, GeneroEdge},
generic_vec::GeneroVector,
EdgeID, EdgeWeight, GraphID,
};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GeneroGraph<B: HgBasis> {
pub id: GraphID,
pub edges: HashMap<EdgeID, GeneroEdge<B>>,
node_to_outbound_edges: HashMap<B, HashSet<EdgeID>>,
}
impl<B: HgBasis> GeneroGraph<B> {
pub fn new() -> Self {
GeneroGraph {
id: Uuid::new_v4(),
edges: HashMap::new(),
node_to_outbound_edges: HashMap::new(),
}
}
pub fn clone_edges(&self) -> Vec<EdgeID> {
self.edges.keys().cloned().collect()
}
pub fn update_edge_weight(&mut self, edge_id: &EdgeID, new_weight: EdgeWeight) {
if new_weight.is_nan() == false {
if let Some(e) = self.edges.get_mut(edge_id) {
e.change_weight(new_weight);
}
}
}
pub fn get_outbound_edges(&self, basis: &B) -> HashSet<EdgeID> {
let mut ret = HashSet::new();
for node in basis.nodes() {
if let Some(potentials) = self.node_to_outbound_edges.get(&node) {
for edge_id in potentials {
if let Some(edge) = self.edges.get(edge_id) {
if edge.can_map_basis(basis) {
ret.insert(edge_id.clone());
}
}
}
}
}
ret
}
pub fn query_edge(&self, edge_id: &EdgeID) -> Option<GeneroEdge<B>> {
self.edges.get(edge_id).cloned()
}
pub fn get_containing_edges(&self, basis: &B) -> HashSet<EdgeID> {
let mut ret = HashSet::new();
for (id, edge) in self.edges.iter() {
if edge.contains(basis) {
ret.insert(id.clone());
}
}
ret
}
pub fn add_edge(&mut self, new_edge: GeneroEdge<B>) {
match new_edge.direction {
EdgeDirection::Directed => {
for node in new_edge.in_nodes.nodes() {
self.node_to_outbound_edges
.entry(node)
.or_default()
.insert(new_edge.id.clone());
}
self.edges.insert(new_edge.id.clone(), new_edge);
}
EdgeDirection::Loop => {
for node in new_edge.in_nodes.nodes() {
self.node_to_outbound_edges
.entry(node)
.or_default()
.insert(new_edge.id.clone());
}
self.edges.insert(new_edge.id.clone(), new_edge);
}
EdgeDirection::Oriented | EdgeDirection::Symmetric => {
for node in new_edge.in_nodes.nodes() {
self.node_to_outbound_edges
.entry(node)
.or_default()
.insert(new_edge.id.clone());
}
for node in new_edge.out_nodes.nodes() {
self.node_to_outbound_edges
.entry(node)
.or_default()
.insert(new_edge.id.clone());
}
self.edges.insert(new_edge.id.clone(), new_edge);
}
EdgeDirection::Undirected => {
for node in new_edge.in_nodes.nodes() {
self.node_to_outbound_edges
.entry(node)
.or_default()
.insert(new_edge.id.clone());
}
self.edges.insert(new_edge.id.clone(), new_edge);
}
}
}
pub fn remove_edge(&mut self, edge_id: &EdgeID) -> Option<GeneroEdge<B>> {
if let Some(edge) = self.edges.remove(edge_id) {
match edge.direction {
EdgeDirection::Directed | EdgeDirection::Loop => {
for node in edge.in_nodes.nodes() {
if let Some(set) = self.node_to_outbound_edges.get_mut(&node) {
set.remove(edge_id);
}
}
Some(edge)
}
EdgeDirection::Oriented | EdgeDirection::Symmetric => {
for node in edge.in_nodes.nodes() {
if let Some(set) = self.node_to_outbound_edges.get_mut(&node) {
set.remove(edge_id);
}
}
for node in edge.out_nodes.nodes() {
if let Some(set) = self.node_to_outbound_edges.get_mut(&node) {
set.remove(edge_id);
}
}
Some(edge)
}
EdgeDirection::Undirected => {
for node in edge.in_nodes.nodes() {
if let Some(set) = self.node_to_outbound_edges.get_mut(&node) {
set.remove(edge_id);
}
}
Some(edge)
}
}
} else {
None
}
}
pub fn edges_of_size(&self, size: usize) -> Vec<EdgeID> {
self.edges
.iter()
.filter_map(|(k, v)| {
if v.input_cardinality() == size {
Some(k)
} else {
None
}
})
.cloned()
.collect()
}
pub fn change_edge_input(&mut self, edge_id: &EdgeID, new_input: B) {
if let Some(mut e) = self.remove_edge(edge_id) {
e.change_input(new_input);
self.add_edge(e);
}
}
pub fn change_edge_output(&mut self, edge_id: &EdgeID, new_output: B) {
if let Some(mut e) = self.remove_edge(edge_id) {
e.change_output(new_output);
self.add_edge(e);
}
}
pub fn query_weight(&self, input: &B, output: &B) -> EdgeWeight {
let mut ret = 0.;
for (b, w) in self.map_basis(input).to_tuples() {
if b == *output {
ret += w;
}
}
ret
}
pub fn query_edges(&self, input: &B, output: &B) -> Vec<EdgeID> {
let outbounds = self.get_outbound_edges(input);
outbounds
.into_iter()
.filter(|e| {
if let Some(edge) = self.edges.get(e) {
edge.is_correctly_mapped(input, output)
} else {
false
}
})
.collect()
}
pub fn query_undirected(&self, input: &B) -> Vec<EdgeID> {
let mut potential_edges = HashSet::new();
for node in input.nodes() {
if potential_edges.len() == 0 && self.node_to_outbound_edges.contains_key(&node) {
potential_edges = potential_edges
.union(self.node_to_outbound_edges.get(&node).unwrap())
.cloned()
.collect();
} else if potential_edges.len() > 0 && self.node_to_outbound_edges.contains_key(&node) {
potential_edges = potential_edges
.intersection(self.node_to_outbound_edges.get(&node).unwrap())
.cloned()
.collect();
}
}
potential_edges
.into_iter()
.filter(|potential_edge| {
if let Some(e) = self.edges.get(&potential_edge) {
e.matches_undirected(input)
} else {
false
}
})
.collect()
}
pub fn query_loop(&self, input: &B) -> Vec<Uuid> {
let possible_loops = self.get_outbound_edges(input);
possible_loops
.into_iter()
.filter(|id| {
if let Some(e) = self.edges.get(id) {
e.is_correctly_mapped(input, input)
} else {
false
}
})
.collect()
}
pub fn map_basis(&self, input: &B) -> GeneroVector<B> {
let mut ret = GeneroVector::new();
let mut good_edges = HashSet::new();
for node in input.nodes() {
if let Some(edges) = self.node_to_outbound_edges.get(&node) {
for edge_id in edges {
if let Some(edge) = self.edges.get(edge_id) {
if edge.can_map_basis(input) {
good_edges.insert(edge_id);
}
}
}
}
}
for edge_id in good_edges {
let e = self
.edges
.get(edge_id)
.expect("This was checked in prior loop.");
ret += &e.map_to_vector(input);
}
ret
}
pub fn map(&self, input: &GeneroVector<B>) -> GeneroVector<B> {
let ret = GeneroVector::new();
for (b, w) in input.basis_to_weight.iter() {
let mut tmp = self.map_basis(&b);
tmp *= *w;
}
ret
}
}
impl<B: HgBasis> Hash for GeneroGraph<B> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
mod tests {
use crate::{structs::{GeneroEdge, GeneroGraph}, SparseBasis};
#[test]
fn test_serialization() {
let mut g: GeneroGraph<SparseBasis<u32>> = GeneroGraph::new();
let e = GeneroEdge::from(
SparseBasis::<u32>::from(&1),
SparseBasis::from(&2),
1.,
crate::EdgeDirection::Symmetric,
);
g.add_edge(e);
let s = serde_json::to_string(&g).expect("could not serialize graph");
dbg!(s);
}
}