Skip to content

Commit

Permalink
Add ergonomic and readability constructs to gate_matrix.rs
Browse files Browse the repository at this point in the history
  • Loading branch information
jlapeyre committed Jun 4, 2024
1 parent 24373e4 commit 04bbbb3
Showing 1 changed file with 78 additions and 230 deletions.
308 changes: 78 additions & 230 deletions crates/circuit/src/gate_matrix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,52 +10,70 @@
// copyright notice, and modified files need to carry a notice indicating
// that they have been altered from the originals.

use num_complex::Complex64;
use num_complex::{Complex64, Complex};
use std::f64::consts::FRAC_1_SQRT_2;

pub static ONE_QUBIT_IDENTITY: [[Complex64; 2]; 2] = [
[Complex64::new(1., 0.), Complex64::new(0., 0.)],
[Complex64::new(0., 0.), Complex64::new(1., 0.)],
];
// This is almost the same as the function that became available in
// num-complex 0.4.6. The difference is that two generic parameters are
// used here rather than one. This allows call like `c64(half_theta.cos(), 0);`
// that mix f64 and integer arguments.
/// Create a new [`Complex<f64>`] with arguments that can convert [`Into<f64>`].
///
/// ```
/// use num_complex::{c64, Complex64};
/// assert_eq!(c64(1, 2), Complex64::new(1.0, 2.0));
/// ```
#[inline]
fn c64<T: Into<f64>, V: Into<f64>>(re: T, im: V) -> Complex64 {
Complex::new(re.into(), im.into())
}

// Many computations are not avaialable when these `const`s are compiled.

// ZERO and ONE are defined in num_complex 0.4.6
const ZERO: Complex64 = Complex64::new(0., 0.);
const ONE: Complex64 = Complex64::new(1., 0.);
const M_ONE: Complex64 = Complex64::new(-1., 0.);
const IM: Complex64 = Complex64::new(0., 1.);
const M_IM: Complex64 = Complex64::new(0., -1.);

pub static ONE_QUBIT_IDENTITY: [[Complex64; 2]; 2] = [[ONE, ZERO], [ZERO, ONE]];

#[inline]
pub fn rx_gate(theta: f64) -> [[Complex64; 2]; 2] {
let half_theta = theta / 2.;
let cos = Complex64::new(half_theta.cos(), 0.);
let isin = Complex64::new(0., -half_theta.sin());
let cos = c64(half_theta.cos(), 0);
let isin = c64(0., -half_theta.sin());
[[cos, isin], [isin, cos]]
}

#[inline]
pub fn ry_gate(theta: f64) -> [[Complex64; 2]; 2] {
let half_theta = theta / 2.;
let cos = Complex64::new(half_theta.cos(), 0.);
let sin = Complex64::new(half_theta.sin(), 0.);
let cos = c64(half_theta.cos(), 0);
let sin = c64(half_theta.sin(), 0);
[[cos, -sin], [sin, cos]]
}

#[inline]
pub fn rz_gate(theta: f64) -> [[Complex64; 2]; 2] {
let ilam2 = Complex64::new(0., 0.5 * theta);
[
[(-ilam2).exp(), Complex64::new(0., 0.)],
[Complex64::new(0., 0.), ilam2.exp()],
]
}

#[inline]
pub fn r_gate(theta: f64, phi: f64) -> [[Complex64; 2]; 2] {
let half_theta = theta / 2.;
let cost = Complex64::new(half_theta.cos(), 0.);
let cost = c64(half_theta.cos(), 0);
let sint = half_theta.sin();
let cosphi = phi.cos();
let sinphi = phi.sin();
[
[cost, Complex64::new(sint * sinphi, -sint * cosphi)],
[Complex64::new(-sint * sinphi, -sint * cosphi), cost],
[cost, c64(sint * sinphi, -sint * cosphi)],
[c64(-sint * sinphi, -sint * cosphi), cost],
]
}

#[inline]
pub fn rz_gate(theta: f64) -> [[Complex64; 2]; 2] {
let ilam2 = c64(0, 0.5 * theta);
[[(-ilam2).exp(), ZERO], [ZERO, ilam2.exp()]]
}

