use super::permission::SymbolPermissions;
use crate::dag::arena::DagArena;
use crate::dag::node::DagNodeId;
use crate::dag::symbol::{OpKind, SymbolKind};
pub fn collect_commutative_add_leaves(
arena: &DagArena,
node_id: DagNodeId,
permissions: &SymbolPermissions,
leaves: &mut Vec<DagNodeId>,
) {
if let Some(node) = arena.get(node_id) {
if node.kind == SymbolKind::Operator(OpKind::Add) {
let is_comm = node.children.iter().all(|child_id| {
if let Some(child_node) = arena.get(child_id) {
match child_node.kind {
SymbolKind::Variable(sym_id) => permissions.is_commutative(sym_id),
_ => true,
}
} else {
true
}
});
if is_comm {
for child_id in node.children.iter() {
collect_commutative_add_leaves(arena, child_id, permissions, leaves);
}
return;
}
}
leaves.push(node_id);
}
}
#[must_use]
pub fn split_commutative_tree(
arena: &DagArena,
root: DagNodeId,
permissions: &SymbolPermissions,
num_chunks: usize,
) -> Vec<Vec<DagNodeId>> {
let mut leaves = Vec::new();
collect_commutative_add_leaves(arena, root, permissions, &mut leaves);
if leaves.is_empty() {
return Vec::new();
}
let n = leaves.len();
let num_chunks = num_chunks.clamp(1, n);
let chunk_size = n.div_ceil(num_chunks);
leaves
.chunks(chunk_size)
.map(<[crate::dag::node::DagNodeId]>::to_vec)
.collect()
}