use burn_quantum::photonic::{CompiledFusionNetwork, NodeKind};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct FabricNodeView {
pub id: usize,
pub label: String,
pub kind: String,
pub position: [f32; 3],
pub storage: [f64; 2],
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct FabricLinkView {
pub id: usize,
pub from: usize,
pub to: usize,
pub ticks: u64,
pub transmission: [f64; 2],
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RouteHopView {
pub link: usize,
pub departure: u64,
pub arrival: u64,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PhotonRouteView {
pub photon: usize,
pub from: usize,
pub to: usize,
pub release: u64,
pub arrival: u64,
pub hops: Vec<RouteHopView>,
pub transmission: [f64; 2],
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct FusionEvent {
pub tick: u64,
pub node: usize,
pub photons: [usize; 2],
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ResourceView {
pub source: usize,
pub photons: Vec<usize>,
pub edges: Vec<(usize, usize)>,
pub hadamards: Vec<usize>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct FabricSnapshot {
pub nodes: Vec<FabricNodeView>,
pub links: Vec<FabricLinkView>,
pub routes: Vec<PhotonRouteView>,
pub fusions: Vec<FusionEvent>,
pub outputs: Vec<usize>,
pub finish_tick: u64,
pub resource_count: usize,
pub photon_count: usize,
#[serde(default)]
pub resources: Vec<ResourceView>,
}
impl FabricSnapshot {
pub fn from_compiled(plan: &CompiledFusionNetwork) -> Self {
let mut offset = 0;
let resources = plan
.program()
.resources()
.iter()
.map(|r| {
let photons = (offset..offset + r.state.qubits()).collect();
offset += r.state.qubits();
ResourceView {
source: r.source.0,
photons,
edges: r.state.edges().to_vec(),
hadamards: r.state.hadamards().to_vec(),
}
})
.collect();
Self {
resources,
nodes: plan
.fabric()
.nodes()
.iter()
.enumerate()
.map(|(id, node)| {
let x = match node.kind {
NodeKind::Source => -3.,
NodeKind::Fusion => 3.,
_ => 0.,
};
let same_role = plan
.fabric()
.nodes()
.iter()
.filter(|n| n.kind == node.kind)
.count();
let rank = plan.fabric().nodes()[..id]
.iter()
.filter(|n| n.kind == node.kind)
.count();
FabricNodeView {
id,
label: format!("{:?} {id}", node.kind),
kind: format!("{:?}", node.kind),
position: [x, (rank as f32 - (same_role - 1) as f32 * 0.5) * 2.2, 0.],
storage: node.storage.values(),
}
})
.collect(),
links: plan
.fabric()
.links()
.iter()
.enumerate()
.map(|(id, link)| FabricLinkView {
id,
from: link.from.0,
to: link.to.0,
ticks: link.ticks,
transmission: link.transmission.values(),
})
.collect(),
routes: plan
.routes()
.iter()
.map(|p| PhotonRouteView {
photon: p.photon.0,
from: p.route.from.0,
to: p.route.to.0,
release: p.route.release,
arrival: p.route.arrival,
transmission: p.route.transmission.values(),
hops: p
.route
.hops
.iter()
.map(|h| RouteHopView {
link: h.link,
departure: h.departure,
arrival: h.arrival,
})
.collect(),
})
.collect(),
fusions: plan
.fusions()
.iter()
.map(|f| FusionEvent {
tick: f.tick,
node: f.at.0,
photons: f.photons.map(|q| q.0),
})
.collect(),
outputs: plan.outputs().iter().map(|q| q.0).collect(),
finish_tick: plan.finish_tick(),
resource_count: plan.program().resources().len(),
photon_count: plan.program().num_photons(),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PhotonLocation {
Node(usize),
Link {
link: usize,
progress: f32,
},
Consumed,
}
impl FabricSnapshot {
pub fn photon_location(&self, photon: usize, tick: f64) -> Option<PhotonLocation> {
if photon >= self.photon_count || !tick.is_finite() || tick < 0. {
return None;
}
if self
.fusions
.iter()
.any(|f| f.photons.contains(&photon) && tick >= f.tick as f64 + 1.)
{
return Some(PhotonLocation::Consumed);
}
if let Some(route) = self.routes.iter().find(|r| r.photon == photon) {
let mut node = route.from;
for hop in &route.hops {
if tick < hop.departure as f64 {
return Some(PhotonLocation::Node(node));
}
let link = self.links.get(hop.link)?;
if tick < hop.arrival as f64 {
return Some(PhotonLocation::Link {
link: hop.link,
progress: ((tick - hop.departure as f64)
/ (hop.arrival - hop.departure) as f64)
as f32,
});
}
node = link.to;
}
Some(PhotonLocation::Node(node))
} else {
self.resources
.iter()
.find(|r| r.photons.contains(&photon))
.map(|r| PhotonLocation::Node(r.source))
}
}
}