pub static HGATE: [[Complex64; 2]; 2] = [
[
Complex64::new(FRAC_1_SQRT_2, 0.),
Expand All @@ -68,268 +86,98 @@ pub static HGATE: [[Complex64; 2]; 2] = [
];

pub static CXGATE: [[Complex64; 4]; 4] = [
[
Complex64::new(1., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
],
[
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(1., 0.),
],
[
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(1., 0.),
Complex64::new(0., 0.),
],
[
Complex64::new(0., 0.),
Complex64::new(1., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
],
[ONE, ZERO, ZERO, ZERO],
[ZERO, ZERO, ZERO, ONE],
[ZERO, ZERO, ONE, ZERO],
[ZERO, ONE, ZERO, ZERO],
];

pub static SXGATE: [[Complex64; 2]; 2] = [
[Complex64::new(0.5, 0.5), Complex64::new(0.5, -0.5)],
[Complex64::new(0.5, -0.5), Complex64::new(0.5, 0.5)],
];

pub static XGATE: [[Complex64; 2]; 2] = [
[Complex64::new(0., 0.), Complex64::new(1., 0.)],
[Complex64::new(1., 0.), Complex64::new(0., 0.)],
];
pub static XGATE: [[Complex64; 2]; 2] = [[ZERO, ONE], [ONE, ZERO]];

pub static ZGATE: [[Complex64; 2]; 2] = [
[Complex64::new(1., 0.), Complex64::new(0., 0.)],
[Complex64::new(0., 0.), Complex64::new(-1., 0.)],
];
pub static ZGATE: [[Complex64; 2]; 2] = [[ONE, ZERO], [ZERO, M_ONE]];

pub static YGATE: [[Complex64; 2]; 2] = [
[Complex64::new(0., 0.), Complex64::new(0., -1.)],
[Complex64::new(0., 1.), Complex64::new(0., 0.)],
];
pub static YGATE: [[Complex64; 2]; 2] = [[ZERO, M_IM], [IM, ZERO]];

pub static CZGATE: [[Complex64; 4]; 4] = [
[
Complex64::new(1., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
],
[
Complex64::new(0., 0.),
Complex64::new(1., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
],
[
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(1., 0.),
Complex64::new(0., 0.),
],
[
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(-1., 0.),
],
[ONE, ZERO, ZERO, ZERO],
[ZERO, ONE, ZERO, ZERO],
[ZERO, ZERO, ONE, ZERO],
[ZERO, ZERO, ZERO, M_ONE],
];

pub static CYGATE: [[Complex64; 4]; 4] = [
[
Complex64::new(1., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
],
[
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., -1.),
],
[
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(1., 0.),
Complex64::new(0., 0.),
],
[
Complex64::new(0., 0.),
Complex64::new(0., 1.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
],
[ONE, ZERO, ZERO, ZERO],
[ZERO, ZERO, ZERO, M_IM],
[ZERO, ZERO, ONE, ZERO],
[ZERO, IM, ZERO, ZERO],
];

pub static CCXGATE: [[Complex64; 8]; 8] = [
[
Complex64::new(1., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
],
[
Complex64::new(0., 0.),
Complex64::new(1., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
],
[
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(1., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
],
[
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(1., 0.),
],
[
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(1., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
],
[
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(1., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
],
[
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(1., 0.),
Complex64::new(0., 0.),
],
[
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(1., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
],
[ONE, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO],
[ZERO, ONE, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO],
[ZERO, ZERO, ONE, ZERO, ZERO, ZERO, ZERO, ZERO],
[ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ONE],
[ZERO, ZERO, ZERO, ZERO, ONE, ZERO, ZERO, ZERO],
[ZERO, ZERO, ZERO, ZERO, ZERO, ONE, ZERO, ZERO],
[ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ONE, ZERO],
[ZERO, ZERO, ZERO, ONE, ZERO, ZERO, ZERO, ZERO],
];

pub static ECRGATE: [[Complex64; 4]; 4] = [
[
Complex64::new(0., 0.),
ZERO,
Complex64::new(FRAC_1_SQRT_2, 0.),
Complex64::new(0., 0.),
ZERO,
Complex64::new(0., FRAC_1_SQRT_2),
],
[
Complex64::new(FRAC_1_SQRT_2, 0.),
Complex64::new(0., 0.),
ZERO,
Complex64::new(0., -FRAC_1_SQRT_2),
Complex64::new(0., 0.),
ZERO,
],
[
Complex64::new(0., 0.),
ZERO,
Complex64::new(0., FRAC_1_SQRT_2),
Complex64::new(0., 0.),
ZERO,
Complex64::new(FRAC_1_SQRT_2, 0.),
],
[
Complex64::new(0., -FRAC_1_SQRT_2),
Complex64::new(0., 0.),
ZERO,
Complex64::new(FRAC_1_SQRT_2, 0.),
Complex64::new(0., 0.),
ZERO,
],
];

pub static SWAPGATE: [[Complex64; 4]; 4] = [
[
Complex64::new(1., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
],
[
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(1., 0.),
Complex64::new(0., 0.),
],
[
Complex64::new(0., 0.),
Complex64::new(1., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
],
[
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(0., 0.),
Complex64::new(1., 0.),
],
[ONE, ZERO, ZERO, ZERO],
[ZERO, ZERO, ONE, ZERO],
[ZERO, ONE, ZERO, ZERO],
[ZERO, ZERO, ZERO, ONE],
];

#[inline]
pub fn global_phase_gate(theta: f64) -> [[Complex64; 1]; 1] {
[[Complex64::new(0., theta).exp()]]
[[c64(0., theta).exp()]]
}

#[inline]
pub fn phase_gate(lam: f64) -> [[Complex64; 2]; 2] {
[
[Complex64::new(1., 0.), Complex64::new(0., 0.)],
[Complex64::new(0., 0.), Complex64::new(0., lam).exp()],
]
[[ONE, ZERO], [ZERO, c64(0., lam).exp()]]
}

#[inline]
pub fn u_gate(theta: f64, phi: f64, lam: f64) -> [[Complex64; 2]; 2] {
let cos = (theta / 2.).cos();
let sin = (theta / 2.).sin();
[
[
Complex64::new(cos, 0.),
(-Complex64::new(0., lam).exp()) * sin,
],
[
Complex64::new(0., phi).exp() * sin,
Complex64::new(0., phi + lam).exp() * cos,
],
[c64(cos, 0), -sin * c64(0, lam).exp() ],
[sin * c64(0, phi).exp(), cos * c64(0, phi + lam).exp()]
]
}

0 comments on commit 04bbbb3

Please sign in to comment.