SimulatedCircuit

Struct SimulatedCircuit 

Source
pub struct SimulatedCircuit { /* private fields */ }
Expand description

Contains the resulting state vector produced from the simulation of a circuit.

Implementations§

Source§

impl SimulatedCircuit

Source

pub fn measure_all( &self, shots: usize, ) -> Measurement<HashMap<ProductState, usize>>

Returns a HashMap that contains the number of times the corresponding state was observed over n measurements of the superpositions (shots).

Explicitly, this performs repeated measurements where a register is attached to the circuit, the resulting superposition measured in the computational basis, and then the reduced state recorded. If the HashMap does not include a product state, then it was not observed over the n measurements.

For efficiency, this will use the cached register from the simulated circuit. If your circuit contains mixed states, then most likely the circuit will have to be simulated again for each shot. To achieve this, use SimulatedCircuit::measure_all_without_cache.

§Example
use quantr::{states::SuperPosition, Circuit, Measurement::Observable, Gate};

let mut circuit = Circuit::new(3).unwrap();

circuit.add_gate(Gate::H, 2).unwrap();
let simulated_circuit = circuit.simulate();

// Measures 500 superpositions.
println!("State | Number of Times Observed");
if let Observable(bin_count) = simulated_circuit.measure_all(500) {
    for (state, observed_count) in bin_count {
        println!("|{}>   : {}", state, observed_count);
    }
}

// State | Number of Times Observed
// |000> : 247
// |001> : 253
Examples found in repository?
examples/generalised_control_not_gate.rs (line 42)
21fn main() -> Result<(), QuantrError> {
22    let mut qc: Circuit = Circuit::new(CIRCUIT_SIZE)?;
23
24    // Multi-controlled gate used here.
25    qc.add_repeating_gate(Gate::X, &[0, 1, 2, 3, 4, 5])?
26        .add_gate(
27            Gate::Custom(
28                multicnot::<CIRCUIT_SIZE>,
29                vec![0, 1, 2, 3, 4],
30                "X".to_string(),
31            ),
32            5,
33        )?;
34
35    let mut circuit_printer: Printer = Printer::new(&qc);
36    circuit_printer.print_diagram();
37
38    qc.set_print_progress(true);
39    let simulated = qc.simulate();
40
41    // Prints the bin count of measured states.
42    if let Measurement::Observable(bin_count) = simulated.measure_all(50) {
43        println!("\nStates observed over 50 measurements:");
44        for (states, count) in bin_count.into_iter() {
45            println!("|{}> : {}", states, count);
46        }
47    }
48
49    Ok(())
50}
More examples
Hide additional examples
examples/custom_gate.rs (line 35)
18fn main() -> Result<(), QuantrError> {
19    let mut qc: Circuit = Circuit::new(4)?;
20
21    // Build a circuit using a CCC-not gate, placing the control nodes on positions 0, 1, 2 and
22    // the target on 3.
23    qc.add_repeating_gate(Gate::X, &[0, 1, 2])?
24        .add_gate(Gate::Custom(cccnot, vec![0, 1, 2], "X".to_string()), 3)?;
25
26    // Prints the circuit, viewing the custom gate.
27    let mut circuit_printer: Printer = Printer::new(&qc);
28    circuit_printer.print_diagram();
29
30    // Prints the simulation process of each gate (excluding identity gates).
31    qc.set_print_progress(true);
32    let simulated = qc.simulate();
33
34    // Prints the bin count of measured states.
35    if let Measurement::Observable(bin_count) = simulated.measure_all(50) {
36        println!("\nStates observed over 50 measurements:");
37        for (states, count) in bin_count.into_iter() {
38            println!("|{}> : {}", states, count);
39        }
40    }
41
42    Ok(())
43}
examples/grovers.rs (line 52)
20fn main() -> Result<(), QuantrError> {
21    let mut circuit = Circuit::new(3)?;
22
23    // Kick state into superposition of equal weights
24    circuit.add_repeating_gate(Gate::H, &[0, 1, 2])?;
25
26    // Oracle
27    circuit.add_gate(Gate::CZ(1), 0)?;
28
29    // Amplitude amplification
30    circuit
31        .add_repeating_gate(Gate::H, &[0, 1, 2])?
32        .add_repeating_gate(Gate::X, &[0, 1, 2])?
33        .add_gate(Gate::H, 2)?
34        .add_gate(Gate::Toffoli(0, 1), 2)?
35        .add_gate(Gate::H, 2)?
36        .add_repeating_gate(Gate::X, &[0, 1, 2])?
37        .add_repeating_gate(Gate::H, &[0, 1, 2])?;
38
39    // Prints the circuit in UTF-8
40    let mut printer = Printer::new(&circuit);
41    printer.print_diagram();
42
43    // Print the progress of the simulation
44    circuit.set_print_progress(true);
45
46    // Simulates the circuit
47    let simulated_circuit = circuit.simulate();
48    println!("");
49
50    // Displays bin count of the resulting 500 repeat measurements of
51    // superpositions. bin_count is a HashMap<ProductState, usize>.
52    if let Measurement::Observable(bin_count) = simulated_circuit.measure_all(500) {
53        println!("[Observable] Bin count of observed states.");
54        for (state, count) in bin_count {
55            println!("|{}> observed {} times", state, count);
56        }
57    } 
58
59    // Returns the superpsoition that cannot be directly observed.
60    if let Measurement::NonObservable(output_super_position) = simulated_circuit.get_state()
61    {
62        println!("\n[Non-Observable] The amplitudes of each state in the final superposition.");
63        for (state, amplitude) in output_super_position.into_iter() {
64            println!("|{}> : {}", state, amplitude);
65        }
66    }
67
68    Ok(())
69}
Source

