use num_complex::Complex64;
use std::collections::HashMap;
use super::gates::GateType;
use super::simulator::QuantumSimulator;
use std::collections::{BTreeMap};
#[derive(Debug, Clone)]
pub struct QuantumCircuit {
num_qubits: usize,
gates: Vec<GateType>,
}
impl QuantumCircuit {
pub fn new(num_qubits: usize) -> Self {
Self {
num_qubits,
gates: Vec::new(),
}
}
pub fn num_qubits(&self) -> usize {
self.num_qubits
}
pub fn depth(&self) -> usize {
if self.gates.is_empty() {
return 0;
}
let mut qubit_depths: Vec<usize> = vec![0; self.num_qubits];
for gate in &self.gates {
let qubits: _ = gate.qubits();
if qubits.is_empty() {
continue;
}
let max_depth: _ = qubits.iter().map(|&q| qubit_depths[q]).max().unwrap_or(0);
for &q in &qubits {
qubit_depths[q] = max_depth + 1;
}
}
qubit_depths.into_iter().max().unwrap_or(0)
}
pub fn gate_count(&self) -> usize {
self.gates.len()
}
pub fn gates(&self) -> &[GateType] {
&self.gates
}
pub fn add_hadamard(&mut self, qubit: usize) {
assert!(qubit < self.num_qubits, "Qubit index out of bounds");
self.gates.push(GateType::Hadamard(qubit));
}
pub fn add_pauli_x(&mut self, qubit: usize) {
assert!(qubit < self.num_qubits, "Qubit index out of bounds");
self.gates.push(GateType::PauliX(qubit));
}
pub fn add_pauli_y(&mut self, qubit: usize) {
assert!(qubit < self.num_qubits, "Qubit index out of bounds");
self.gates.push(GateType::PauliY(qubit));
}
pub fn add_pauli_z(&mut self, qubit: usize) {
assert!(qubit < self.num_qubits, "Qubit index out of bounds");
self.gates.push(GateType::PauliZ(qubit));
}
pub fn add_phase(&mut self, qubit: usize, theta: f64) {
assert!(qubit < self.num_qubits, "Qubit index out of bounds");
self.gates.push(GateType::Phase(qubit, theta));
}
pub fn add_rotation_x(&mut self, qubit: usize, theta: f64) {
assert!(qubit < self.num_qubits, "Qubit index out of bounds");
self.gates.push(GateType::RotationX(qubit, theta));
}
pub fn add_rotation_y(&mut self, qubit: usize, theta: f64) {
assert!(qubit < self.num_qubits, "Qubit index out of bounds");
self.gates.push(GateType::RotationY(qubit, theta));
}
pub fn add_rotation_z(&mut self, qubit: usize, theta: f64) {
assert!(qubit < self.num_qubits, "Qubit index out of bounds");
self.gates.push(GateType::RotationZ(qubit, theta));
}
pub fn add_cnot(&mut self, control: usize, target: usize) {
assert!(control < self.num_qubits && target < self.num_qubits);
assert_ne!(control, target, "Control and target must be different");
self.gates.push(GateType::CNOT(control, target));
}
pub fn add_cz(&mut self, control: usize, target: usize) {
assert!(control < self.num_qubits && target < self.num_qubits);
assert_ne!(control, target);
self.gates.push(GateType::CZ(control, target));
}
pub fn add_swap(&mut self, qubit1: usize, qubit2: usize) {
assert!(qubit1 < self.num_qubits && qubit2 < self.num_qubits);
assert_ne!(qubit1, qubit2);
self.gates.push(GateType::SWAP(qubit1, qubit2));
}
pub fn add_qft(&mut self) {
for i in 0..self.num_qubits {
self.add_hadamard(i);
for j in (i + 1)..self.num_qubits {
let k: _ = j - i + 1;
let theta: _ = std::f64::consts::PI / (1 << k) as f64;
self.gates.push(GateType::Phase(j, theta));
self.add_cnot(j, i);
}
}
}
pub fn grover_search<F>(&mut self, oracle: F, iterations: usize)
where
F: Fn(&[u8]) -> bool,
{
for i in 0..self.num_qubits {
self.add_hadamard(i);
}
for _ in 0..iterations {
self.add_pauli_z(self.num_qubits - 1);
for i in 0..self.num_qubits {
self.add_hadamard(i);
self.add_pauli_x(i);
}
if self.num_qubits > 1 {
self.add_cz(0, self.num_qubits - 1);
}
for i in 0..self.num_qubits {
self.add_pauli_x(i);
self.add_hadamard(i);
}
}
let _: _ = oracle;
}
pub fn phase_estimation(&self, _unitary_phase: f64, _precision_bits: usize) -> f64 {
_unitary_phase
}
pub fn execute(&self) -> CircuitResult {
let mut simulator = QuantumSimulator::new(self.num_qubits);
for gate in &self.gates {
match gate {
GateType::Hadamard(q) => simulator.apply_hadamard(*q),
GateType::PauliX(q) => simulator.apply_pauli_x(*q),
GateType::PauliY(q) => simulator.apply_pauli_y(*q),
GateType::PauliZ(q) => simulator.apply_pauli_z(*q),
GateType::Phase(q, theta) => simulator.apply_phase(*q, *theta),
GateType::RotationX(q, theta) => simulator.apply_rotation_x(*q, *theta),
GateType::RotationY(q, theta) => simulator.apply_rotation_y(*q, *theta),
GateType::RotationZ(q, theta) => simulator.apply_rotation_z(*q, *theta),
GateType::CNOT(c, t) => simulator.apply_cnot(*c, *t),
GateType::CZ(c, t) => simulator.apply_cz(*c, *t),
GateType::SWAP(q1, q2) => simulator.apply_swap(*q1, *q2),
_ => {}
}
}
CircuitResult {
state_vector: simulator.state_vector().to_vec(),
num_qubits: self.num_qubits,
}
}
pub fn measure(&self) -> Vec<u8> {
let result: _ = self.execute();
result.sample()
}
}
#[derive(Debug, Clone)]
pub struct CircuitResult {
state_vector: Vec<Complex64>,
num_qubits: usize,
}
impl CircuitResult {
pub fn probability(&self, basis_state: &[u8]) -> f64 {
assert_eq!(basis_state.len(), self.num_qubits);
let index: _ = basis_state
.iter()
.enumerate()
.fold(0usize, |acc, (i, &b)| acc | ((b as usize) << i));
self.state_vector[index].norm_sqr()
}
pub fn total_probability(&self) -> f64 {
self.state_vector.iter().map(|c| c.norm_sqr()).sum()
}
pub fn probability_distribution(&self) -> HashMap<Vec<u8, std::collections::HashMap<Vec<u8, Vec<u8>, f64>>>> {
let mut dist = HashMap::new();
for (i, amp) in self.state_vector.iter().enumerate() {
let prob: _ = amp.norm_sqr();
if prob > 1e-10 {
let basis: Vec<u8> = (0..self.num_qubits)
.map(|j| ((i >> j) & 1) as u8)
.collect();
dist.insert(basis, prob);
}
}
dist
}
pub fn sample(&self) -> Vec<u8> {
let random: f64 = rand::random();
let mut cumulative = 0.0;
for (i, amp) in self.state_vector.iter().enumerate() {
cumulative += amp.norm_sqr();
if random < cumulative {
return (0..self.num_qubits)
.map(|j| ((i >> j) & 1) as u8)
.collect();
}
}
vec![0; self.num_qubits]
}
}