use std::collections::{HashMap, VecDeque};
use std::hash::Hash;
use crate::graph::graph_classifier::{GraphClass, GraphValue};
use crate::graph::graph_query::GraphQuery;
use crate::graph::graph_view::GraphView;
use crate::pattern::Pattern;
fn topo_shape_sort<Extra, V: GraphValue>(elems: &[(GraphClass<Extra>, Pattern<V>)]) -> Vec<usize>
where
V::Id: Eq + Hash + Clone,
{
let mut buckets: [Vec<usize>; 5] = [Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new()];
for (i, (cls, _)) in elems.iter().enumerate() {
let rank = match cls {
GraphClass::GNode => 0,
GraphClass::GRelationship => 1,
GraphClass::GWalk => 2,
GraphClass::GAnnotation => 3,
GraphClass::GOther(_) => 4,
};
buckets[rank].push(i);
}
let mut result = Vec::with_capacity(elems.len());
for (rank, bucket) in buckets.iter().enumerate() {
if rank >= 3 {
result.extend(within_bucket_topo_sort(elems, bucket));
} else {
result.extend_from_slice(bucket);
}
}
result
}
fn within_bucket_topo_sort<Extra, V: GraphValue>(
elems: &[(GraphClass<Extra>, Pattern<V>)],
bucket: &[usize],
) -> Vec<usize>
where
V::Id: Eq + Hash + Clone,
{
if bucket.is_empty() {
return Vec::new();
}
let n = bucket.len();
let id_to_bucket_pos: HashMap<V::Id, usize> = bucket
.iter()
.enumerate()
.map(|(pos, &idx)| (elems[idx].1.value.identify().clone(), pos))
.collect();
let mut in_degree = vec![0usize; n];
let mut dependents: Vec<Vec<usize>> = vec![Vec::new(); n];
for pos in 0..n {
let (_, p) = &elems[bucket[pos]];
for e in &p.elements {
let eid = e.value.identify();
if let Some(&dep_pos) = id_to_bucket_pos.get(eid) {
in_degree[pos] += 1;
dependents[dep_pos].push(pos);
}
}
}
let mut queue: VecDeque<usize> = (0..n).filter(|&pos| in_degree[pos] == 0).collect();
let mut sorted_positions: Vec<usize> = Vec::with_capacity(n);
while let Some(pos) = queue.pop_front() {
sorted_positions.push(pos);
for &succ_pos in &dependents[pos] {
in_degree[succ_pos] -= 1;
if in_degree[succ_pos] == 0 {
queue.push_back(succ_pos);
}
}
}
let mut in_sorted = vec![false; n];
for &pos in &sorted_positions {
in_sorted[pos] = true;
}
for (pos, &included) in in_sorted.iter().enumerate() {
if !included {
sorted_positions.push(pos);
}
}
sorted_positions.iter().map(|&pos| bucket[pos]).collect()
}
fn para_graph_with_seed<Extra, V: GraphValue, R: Clone>(
f: &impl Fn(&GraphQuery<V>, &Pattern<V>, &[R]) -> R,
view: &GraphView<Extra, V>,
seed: HashMap<V::Id, R>,
) -> HashMap<V::Id, R>
where
V::Id: Eq + Hash + Clone,
{
let query = &view.view_query;
let order = topo_shape_sort(&view.view_elements);
let mut acc = seed;
for i in order {
let (_, p) = &view.view_elements[i];
let sub_results: Vec<R> = p
.elements
.iter()
.filter_map(|e| acc.get(e.value.identify()).cloned())
.collect();
let r = f(query, p, &sub_results);
acc.insert(p.value.identify().clone(), r);
}
acc
}
#[inline]
pub fn para_graph<Extra, V: GraphValue, R: Clone>(
f: impl Fn(&GraphQuery<V>, &Pattern<V>, &[R]) -> R,
view: &GraphView<Extra, V>,
) -> HashMap<V::Id, R>
where
V::Id: Eq + Hash + Clone,
{
para_graph_with_seed(&f, view, HashMap::new())
}
#[inline]
pub fn para_graph_fixed<Extra, V: GraphValue, R: Clone>(
converged: impl Fn(&R, &R) -> bool,
f: impl Fn(&GraphQuery<V>, &Pattern<V>, &[R]) -> R,
init: R,
view: &GraphView<Extra, V>,
) -> HashMap<V::Id, R>
where
V::Id: Eq + Hash + Clone,
{
let mut current: HashMap<V::Id, R> = view
.view_elements
.iter()
.map(|(_, p)| (p.value.identify().clone(), init.clone()))
.collect();
loop {
let next = para_graph_with_seed(&f, view, current.clone());
let all_converged = next
.iter()
.all(|(k, new_r)| current.get(k).is_some_and(|old_r| converged(old_r, new_r)));
current = next;
if all_converged {
break;
}
}
current
}