use std::{
cmp::max,
collections::BinaryHeap,
num::{NonZeroU32, NonZeroU64},
};
use awint::awint_dag::triple_arena::{Advancer, Ptr};
use crate::{
route::{ChannelWidths, Channeler, PEmbedding, Programmability, Referent},
utils::SmallSet,
Error,
};
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct InternalBehavior {
pub subnodes_in_tree: usize,
pub lut_bits: usize,
}
impl InternalBehavior {
pub fn empty() -> Self {
Self {
subnodes_in_tree: 1,
lut_bits: 0,
}
}
}
#[derive(Debug, Clone)]
pub struct CNode<PCNode: Ptr, PCEdge: Ptr> {
pub p_this_cnode: PCNode,
pub lvl: u16,
pub p_supernode: Option<PCNode>,
pub internal_behavior: InternalBehavior,
pub embeddings: SmallSet<PEmbedding>,
pub alg_visit: NonZeroU64,
pub alg_entry_width: usize,
pub alg_edge: (Option<PCEdge>, usize),
}
impl<PCNode: Ptr, PCEdge: Ptr> CNode<PCNode, PCEdge> {
pub fn internal_behavior(&self) -> &InternalBehavior {
&self.internal_behavior
}
}
impl<PCNode: Ptr, PCEdge: Ptr> Channeler<PCNode, PCEdge> {
pub fn make_top_level_cnode<I>(
&mut self,
subnodes: I,
lvl: u16,
internal_behavior: InternalBehavior,
) -> PCNode
where
I: IntoIterator<Item = PCNode>,
{
let p_cnode = self.cnodes.insert_with(|p_this_cnode| {
(Referent::ThisCNode, CNode {
p_this_cnode,
lvl,
p_supernode: None,
internal_behavior,
embeddings: SmallSet::new(),
alg_visit: NonZeroU64::new(1).unwrap(),
alg_entry_width: 0,
alg_edge: (None, 0),
})
});
for p_subnode in subnodes {
if let Some(p) = self.top_level_cnodes.find_key(&p_subnode) {
self.top_level_cnodes.remove(p).unwrap();
}
let p_supernode = self
.cnodes
.insert_key(p_cnode, Referent::SubNode(p_subnode))
.unwrap();
let cnode = self.cnodes.get_val_mut(p_subnode).unwrap();
cnode.p_supernode = Some(p_supernode);
}
let _ = self.top_level_cnodes.insert(p_cnode, ());
p_cnode
}
#[must_use]
pub fn get_supernode_referent(&self, p: PCNode) -> Option<PCNode> {
self.cnodes.get_val(p)?.p_supernode
}
#[must_use]
pub fn get_supernode(&self, p: PCNode) -> Option<PCNode> {
let p_supernode_ref = self.cnodes.get_val(p)?.p_supernode?;
Some(self.cnodes.get_val(p_supernode_ref)?.p_this_cnode)
}
pub fn find_common_supernode(&self, p_back0: PCNode, p_back1: PCNode) -> Option<PCNode> {
let cnode0 = self.cnodes.get_val(p_back0).unwrap();
let mut lvl0 = cnode0.lvl;
let mut p_cnode0 = cnode0.p_this_cnode;
let cnode1 = self.cnodes.get_val(p_back1).unwrap();
let mut lvl1 = cnode1.lvl;
let mut p_cnode1 = cnode1.p_this_cnode;
loop {
if p_cnode0 == p_cnode1 {
return Some(p_cnode0)
}
if lvl0 < lvl1 {
if let Some(p_super_cnode) = self.get_supernode(p_cnode0) {
p_cnode0 = p_super_cnode;
} else {
return None
}
lvl0 += 1;
} else if lvl0 > lvl1 {
if let Some(p_super_cnode) = self.get_supernode(p_cnode1) {
p_cnode1 = p_super_cnode;
} else {
return None
}
lvl1 += 1;
} else {
break
}
}
loop {
if let Some(p_super_cnode) = self.get_supernode(p_cnode0) {
p_cnode0 = p_super_cnode;
} else {
return None
}
if let Some(p_super_cnode) = self.get_supernode(p_cnode1) {
p_cnode1 = p_super_cnode;
} else {
return None
}
if p_cnode0 == p_cnode1 {
return Some(p_cnode0)
}
}
}
}
pub fn generate_hierarchy<PCNode: Ptr, PCEdge: Ptr>(
channeler: &mut Channeler<PCNode, PCEdge>,
) -> Result<(), Error> {
let mut final_top_level_cnodes = Vec::<PCNode>::new();
let mut possibly_single_subnode = Vec::<PCNode>::new();
let mut next_level_cnodes = Vec::<PCNode>::new();
let mut priority = BinaryHeap::<(usize, PCNode)>::new();
for cnode in channeler.cnodes.vals() {
if cnode.lvl != 0 {
return Err(Error::OtherStr(
"hierarchy appears to have been generated before",
))
}
priority.push((0, cnode.p_this_cnode));
}
let mut current_lvl = 0u16;
'outer: loop {
let p_consider = if let Some((_, p_consider)) = priority.pop() {
p_consider
} else {
if next_level_cnodes.is_empty() {
break
}
current_lvl = current_lvl.checked_add(1).unwrap();
generate_hierarchy_level(
current_lvl,
channeler,
&mut priority,
&mut possibly_single_subnode,
&mut next_level_cnodes,
)?;
continue;
};
let cnode = channeler.cnodes.get_val(p_consider).unwrap();
if cnode.p_supernode.is_some() {
continue
}
let related = channeler.related_nodes(p_consider);
if related.len() == 1 {
final_top_level_cnodes.push(p_consider);
continue
}
let mut subnodes_in_tree = 0usize;
let mut lut_bits = 0usize;
for p_related in related.iter().copied() {
let related_cnode = channeler.cnodes.get_val(p_related).unwrap();
subnodes_in_tree = subnodes_in_tree
.checked_add(related_cnode.internal_behavior.subnodes_in_tree)
.unwrap();
lut_bits = lut_bits
.checked_add(related_cnode.internal_behavior.lut_bits)
.unwrap();
if related_cnode.p_supernode.is_some() {
possibly_single_subnode.push(p_consider);
continue 'outer
}
}
let p_next_lvl = channeler.make_top_level_cnode(
related.iter().copied(),
current_lvl.checked_add(1).unwrap(),
InternalBehavior {
subnodes_in_tree,
lut_bits,
},
);
next_level_cnodes.push(p_next_lvl);
}
if channeler.top_level_cnodes.len() > 1 {
let mut set = vec![];
let mut max_lvl = 0;
let mut subnodes_in_tree = 0usize;
let mut lut_bits = 0usize;
for p_cnode in channeler.top_level_cnodes.keys().copied() {
set.push(p_cnode);
let cnode = channeler.cnodes.get_val(p_cnode).unwrap();
subnodes_in_tree = subnodes_in_tree
.checked_add(cnode.internal_behavior.subnodes_in_tree)
.unwrap();
lut_bits = lut_bits
.checked_add(cnode.internal_behavior().lut_bits)
.unwrap();
max_lvl = max(max_lvl, cnode.lvl);
}
channeler.make_top_level_cnode(set, max_lvl.checked_add(1).unwrap(), InternalBehavior {
subnodes_in_tree,
lut_bits,
});
}
Ok(())
}
pub fn generate_hierarchy_level<PCNode: Ptr, PCEdge: Ptr>(
current_lvl: u16,
channeler: &mut Channeler<PCNode, PCEdge>,
priority: &mut BinaryHeap<(usize, PCNode)>,
possibly_single_subnode: &mut Vec<PCNode>,
next_level_cnodes: &mut Vec<PCNode>,
) -> Result<(), Error> {
for p in possibly_single_subnode.drain(..) {
let cnode = channeler.cnodes.get_val(p).unwrap();
if cnode.p_supernode.is_some() {
continue
}
let p_next_lvl =
channeler.make_top_level_cnode([p], current_lvl, cnode.internal_behavior().clone());
next_level_cnodes.push(p_next_lvl);
}
for p_consider in next_level_cnodes.drain(..) {
let direct_subnode_visit = channeler.next_alg_visit();
let mut subnode_set = vec![];
let mut subnode_adv = channeler.advancer_subnodes_of_node(p_consider);
while let Some(p_subnode) = subnode_adv.advance(channeler) {
channeler.cnodes.get_val_mut(p_subnode).unwrap().alg_visit = direct_subnode_visit;
subnode_set.push(p_subnode);
}
let related_visit = channeler.next_alg_visit();
let mut source_set = vec![];
let mut channel_widths = ChannelWidths::empty();
let mut lut_bits = 0usize;
for p_subnode in subnode_set.iter().copied() {
let mut adv = channeler.cnodes.advancer_surject(p_subnode);
while let Some(p_referent) = adv.advance(&channeler.cnodes) {
if let Referent::CEdgeIncidence(p_cedge, i) =
*channeler.cnodes.get_key(p_referent).unwrap()
{
if i.is_none() {
let cedge = channeler.cedges.get_mut(p_cedge).unwrap();
let w = match cedge.programmability() {
Programmability::TNode => 1,
Programmability::StaticLut(lut) => {
lut_bits = lut_bits.checked_add(lut.bw()).unwrap();
1
}
Programmability::ArbitraryLut(arbitrary_lut) => {
lut_bits = lut_bits
.checked_add(arbitrary_lut.lut_config().len())
.unwrap();
1
}
Programmability::SelectorLut(_) => 1,
Programmability::Bulk(bulk) => bulk.channel_exit_width,
};
channel_widths.channel_exit_width =
channel_widths.channel_exit_width.checked_add(w).unwrap();
for (i, p_incident) in cedge.sources().iter().copied().enumerate() {
let cnode = channeler.cnodes.get_val_mut(p_incident).unwrap();
if cnode.alg_visit != direct_subnode_visit {
let p_supernode = cnode.p_supernode.unwrap();
let supernode = channeler.cnodes.get_val_mut(p_supernode).unwrap();
if supernode.alg_visit != related_visit {
supernode.alg_visit = related_visit;
supernode.alg_entry_width = 0;
source_set.push(supernode.p_this_cnode);
}
let w = match cedge.programmability() {
Programmability::TNode
| Programmability::StaticLut(_)
| Programmability::ArbitraryLut(_)
| Programmability::SelectorLut(_) => 1,
Programmability::Bulk(bulk) => bulk.channel_entry_widths[i],
};
supernode.alg_entry_width =
supernode.alg_entry_width.checked_add(w).unwrap();
}
}
}
}
}
}
let internal_behavior = &mut channeler
.cnodes
.get_val_mut(p_consider)
.unwrap()
.internal_behavior;
internal_behavior.lut_bits = internal_behavior.lut_bits.checked_add(lut_bits).unwrap();
let channel_exit_width = channel_widths.channel_exit_width;
priority.push((channel_exit_width, p_consider));
if !source_set.is_empty() {
for source in source_set.iter().cloned() {
let cnode = channeler.cnodes.get_val(source).unwrap();
channel_widths
.channel_entry_widths
.push(cnode.alg_entry_width);
}
channeler.make_cedge(
&source_set,
p_consider,
Programmability::Bulk(channel_widths),
NonZeroU32::new(
u32::try_from(channel_exit_width.clamp(1, u32::MAX as usize)).unwrap(),
)
.unwrap(),
);
}
}
Ok(())
}