pub fn measure_all_without_cache( self, shots: usize, ) -> Measurement<HashMap<ProductState, usize>>

Similar to SimulatedCircuit::measure_all, however for every shot it will simulate the circuit, where the input register is reset to the zero state.

This potentially allows for mixed states to be simulated, through the implementation of Gate::Custom. In doing so will dramatically increase the simulation time, as a new circuit will be simulated for each shot.

Source

pub fn get_state(&self) -> Measurement<&SuperPosition>

Returns the resulting superposition after the circuit has been simulated using super::Circuit::simulate.

This is a non-physical observable, as the superposition would reduce to a single state upon measurement.

§Example
use quantr::{states::SuperPosition, Circuit, Measurement::NonObservable, Gate};

let mut circuit = Circuit::new(3).unwrap();

circuit.add_gate(Gate::H, 2).unwrap();
circuit.add_gate(Gate::Y, 2).unwrap();
let simulated_circuit = circuit.simulate();

println!("State | Amplitude of State");
if let NonObservable(super_pos) = simulated_circuit.get_state() {
    for (state, amplitude) in super_pos.into_iter() {
        println!("|{}>   : {}", state.to_string(), amplitude);
    }
}

// State | Amplitude of State
// |000> : 0 - 0.71...i
// |001> : 0 + 0.71...i
Examples found in repository?
examples/post_select.rs (line 29)
17fn main() -> Result<(), QuantrError> {
18    let mut qc = Circuit::new(3)?;
19
20    qc.add_repeating_gate(Gate::H, &[0, 1, 2])?
21        .add_gate(Gate::Custom(post_select, vec![], "P".to_string()), 1)?;
22
23    let mut printer = Printer::new(&qc);
24    printer.print_diagram();
25
26    qc.set_print_progress(true);
27    let simulated_qc = qc.simulate();
28
29    if let Measurement::NonObservable(final_sup) = simulated_qc.get_state() {
30        println!("\nThe final superposition is:");
31        for (state, amplitude) in final_sup.into_iter() {
32            println!("|{}> : {}", state, amplitude);
33        }
34    }
35
36    Ok(())
37}
More examples
Hide additional examples
examples/qft.rs (line 35)
21fn main() -> Result<(), QuantrError> {
22    let mut qc: Circuit = Circuit::new(3)?;
23
24    // Apply qft
25    qc.add_repeating_gate(Gate::X, &[1, 2])?
26        .add_gate(Gate::Custom(qft, vec![0, 1], "QFT".to_string()), 2)?; // QFT on bits 0, 1 and 2
27
28    let mut printer = Printer::new(&qc);
29    printer.print_diagram();
30
31    qc.set_print_progress(true);
32
33    let simulated_circuit = qc.simulate();
34
35    if let Measurement::NonObservable(final_sup) = simulated_circuit.get_state() {
36        println!("\nThe final superposition is:");
37        for (state, amplitude) in final_sup.into_iter() {
38            println!("|{}> : {}", state, amplitude);
39        }
40    }
41
42    Ok(())
43}
examples/grovers.rs (line 60)
20fn main() -> Result<(), QuantrError> {
21    let mut circuit = Circuit::new(3)?;
22
23    // Kick state into superposition of equal weights
24    circuit.add_repeating_gate(Gate::H, &[0, 1, 2])?;
25
26    // Oracle
27    circuit.add_gate(Gate::CZ(1), 0)?;
28
29    // Amplitude amplification
30    circuit
31        .add_repeating_gate(Gate::H, &[0, 1, 2])?
32        .add_repeating_gate(Gate::X, &[0, 1, 2])?
33        .add_gate(Gate::H, 2)?
34        .add_gate(Gate::Toffoli(0, 1), 2)?
35        .add_gate(Gate::H, 2)?
36        .add_repeating_gate(Gate::X, &[0, 1, 2])?
37        .add_repeating_gate(Gate::H, &[0, 1, 2])?;
38
39    // Prints the circuit in UTF-8
40    let mut printer = Printer::new(&circuit);
41    printer.print_diagram();
42
43    // Print the progress of the simulation
44    circuit.set_print_progress(true);
45
46    // Simulates the circuit
47    let simulated_circuit = circuit.simulate();
48    println!("");
49
50    // Displays bin count of the resulting 500 repeat measurements of
51    // superpositions. bin_count is a HashMap<ProductState, usize>.
52    if let Measurement::Observable(bin_count) = simulated_circuit.measure_all(500) {
53        println!("[Observable] Bin count of observed states.");
54        for (state, count) in bin_count {
55            println!("|{}> observed {} times", state, count);
56        }
57    } 
58
59    // Returns the superpsoition that cannot be directly observed.
60    if let Measurement::NonObservable(output_super_position) = simulated_circuit.get_state()
61    {
62        println!("\n[Non-Observable] The amplitudes of each state in the final superposition.");
63        for (state, amplitude) in output_super_position.into_iter() {
64            println!("|{}> : {}", state, amplitude);
65        }
66    }
67
68    Ok(())
69}
Source

