[−][src]Crate qip
Quantum Computing library leveraging graph building to build efficient quantum circuit simulations. Rust is a great language for quantum computing with gate models because the borrow checker is very similar to the No-cloning theorem.
See all the examples in the examples directory of the Github repository.
Example (CSWAP)
Here's an example of a small circuit where two groups of Registers are swapped conditioned on a third. This circuit is very small, only three operations plus a measurement, so the boilerplate can look quite large in comparison, but that setup provides the ability to construct circuits easily and safely when they do get larger.
use qip::*; // Make a new circuit builder. let mut b = OpBuilder::new(); // Make three registers of sizes 1, 3, 3 (7 qubits total). let q = b.qubit(); // Same as b.register(1)?; let ra = b.register(3)?; let rb = b.register(3)?; // We will want to feed in some inputs later, hang on to the handles // so we don't need to actually remember any indices. let a_handle = ra.handle(); let b_handle = rb.handle(); // Define circuit // First apply an H to r let q = b.hadamard(q); // Then swap ra and rb, conditioned on q. let (q, _, _) = b.cswap(q, ra, rb)?; // Finally apply H to q again. let q = b.hadamard(q); // Add a measurement to the first qubit, save a reference so we can get the result later. let (q, m_handle) = b.measure(q); // Now q is the end result of the above circuit, and we can run the circuit by referencing it. // Make an initial state: |0,000,001> (default value for registers not mentioned is 0). let initial_state = [a_handle.make_init_from_index(0b000)?, b_handle.make_init_from_index(0b001)?]; // Run circuit with a given precision. let (_, measured) = run_local_with_init::<f64>(&q, &initial_state)?; // Lookup the result of the measurement we performed using the handle, and the probability // of getting that measurement. let (result, p) = measured.get_measurement(&m_handle).unwrap(); // Print the measured result println!("Measured: {:?} (with chance {:?})", result, p);
The Program Macro
While the borrow checker included in rust is a wonderful tool for checking that our registers are behaving, it can be cumbersome. For that reason qip also includes a macro which provides an API similar to that which you would see in quantum computing textbooks
use qip::*; let n = 3; let mut b = OpBuilder::new(); let ra = b.register(n)?; let rb = b.register(n)?; fn gamma(b: &mut dyn UnitaryBuilder, mut rs: Vec<Register>) -> Result<Vec<Register>, CircuitError> { let rb = rs.pop().unwrap(); let ra = rs.pop().unwrap(); let (ra, rb) = b.cnot(ra, rb); let (rb, ra) = b.cnot(rb, ra); Ok(vec![ra, rb]) } let (ra, rb) = program!(&mut b, ra, rb; // Applies gamma to |ra[0] ra[1]>|ra[2]> gamma ra[0..2], ra[2]; // Applies gamma to |ra[0] rb[0]>|ra[2]> gamma |ra[0], rb[0],| ra[2]; // Applies gamma to |ra[0]>|rb[0] ra[2]> gamma ra[0], |rb[0], ra[2],|; // Applies gamma to |ra[0] ra[1]>|ra[2]> if rb == |111> control gamma rb, ra[0..2], ra[2]; // Applies gamma to |ra[0] ra[1]>|ra[2]> if rb == |110> (rb[0] == |0>, rb[1] == 1, ...) control(0b110) gamma rb, ra[0..2], ra[2]; )?; let r = b.merge(vec![ra, rb])?;
To clean up gamma we can use the wrap_fn
macro:
use qip::*; let n = 3; let mut b = OpBuilder::new(); let ra = b.register(n)?; let rb = b.register(n)?; fn gamma(b: &mut dyn UnitaryBuilder, ra: Register, rb: Register) -> (Register, Register) { let (ra, rb) = b.cnot(ra, rb); let (rb, ra) = b.cnot(rb, ra); (ra, rb) } // Make a function gamma_op from gamma which matches the spec required by program!(...). // Here we tell wrap_fn! that gamma takes two registers, which we will internally call ra, rb. wrap_fn!(gamma_op, gamma, ra, rb); // if gamma returns a Result<(Register, Register), CircuitError>, write (gamma) instead. // wrap_fn!(gamma_op, (gamma), ra, rb) let (ra, rb) = program!(&mut b, ra, rb; gamma_op ra[0..2], ra[2]; )?; let r = b.merge(vec![ra, rb])?;
And with these wrapped functions, automatically produce their conjugates / inverses:
use qip::*; let n = 3; let mut b = OpBuilder::new(); let ra = b.register(n)?; let rb = b.register(n)?; fn gamma(b: &mut dyn UnitaryBuilder, ra: Register, rb: Register) -> (Register, Register) { let (ra, rb) = b.cnot(ra, rb); let (rb, ra) = b.cnot(rb, ra); (ra, rb) } wrap_fn!(gamma_op, gamma, ra, rb); invert_fn!(inv_gamma_op, gamma_op); // This program is equivalent to the identity (U^-1 U = I). let (ra, rb) = program!(&mut b, ra, rb; gamma_op ra, rb[2]; inv_gamma_op ra, rb[2]; )?;
Re-exports
pub use self::builders::*; |
pub use self::common_circuits::*; |
pub use self::errors::*; |
pub use self::macros::*; |
pub use self::pipeline::run_local; |
pub use self::pipeline::run_local_with_init; |
pub use self::pipeline::run_with_state; |
pub use self::pipeline::QuantumState; |
pub use self::pipeline_debug::run_debug; |
pub use self::qubits::Register; |
pub use self::types::Precision; |
Modules
boolean_circuits | Quantum analogues of boolean circuits |
builders | Opbuilder and such |
common_circuits | Common circuits for general usage. |
errors | Error values for the library. |
iterators | Efficient iterators for sparse kronprod matrices. |
macros | Macros for general ease of use. |
measurement_ops | Functions for measuring states. |
pipeline | Code for building pipelines. |
pipeline_debug | Tools for displaying pipelines. |
qfft | Quantum fourier transform support. |
qubits | Basic classes for defining circuits/pipelines. |
sparse_state | Sparse quantum states |
state_ops | Functions for running ops on states. |
trace_state | Tracing state |
types | Commonly used types. |
unitary_decomposition | Break unitary matrices into circuits. |
utils | Commonly used short functions. |
Macros
invert_fn | Wrap a function to create a version compatible with |
program | A helper macro for applying functions to specific qubits in registers. |
register_expr | A helper macro for applying functions to specific qubits in registers. |
wrap_and_invert | Wrap a function to create a version compatible with |
wrap_fn | Allows the wrapping of a function with signature:
|
Structs
Complex | A complex number in Cartesian form. |