55 个版本 (5 个稳定版)

1.4.0 2023年5月12日
1.0.0-beta.12022年11月8日
0.15.3 2021年9月2日
0.15.0 2021年6月14日
0.1.8 2019年7月18日

#86 in 仿真器

每月33次下载

MIT 许可证

195KB
4K SLoC

利用图构建来构建高效量子电路模拟的量子计算库。Rust 是量子计算的良好语言,因为借用检查器与不可复制定理非常相似。

请参阅 GitHub 仓库 示例目录 中的所有示例。

示例 (CSWAP)

这是一个示例,其中两个寄存器组在第三个寄存器的条件下交换。这个电路非常小,只有三个操作加上一个测量,所以与比较起来,样板代码看起来相当大,但这个设置提供了在电路变大时轻松且安全地构建电路的能力。

use qip::prelude::*;
use std::num::NonZeroUsize;

// Make a new circuit builder.
let mut b = LocalBuilder::<f64>::default();
let n = NonZeroUsize::new(3).unwrap();

// Make three registers of sizes 1, 3, 3 (7 qubits total).
let q = b.qubit();  // Same as b.register(1)?;
let ra = b.register(n);
let rb = b.register(n);

// Define circuit
// First apply an H to q
let q = b.h(q);
// Then swap ra and rb, conditioned on q.
let mut cb = b.condition_with(q);
let (ra, rb) = cb.swap(ra, rb)?;
let q = cb.dissolve();
// Finally apply H to q again.
let q = b.h(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.

// Run circuit with a given precision.
let (_, measured) = b.calculate_state_with_init([(&ra, 0b000), (&rb, 0b001)]);

// 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);

// Print the measured result
println!("Measured: {:?} (with chance {:?})", result, p);

程序宏

虽然 Rust 中包含的借用检查器是一个检查我们的寄存器行为的出色工具,但它可能有些繁琐。因此,qip 还包括一个宏,它提供了一个类似于你在量子计算教科书中看到的 API。

use qip::prelude::*;
use std::num::NonZeroUsize;
use qip_macros::program;

fn gamma<B>(b: &mut B, ra: B::Register, rb: B::Register) -> CircuitResult<(B::Register, B::Register)>
   where B: AdvancedCircuitBuilder<f64>
{
    let (ra, rb) = b.toffoli(ra, rb)?;
    let (rb, ra) = b.toffoli(rb, ra)?;
    Ok((ra, rb))
}

let n = NonZeroUsize::new(3).unwrap();
let mut b = LocalBuilder::default();
let ra = b.register(n);
let rb = b.register(n);


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]>
    // Notice ra[0] and rb[0] are grouped by brackets.
    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_two_registers(ra, rb);

我们也可以将其应用于接受其他参数的函数。在这里,gamma 接受一个布尔参数 skip,在寄存器之前传入。 程序宏中函数的参数不能引用输入寄存器

use qip::prelude::*;
use std::num::NonZeroUsize;
use qip_macros::program;

fn gamma<B>(b: &mut B, skip: bool, ra: B::Register, rb: B::Register) -> CircuitResult<(B::Register, B::Register)>
   where B: AdvancedCircuitBuilder<f64>
{
    let (ra, rb) = b.toffoli(ra, rb)?;
    let (rb, ra) = if skip {
        b.toffoli(rb, ra)?
    } else {
        (rb, ra)
    };
    Ok((ra, rb))
}

let n = NonZeroUsize::new(3).unwrap();
let mut b = LocalBuilder::default();
let ra = b.register(n);
let rb = b.register(n);

let (ra, rb) = program!(&mut b; ra, rb;
    gamma(true) ra[0..2], ra[2];
    gamma(0 == 1) ra[0..2], ra[2];
)?;
let r = b.merge_two_registers(ra, rb);

反转宏

通常需要定义寄存器的函数以及它们的逆函数,#[invert] 宏自动化了此过程的很大一部分。

use qip::prelude::*;
use std::num::NonZeroUsize;
use qip_macros::*;

use qip::inverter::Invertable;
// Make gamma and its inverse: gamma_inv
#[invert(gamma_inv)]
fn gamma<B>(b: &mut B, ra: B::Register, rb: B::Register) -> CircuitResult<(B::Register, B::Register)>
   where B: AdvancedCircuitBuilder<f64> + Invertable<SimilarBuilder=B>
{
    let (ra, rb) = b.toffoli(ra, rb)?;
    let (rb, ra) = b.toffoli(rb, ra)?;
    Ok((ra, rb))
}

let n = NonZeroUsize::new(3).unwrap();
let mut b = LocalBuilder::default();
let ra = b.register(n);
let rb = b.register(n);


let (ra, rb) = program!(&mut b; ra, rb;
    gamma ra[0..2], ra[2];
    gamma_inv ra[0..2], ra[2];
)?;
let r = b.merge_two_registers(ra, rb);

要反转具有额外参数的函数,我们必须列出非寄存器参数。

use qip::prelude::*;
use std::num::NonZeroUsize;
use qip_macros::*;

use qip::inverter::Invertable;
// Make gamma and its inverse: gamma_inv
#[invert(gamma_inv, skip)]
fn gamma<B>(b: &mut B, skip: bool, ra: B::Register, rb: B::Register) -> CircuitResult<(B::Register, B::Register)>
   where B: AdvancedCircuitBuilder<f64> + Invertable<SimilarBuilder=B>
{
    let (ra, rb) = b.toffoli(ra, rb)?;
    let (rb, ra) = if skip {
        b.toffoli(rb, ra)?
    } else {
        (rb, ra)
    };
    Ok((ra, rb))
}

let n = NonZeroUsize::new(3).unwrap();
let mut b = LocalBuilder::default();
let ra = b.register(n);
let rb = b.register(n);

let (ra, rb) = program!(&mut b; ra, rb;
    gamma(true) ra[0..2], ra[2];
    gamma_inv(true) ra[0..2], ra[2];
)?;
let r = b.merge_two_registers(ra, rb);

依赖项

~1–1.4MB
~28K SLoC