pub fn print_warnings(&mut self, printing: bool)

Sets if the printer should display warnings.

Source

pub fn get_circuit_gates(&self) -> &Vec<Gate>

The slice of gates that composed the circuit, equivalent to Circuit::get_gates.

Source

pub fn get_num_qubits(&self) -> usize

The number of qubits that composed the circuit, equivalent to Circuit::get_num_qubits.

Source

pub fn set_print_progress(&mut self, printing: bool)

Sets whether the simulation progress of the circuit will be printed to the terminal. This value is inherited from the circuit this struct was derived from.

Source

pub fn take_state(self) -> Measurement<SuperPosition>

Takes ownership of the state that the SimulatedCircuit wraps around, that is the state that resulted from a circuit simulation.

Examples found in repository?
examples/qft.rs (line 64)
47fn qft(input_state: ProductState) -> Option<SuperPosition> {
48    let qubit_num = input_state.num_qubits();
49    let mut mini_circuit: Circuit = Circuit::new(qubit_num).unwrap();
50
51    for pos in 0..qubit_num {
52        mini_circuit.add_gate(Gate::H, pos).unwrap();
53        for k in 2..=(qubit_num - pos) {
54            mini_circuit
55                .add_gate(Gate::CRk(k as i32, pos + k - 1), pos)
56                .unwrap();
57        }
58    }
59
60    mini_circuit
61        .change_register(SuperPosition::from(input_state))
62        .unwrap();
63
64    Some(mini_circuit.simulate().take_state().take())
65}

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.