| """ |
| FireEcho Quantum Gold - Circuit Builder |
| |
| Provides a high-level interface for constructing quantum circuits |
| similar to Qiskit/Cirq but optimized for FireEcho's SM120 backend. |
| |
| Example: |
| qc = QuantumCircuit(3) |
| qc.h(0) # Hadamard on qubit 0 |
| qc.cx(0, 1) # CNOT: control=0, target=1 |
| qc.cx(0, 2) # CNOT: control=0, target=2 |
| # Result: GHZ state (|000⟩ + |111⟩)/√2 |
| """ |
|
|
| from dataclasses import dataclass, field |
| from typing import List, Tuple, Optional, Union, Any |
| import math |
|
|
|
|
| @dataclass |
| class QuantumRegister: |
| """ |
| A register of qubits. |
| |
| Args: |
| size: Number of qubits in the register |
| name: Optional name for the register |
| """ |
| size: int |
| name: str = "q" |
| |
| def __getitem__(self, idx: int) -> int: |
| """Get qubit index.""" |
| if idx < 0 or idx >= self.size: |
| raise IndexError(f"Qubit index {idx} out of range [0, {self.size})") |
| return idx |
| |
| def __len__(self) -> int: |
| return self.size |
| |
| def __iter__(self): |
| return iter(range(self.size)) |
|
|
|
|
| @dataclass |
| class Gate: |
| """Representation of a quantum gate operation.""" |
| name: str |
| targets: Tuple[int, ...] |
| params: Tuple[float, ...] = () |
| |
| def __repr__(self): |
| if self.params: |
| param_str = ", ".join(f"{p:.4f}" for p in self.params) |
| return f"{self.name}({param_str}) @ {self.targets}" |
| return f"{self.name} @ {self.targets}" |
|
|
|
|
| class QuantumCircuit: |
| """ |
| Quantum circuit builder for FireEcho Quantum Gold. |
| |
| Supports all standard gates and provides methods for |
| circuit visualization, optimization, and execution. |
| |
| Args: |
| num_qubits: Number of qubits in the circuit |
| name: Optional circuit name |
| |
| Example: |
| # Create a Bell state |
| qc = QuantumCircuit(2) |
| qc.h(0) |
| qc.cx(0, 1) |
| |
| # Execute |
| sim = QuantumSimulator() |
| state = sim.run(qc) |
| """ |
| |
| def __init__(self, num_qubits: int, name: str = "circuit"): |
| self.num_qubits = num_qubits |
| self.name = name |
| self.gates: List[Gate] = [] |
| self.register = QuantumRegister(num_qubits) |
| |
| def _validate_qubit(self, qubit: int, name: str = "qubit"): |
| """Validate qubit index.""" |
| if qubit < 0 or qubit >= self.num_qubits: |
| raise ValueError( |
| f"{name} index {qubit} out of range [0, {self.num_qubits})" |
| ) |
| |
| |
| |
| |
| |
| def h(self, qubit: int) -> 'QuantumCircuit': |
| """ |
| Hadamard gate. |
| |
| Creates superposition: H|0⟩ = (|0⟩+|1⟩)/√2 |
| """ |
| self._validate_qubit(qubit) |
| self.gates.append(Gate("H", (qubit,))) |
| return self |
| |
| def x(self, qubit: int) -> 'QuantumCircuit': |
| """ |
| Pauli-X (NOT) gate. |
| |
| Bit flip: X|0⟩ = |1⟩, X|1⟩ = |0⟩ |
| """ |
| self._validate_qubit(qubit) |
| self.gates.append(Gate("X", (qubit,))) |
| return self |
| |
| def y(self, qubit: int) -> 'QuantumCircuit': |
| """ |
| Pauli-Y gate. |
| |
| Y|0⟩ = i|1⟩, Y|1⟩ = -i|0⟩ |
| """ |
| self._validate_qubit(qubit) |
| self.gates.append(Gate("Y", (qubit,))) |
| return self |
| |
| def z(self, qubit: int) -> 'QuantumCircuit': |
| """ |
| Pauli-Z gate. |
| |
| Phase flip: Z|0⟩ = |0⟩, Z|1⟩ = -|1⟩ |
| """ |
| self._validate_qubit(qubit) |
| self.gates.append(Gate("Z", (qubit,))) |
| return self |
| |
| def s(self, qubit: int) -> 'QuantumCircuit': |
| """S gate (√Z, π/2 phase).""" |
| self._validate_qubit(qubit) |
| self.gates.append(Gate("S", (qubit,))) |
| return self |
| |
| def sdg(self, qubit: int) -> 'QuantumCircuit': |
| """S-dagger gate (S†, -π/2 phase).""" |
| self._validate_qubit(qubit) |
| self.gates.append(Gate("SDG", (qubit,))) |
| return self |
| |
| def t(self, qubit: int) -> 'QuantumCircuit': |
| """T gate (π/4 phase).""" |
| self._validate_qubit(qubit) |
| self.gates.append(Gate("T", (qubit,))) |
| return self |
| |
| def tdg(self, qubit: int) -> 'QuantumCircuit': |
| """T-dagger gate (T†, -π/4 phase).""" |
| self._validate_qubit(qubit) |
| self.gates.append(Gate("TDG", (qubit,))) |
| return self |
| |
| def rx(self, theta: float, qubit: int) -> 'QuantumCircuit': |
| """ |
| Rotation around X-axis. |
| |
| Rx(θ) = exp(-iθX/2) |
| """ |
| self._validate_qubit(qubit) |
| self.gates.append(Gate("RX", (qubit,), (theta,))) |
| return self |
| |
| def ry(self, theta: float, qubit: int) -> 'QuantumCircuit': |
| """ |
| Rotation around Y-axis. |
| |
| Ry(θ) = exp(-iθY/2) |
| """ |
| self._validate_qubit(qubit) |
| self.gates.append(Gate("RY", (qubit,), (theta,))) |
| return self |
| |
| def rz(self, theta: float, qubit: int) -> 'QuantumCircuit': |
| """ |
| Rotation around Z-axis. |
| |
| Rz(θ) = exp(-iθZ/2) |
| """ |
| self._validate_qubit(qubit) |
| self.gates.append(Gate("RZ", (qubit,), (theta,))) |
| return self |
| |
| def p(self, phi: float, qubit: int) -> 'QuantumCircuit': |
| """ |
| Phase gate. |
| |
| P(φ) = [[1, 0], [0, e^(iφ)]] |
| """ |
| self._validate_qubit(qubit) |
| self.gates.append(Gate("P", (qubit,), (phi,))) |
| return self |
| |
| def u(self, theta: float, phi: float, lam: float, qubit: int) -> 'QuantumCircuit': |
| """ |
| General single-qubit unitary gate. |
| |
| U(θ,φ,λ) = Rz(φ) Ry(θ) Rz(λ) |
| """ |
| self._validate_qubit(qubit) |
| self.gates.append(Gate("U", (qubit,), (theta, phi, lam))) |
| return self |
| |
| |
| |
| |
| |
| def cx(self, control: int, target: int) -> 'QuantumCircuit': |
| """ |
| CNOT (Controlled-NOT) gate. |
| |
| Flips target qubit when control is |1⟩. |
| """ |
| self._validate_qubit(control, "control") |
| self._validate_qubit(target, "target") |
| if control == target: |
| raise ValueError("Control and target must be different qubits") |
| self.gates.append(Gate("CX", (control, target))) |
| return self |
| |
| def cnot(self, control: int, target: int) -> 'QuantumCircuit': |
| """Alias for cx().""" |
| return self.cx(control, target) |
| |
| def cy(self, control: int, target: int) -> 'QuantumCircuit': |
| """Controlled-Y gate.""" |
| self._validate_qubit(control, "control") |
| self._validate_qubit(target, "target") |
| self.gates.append(Gate("CY", (control, target))) |
| return self |
| |
| def cz(self, control: int, target: int) -> 'QuantumCircuit': |
| """ |
| Controlled-Z gate. |
| |
| Applies Z to target when control is |1⟩. |
| """ |
| self._validate_qubit(control, "control") |
| self._validate_qubit(target, "target") |
| self.gates.append(Gate("CZ", (control, target))) |
| return self |
| |
| def swap(self, qubit1: int, qubit2: int) -> 'QuantumCircuit': |
| """SWAP gate - exchanges two qubits.""" |
| self._validate_qubit(qubit1, "qubit1") |
| self._validate_qubit(qubit2, "qubit2") |
| self.gates.append(Gate("SWAP", (qubit1, qubit2))) |
| return self |
| |
| def cp(self, phi: float, control: int, target: int) -> 'QuantumCircuit': |
| """Controlled phase gate.""" |
| self._validate_qubit(control, "control") |
| self._validate_qubit(target, "target") |
| self.gates.append(Gate("CP", (control, target), (phi,))) |
| return self |
| |
| def crx(self, theta: float, control: int, target: int) -> 'QuantumCircuit': |
| """Controlled Rx rotation.""" |
| self._validate_qubit(control, "control") |
| self._validate_qubit(target, "target") |
| self.gates.append(Gate("CRX", (control, target), (theta,))) |
| return self |
| |
| def cry(self, theta: float, control: int, target: int) -> 'QuantumCircuit': |
| """Controlled Ry rotation.""" |
| self._validate_qubit(control, "control") |
| self._validate_qubit(target, "target") |
| self.gates.append(Gate("CRY", (control, target), (theta,))) |
| return self |
| |
| def crz(self, theta: float, control: int, target: int) -> 'QuantumCircuit': |
| """Controlled Rz rotation.""" |
| self._validate_qubit(control, "control") |
| self._validate_qubit(target, "target") |
| self.gates.append(Gate("CRZ", (control, target), (theta,))) |
| return self |
| |
| |
| |
| |
| |
| def ccx(self, control1: int, control2: int, target: int) -> 'QuantumCircuit': |
| """ |
| Toffoli (CCX) gate. |
| |
| Flips target when both controls are |1⟩. |
| """ |
| self._validate_qubit(control1, "control1") |
| self._validate_qubit(control2, "control2") |
| self._validate_qubit(target, "target") |
| self.gates.append(Gate("CCX", (control1, control2, target))) |
| return self |
| |
| def toffoli(self, control1: int, control2: int, target: int) -> 'QuantumCircuit': |
| """Alias for ccx().""" |
| return self.ccx(control1, control2, target) |
| |
| def cswap(self, control: int, target1: int, target2: int) -> 'QuantumCircuit': |
| """ |
| Fredkin (CSWAP) gate. |
| |
| Swaps target1 and target2 when control is |1⟩. |
| """ |
| self._validate_qubit(control, "control") |
| self._validate_qubit(target1, "target1") |
| self._validate_qubit(target2, "target2") |
| self.gates.append(Gate("CSWAP", (control, target1, target2))) |
| return self |
| |
| def fredkin(self, control: int, target1: int, target2: int) -> 'QuantumCircuit': |
| """Alias for cswap().""" |
| return self.cswap(control, target1, target2) |
| |
| |
| |
| |
| |
| def measure(self, qubit: int) -> 'QuantumCircuit': |
| """Mark qubit for measurement.""" |
| self._validate_qubit(qubit) |
| self.gates.append(Gate("MEASURE", (qubit,))) |
| return self |
| |
| def measure_all(self) -> 'QuantumCircuit': |
| """Mark all qubits for measurement.""" |
| for i in range(self.num_qubits): |
| self.measure(i) |
| return self |
| |
| |
| |
| |
| |
| def barrier(self, *qubits: int) -> 'QuantumCircuit': |
| """ |
| Insert a barrier (prevents gate fusion across barrier). |
| |
| If no qubits specified, applies to all. |
| """ |
| if not qubits: |
| qubits = tuple(range(self.num_qubits)) |
| for q in qubits: |
| self._validate_qubit(q) |
| self.gates.append(Gate("BARRIER", qubits)) |
| return self |
| |
| def id(self, qubit: int) -> 'QuantumCircuit': |
| """Identity gate (no-op, useful for timing).""" |
| self._validate_qubit(qubit) |
| self.gates.append(Gate("I", (qubit,))) |
| return self |
| |
| |
| |
| |
| |
| def compose(self, other: 'QuantumCircuit', qubits: Optional[List[int]] = None) -> 'QuantumCircuit': |
| """ |
| Append another circuit to this one. |
| |
| Args: |
| other: Circuit to append |
| qubits: Qubit mapping (if circuits have different sizes) |
| """ |
| if qubits is None: |
| if other.num_qubits != self.num_qubits: |
| raise ValueError( |
| f"Circuit sizes don't match: {self.num_qubits} vs {other.num_qubits}. " |
| "Provide qubit mapping." |
| ) |
| qubits = list(range(self.num_qubits)) |
| |
| for gate in other.gates: |
| mapped_targets = tuple(qubits[t] for t in gate.targets) |
| self.gates.append(Gate(gate.name, mapped_targets, gate.params)) |
| |
| return self |
| |
| def inverse(self) -> 'QuantumCircuit': |
| """ |
| Return the inverse (adjoint) of this circuit. |
| |
| Reverses gate order and applies gate inverses. |
| """ |
| inv = QuantumCircuit(self.num_qubits, f"{self.name}_inv") |
| |
| for gate in reversed(self.gates): |
| name = gate.name |
| targets = gate.targets |
| params = gate.params |
| |
| |
| if name in ("H", "X", "Y", "Z", "CX", "CZ", "SWAP", "CCX", "CSWAP", "I"): |
| |
| inv.gates.append(Gate(name, targets, params)) |
| elif name == "S": |
| inv.gates.append(Gate("SDG", targets)) |
| elif name == "SDG": |
| inv.gates.append(Gate("S", targets)) |
| elif name == "T": |
| inv.gates.append(Gate("TDG", targets)) |
| elif name == "TDG": |
| inv.gates.append(Gate("T", targets)) |
| elif name in ("RX", "RY", "RZ", "P", "CP", "CRX", "CRY", "CRZ"): |
| |
| inv.gates.append(Gate(name, targets, (-params[0],))) |
| elif name == "U": |
| |
| inv.gates.append(Gate("U", targets, (-params[0], -params[2], -params[1]))) |
| elif name in ("BARRIER", "MEASURE"): |
| |
| inv.gates.append(Gate(name, targets, params)) |
| else: |
| raise ValueError(f"Unknown gate for inverse: {name}") |
| |
| return inv |
| |
| |
| |
| |
| |
| @property |
| def depth(self) -> int: |
| """ |
| Circuit depth (number of gate layers). |
| |
| Gates on different qubits can execute in parallel. |
| """ |
| if not self.gates: |
| return 0 |
| |
| qubit_depths = [0] * self.num_qubits |
| |
| for gate in self.gates: |
| if gate.name in ("BARRIER", "MEASURE"): |
| continue |
| |
| max_depth = max(qubit_depths[t] for t in gate.targets) |
| new_depth = max_depth + 1 |
| |
| for t in gate.targets: |
| qubit_depths[t] = new_depth |
| |
| return max(qubit_depths) if qubit_depths else 0 |
| |
| @property |
| def size(self) -> int: |
| """Total number of gates (excluding barriers).""" |
| return sum(1 for g in self.gates if g.name not in ("BARRIER", "MEASURE")) |
| |
| def count_ops(self) -> dict: |
| """Count occurrences of each gate type.""" |
| counts = {} |
| for gate in self.gates: |
| counts[gate.name] = counts.get(gate.name, 0) + 1 |
| return counts |
| |
| |
| |
| |
| |
| def draw(self, output: str = "text", figsize: tuple = None): |
| """ |
| Draw the circuit. |
| |
| Args: |
| output: Output format: |
| - 'text': ASCII text representation |
| - 'mpl': Matplotlib figure |
| - 'latex': LaTeX string (for papers) |
| figsize: Figure size for matplotlib (width, height) |
| |
| Returns: |
| String (text/latex) or matplotlib Figure (mpl) |
| """ |
| if output == "text": |
| return self._draw_text() |
| elif output == "mpl": |
| return self._draw_matplotlib(figsize) |
| elif output == "latex": |
| return self._draw_latex() |
| else: |
| raise ValueError(f"Unsupported output format: {output}. Use 'text', 'mpl', or 'latex'") |
| |
| def _draw_text(self) -> str: |
| """ASCII art circuit diagram.""" |
| lines = [f"QuantumCircuit '{self.name}' ({self.num_qubits} qubits, depth={self.depth})"] |
| lines.append("=" * 60) |
| |
| |
| wire_chars = {q: [] for q in range(self.num_qubits)} |
| |
| for gate in self.gates: |
| |
| targets = gate.targets |
| name = gate.name |
| |
| |
| if name in ('H', 'X', 'Y', 'Z', 'S', 'T', 'I'): |
| symbol = f"[{name}]" |
| elif name in ('RX', 'RY', 'RZ'): |
| symbol = f"[{name[1]}({gate.params[0]:.2f})]" |
| elif name == 'CX': |
| symbol = None |
| elif name == 'CZ': |
| symbol = None |
| elif name == 'SWAP': |
| symbol = None |
| else: |
| symbol = f"[{name}]" |
| |
| if len(targets) == 1: |
| q = targets[0] |
| wire_chars[q].append(symbol or f"[{name}]") |
| for other in range(self.num_qubits): |
| if other != q: |
| wire_chars[other].append("─" * len(symbol or f"[{name}]")) |
| elif len(targets) == 2: |
| q1, q2 = min(targets), max(targets) |
| if name == 'CX': |
| ctrl_q = targets[0] |
| targ_q = targets[1] |
| for q in range(self.num_qubits): |
| if q == ctrl_q: |
| wire_chars[q].append("─●─") |
| elif q == targ_q: |
| wire_chars[q].append("─⊕─") |
| elif q1 < q < q2: |
| wire_chars[q].append("─│─") |
| else: |
| wire_chars[q].append("───") |
| elif name == 'SWAP': |
| for q in range(self.num_qubits): |
| if q in targets: |
| wire_chars[q].append("─×─") |
| elif q1 < q < q2: |
| wire_chars[q].append("─│─") |
| else: |
| wire_chars[q].append("───") |
| else: |
| for q in range(self.num_qubits): |
| if q in targets: |
| wire_chars[q].append(f"[{name}]") |
| else: |
| wire_chars[q].append("─" * (len(name) + 2)) |
| |
| |
| lines.append("") |
| for q in range(self.num_qubits): |
| wire = f"q{q}: ─" + "".join(wire_chars[q][:20]) + "─" |
| if len(wire_chars[q]) > 20: |
| wire += "..." |
| lines.append(wire) |
| lines.append("") |
| |
| lines.append("=" * 60) |
| lines.append(f"Gate counts: {self.count_ops()}") |
| |
| return "\n".join(lines) |
| |
| def _draw_matplotlib(self, figsize: tuple = None): |
| """ |
| Draw circuit using matplotlib. |
| |
| Returns matplotlib Figure object. |
| """ |
| try: |
| import matplotlib.pyplot as plt |
| import matplotlib.patches as patches |
| except ImportError: |
| raise ImportError("matplotlib required for 'mpl' output. Install with: pip install matplotlib") |
| |
| if figsize is None: |
| figsize = (max(12, self.depth * 0.5), max(4, self.num_qubits * 0.8)) |
| |
| fig, ax = plt.subplots(figsize=figsize) |
| |
| |
| wire_spacing = 1.0 |
| gate_width = 0.6 |
| gate_height = 0.6 |
| x_spacing = 0.8 |
| |
| |
| max_x = max(self.depth + 2, 5) |
| for q in range(self.num_qubits): |
| y = (self.num_qubits - 1 - q) * wire_spacing |
| ax.plot([0, max_x * x_spacing], [y, y], 'k-', linewidth=1) |
| ax.text(-0.5, y, f'q{q}', ha='right', va='center', fontsize=10) |
| |
| |
| x_pos = [1.0] * self.num_qubits |
| |
| |
| for gate in self.gates: |
| name = gate.name |
| targets = gate.targets |
| |
| if name in ('BARRIER', 'MEASURE'): |
| continue |
| |
| |
| gate_x = max(x_pos[q] for q in targets) |
| |
| if len(targets) == 1: |
| q = targets[0] |
| y = (self.num_qubits - 1 - q) * wire_spacing |
| |
| |
| rect = patches.FancyBboxPatch( |
| (gate_x - gate_width/2, y - gate_height/2), |
| gate_width, gate_height, |
| boxstyle="round,pad=0.02", |
| facecolor='white', |
| edgecolor='black', |
| linewidth=1.5 |
| ) |
| ax.add_patch(rect) |
| |
| |
| label = name |
| if name in ('RX', 'RY', 'RZ') and gate.params: |
| label = f"{name}\n({gate.params[0]:.2f})" |
| ax.text(gate_x, y, label, ha='center', va='center', fontsize=8) |
| |
| x_pos[q] = gate_x + x_spacing |
| |
| elif len(targets) == 2: |
| q1, q2 = targets |
| y1 = (self.num_qubits - 1 - q1) * wire_spacing |
| y2 = (self.num_qubits - 1 - q2) * wire_spacing |
| |
| if name == 'CX': |
| |
| ax.plot(gate_x, y1, 'ko', markersize=8) |
| |
| circle = patches.Circle((gate_x, y2), 0.2, fill=False, |
| edgecolor='black', linewidth=2) |
| ax.add_patch(circle) |
| ax.plot([gate_x, gate_x], [y2-0.2, y2+0.2], 'k-', linewidth=2) |
| ax.plot([gate_x-0.2, gate_x+0.2], [y2, y2], 'k-', linewidth=2) |
| |
| ax.plot([gate_x, gate_x], [y1, y2], 'k-', linewidth=1) |
| |
| elif name == 'CZ': |
| ax.plot(gate_x, y1, 'ko', markersize=8) |
| ax.plot(gate_x, y2, 'ko', markersize=8) |
| ax.plot([gate_x, gate_x], [y1, y2], 'k-', linewidth=1) |
| |
| elif name == 'SWAP': |
| ax.plot(gate_x, y1, 'x', markersize=12, mew=2, color='black') |
| ax.plot(gate_x, y2, 'x', markersize=12, mew=2, color='black') |
| ax.plot([gate_x, gate_x], [y1, y2], 'k-', linewidth=1) |
| |
| else: |
| |
| y_min, y_max = min(y1, y2), max(y1, y2) |
| rect = patches.FancyBboxPatch( |
| (gate_x - gate_width/2, y_min - gate_height/4), |
| gate_width, y_max - y_min + gate_height/2, |
| boxstyle="round,pad=0.02", |
| facecolor='lightblue', |
| edgecolor='black', |
| linewidth=1.5 |
| ) |
| ax.add_patch(rect) |
| ax.text(gate_x, (y1 + y2) / 2, name, ha='center', va='center', fontsize=8) |
| |
| x_pos[q1] = gate_x + x_spacing |
| x_pos[q2] = gate_x + x_spacing |
| |
| elif len(targets) == 3: |
| |
| ys = [(self.num_qubits - 1 - q) * wire_spacing for q in targets] |
| y_min, y_max = min(ys), max(ys) |
| |
| if name == 'CCX': |
| ax.plot(gate_x, ys[0], 'ko', markersize=8) |
| ax.plot(gate_x, ys[1], 'ko', markersize=8) |
| circle = patches.Circle((gate_x, ys[2]), 0.2, fill=False, |
| edgecolor='black', linewidth=2) |
| ax.add_patch(circle) |
| ax.plot([gate_x, gate_x], [y_min, y_max], 'k-', linewidth=1) |
| else: |
| rect = patches.FancyBboxPatch( |
| (gate_x - gate_width/2, y_min - gate_height/4), |
| gate_width, y_max - y_min + gate_height/2, |
| boxstyle="round,pad=0.02", |
| facecolor='lightyellow', |
| edgecolor='black', |
| linewidth=1.5 |
| ) |
| ax.add_patch(rect) |
| ax.text(gate_x, (y_min + y_max) / 2, name, ha='center', va='center', fontsize=8) |
| |
| for q in targets: |
| x_pos[q] = gate_x + x_spacing |
| |
| |
| ax.set_xlim(-1, max_x * x_spacing + 1) |
| ax.set_ylim(-wire_spacing, self.num_qubits * wire_spacing) |
| ax.set_aspect('equal') |
| ax.axis('off') |
| ax.set_title(f"Circuit: {self.name} ({self.num_qubits} qubits, depth {self.depth})") |
| |
| plt.tight_layout() |
| return fig |
| |
| def _draw_latex(self) -> str: |
| """Generate LaTeX/quantikz code for the circuit.""" |
| lines = [r"\begin{quantikz}"] |
| |
| for q in range(self.num_qubits): |
| wire = [r"\lstick{$q_" + str(q) + r"$}"] |
| |
| for gate in self.gates: |
| if q not in gate.targets: |
| wire.append(r"\qw") |
| elif len(gate.targets) == 1: |
| name = gate.name |
| if name == 'H': |
| wire.append(r"\gate{H}") |
| elif name == 'X': |
| wire.append(r"\gate{X}") |
| elif name == 'Y': |
| wire.append(r"\gate{Y}") |
| elif name == 'Z': |
| wire.append(r"\gate{Z}") |
| elif name == 'S': |
| wire.append(r"\gate{S}") |
| elif name == 'T': |
| wire.append(r"\gate{T}") |
| elif name in ('RX', 'RY', 'RZ'): |
| angle = gate.params[0] |
| wire.append(rf"\gate{{{name}({angle:.2f})}}") |
| else: |
| wire.append(rf"\gate{{{name}}}") |
| elif len(gate.targets) == 2: |
| if gate.name == 'CX': |
| if gate.targets[0] == q: |
| wire.append(r"\ctrl{" + str(gate.targets[1] - q) + r"}") |
| else: |
| wire.append(r"\targ{}") |
| else: |
| wire.append(rf"\gate{{{gate.name}}}") |
| |
| wire.append(r"\qw") |
| lines.append(" & ".join(wire) + r" \\") |
| |
| lines.append(r"\end{quantikz}") |
| return "\n".join(lines) |
| |
| def __repr__(self): |
| return f"QuantumCircuit(num_qubits={self.num_qubits}, gates={len(self.gates)}, depth={self.depth})" |
| |
| def __str__(self): |
| return self.draw() |
| |
| def __len__(self): |
| return len(self.gates) |
| |
| def copy(self) -> 'QuantumCircuit': |
| """Return a copy of this circuit.""" |
| qc = QuantumCircuit(self.num_qubits, self.name) |
| qc.gates = [Gate(g.name, g.targets, g.params) for g in self.gates] |
| return qc |
|
|