use std::{
cmp::{max, Reverse},
collections::BinaryHeap,
num::NonZeroU64,
};
use awint::awint_dag::triple_arena::Advancer;
use crate::{
route::{Edge, EdgeKind, EmbeddingKind, PEmbedding, QCNode, Referent, Router},
Error,
};
pub(crate) fn route(router: &mut Router) -> Result<(), Error> {
let mut max_lvl = 0;
for q_cnode in router.target_channeler().top_level_cnodes.keys() {
let cnode = router.target_channeler().cnodes.get_val(*q_cnode).unwrap();
max_lvl = max(max_lvl, cnode.lvl);
}
loop {
if max_lvl == 0 {
break
}
max_lvl = max_lvl.checked_sub(1).unwrap();
route_level(router, max_lvl)?;
}
Ok(())
}
fn route_level(router: &mut Router, max_lvl: u16) -> Result<(), Error> {
let max_loops = 1u64;
for _ in 0..max_loops {
let violations = false;
let mut adv = router.embeddings().advancer();
while let Some(p_embedding) = adv.advance(router.embeddings()) {
route_embedding(router, max_lvl, p_embedding)?;
}
if !violations {
break
}
}
Ok(())
}
fn route_embedding(
router: &mut Router,
max_lvl: u16,
p_embedding: PEmbedding,
) -> Result<(), Error> {
let embedding = router.embeddings.get(p_embedding).unwrap();
match embedding.program {
EmbeddingKind::Edge(_) => todo!(),
EmbeddingKind::Node(_) => {
let q_source = embedding.target_hyperpath.source();
let source = router.target_channeler().cnodes.get_val(q_source).unwrap();
let source_lvl = source.lvl;
assert!(source_lvl <= max_lvl);
let len = embedding.target_hyperpath.paths().len();
for path_i in 0..len {
loop {
let path = &router
.embeddings
.get(p_embedding)
.unwrap()
.target_hyperpath
.paths()[path_i];
let mut node_lvl = source_lvl;
let mut edge_i = None;
let mut edge_end_i = None;
for (i, edge) in path.edges().iter().copied().enumerate() {
match edge.kind {
EdgeKind::Transverse(..) => (),
EdgeKind::Concentrate => {
node_lvl = node_lvl.checked_add(1).unwrap();
edge_i = Some(i);
edge_end_i = None;
}
EdgeKind::Dilute => {
node_lvl = node_lvl.checked_sub(1).unwrap();
if edge_end_i.is_none() {
edge_end_i = Some(i);
}
}
}
}
if let Some(edge_i) = edge_i {
if let Some(edge_end_i) = edge_end_i {
let found =
dilute_plateau(router, p_embedding, path_i, edge_i, edge_end_i)?;
if !found {
return Err(Error::OtherString(format!(
"could not find possible routing (disregarding width \
constraints) for embedding {p_embedding:?}, unless this is a \
poorly connected target or edge case, then this is probably \
a bug with the router"
)));
}
} else {
unreachable!();
}
} else {
break
}
}
}
}
}
Ok(())
}
fn dilute_plateau(
router: &mut Router,
p_embedding: PEmbedding,
path_i: usize,
edge_i: usize,
edge_end_i: usize,
) -> Result<bool, Error> {
let embedding = router.embeddings.get(p_embedding).unwrap();
let q_source = embedding.target_hyperpath.source();
let path = &embedding.target_hyperpath.paths()[path_i];
let start = if edge_i == 0 {
q_source
} else {
path.edges()[edge_i - 1].to
};
let end = path.edges()[edge_end_i].to;
let cnode = router.target_channeler.cnodes.get_val(start).unwrap();
let mut max_backbone_lvl = if cnode.p_supernode.is_some() {
Some(cnode.lvl + 1)
} else {
None
};
let backbone_visit = router.target_channeler.next_alg_visit();
for edge in &path.edges()[edge_i..edge_end_i] {
router
.target_channeler
.cnodes
.get_val_mut(edge.to)
.unwrap()
.alg_visit = backbone_visit;
}
loop {
let found =
route_path_on_level(router, backbone_visit, max_backbone_lvl, start, end).unwrap();
if found {
break
}
if max_backbone_lvl.is_none() {
return Ok(false)
}
max_backbone_lvl = max_backbone_lvl.map(|x| x + 1);
let embedding = router.embeddings.get(p_embedding).unwrap();
let path = &embedding.target_hyperpath.paths()[path_i];
for edge in &path.edges()[edge_i..edge_end_i] {
let mut q_supernode = router
.target_channeler
.cnodes
.get_val(edge.to)
.unwrap()
.p_supernode;
loop {
if let Some(q) = q_supernode {
let cnode = router.target_channeler.cnodes.get_val_mut(q).unwrap();
if cnode.lvl == max_backbone_lvl.unwrap() {
cnode.alg_visit = backbone_visit;
break
}
q_supernode = cnode.p_supernode;
} else {
return Ok(false)
}
}
}
}
let mut new_path = vec![];
let mut q_cnode = end;
loop {
let cnode = router.target_channeler.cnodes.get_val_mut(q_cnode).unwrap();
if let (Some(q_cedge), j) = cnode.alg_edge {
let cedge = router.target_channeler.cedges.get(q_cedge).unwrap();
new_path.push(Edge {
kind: EdgeKind::Transverse(q_cedge, j),
to: cnode.p_this_cnode,
});
q_cnode = cedge.sources()[j];
} else {
break
}
}
let edges = router
.embeddings
.get(p_embedding)
.unwrap()
.target_hyperpath
.paths()[path_i]
.edges();
let mut completed_path = edges[..edge_i].to_vec();
while let Some(edge) = new_path.pop() {
completed_path.push(edge);
}
completed_path.extend(edges[(edge_end_i + 1)..].iter().copied());
router
.embeddings
.get_mut(p_embedding)
.unwrap()
.target_hyperpath
.paths_mut()[path_i]
.edges = completed_path;
Ok(true)
}
fn route_path_on_level(
router: &mut Router,
backbone_visit: NonZeroU64,
max_backbone_lvl: Option<u16>,
start: QCNode,
end: QCNode,
) -> Result<bool, Error> {
let front_visit = router.target_channeler.next_alg_visit();
let mut priority = BinaryHeap::new();
let cnode = router.target_channeler.cnodes.get_val_mut(start).unwrap();
let route_lvl = cnode.lvl;
cnode.alg_visit = front_visit;
cnode.alg_edge.0 = None;
let mut adv = router.target_channeler.cnodes.advancer_surject(start);
while let Some(q_referent) = adv.advance(&router.target_channeler.cnodes) {
if let Referent::CEdgeIncidence(q_cedge, Some(source_j)) =
*router.target_channeler.cnodes.get_key(q_referent).unwrap()
{
let cedge = router.target_channeler.cedges.get(q_cedge).unwrap();
priority.push(Reverse((
cedge.delay_weight.get().saturating_add(cedge.lagrangian),
q_cedge,
source_j,
)));
}
}
let mut found = false;
while let Some(Reverse((cost, q_cedge, source_j))) = priority.pop() {
let cedge = router.target_channeler.cedges.get(q_cedge).unwrap();
let q_cnode = cedge.sink();
let cnode = router.target_channeler.cnodes.get_val_mut(q_cnode).unwrap();
let q_cnode = cnode.p_this_cnode;
if cnode.alg_visit != front_visit {
cnode.alg_visit = front_visit;
cnode.alg_edge = (Some(q_cedge), source_j);
if q_cnode == end {
found = true;
break
}
let mut lvl = route_lvl;
let mut q_cnode_consider = q_cnode;
let mut use_it = false;
if let Some(max_backbone_lvl) = max_backbone_lvl {
while lvl <= max_backbone_lvl {
let cnode_consider = router
.target_channeler
.cnodes
.get_val(q_cnode_consider)
.unwrap();
if cnode_consider.alg_visit == backbone_visit {
use_it = true;
break
}
if let Some(q_supernode) = cnode_consider.p_supernode {
q_cnode_consider = q_supernode;
lvl += 1;
} else {
return Err(Error::OtherStr(
"`route_path_on_level` called with too high of a `backbone_lvl`",
))
}
}
} else {
use_it = true;
}
if use_it {
let mut adv = router.target_channeler.cnodes.advancer_surject(q_cnode);
while let Some(q_referent1) = adv.advance(&router.target_channeler.cnodes) {
if let Referent::CEdgeIncidence(q_cedge1, Some(source_j1)) =
*router.target_channeler.cnodes.get_key(q_referent1).unwrap()
{
let cedge = router.target_channeler.cedges.get(q_cedge1).unwrap();
priority.push(Reverse((
cost.saturating_add(cedge.delay_weight.get())
.saturating_add(cedge.lagrangian),
q_cedge1,
source_j1,
)));
}
}
}
}
}
Ok(found)
}