use crate::core::QduId; use crate::operations::Operation;
use std::collections::{HashMap, HashSet}; use std::fmt;
#[derive(Clone, PartialEq)] pub struct Circuit {
qdus: HashSet<QduId>,
operations: Vec<Operation>,
}
impl Circuit {
pub fn new() -> Self {
Self {
qdus: HashSet::new(),
operations: Vec::new(),
}
}
pub fn add_operation(&mut self, op: Operation) {
for qdu_id in op.involved_qdus() {
self.qdus.insert(qdu_id);
}
self.operations.push(op);
}
pub fn add_operations<I>(&mut self, ops: I)
where
I: IntoIterator<Item = Operation>,
{
for op in ops {
self.add_operation(op);
}
}
pub fn qdus(&self) -> &HashSet<QduId> {
&self.qdus
}
pub fn operations(&self) -> &[Operation] {
&self.operations
}
pub fn len(&self) -> usize {
self.operations.len()
}
pub fn is_empty(&self) -> bool {
self.operations.is_empty()
}
}
impl Default for Circuit {
fn default() -> Self {
Self::new()
}
}
pub struct CircuitBuilder {
circuit: Circuit,
}
impl CircuitBuilder {
pub fn new() -> Self {
Self {
circuit: Circuit::new(),
}
}
pub fn add_op(mut self, op: Operation) -> Self {
self.circuit.add_operation(op);
self
}
pub fn add_ops<I>(mut self, ops: I) -> Self
where
I: IntoIterator<Item = Operation>,
{
self.circuit.add_operations(ops);
self
}
pub fn build(self) -> Circuit {
self.circuit
}
}
impl Default for CircuitBuilder {
fn default() -> Self {
Self::new()
}
}
impl fmt::Display for Circuit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.operations.is_empty() {
return writeln!(f, "onq::Circuit[0 operations on 0 QDUs]");
}
let ops = &self.operations;
let num_ops = ops.len();
let mut sorted_qdus: Vec<QduId> = self.qdus.iter().cloned().collect();
sorted_qdus.sort(); let num_qdus = sorted_qdus.len();
let qdu_to_row: HashMap<QduId, usize> = sorted_qdus
.iter()
.enumerate()
.map(|(i, qid)| (*qid, i))
.collect();
let max_label_width = sorted_qdus
.iter()
.map(|qid| format!("{}", qid).len())
.max()
.unwrap_or(0);
let label_padding = " ".repeat(max_label_width + 2);
const GATE_WIDTH: usize = 7; const WIRE: &str = "───────"; const V_WIRE: char = '│';
const H_WIRE: char = '─';
let mut op_grid: Vec<Vec<String>> = vec![vec![WIRE.to_string(); num_ops]; num_qdus];
let mut v_connect: Vec<Vec<char>> = vec![vec![' '; num_ops]; num_qdus];
fn format_gate(symbol: &str) -> String {
let slen = symbol.chars().count(); if slen >= GATE_WIDTH {
symbol.chars().take(GATE_WIDTH).collect()
} else {
let total_dashes = GATE_WIDTH - slen;
let pre_dashes = total_dashes / 2;
let post_dashes = total_dashes - pre_dashes;
format!(
"{}{}{}",
H_WIRE.to_string().repeat(pre_dashes),
symbol,
H_WIRE.to_string().repeat(post_dashes)
)
}
}
for (t, op) in ops.iter().enumerate() {
match op {
Operation::PhaseShift { target, .. } => {
if let Some(r) = qdu_to_row.get(target) {
op_grid[*r][t] = format_gate("P"); }
}
Operation::InteractionPattern { target, pattern_id } => {
if let Some(r) = qdu_to_row.get(target) {
let symbol = match pattern_id.as_str() {
"Identity" => continue, "QualityFlip" => "X",
"PhaseIntroduce" => "Z",
"HalfPhase" => "S",
"HalfPhase_Inv" => "S†",
"QuarterPhase" => "T",
"QuarterPhase_Inv" => "T†",
"QualitativeY" => "Y",
"PhiRotate" => "ΦR", "Superposition" => "H",
"SqrtFlip" => "√X", _ => "?", };
op_grid[*r][t] = format_gate(symbol);
}
}
Operation::ControlledInteraction {
control,
target,
pattern_id,
} => {
if let (Some(r_ctrl), Some(r_tgt)) =
(qdu_to_row.get(control), qdu_to_row.get(target))
{
let target_symbol = match pattern_id.as_str() {
"QualityFlip" => "X", _ => "●", };
op_grid[*r_ctrl][t] = format_gate("@");
op_grid[*r_tgt][t] = format_gate(target_symbol);
let r_min = (*r_ctrl).min(*r_tgt);
let r_max = (*r_ctrl).max(*r_tgt);
for row_vec in v_connect.iter_mut().take(r_max).skip(r_min) {
row_vec[t] = V_WIRE;
}
}
}
Operation::RelationalLock { qdu1, qdu2, .. } => {
if let (Some(r1), Some(r2)) = (qdu_to_row.get(qdu1), qdu_to_row.get(qdu2)) {
let r_min = (*r1).min(*r2);
let r_max = (*r1).max(*r2);
op_grid[r_min][t] = format_gate("@"); op_grid[r_max][t] = format_gate("●");
for row_vec in v_connect.iter_mut().take(r_max).skip(r_min) {
row_vec[t] = V_WIRE;
}
}
}
Operation::Stabilize { targets } => {
for target_qid in targets {
if let Some(r) = qdu_to_row.get(target_qid) {
op_grid[*r][t] = format_gate("M");
}
}
}
}
}
writeln!(
f,
"onq::Circuit[{} operations on {} QDUs]",
num_ops, num_qdus
)?;
for r in 0..num_qdus {
let label = format!("{}: ", sorted_qdus[r]);
write!(f, "{:<width$}", label, width = max_label_width + 2)?;
writeln!(f, "{}", op_grid[r].join(""))?;
if r < num_qdus - 1 {
write!(f, "{}", label_padding)?; for connector in v_connect[r].iter().take(num_ops) {
let padding_needed = GATE_WIDTH.saturating_sub(1); let pre_pad = padding_needed / 2;
let post_pad = padding_needed - pre_pad;
write!(
f,
"{}{}{}",
" ".repeat(pre_pad),
connector,
" ".repeat(post_pad)
)?;
}
writeln!(f)?; }
}
Ok(())
}
}
impl fmt::Debug for Circuit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}