1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
use crate::backend::backend::{Gate1, Gate2};
pub struct CircuitRecorder {
pub operations: Vec<Operation>,
n_qubits: usize,
}
pub enum Operation {
Single(usize, Gate1),
Two(usize, usize, Gate2),
Measure(usize),
}
impl CircuitRecorder {
pub fn new(n_qubits: usize) -> Self {
CircuitRecorder {
operations: Vec::new(),
n_qubits,
}
}
pub fn record_single(&mut self, qubit: usize, gate: Gate1) {
self.operations.push(Operation::Single(qubit, gate));
}
pub fn record_two(&mut self, q1: usize, q2: usize, gate: Gate2) {
self.operations.push(Operation::Two(q1, q2, gate));
}
pub fn record_measure(&mut self, qubit: usize) {
self.operations.push(Operation::Measure(qubit));
}
pub fn to_ascii(&self) -> String {
let mut circuit = vec![String::new(); self.n_qubits];
// Initialize qubit lines
for i in 0..self.n_qubits {
circuit[i] = format!("q{}: ", i);
}
// we add gates
for op in &self.operations {
let _width = 5; // Fixed width for alignment
// Extend all lines to same length
let max_len = circuit.iter().map(|s| s.len()).max().unwrap_or(0);
for line in &mut circuit {
while line.len() < max_len {
line.push('─');
}
}
match op {
Operation::Single(q, gate) => {
let gate_str = match gate {
Gate1::H => "┤H├",
Gate1::X => "┤X├",
Gate1::Y => "┤Y├",
Gate1::Z => "┤Z├",
Gate1::S => "┤S├",
Gate1::SDag => "┤S†├",
Gate1::T => "┤T├",
Gate1::TDag => "┤T†├",
Gate1::Rx(_) => "┤Rx├",
Gate1::Ry(_) => "┤Ry├",
Gate1::Rz(_) => "┤Rz├",
};
circuit[*q].push_str(gate_str);
// Fill other qubits with wires
for (i, line) in circuit.iter_mut().enumerate() {
if i != *q {
line.push_str("───");
}
}
}
Operation::Two(q1, q2, gate) => {
let (top, bottom) = if q1 < q2 { (q1, q2) } else { (q2, q1) };
match gate {
Gate2::CNOT => {
circuit[*q1].push_str(if *q1 == *top {
"┤●├"
} else {
"┤⊕├"
});
circuit[*q2].push_str(if *q2 == *top {
"┤●├"
} else {
"┤⊕├"
});
// Connect with vertical lines
for i in (*top + 1)..*bottom {
circuit[i].push_str("┤│├");
}
}
Gate2::CZ => {
// Both qubits get control dots for CZ
circuit[*q1].push_str("┤●├");
circuit[*q2].push_str("┤●├");
// Connect with vertical lines
for i in (*top + 1)..*bottom {
circuit[i].push_str("┤│├");
}
}
Gate2::SWAP => {
// Both qubits get X symbols for SWAP
circuit[*q1].push_str("┤×├");
circuit[*q2].push_str("┤×├");
// Connect with vertical lines
for i in (*top + 1)..*bottom {
circuit[i].push_str("┤│├");
}
}
Gate2::CY => {
circuit[*q1].push_str(if *q1 == *top {
"┤●├"
} else {
"┤Y├"
});
circuit[*q2].push_str(if *q2 == *top {
"┤●├"
} else {
"┤Y├"
});
// Connect with vertical lines
for i in (*top + 1)..*bottom {
circuit[i].push_str("┤│├");
}
}
}
// Fill other qubits
for (i, line) in circuit.iter_mut().enumerate() {
if i != *q1 && i != *q2 && !((*top < i) && (i < *bottom)) {
line.push_str("───");
}
}
}
Operation::Measure(q) => {
circuit[*q].push_str("┤M├");
for (i, line) in circuit.iter_mut().enumerate() {
if i != *q {
line.push_str("───");
}
}
}
}
}
circuit.join("\n")
}
}