use crate::{
complex_re,
states::{ProductState, SuperPosition},
Measurement,
};
use crate::{Circuit, Gate};
use std::collections::HashMap;
pub struct SimulatedCircuit {
pub(crate) circuit_gates: Vec<Gate>,
pub(crate) num_qubits: usize,
pub(crate) register: SuperPosition,
pub(crate) config_progress: bool,
pub(super) disable_warnings: bool,
}
impl SimulatedCircuit {
pub fn measure_all(&self, shots: usize) -> Measurement<HashMap<ProductState, usize>> {
let mut bin_count: HashMap<ProductState, usize> = Default::default();
if self.circuit_gates.iter().any(|x| x.is_custom_gate()) && !self.disable_warnings {
eprintln!("\x1b[93m[Quantr Warning] Custom gates were detected in the circuit. Measurements will be taken from a cached register in memory, and so if the Custom gate does NOT implement a unitary mapping, the measure_all method will most likely lead to wrong results. To simulate a circuit without cache, see SimulatedCircuit::measure_all_without_cache.\x1b[0m")
}
for _ in 0..shots {
self.add_to_bin(&mut bin_count);
}
Measurement::Observable(bin_count)
}
pub fn measure_all_without_cache(
self,
shots: usize,
) -> Measurement<HashMap<ProductState, usize>> {
let mut bin_count: HashMap<ProductState, usize> = Default::default();
let mut simulated_circ = self;
simulated_circ.add_to_bin(&mut bin_count);
if simulated_circ.config_progress {
println!("Measured state # 1/{}", shots);
}
for i in 0..shots - 1 {
simulated_circ
.register
.amplitudes
.fill(num_complex::Complex64::ZERO);
simulated_circ.register.amplitudes[0] = complex_re!(1f64);
if simulated_circ.config_progress {
println!("Register reset to zero state")
}
let circuit = Circuit {
circuit_gates: simulated_circ.circuit_gates,
num_qubits: simulated_circ.num_qubits,
register: Some(simulated_circ.register),
config_progress: simulated_circ.config_progress,
};
simulated_circ = circuit.simulate();
simulated_circ.add_to_bin(&mut bin_count);
if simulated_circ.config_progress {
println!("Measured state # {}/{}", i + 2, shots);
}
}
Measurement::Observable(bin_count)
}
fn add_to_bin(&self, bin: &mut HashMap<ProductState, usize>) {
match self.register.measure() {
Some(state) => {
bin.entry(state)
.and_modify(|count| {
*count = *count + 1;
})
.or_insert(1);
}
None if !self.disable_warnings => {
eprintln!("\x1b[93m[Quantr Warning] The superposition failed to collapse to a state during repeat measurements. This is likely due to the use of Gate::Custom where the mapping is not unitary.\x1b[0m")
}
None => {}
}
}
pub fn get_state(&self) -> Measurement<&SuperPosition> {
Measurement::NonObservable(&self.register)
}
pub fn print_warnings(&mut self, printing: bool) {
self.disable_warnings = printing;
}
pub fn get_circuit_gates(&self) -> &Vec<Gate> {
&self.circuit_gates
}
pub fn get_num_qubits(&self) -> usize {
self.num_qubits
}
pub fn set_print_progress(&mut self, printing: bool) {
self.config_progress = printing;
}
pub fn take_state(self) -> Measurement<SuperPosition> {
Measurement::NonObservable(self.register)
}
}