[][src]Crate qip

Quantum Computing library leveraging graph building to build efficient quantum circuit simulations.

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 compairison, 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();
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 run this subcircuit conditioned on r, applied to ra and rb
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>
let initial_state = [a_handle.make_init_from_index(0)?,
                     b_handle.make_init_from_index(1)?];
// 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.
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)?;

let 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);
    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> (meaning rb[0] == |0>)
    control(0b110) gamma rb, ra[0..2], ra[2];
)?;
let r = b.merge(vec![ra, rb])?;

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.

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! as well as an inverse which is also compatible.

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 program! as well as an inverse which is also compatible.

wrap_fn

Allows the wrapping of a function with signature: Fn(&mut dyn UnitaryBuilder, Register, Register, ...) -> (Register, ...) or Fn(&mut dyn UnitaryBuilder, Register, Register, ...) -> Result<(Register, ...), CircuitError> to make a new function with signature: Fn(&mut dyn UnitaryBuilder, Vec<Register>) -> Result<Vec<Register>, CircuitError> and is therefore compatible with program!.

Structs

Complex

A complex number in Cartesian form.