From a08ade70112e835717765fdc806f00834976e7cb Mon Sep 17 00:00:00 2001 From: aokyut Date: Wed, 28 Feb 2024 18:24:30 +0900 Subject: [PATCH] add doc-comment --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 78 ++++++++++--- README.tpl | 2 +- src/gates.rs | 318 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/lib.rs | 158 ++++++++----------------- 6 files changed, 431 insertions(+), 129 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 006f8b8..85b8adb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = 3 [[package]] name = "Qit" -version = "0.1.2" +version = "0.1.3" dependencies = [ "rand", ] diff --git a/Cargo.toml b/Cargo.toml index 68be290..bc65bdc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "Qit" license = "MIT" author = ["epaperamic@gmail.com"] -version = "0.1.2" +version = "0.1.3" edition = "2021" readme = "README.md" description = "Quantum computer simulator library without matrix operations." diff --git a/README.md b/README.md index 2dad341..cb80ef5 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,86 @@ [![Tests](https://github.com/aokyut/Qit/actions/workflows/rust.yml/badge.svg)](https://github.com/aokyut/Qit/actions/workflows/rust.yml) -# Qits +# Qit Simple quantum computer simulator library without matrix operations. + + ## Example +All gates can make changes to the qubit using the apply method. +### Usage basic gates ```rust -use Qit::core::{gates::{X, Applicable}, Qubits}; +use Qit::core::{Applicable, Operator, Qubits}; +use Qit::gates::{CX, H, U, X, Z}; + +// 1-Bit Gate +let h_0 = H::new(0); +// create |0⟩ Qubit +let q_in = Qubits::zeros(1); +let q_out = h_0.apply(q_in); +q_out.print_cmps(); +// |0⟩ : +0.707 +0.000i +// |1⟩ : +0.707 +0.000i -let x_gate = X::new(0); +// 2-Bit Gate +let cx01 = CX::new(0, 1); +// q_in = |01⟩ Qubit +let q_in = Qubits::from_num(2, 1); +let q_out = cx01.apply(q_in); +q_out.print_cmps(); +// |00⟩ : +0.000 +0.000i +// |01⟩ : +0.000 +0.000i +// |10⟩ : +0.000 +0.000i +// |11⟩ : +1.000 +0.000i -// make Qbit|000⟩ Qubits::from_num(size: 3, num: 0) -let q_in = Qubits::from_num(3, 0); +// Combine gates into one unitary gate +let x = X::new(0); +let cx01 = CX::new(0, 1); +let z = Z::new(1); +let circ: Vec> = vec![Box::new(x), Box::new(cx01), Box::new(z)]; +let u = U::new(circ, String::from("example_circ")); -// apply gate to Qbit -let q_out = x_gate.apply(q_in); +let q_in = Qubits::from_num(2, 0); +let q_out = u.apply(q_in); +q_out.print_cmps(); +// |00⟩ : +0.000 +0.000i +// |01⟩ : +0.000 +0.000i +// |10⟩ : -0.000 -0.000i +// |11⟩ : -1.000 -0.000i +``` + +### Usage prepared circuits +The circuits module implements a function that gives a circuit created using the structure of the gates module. -q_out.print_probs(); +```rust +use Qit::circuits::wrapping_qsub_const; +use Qit::core::{Applicable, Qubits}; +use Qit::gates::U; + +let b = vec![0, 1, 2]; +let sub_2 = wrapping_qsub_const(&b, 2); +let sub_3 = wrapping_qsub_const(&b, 3); + +// combine sub_2 and sub_3 +let sub_5 = U::new( + vec![Box::new(sub_2), Box::new(sub_3)], + String::from("sub_5"), +); +// q_in = |111⟩ +let q_in = Qubits::from_num(3, 7); +let q_out = sub_5.apply(q_in); + +q_out.print_cmps(); // |000⟩ : +0.000 +0.000i -// |001⟩ : +1.000 +0.000i -// |010⟩ : +0.000 +0.000i +// |001⟩ : +0.000 +0.000i +// |010⟩ : +1.000 +0.000i // |011⟩ : +0.000 +0.000i // |100⟩ : +0.000 +0.000i // |101⟩ : +0.000 +0.000i // |110⟩ : +0.000 +0.000i // |111⟩ : +0.000 +0.000i - - ``` -Current version: 0.1.1 +Current version: 0.1.3 Some additional info here diff --git a/README.tpl b/README.tpl index 9f0a401..27e0fb1 100644 --- a/README.tpl +++ b/README.tpl @@ -1,4 +1,4 @@ -{{badges}} +[![Tests](https://github.com/aokyut/Qit/actions/workflows/rust.yml/badge.svg)](https://github.com/aokyut/Qit/actions/workflows/rust.yml) # {{crate}} diff --git a/src/gates.rs b/src/gates.rs index 3e9b65e..2c3fe62 100644 --- a/src/gates.rs +++ b/src/gates.rs @@ -1,5 +1,146 @@ /*! Basic gates that make up quantum circuits and traits related to gate applications + + The following gates can act directly on qubits. + +* 1-Bit Gates + * X(X-Gate. Not Gate) + * Y(Y-Gate) + * Z(Z-Gate) + * H(Hadamard-Gate) + * R(R_z-Gate. Gate that rotates at any angle around the z-axis) +* 2-Bit Gate + * CX(Controlled Not Gate) +* 3-Bit Gate + * CCX(Controlled Controlled Not Gate) +* N-Bit Gate + * CNX(Controlled Controlled ...(n) Not Gate) + +CNX is an X gate with an arbitrary number of control bits prepared for convenience in circuit creation. + +In addition to the above, there is a U structure that combines multiple gates into one circuit, +and a CU structure that allows you to control multiple gates with one bit. + +# Example +All gates can make changes to the qubit using the apply method. +## 1-Bit Gates +``` +use Qit::{gates::{X, Y, Z, H, R}, core::{Applicable, Qubits}}; +use std::f64::consts::PI; + +// create gate struct +let x_0 = X::new(0); +// make Qbit|000⟩ Qubits::from_num(size: 3, num: 0) +let q_in = Qubits::from_num(2, 0); +// apply X-gate to Qbit +let q_out = x_0.apply(q_in); + +q_out.print_probs(); +// |00⟩ : +0.000 +0.000i +// |01⟩ : +1.000 +0.000i +// |10⟩ : +0.000 +0.000i +// |11⟩ : +0.000 +0.000i + +// Y-Gate +let y_0 = Y::new(0); +let q_in = Qubits::zeros(2); +let q_out = y_0.apply(q_in); +q_out.print_cmps(); +// |00⟩ : +0.000 +0.000i +// |01⟩ : +0.000 -1.000i +// |10⟩ : +0.000 +0.000i +// |11⟩ : +0.000 +0.000i + +// Z-Gate +let z_0 = Z::new(0); +let q_in = Qubits::from_num(2, 1); +let q_out = z_0.apply(q_in); +q_out.print_cmps(); +// |00⟩ : +0.000 +0.000i +// |01⟩ : -1.000 -0.000i +// |10⟩ : +0.000 +0.000i +// |11⟩ : -0.000 -0.000i + +// Hadamard-Gate +let h_0 = H::new(0); +let q_in = Qubits::zeros(2); +let q_out = h_0.apply(q_in); +q_out.print_cmps(); +// |00⟩ : +0.707 +0.000i +// |01⟩ : +0.707 +0.000i +// |10⟩ : +0.000 +0.000i +// |11⟩ : +0.000 +0.000i + +// R gate requires angle of f64. +let angle = 0.5 * PI; +let r_0 = R::new(0, angle); +let q_in = q_out; +let q_out = r_0.apply(q_in); +q_out.print_cmps(); +// |00⟩ : +0.707 +0.000i +// |01⟩ : +0.000 +0.707i +// |10⟩ : +0.000 +0.000i +// |11⟩ : +0.000 +0.000i + +``` + +## 2-Bit Gate +``` +use Qit::core::{Applicable, Qubits, Comp}; +use Qit::gates::CX; + +// create CX(0 → 1) +let cx01 = CX::new(0, 1); +let q_in = Qubits::from_num(2, 1); +let q_out = cx01.apply(q_in); +q_out.print_cmps(); +// |00⟩ : +0.000 +0.000i +// |01⟩ : +0.000 +0.000i +// |10⟩ : +0.000 +0.000i +// |11⟩ : +1.000 +0.000i +assert_eq!(q_out.bits[0b11], Comp::new(1.0, 0.0)); +``` + +## 3-Bit Gate +``` +use Qit::core::{Applicable, Comp, Qubits}; +use Qit::gates::CCX; + +let ccx = CCX::new(0, 1, 2); +// q_in = |011⟩ +let q_in = Qubits::from_num(3, 3); +let q_out = ccx.apply(q_in); +q_out.print_cmps(); +// |000⟩ : +0.000 +0.000i +// |001⟩ : +0.000 +0.000i +// |010⟩ : +0.000 +0.000i +// |011⟩ : +0.000 +0.000i +// |100⟩ : +0.000 +0.000i +// |101⟩ : +0.000 +0.000i +// |110⟩ : +0.000 +0.000i +// |111⟩ : +1.000 +0.000i +assert_eq!(q_out.bits[0b111], Comp::new(1.0, 0.0)); +``` + +## n-Bit Gate +``` +use Qit::core::{Applicable, Comp, Qubits}; +use Qit::gates::CNX; + +let cnx = CNX::new(vec![0, 1, 2], 3); +// q_in = |0111⟩ +let q_in = Qubits::from_num(4, 7); +let q_out = cnx.apply(q_in); +q_out.print_cmps(); +// |0000⟩ : +0.000 +0.000i +// |0001⟩ : +0.000 +0.000i +// . +// . +// . +// |1110⟩ : +0.000 +0.000i +// |1111⟩ : +1.000 +0.000i +assert_eq!(q_out.bits[0b1111], Comp::new(1.0, 0.0)); +``` */ use std::f64::consts::SQRT_2; @@ -10,6 +151,22 @@ const SQRT2_INV: f64 = 1.0 / SQRT_2; /** * Hadamard Gate. 1√2(|0⟩⟨0| + |1⟩⟨0| + |0⟩⟨1| - |1⟩⟨1|) + + # Usage + ``` +use Qit::{gates::H, core::{Applicable, Qubits}}; + +// Hadamard-Gate +let h_0 = H::new(0); +let q_in = Qubits::zeros(2); +let q_out = h_0.apply(q_in); +q_out.print_cmps(); +// |00⟩ : +0.707 +0.000i +// |01⟩ : +0.707 +0.000i +// |10⟩ : +0.000 +0.000i +// |11⟩ : +0.000 +0.000i + ``` + */ #[derive(Clone, Copy)] pub struct H { @@ -49,6 +206,21 @@ impl Operator for H {} /** Not Gate(pauli-X). (|1⟩⟨0| + |0⟩⟨1|) + +# Usage +``` +use Qit::{gates::X, core::{Applicable, Qubits}}; + +// X-Gate +let x_0 = X::new(0); +let q_in = Qubits::from_num(2, 0); +let q_out = x_0.apply(q_in); +q_out.print_probs(); +// |00⟩ : +0.000 +0.000i +// |01⟩ : +1.000 +0.000i +// |10⟩ : +0.000 +0.000i +// |11⟩ : +0.000 +0.000i +``` */ #[derive(Clone, Copy)] pub struct X { @@ -87,6 +259,21 @@ impl Operator for X {} /** pauli-Y Gate. i(|1⟩⟨0| - |0⟩⟨1|) + +# Usage +``` +use Qit::{gates::Y, core::{Applicable, Qubits}}; + +// Y-Gate +let y_0 = Y::new(0); +let q_in = Qubits::zeros(2); +let q_out = y_0.apply(q_in); +q_out.print_cmps(); +// |00⟩ : +0.000 +0.000i +// |01⟩ : +0.000 -1.000i +// |10⟩ : +0.000 +0.000i +// |11⟩ : +0.000 +0.000i +``` */ #[derive(Clone, Copy)] pub struct Y { @@ -126,6 +313,22 @@ impl Operator for Y {} /** pauli-Z Gate. (|0⟩⟨0| - |1⟩⟨1|) + + # Usage + + ``` +use Qit::{gates::Z, core::{Applicable, Qubits}}; + +// Z-Gate +let z_0 = Z::new(0); +let q_in = Qubits::from_num(2, 1); +let q_out = z_0.apply(q_in); +q_out.print_cmps(); +// |00⟩ : +0.000 +0.000i +// |01⟩ : -1.000 -0.000i +// |10⟩ : +0.000 +0.000i +// |11⟩ : -0.000 -0.000i + ``` */ #[derive(Clone, Copy)] pub struct Z { @@ -166,6 +369,23 @@ Phase shift Gate. (|0⟩⟨0| + exp(ir)|1⟩⟨1|) (|0⟩ + |1⟩) →R(π)→ (|0⟩ - |1⟩) (|0⟩ + |1⟩) →R(π/2)→ (|0⟩ + i|1⟩) + +# Usage +``` +use Qit::{gates::R, core::{Applicable, Qubits, Comp}}; +use std::f64::consts::PI; + +// R gate requires angle of f64. +let angle = 0.5 * PI; +let r_0 = R::new(0, angle); +let q_in = Qubits::from_num(2, 1); +let q_out = r_0.apply(q_in); +q_out.print_cmps(); +// |00⟩ : +0.000 +0.000i +// |01⟩ : +0.000 +1.000i +// |10⟩ : +0.000 +0.000i +// |11⟩ : +0.000 +0.000i +``` */ #[derive(Clone, Copy)] pub struct R { @@ -206,6 +426,24 @@ impl Operator for R {} /** Controlled-Not Gate. + +# Usage + +``` +use Qit::core::{Applicable, Qubits, Comp}; +use Qit::gates::CX; + +// create CX(0 → 1) +let cx01 = CX::new(0, 1); +let q_in = Qubits::from_num(2, 1); +let q_out = cx01.apply(q_in); +q_out.print_cmps(); +// |00⟩ : +0.000 +0.000i +// |01⟩ : +0.000 +0.000i +// |10⟩ : +0.000 +0.000i +// |11⟩ : +1.000 +0.000i +assert_eq!(q_out.bits[0b11], Comp::new(1.0, 0.0)); +``` */ #[derive(Clone, Copy)] pub struct CX { @@ -246,6 +484,28 @@ impl Operator for CX {} /** Controlled-Controlled-Not(CXX) Gate. + +# Usage + +``` +use Qit::core::{Applicable, Comp, Qubits}; +use Qit::gates::CCX; + +let ccx = CCX::new(0, 1, 2); +// q_in = |011⟩ +let q_in = Qubits::from_num(3, 3); +let q_out = ccx.apply(q_in); +q_out.print_cmps(); +// |000⟩ : +0.000 +0.000i +// |001⟩ : +0.000 +0.000i +// |010⟩ : +0.000 +0.000i +// |011⟩ : +0.000 +0.000i +// |100⟩ : +0.000 +0.000i +// |101⟩ : +0.000 +0.000i +// |110⟩ : +0.000 +0.000i +// |111⟩ : +1.000 +0.000i +assert_eq!(q_out.bits[0b111], Comp::new(1.0, 0.0)); +``` */ #[derive(Clone, Copy)] pub struct CCX { @@ -291,6 +551,26 @@ impl Operator for CCX {} /** Controlled-Controlled-Controlled-...(N)-Not Gate + +# Usage +``` +use Qit::core::{Applicable, Comp, Qubits}; +use Qit::gates::CNX; + +let cnx = CNX::new(vec![0, 1, 2], 3); +// q_in = |0111⟩ +let q_in = Qubits::from_num(4, 7); +let q_out = cnx.apply(q_in); +q_out.print_cmps(); +// |0000⟩ : +0.000 +0.000i +// |0001⟩ : +0.000 +0.000i +// . +// . +// . +// |1110⟩ : +0.000 +0.000i +// |1111⟩ : +1.000 +0.000i +assert_eq!(q_out.bits[0b1111], Comp::new(1.0, 0.0)); +``` */ #[derive(Clone)] pub struct CNX { @@ -345,7 +625,43 @@ impl Operator for CNX {} /** Controlled-Unitary Gate. Control a group of arbitrary gates using a specific qubit. - */ + +``` +use Qit::circuits::wrapping_qadd_const; +use Qit::core::{Applicable, Comp, Operator, Qubits}; +use Qit::gates::CU; + +// make controlled-add_3 +let b_in = vec![0, 1, 2]; +let controll_bit = 3; + +let add_3 = wrapping_qadd_const(&b_in, 3); +let controlled_add_3 = CU::from_u(controll_bit, add_3); + +// or +let add_3 = wrapping_qadd_const(&b_in, 3); +let add_3_gates: Vec> = add_3.gates; +let controlled_add_3 = CU::new( + controll_bit, + add_3_gates, + String::from("something_name_you_like"), +); + +// q_in = |1001⟩ +let q_in = Qubits::from_num(4, 0b1001); +let q_out = controlled_add_3.apply(q_in); +q_out.print_cmps(); +// |0000⟩ : +0.000 +0.000i +// . +// . +// . +// |1011⟩ : +0.000 +0.000i +// |1100⟩ : +1.000 +0.000i +// |1101⟩ : +0.000 +0.000i +// |1110⟩ : +0.000 +0.000i +// |1111⟩ : +0.000 +0.000i +``` +*/ pub struct CU { controll_bit: usize, gates: Vec>, diff --git a/src/lib.rs b/src/lib.rs index 5e8a7f5..4984192 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,96 +2,25 @@ Simple quantum computer simulator library without matrix operations. -The following gates can act directly on qubits. - -* 1-Bit Gates - * X(X-Gate. Not Gate) - * Y(Y-Gate) - * Z(Z-Gate) - * H(Hadamard-Gate) - * R(R_z-Gate. Gate that rotates at any angle around the z-axis) -* 2-Bit Gate - * CX(Controlled Not Gate) -* 3-Bit Gate - * CCX(Controlled Controlled Not Gate) -* N-Bit Gate - * CNX(Controlled Controlled ...(n) Not Gate) - -CNX is an X gate with an arbitrary number of control bits prepared for convenience in circuit creation. - -In addition to the above, there is a U structure that combines multiple gates into one circuit, -and a CU structure that allows you to control multiple gates with one bit. - # Example All gates can make changes to the qubit using the apply method. -## 1-Bit Gates +## Usage basic gates ``` -use Qit::{gates::{X, Y, Z, H, R}, core::{Applicable, Qubits}}; -use std::f64::consts::PI; - -// create gate struct -let x_0 = X::new(0); -// make Qbit|000⟩ Qubits::from_num(size: 3, num: 0) -let q_in = Qubits::from_num(2, 0); -// apply X-gate to Qbit -let q_out = x_0.apply(q_in); - -q_out.print_probs(); -// |00⟩ : +0.000 +0.000i -// |01⟩ : +1.000 +0.000i -// |10⟩ : +0.000 +0.000i -// |11⟩ : +0.000 +0.000i - -// Y-Gate -let y_0 = Y::new(0); -let q_in = Qubits::zeros(2); -let q_out = y_0.apply(q_in); -q_out.print_cmps(); -// |00⟩ : +0.000 +0.000i -// |01⟩ : +0.000 -1.000i -// |10⟩ : +0.000 +0.000i -// |11⟩ : +0.000 +0.000i - -// Z-Gate -let z_0 = Z::new(0); -let q_in = Qubits::from_num(2, 1); -let q_out = z_0.apply(q_in); -q_out.print_cmps(); -// |00⟩ : +0.000 +0.000i -// |01⟩ : -1.000 -0.000i -// |10⟩ : +0.000 +0.000i -// |11⟩ : -0.000 -0.000i +use Qit::core::{Applicable, Operator, Qubits}; +use Qit::gates::{CX, H, U, X, Z}; -// Hadamard-Gate +// 1-Bit Gate let h_0 = H::new(0); -let q_in = Qubits::zeros(2); +// create |0⟩ Qubit +let q_in = Qubits::zeros(1); let q_out = h_0.apply(q_in); q_out.print_cmps(); -// |00⟩ : +0.707 +0.000i -// |01⟩ : +0.707 +0.000i -// |10⟩ : +0.000 +0.000i -// |11⟩ : +0.000 +0.000i +// |0⟩ : +0.707 +0.000i +// |1⟩ : +0.707 +0.000i -// R gate requires angle of f64. -let angle = 0.5 * PI; -let r_0 = R::new(0, angle); -let q_in = q_out; -let q_out = r_0.apply(q_in); -q_out.print_cmps(); -// |00⟩ : +0.707 +0.000i -// |01⟩ : +0.000 +0.707i -// |10⟩ : +0.000 +0.000i -// |11⟩ : +0.000 +0.000i - -``` - -## 2-Bit Gate -``` -use Qit::core::{Applicable, Qubits, Comp}; -use Qit::gates::CX; - -// create CX(0 → 1) +// 2-Bit Gate let cx01 = CX::new(0, 1); +// q_in = |01⟩ Qubit let q_in = Qubits::from_num(2, 1); let q_out = cx01.apply(q_in); q_out.print_cmps(); @@ -99,48 +28,53 @@ q_out.print_cmps(); // |01⟩ : +0.000 +0.000i // |10⟩ : +0.000 +0.000i // |11⟩ : +1.000 +0.000i -assert_eq!(q_out.bits[0b11], Comp::new(1.0, 0.0)); + +// Combine gates into one unitary gate +let x = X::new(0); +let cx01 = CX::new(0, 1); +let z = Z::new(1); +let circ: Vec> = vec![Box::new(x), Box::new(cx01), Box::new(z)]; +let u = U::new(circ, String::from("example_circ")); + +let q_in = Qubits::from_num(2, 0); +let q_out = u.apply(q_in); +q_out.print_cmps(); +// |00⟩ : +0.000 +0.000i +// |01⟩ : +0.000 +0.000i +// |10⟩ : -0.000 -0.000i +// |11⟩ : -1.000 -0.000i ``` -## 3-Bit Gate +## Usage prepared circuits +The circuits module implements a function that gives a circuit created using the structure of the gates module. + ``` -use Qit::core::{Applicable, Comp, Qubits}; -use Qit::gates::CCX; +use Qit::circuits::wrapping_qsub_const; +use Qit::core::{Applicable, Qubits}; +use Qit::gates::U; + +let b = vec![0, 1, 2]; +let sub_2 = wrapping_qsub_const(&b, 2); +let sub_3 = wrapping_qsub_const(&b, 3); + +// combine sub_2 and sub_3 +let sub_5 = U::new( + vec![Box::new(sub_2), Box::new(sub_3)], + String::from("sub_5"), +); +// q_in = |111⟩ +let q_in = Qubits::from_num(3, 7); +let q_out = sub_5.apply(q_in); -let ccx = CCX::new(0, 1, 2); -// q_in = |011⟩ -let q_in = Qubits::from_num(3, 3); -let q_out = ccx.apply(q_in); q_out.print_cmps(); // |000⟩ : +0.000 +0.000i // |001⟩ : +0.000 +0.000i -// |010⟩ : +0.000 +0.000i +// |010⟩ : +1.000 +0.000i // |011⟩ : +0.000 +0.000i // |100⟩ : +0.000 +0.000i // |101⟩ : +0.000 +0.000i // |110⟩ : +0.000 +0.000i -// |111⟩ : +1.000 +0.000i -assert_eq!(q_out.bits[0b111], Comp::new(1.0, 0.0)); -``` - -## n-Bit Gate -``` -use Qit::core::{Applicable, Comp, Qubits}; -use Qit::gates::CNX; - -let cnx = CNX::new(vec![0, 1, 2], 3); -// q_in = |0111⟩ -let q_in = Qubits::from_num(4, 7); -let q_out = cnx.apply(q_in); -q_out.print_cmps(); -// |0000⟩ : +0.000 +0.000i -// |0001⟩ : +0.000 +0.000i -// . -// . -// . -// |1110⟩ : +0.000 +0.000i -// |1111⟩ : +1.000 +0.000i -assert_eq!(q_out.bits[0b1111], Comp::new(1.0, 0.0)); +// |111⟩ : +0.000 +0.000i ``` */