From 04bbbb3e40b83fa3220834ea46cde19b8b734428 Mon Sep 17 00:00:00 2001 From: John Lapeyre Date: Tue, 4 Jun 2024 16:07:12 -0400 Subject: [PATCH] Add ergonomic and readability constructs to gate_matrix.rs --- crates/circuit/src/gate_matrix.rs | 308 ++++++++---------------------- 1 file changed, 78 insertions(+), 230 deletions(-) diff --git a/crates/circuit/src/gate_matrix.rs b/crates/circuit/src/gate_matrix.rs index 2ad6d720b4f0..55f32f3ec034 100644 --- a/crates/circuit/src/gate_matrix.rs +++ b/crates/circuit/src/gate_matrix.rs @@ -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`] with arguments that can convert [`Into`]. +/// +/// ``` +/// use num_complex::{c64, Complex64}; +/// assert_eq!(c64(1, 2), Complex64::new(1.0, 2.0)); +/// ``` +#[inline] +fn c64, V: Into>(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.), @@ -68,30 +86,10 @@ 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] = [ @@ -99,223 +97,79 @@ pub static SXGATE: [[Complex64; 2]; 2] = [ [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] @@ -323,13 +177,7 @@ 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()] ] }