use crate::circuit::CliffordGate;
use crate::circuit::parser;
use crate::circuit::random_clifford;
use crate::error::Result;
use std::fmt;
#[derive(Debug, Clone)]
pub struct CliffordCircuit {
pub num_qubits: usize,
pub gates: Vec<CliffordGate>,
}
impl CliffordCircuit {
pub fn new(num_qubits: usize) -> Self {
CliffordCircuit {
num_qubits,
gates: Vec::new(),
}
}
pub fn tensor(&self, other: &CliffordCircuit) -> Self {
let mut new_circuit = CliffordCircuit::new(self.num_qubits + other.num_qubits);
for gate in &self.gates {
new_circuit.gates.push(gate.clone());
}
for gate in &other.gates {
new_circuit.gates.push(gate.shifted(self.num_qubits));
}
new_circuit
}
pub fn append(&mut self, other: &CliffordCircuit) {
for gate in &other.gates {
self.gates.push(gate.clone());
}
}
pub fn add_gate(&mut self, gate: CliffordGate) {
self.gates.push(gate);
}
pub fn add_gates(&mut self, gates: Vec<CliffordGate>) {
for gate in gates {
self.add_gate(gate);
}
}
pub fn apply_h(&mut self, qarg: usize) {
self.add_gate(CliffordGate::H(qarg));
}
pub fn apply_x(&mut self, qarg: usize) {
self.add_gate(CliffordGate::X(qarg));
}
pub fn apply_y(&mut self, qarg: usize) {
self.add_gate(CliffordGate::Y(qarg));
}
pub fn apply_z(&mut self, qarg: usize) {
self.add_gate(CliffordGate::Z(qarg));
}
pub fn apply_s(&mut self, qarg: usize) {
self.add_gate(CliffordGate::S(qarg));
}
pub fn apply_sdg(&mut self, qarg: usize) {
self.add_gate(CliffordGate::Sdg(qarg));
}
pub fn apply_sqrt_x(&mut self, qarg: usize) {
self.add_gate(CliffordGate::SqrtX(qarg));
}
pub fn apply_sqrt_xdg(&mut self, qarg: usize) {
self.add_gate(CliffordGate::SqrtXdg(qarg));
}
pub fn apply_cx(&mut self, control: usize, target: usize) {
self.add_gate(CliffordGate::CX(control, target));
}
pub fn apply_cz(&mut self, qarg1: usize, qarg2: usize) {
self.add_gate(CliffordGate::CZ(qarg1, qarg2));
}
pub fn apply_swap(&mut self, qarg1: usize, qarg2: usize) {
self.add_gate(CliffordGate::Swap(qarg1, qarg2));
}
pub fn from_qasm_file(path: &str) -> Result<Self> {
parser::from_qasm_file(path)
}
pub fn from_qasm_str(qasm_str: &str) -> Result<Self> {
parser::from_qasm_str(qasm_str)
}
pub fn to_qasm_str(&self, reg_name: &str) -> String {
parser::to_qasm_str(self, reg_name)
}
pub fn to_qasm_file(&self, path: &str, reg_name: &str) -> Result<()> {
parser::to_qasm_file(self, path, reg_name)
}
pub fn random_clifford(num_qubits: usize, seed: Option<[u8; 32]>) -> Self {
random_clifford::random_clifford(num_qubits, seed)
}
}
impl fmt::Display for CliffordCircuit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "CliffordCircuit(num_qubits={}) [", self.num_qubits)?;
for (i, gate) in self.gates.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", gate)?;
}
write!(f, "]")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_append_circuit() {
let mut circuit1 = CliffordCircuit::new(2);
circuit1.apply_h(0);
let mut circuit2 = CliffordCircuit::new(2);
circuit2.apply_cx(0, 1);
circuit1.append(&circuit2);
assert_eq!(circuit1.gates.len(), 2);
assert_eq!(circuit1.gates[0], CliffordGate::H(0));
assert_eq!(circuit1.gates[1], CliffordGate::CX(0, 1));
}
#[test]
fn test_tensor_circuit() {
let mut circuit1 = CliffordCircuit::new(2);
circuit1.apply_h(0);
let mut circuit2 = CliffordCircuit::new(3);
circuit2.apply_cx(0, 1);
let tensor_circuit = circuit1.tensor(&circuit2);
assert_eq!(tensor_circuit.num_qubits, 5);
assert_eq!(tensor_circuit.gates.len(), 2);
assert_eq!(tensor_circuit.gates[0], CliffordGate::H(0));
assert_eq!(tensor_circuit.gates[1], CliffordGate::CX(2, 3));
}
#[test]
fn test_clifford_circuit_display() {
let mut circuit = CliffordCircuit::new(2);
circuit.apply_h(0);
circuit.apply_cx(0, 1);
let display_str = format!("{}", circuit);
assert_eq!(
display_str,
"CliffordCircuit(num_qubits=2) [H(0), CX(0, 1)]"
);
}
}