Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Rust representation for most controlled gates #12659

Merged
merged 25 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6c1c84f
Add C3X (MCX), extend rust tests to multi-controlled gates.
ElePT Jun 24, 2024
e0fc815
Merge branch 'main' of https://github.com/Qiskit/qiskit into oxidize-…
ElePT Jun 25, 2024
ba76884
Add macro to generate multi-controlled gates. Add CU, CU1, CU3, C3SX,…
ElePT Jun 25, 2024
6270ace
Kill C4XGate
ElePT Jun 25, 2024
8cc2886
Finish adding gates, add circuit construction methods when possible.
ElePT Jun 25, 2024
325cf6c
Add import paths, fix drawer test.
ElePT Jun 26, 2024
9b47121
Establish CGates with non-default control states as non-standard in c…
ElePT Jun 27, 2024
2f2e697
Fix merge conflicts
ElePT Jul 1, 2024
2a67f73
Fix merge conflicts
ElePT Jul 1, 2024
9a41e6f
Apply macro on missing gates
ElePT Jul 1, 2024
4e089b1
Add RCCX gate and RC3X (RCCCX) gate.
ElePT Jul 2, 2024
0284d15
Merge branch 'main' of https://github.com/Qiskit/qiskit into oxidize-…
ElePT Jul 2, 2024
e393557
Make equivalence tests more explicit
ElePT Jul 2, 2024
466bced
Fix lint
ElePT Jul 2, 2024
617af9d
Modify circuit methods for consistency
ElePT Jul 2, 2024
05fe760
Fix default ctrl state for 3q+ gates, add test for CCZ
ElePT Jul 2, 2024
da3e598
Apply comments from Matt's code review
ElePT Jul 2, 2024
b70799a
Fix ctrl_state logic
ElePT Jul 2, 2024
f05c9a1
Rename c3x to mcx?
ElePT Jul 2, 2024
5812ecc
Brackets didn't match explanation
ElePT Jul 2, 2024
5583095
Merge branch 'main' into oxidize-gates-5
ElePT Jul 3, 2024
6e7b076
Make sure controlled test doesn't use custom ControlledGate instances.
ElePT Jul 3, 2024
8c922aa
Rename c4x to mcx in Rust space.
ElePT Jul 3, 2024
2a98908
Return PyResult rather than panic on error
jlapeyre Jul 3, 2024
d834621
Add suggestion from Matt's code review
ElePT Jul 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
246 changes: 107 additions & 139 deletions crates/circuit/src/gate_matrix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,30 @@ const fn c64(re: f64, im: f64) -> Complex64 {
pub static ONE_QUBIT_IDENTITY: [[Complex64; 2]; 2] =
[[c64(1., 0.), c64(0., 0.)], [c64(0., 0.), c64(1., 0.)]];

// Utility for generating static matrices for controlled gates with "n" control qubits.
// It assumes that the first "n-1" qubits are controls and the last qubit is the target.
macro_rules! make_n_controlled_gate {
($gate_matrix:expr, $n_control_qubits:expr) => {{
const DIM: usize = 2_usize.pow($n_control_qubits as u32 + 1_u32);
// DIM x DIM matrix of all zeros
let mut matrix: [[Complex64; DIM]; DIM] = [[c64(0., 0.); DIM]; DIM];
// DIM x DIM diagonal matrix
{
let mut i = 0;
while i < DIM {
matrix[i][i] = c64(1., 0.);
i += 1;
}
}
// Insert elements of gate_matrix in columns DIM/2-1 and DIM-1
matrix[DIM / 2 - 1][DIM / 2 - 1] = $gate_matrix[0][0];
matrix[DIM - 1][DIM - 1] = $gate_matrix[1][1];
matrix[DIM / 2 - 1][DIM - 1] = $gate_matrix[0][1];
matrix[DIM - 1][DIM / 2 - 1] = $gate_matrix[1][0];
matrix
}};
}

#[inline]
pub fn rx_gate(theta: f64) -> [[Complex64; 2]; 2] {
let half_theta = theta / 2.;
Expand All @@ -46,16 +70,30 @@ pub fn rz_gate(theta: f64) -> [[Complex64; 2]; 2] {
[[(-ilam2).exp(), c64(0., 0.)], [c64(0., 0.), ilam2.exp()]]
}

pub static X_GATE: [[Complex64; 2]; 2] = [[c64(0., 0.), c64(1., 0.)], [c64(1., 0.), c64(0., 0.)]];

pub static Z_GATE: [[Complex64; 2]; 2] = [[c64(1., 0.), c64(0., 0.)], [c64(0., 0.), c64(-1., 0.)]];

pub static Y_GATE: [[Complex64; 2]; 2] = [[c64(0., 0.), c64(0., -1.)], [c64(0., 1.), c64(0., 0.)]];

pub static H_GATE: [[Complex64; 2]; 2] = [
[c64(FRAC_1_SQRT_2, 0.), c64(FRAC_1_SQRT_2, 0.)],
[c64(FRAC_1_SQRT_2, 0.), c64(-FRAC_1_SQRT_2, 0.)],
];

pub static CX_GATE: [[Complex64; 4]; 4] = [
[c64(1., 0.), c64(0., 0.), c64(0., 0.), c64(0., 0.)],
[c64(0., 0.), c64(0., 0.), c64(0., 0.), c64(1., 0.)],
[c64(0., 0.), c64(0., 0.), c64(1., 0.), c64(0., 0.)],
[c64(0., 0.), c64(1., 0.), c64(0., 0.), c64(0., 0.)],
pub static S_GATE: [[Complex64; 2]; 2] = [[c64(1., 0.), c64(0., 0.)], [c64(0., 0.), c64(0., 1.)]];

pub static SDG_GATE: [[Complex64; 2]; 2] =
[[c64(1., 0.), c64(0., 0.)], [c64(0., 0.), c64(0., -1.)]];

pub static T_GATE: [[Complex64; 2]; 2] = [
[c64(1., 0.), c64(0., 0.)],
[c64(0., 0.), c64(FRAC_1_SQRT_2, FRAC_1_SQRT_2)],
];

pub static TDG_GATE: [[Complex64; 2]; 2] = [
[c64(1., 0.), c64(0., 0.)],
[c64(0., 0.), c64(FRAC_1_SQRT_2, -FRAC_1_SQRT_2)],
];

pub static SX_GATE: [[Complex64; 2]; 2] = [
Expand All @@ -68,108 +106,19 @@ pub static SXDG_GATE: [[Complex64; 2]; 2] = [
[c64(0.5, 0.5), c64(0.5, -0.5)],
];

pub static X_GATE: [[Complex64; 2]; 2] = [[c64(0., 0.), c64(1., 0.)], [c64(1., 0.), c64(0., 0.)]];
pub static CX_GATE: [[Complex64; 4]; 4] = make_n_controlled_gate!(X_GATE, 1);

pub static Z_GATE: [[Complex64; 2]; 2] = [[c64(1., 0.), c64(0., 0.)], [c64(0., 0.), c64(-1., 0.)]];
pub static CZ_GATE: [[Complex64; 4]; 4] = make_n_controlled_gate!(Z_GATE, 1);

pub static Y_GATE: [[Complex64; 2]; 2] = [[c64(0., 0.), c64(0., -1.)], [c64(0., 1.), c64(0., 0.)]];
pub static CY_GATE: [[Complex64; 4]; 4] = make_n_controlled_gate!(Y_GATE, 1);

pub static CZ_GATE: [[Complex64; 4]; 4] = [
[c64(1., 0.), c64(0., 0.), c64(0., 0.), c64(0., 0.)],
[c64(0., 0.), c64(1., 0.), c64(0., 0.), c64(0., 0.)],
[c64(0., 0.), c64(0., 0.), c64(1., 0.), c64(0., 0.)],
[c64(0., 0.), c64(0., 0.), c64(0., 0.), c64(-1., 0.)],
];
pub static CCX_GATE: [[Complex64; 8]; 8] = make_n_controlled_gate!(X_GATE, 2);

pub static CY_GATE: [[Complex64; 4]; 4] = [
[c64(1., 0.), c64(0., 0.), c64(0., 0.), c64(0., 0.)],
[c64(0., 0.), c64(0., 0.), c64(0., 0.), c64(0., -1.)],
[c64(0., 0.), c64(0., 0.), c64(1., 0.), c64(0., 0.)],
[c64(0., 0.), c64(0., 1.), c64(0., 0.), c64(0., 0.)],
];
pub static CCZ_GATE: [[Complex64; 8]; 8] = make_n_controlled_gate!(Z_GATE, 2);

pub static CCX_GATE: [[Complex64; 8]; 8] = [
[
c64(1., 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
],
[
c64(0., 0.),
c64(1., 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
],
[
c64(0., 0.),
c64(0., 0.),
c64(1., 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
],
[
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
c64(1., 0.),
],
[
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
c64(1., 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
],
[
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
c64(1., 0.),
c64(0., 0.),
c64(0., 0.),
],
[
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
c64(1., 0.),
c64(0., 0.),
],
[
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
c64(1., 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., 0.),
],
];
pub static C3X_GATE: [[Complex64; 16]; 16] = make_n_controlled_gate!(X_GATE, 3);

pub static C3SX_GATE: [[Complex64; 16]; 16] = make_n_controlled_gate!(SX_GATE, 3);

pub static ECR_GATE: [[Complex64; 4]; 4] = [
[
Expand Down Expand Up @@ -211,21 +160,6 @@ pub static ISWAP_GATE: [[Complex64; 4]; 4] = [
[c64(0., 0.), c64(0., 0.), c64(0., 0.), c64(1., 0.)],
];

pub static S_GATE: [[Complex64; 2]; 2] = [[c64(1., 0.), c64(0., 0.)], [c64(0., 0.), c64(0., 1.)]];

pub static SDG_GATE: [[Complex64; 2]; 2] =
[[c64(1., 0.), c64(0., 0.)], [c64(0., 0.), c64(0., -1.)]];

pub static T_GATE: [[Complex64; 2]; 2] = [
[c64(1., 0.), c64(0., 0.)],
[c64(0., 0.), c64(FRAC_1_SQRT_2, FRAC_1_SQRT_2)],
];

pub static TDG_GATE: [[Complex64; 2]; 2] = [
[c64(1., 0.), c64(0., 0.)],
[c64(0., 0.), c64(FRAC_1_SQRT_2, -FRAC_1_SQRT_2)],
];

#[inline]
pub fn global_phase_gate(theta: f64) -> [[Complex64; 1]; 1] {
[[c64(0., theta).exp()]]
Expand All @@ -249,28 +183,6 @@ pub fn u_gate(theta: f64, phi: f64, lam: f64) -> [[Complex64; 2]; 2] {
]
}

#[inline]
pub fn xx_minus_yy_gate(theta: f64, beta: f64) -> [[Complex64; 4]; 4] {
let cos = (theta / 2.).cos();
let sin = (theta / 2.).sin();
[
[
c64(cos, 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., -sin) * c64(0., -beta).exp(),
],
[c64(0., 0.), c64(1., 0.), c64(0., 0.), c64(0., 0.)],
[c64(0., 0.), c64(0., 0.), c64(1., 0.), c64(0., 0.)],
[
c64(0., -sin) * c64(0., beta).exp(),
c64(0., 0.),
c64(0., 0.),
c64(cos, 0.),
],
]
}

#[inline]
pub fn u1_gate(lam: f64) -> [[Complex64; 2]; 2] {
[
Expand Down Expand Up @@ -303,6 +215,62 @@ pub fn u3_gate(theta: f64, phi: f64, lam: f64) -> [[Complex64; 2]; 2] {
]
}

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

#[inline]
pub fn cu1_gate(lam: f64) -> [[Complex64; 4]; 4] {
let gate_matrix = u1_gate(lam);
make_n_controlled_gate!(gate_matrix, 1)
}

#[inline]
pub fn cu3_gate(theta: f64, phi: f64, lam: f64) -> [[Complex64; 4]; 4] {
let gate_matrix = u3_gate(theta, phi, lam);
make_n_controlled_gate!(gate_matrix, 1)
}

#[inline]
pub fn xx_minus_yy_gate(theta: f64, beta: f64) -> [[Complex64; 4]; 4] {
let cos = (theta / 2.).cos();
let sin = (theta / 2.).sin();
[
[
c64(cos, 0.),
c64(0., 0.),
c64(0., 0.),
c64(0., -sin) * c64(0., -beta).exp(),
],
[c64(0., 0.), c64(1., 0.), c64(0., 0.), c64(0., 0.)],
[c64(0., 0.), c64(0., 0.), c64(1., 0.), c64(0., 0.)],
[
c64(0., -sin) * c64(0., beta).exp(),
c64(0., 0.),
c64(0., 0.),
c64(cos, 0.),
],
]
}

#[inline]
pub fn xx_plus_yy_gate(theta: f64, beta: f64) -> [[Complex64; 4]; 4] {
let cos = (theta / 2.).cos();
Expand Down
8 changes: 4 additions & 4 deletions crates/circuit/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,15 +177,15 @@ static STDGATE_IMPORT_PATHS: [[&str; 2]; STANDARD_GATE_SIZE] = [
// CU3Gate = 41
["qiskit.circuit.library.standard_gates.u3", "CU3Gate"],
// C3XGate = 42
["placeholder", "placeholder"],
["qiskit.circuit.library.standard_gates.x", "C3XGate"],
// C3SXGate = 43
["placeholder", "placeholder"],
["qiskit.circuit.library.standard_gates.sx", "C3SXGate"],
// C4XGate = 44
["placeholder", "placeholder"],
["qiskit.circuit.library.standard_gates.x", "C4XGate"],
// DCXGate = 45
["placeholder", "placeholder"],
// CCZGate = 46
["placeholder", "placeholder"],
["qiskit.circuit.library.standard_gates.z", "CCZGate"],
// RCCXGate = 47
["placeholder", "placeholder"],
// RC3XGate = 48
Expand Down
Loading
Loading