From 507d5b3a89363634ef51779595d00f618ca58f88 Mon Sep 17 00:00:00 2001 From: Thiago Melo Date: Wed, 7 Sep 2022 17:30:40 -0300 Subject: [PATCH 01/17] Optimization for the MCX Recursive Gate Change the recursive method for the Lemma 9 of arXiv:1501.06911, first shown in Lemma 7.3 of https://link.aps.org/doi/10.1103/PhysRevA.52.3457 Co-Authored-By: Rafaella Vale <26910380+rafaella-vale@users.noreply.github.com> Co-Authored-By: Jefferson Deyvis <67497412+jeffersondeyvis@users.noreply.github.com> --- qiskit/circuit/library/standard_gates/x.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/qiskit/circuit/library/standard_gates/x.py b/qiskit/circuit/library/standard_gates/x.py index cc6eebc2f96e..42d0afc552f9 100644 --- a/qiskit/circuit/library/standard_gates/x.py +++ b/qiskit/circuit/library/standard_gates/x.py @@ -1093,8 +1093,22 @@ def _define(self): qc._append(C4XGate(), q[:], []) self.definition = qc else: - for instr, qargs, cargs in self._recurse(q[:-1], q_ancilla=q[-1]): - qc._append(instr, qargs, cargs) + num_ctrl_qubits = len(q) - 1 + q_ancilla = q[-1] + q_target = q[-2] + middle = ceil(num_ctrl_qubits / 2) + first_half = [*q[:middle]] + second_half = [*q[middle:num_ctrl_qubits - 1], q_ancilla] + + qc._append(MCXVChain(num_ctrl_qubits=len(first_half), dirty_ancillas=True), \ + [*first_half, q_ancilla, *q[middle:middle + len(first_half) - 2]], []) + qc._append(MCXVChain(num_ctrl_qubits=len(second_half), dirty_ancillas=True), \ + [*second_half, q_target, *q[:len(second_half) - 2]], []) + qc._append(MCXVChain(num_ctrl_qubits=len(first_half), dirty_ancillas=True), \ + [*first_half, q_ancilla, *q[middle:middle + len(first_half) - 2]], []) + qc._append(MCXVChain(num_ctrl_qubits=len(second_half), dirty_ancillas=True), \ + [*second_half, q_target, *q[:len(second_half) - 2]], []) + self.definition = qc def _recurse(self, q, q_ancilla=None): From 4671b7e32bf9e689b35f07e3464ceffddb99fa30 Mon Sep 17 00:00:00 2001 From: Thiago Melo Date: Wed, 7 Sep 2022 17:39:59 -0300 Subject: [PATCH 02/17] Revert "Optimization for the MCX Recursive Gate" This reverts commit 507d5b3a89363634ef51779595d00f618ca58f88. Co-Authored-By: Rafaella Vale <26910380+rafaella-vale@users.noreply.github.com> Co-Authored-By: Jefferson Deyvis <67497412+jeffersondeyvis@users.noreply.github.com> --- qiskit/circuit/library/standard_gates/x.py | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/qiskit/circuit/library/standard_gates/x.py b/qiskit/circuit/library/standard_gates/x.py index 42d0afc552f9..cc6eebc2f96e 100644 --- a/qiskit/circuit/library/standard_gates/x.py +++ b/qiskit/circuit/library/standard_gates/x.py @@ -1093,22 +1093,8 @@ def _define(self): qc._append(C4XGate(), q[:], []) self.definition = qc else: - num_ctrl_qubits = len(q) - 1 - q_ancilla = q[-1] - q_target = q[-2] - middle = ceil(num_ctrl_qubits / 2) - first_half = [*q[:middle]] - second_half = [*q[middle:num_ctrl_qubits - 1], q_ancilla] - - qc._append(MCXVChain(num_ctrl_qubits=len(first_half), dirty_ancillas=True), \ - [*first_half, q_ancilla, *q[middle:middle + len(first_half) - 2]], []) - qc._append(MCXVChain(num_ctrl_qubits=len(second_half), dirty_ancillas=True), \ - [*second_half, q_target, *q[:len(second_half) - 2]], []) - qc._append(MCXVChain(num_ctrl_qubits=len(first_half), dirty_ancillas=True), \ - [*first_half, q_ancilla, *q[middle:middle + len(first_half) - 2]], []) - qc._append(MCXVChain(num_ctrl_qubits=len(second_half), dirty_ancillas=True), \ - [*second_half, q_target, *q[:len(second_half) - 2]], []) - + for instr, qargs, cargs in self._recurse(q[:-1], q_ancilla=q[-1]): + qc._append(instr, qargs, cargs) self.definition = qc def _recurse(self, q, q_ancilla=None): From af4c3f68aaa61ba1f405c382546f2cc97cd119d3 Mon Sep 17 00:00:00 2001 From: Thiago Melo Date: Wed, 7 Sep 2022 17:43:39 -0300 Subject: [PATCH 03/17] Revert "Revert "Optimization for the MCX Recursive Gate"" This reverts commit 4671b7e32bf9e689b35f07e3464ceffddb99fa30. --- qiskit/circuit/library/standard_gates/x.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/qiskit/circuit/library/standard_gates/x.py b/qiskit/circuit/library/standard_gates/x.py index cc6eebc2f96e..42d0afc552f9 100644 --- a/qiskit/circuit/library/standard_gates/x.py +++ b/qiskit/circuit/library/standard_gates/x.py @@ -1093,8 +1093,22 @@ def _define(self): qc._append(C4XGate(), q[:], []) self.definition = qc else: - for instr, qargs, cargs in self._recurse(q[:-1], q_ancilla=q[-1]): - qc._append(instr, qargs, cargs) + num_ctrl_qubits = len(q) - 1 + q_ancilla = q[-1] + q_target = q[-2] + middle = ceil(num_ctrl_qubits / 2) + first_half = [*q[:middle]] + second_half = [*q[middle:num_ctrl_qubits - 1], q_ancilla] + + qc._append(MCXVChain(num_ctrl_qubits=len(first_half), dirty_ancillas=True), \ + [*first_half, q_ancilla, *q[middle:middle + len(first_half) - 2]], []) + qc._append(MCXVChain(num_ctrl_qubits=len(second_half), dirty_ancillas=True), \ + [*second_half, q_target, *q[:len(second_half) - 2]], []) + qc._append(MCXVChain(num_ctrl_qubits=len(first_half), dirty_ancillas=True), \ + [*first_half, q_ancilla, *q[middle:middle + len(first_half) - 2]], []) + qc._append(MCXVChain(num_ctrl_qubits=len(second_half), dirty_ancillas=True), \ + [*second_half, q_target, *q[:len(second_half) - 2]], []) + self.definition = qc def _recurse(self, q, q_ancilla=None): From 8ca0031b1af9c107390eac1e6f00b9f86865f37f Mon Sep 17 00:00:00 2001 From: Thiago Melo Date: Wed, 7 Sep 2022 17:45:40 -0300 Subject: [PATCH 04/17] Optimization for MCX Recursive Fixing co-authors Co-Authored-By: Rafaella Vale <26910380+rafaella-vale@users.noreply.github.com> Co-Authored-By: Jefferson Deyvis <67497412+jeffersondeyvis@users.noreply.github.com> Co-Authored-By: Adenilton Silva <7927558+adjs@users.noreply.github.com> --- qiskit/circuit/library/standard_gates/x.py | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/qiskit/circuit/library/standard_gates/x.py b/qiskit/circuit/library/standard_gates/x.py index 42d0afc552f9..cc6eebc2f96e 100644 --- a/qiskit/circuit/library/standard_gates/x.py +++ b/qiskit/circuit/library/standard_gates/x.py @@ -1093,22 +1093,8 @@ def _define(self): qc._append(C4XGate(), q[:], []) self.definition = qc else: - num_ctrl_qubits = len(q) - 1 - q_ancilla = q[-1] - q_target = q[-2] - middle = ceil(num_ctrl_qubits / 2) - first_half = [*q[:middle]] - second_half = [*q[middle:num_ctrl_qubits - 1], q_ancilla] - - qc._append(MCXVChain(num_ctrl_qubits=len(first_half), dirty_ancillas=True), \ - [*first_half, q_ancilla, *q[middle:middle + len(first_half) - 2]], []) - qc._append(MCXVChain(num_ctrl_qubits=len(second_half), dirty_ancillas=True), \ - [*second_half, q_target, *q[:len(second_half) - 2]], []) - qc._append(MCXVChain(num_ctrl_qubits=len(first_half), dirty_ancillas=True), \ - [*first_half, q_ancilla, *q[middle:middle + len(first_half) - 2]], []) - qc._append(MCXVChain(num_ctrl_qubits=len(second_half), dirty_ancillas=True), \ - [*second_half, q_target, *q[:len(second_half) - 2]], []) - + for instr, qargs, cargs in self._recurse(q[:-1], q_ancilla=q[-1]): + qc._append(instr, qargs, cargs) self.definition = qc def _recurse(self, q, q_ancilla=None): From e3729c9075efc5cb6b00561b19580d1fc31c8260 Mon Sep 17 00:00:00 2001 From: Thiago Melo Date: Wed, 7 Sep 2022 17:46:33 -0300 Subject: [PATCH 05/17] Optimization of MCX Recursive Now with fixed co-authors Co-Authored-By: Rafaella Vale <26910380+rafaella-vale@users.noreply.github.com> Co-Authored-By: Jefferson Deyvis <67497412+jeffersondeyvis@users.noreply.github.com> Co-Authored-By: Adenilton Silva <7927558+adjs@users.noreply.github.com> --- qiskit/circuit/library/standard_gates/x.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/qiskit/circuit/library/standard_gates/x.py b/qiskit/circuit/library/standard_gates/x.py index cc6eebc2f96e..42d0afc552f9 100644 --- a/qiskit/circuit/library/standard_gates/x.py +++ b/qiskit/circuit/library/standard_gates/x.py @@ -1093,8 +1093,22 @@ def _define(self): qc._append(C4XGate(), q[:], []) self.definition = qc else: - for instr, qargs, cargs in self._recurse(q[:-1], q_ancilla=q[-1]): - qc._append(instr, qargs, cargs) + num_ctrl_qubits = len(q) - 1 + q_ancilla = q[-1] + q_target = q[-2] + middle = ceil(num_ctrl_qubits / 2) + first_half = [*q[:middle]] + second_half = [*q[middle:num_ctrl_qubits - 1], q_ancilla] + + qc._append(MCXVChain(num_ctrl_qubits=len(first_half), dirty_ancillas=True), \ + [*first_half, q_ancilla, *q[middle:middle + len(first_half) - 2]], []) + qc._append(MCXVChain(num_ctrl_qubits=len(second_half), dirty_ancillas=True), \ + [*second_half, q_target, *q[:len(second_half) - 2]], []) + qc._append(MCXVChain(num_ctrl_qubits=len(first_half), dirty_ancillas=True), \ + [*first_half, q_ancilla, *q[middle:middle + len(first_half) - 2]], []) + qc._append(MCXVChain(num_ctrl_qubits=len(second_half), dirty_ancillas=True), \ + [*second_half, q_target, *q[:len(second_half) - 2]], []) + self.definition = qc def _recurse(self, q, q_ancilla=None): From 4f10325c6468aaba859c229d8ff8172e628eacd4 Mon Sep 17 00:00:00 2001 From: rafaella-vale <26910380+rafaella-vale@users.noreply.github.com> Date: Thu, 8 Sep 2022 11:05:31 -0300 Subject: [PATCH 06/17] refactored MCXRecursive and unused method deleted --- qiskit/circuit/library/standard_gates/x.py | 53 +++++++++------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/qiskit/circuit/library/standard_gates/x.py b/qiskit/circuit/library/standard_gates/x.py index 42d0afc552f9..a99cd3159ea4 100644 --- a/qiskit/circuit/library/standard_gates/x.py +++ b/qiskit/circuit/library/standard_gates/x.py @@ -1098,42 +1098,31 @@ def _define(self): q_target = q[-2] middle = ceil(num_ctrl_qubits / 2) first_half = [*q[:middle]] - second_half = [*q[middle:num_ctrl_qubits - 1], q_ancilla] + second_half = [*q[middle : num_ctrl_qubits - 1], q_ancilla] - qc._append(MCXVChain(num_ctrl_qubits=len(first_half), dirty_ancillas=True), \ - [*first_half, q_ancilla, *q[middle:middle + len(first_half) - 2]], []) - qc._append(MCXVChain(num_ctrl_qubits=len(second_half), dirty_ancillas=True), \ - [*second_half, q_target, *q[:len(second_half) - 2]], []) - qc._append(MCXVChain(num_ctrl_qubits=len(first_half), dirty_ancillas=True), \ - [*first_half, q_ancilla, *q[middle:middle + len(first_half) - 2]], []) - qc._append(MCXVChain(num_ctrl_qubits=len(second_half), dirty_ancillas=True), \ - [*second_half, q_target, *q[:len(second_half) - 2]], []) + qc._append( + MCXVChain(num_ctrl_qubits=len(first_half), dirty_ancillas=True), + qargs=[*first_half, q_ancilla, *q[middle : middle + len(first_half) - 2]], + cargs=[], + ) + qc._append( + MCXVChain(num_ctrl_qubits=len(second_half), dirty_ancillas=True), + qargs=[*second_half, q_target, *q[: len(second_half) - 2]], + cargs=[], + ) + qc._append( + MCXVChain(num_ctrl_qubits=len(first_half), dirty_ancillas=True), + qargs=[*first_half, q_ancilla, *q[middle : middle + len(first_half) - 2]], + cargs=[], + ) + qc._append( + MCXVChain(num_ctrl_qubits=len(second_half), dirty_ancillas=True), + qargs=[*second_half, q_target, *q[: len(second_half) - 2]], + cargs=[], + ) self.definition = qc - def _recurse(self, q, q_ancilla=None): - # recursion stop - if len(q) == 4: - return [(C3XGate(), q[:], [])] - if len(q) == 5: - return [(C4XGate(), q[:], [])] - if len(q) < 4: - raise AttributeError("Something went wrong in the recursion, have less than 4 qubits.") - - # recurse - num_ctrl_qubits = len(q) - 1 - middle = ceil(num_ctrl_qubits / 2) - first_half = [*q[:middle], q_ancilla] - second_half = [*q[middle:num_ctrl_qubits], q_ancilla, q[num_ctrl_qubits]] - - rule = [] - rule += self._recurse(first_half, q_ancilla=q[middle]) - rule += self._recurse(second_half, q_ancilla=q[middle - 1]) - rule += self._recurse(first_half, q_ancilla=q[middle]) - rule += self._recurse(second_half, q_ancilla=q[middle - 1]) - - return rule - class MCXVChain(MCXGate): """Implement the multi-controlled X gate using a V-chain of CX gates.""" From a891dc4e34232e66f352dbf51ed66fa2585f9bc3 Mon Sep 17 00:00:00 2001 From: rafaella-vale <26910380+rafaella-vale@users.noreply.github.com> Date: Thu, 8 Sep 2022 17:42:31 -0300 Subject: [PATCH 07/17] fixed qasm string for mcx test with variants --- test/python/circuit/test_circuit_qasm.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/test/python/circuit/test_circuit_qasm.py b/test/python/circuit/test_circuit_qasm.py index cd3b4fe90fac..452a45abd12d 100644 --- a/test/python/circuit/test_circuit_qasm.py +++ b/test/python/circuit/test_circuit_qasm.py @@ -270,6 +270,8 @@ def test_circuit_qasm_with_mcx_gate(self): qc = QuantumCircuit(4) qc.mcx([0, 1, 2], 3) + print(qc.decompose().draw()) + # qasm output doesn't support parameterized gate yet. # param0 for "gate mcuq(param0) is not used inside the definition expected_qasm = """OPENQASM 2.0; @@ -288,20 +290,23 @@ def test_circuit_qasm_with_mcx_gate_variants(self): qc.append(cl.MCXGrayCode(n), range(n + 1)) qc.append(cl.MCXRecursive(n), range(n + 2)) qc.append(cl.MCXVChain(n), range(2 * n - 1)) + mcx_vchain_id = id(qc.data[-1].operation) # qasm output doesn't support parameterized gate yet. # param0 for "gate mcuq(param0) is not used inside the definition expected_qasm = """OPENQASM 2.0; include "qelib1.inc"; -gate mcx q0,q1,q2,q3 { h q3; p(pi/8) q0; p(pi/8) q1; p(pi/8) q2; p(pi/8) q3; cx q0,q1; p(-pi/8) q1; cx q0,q1; cx q1,q2; p(-pi/8) q2; cx q0,q2; p(pi/8) q2; cx q1,q2; p(-pi/8) q2; cx q0,q2; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; h q3; } -gate mcu1(param0) q0,q1,q2,q3,q4,q5 { cu1(pi/16) q4,q5; cx q4,q3; cu1(-pi/16) q3,q5; cx q4,q3; cu1(pi/16) q3,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; } -gate mcx_gray q0,q1,q2,q3,q4,q5 { h q5; mcu1(pi) q0,q1,q2,q3,q4,q5; h q5; } -gate mcx_recursive q0,q1,q2,q3,q4,q5,q6 { mcx q0,q1,q2,q6; mcx q3,q4,q6,q5; mcx q0,q1,q2,q6; mcx q3,q4,q6,q5; } -gate mcx_vchain q0,q1,q2,q3,q4,q5,q6,q7,q8 { rccx q0,q1,q6; rccx q2,q6,q7; rccx q3,q7,q8; ccx q4,q8,q5; rccx q3,q7,q8; rccx q2,q6,q7; rccx q0,q1,q6; } +gate mcx_vchain q0,q1,q2,q3,q4 {{ u2(0,pi) q3; cx q3,q4; u1(-pi/4) q4; cx q2,q4; u1(pi/4) q4; cx q3,q4; u1(-pi/4) q4; cx q2,q4; u1(pi/4) q4; rccx q0,q1,q4; u1(-pi/4) q4; cx q2,q4; u1(pi/4) q4; cx q3,q4; u1(-pi/4) q4; cx q2,q4; u1(pi/4) q4; cx q3,q4; u2(0,pi) q3; rccx q0,q1,q4; }} +gate mcu1(param0) q0,q1,q2,q3,q4,q5 {{ cu1(pi/16) q4,q5; cx q4,q3; cu1(-pi/16) q3,q5; cx q4,q3; cu1(pi/16) q3,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; }} +gate mcx_gray q0,q1,q2,q3,q4,q5 {{ h q5; mcu1(pi) q0,q1,q2,q3,q4,q5; h q5; }} +gate mcx_recursive q0,q1,q2,q3,q4,q5,q6 {{ mcx_vchain q0,q1,q2,q6,q3; mcx_vchain q3,q4,q6,q5,q0; mcx_vchain q0,q1,q2,q6,q3; mcx_vchain q3,q4,q6,q5,q0; }} +gate mcx_vchain_{0} q0,q1,q2,q3,q4,q5,q6,q7,q8 {{ rccx q0,q1,q6; rccx q2,q6,q7; rccx q3,q7,q8; ccx q4,q8,q5; rccx q3,q7,q8; rccx q2,q6,q7; rccx q0,q1,q6; }} qreg q[9]; mcx_gray q[0],q[1],q[2],q[3],q[4],q[5]; mcx_recursive q[0],q[1],q[2],q[3],q[4],q[5],q[6]; -mcx_vchain q[0],q[1],q[2],q[3],q[4],q[5],q[6],q[7],q[8];\n""" +mcx_vchain_{0} q[0],q[1],q[2],q[3],q[4],q[5],q[6],q[7],q[8];\n""".format( + mcx_vchain_id + ) self.assertEqual(qc.qasm(), expected_qasm) From 09f08840f1e81bb737b3e8ba6806dcd93fc541f5 Mon Sep 17 00:00:00 2001 From: rafaella-vale <26910380+rafaella-vale@users.noreply.github.com> Date: Fri, 9 Sep 2022 12:36:28 -0300 Subject: [PATCH 08/17] remove draw --- test/python/circuit/test_circuit_qasm.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/python/circuit/test_circuit_qasm.py b/test/python/circuit/test_circuit_qasm.py index 452a45abd12d..7c277dfe74e6 100644 --- a/test/python/circuit/test_circuit_qasm.py +++ b/test/python/circuit/test_circuit_qasm.py @@ -270,8 +270,6 @@ def test_circuit_qasm_with_mcx_gate(self): qc = QuantumCircuit(4) qc.mcx([0, 1, 2], 3) - print(qc.decompose().draw()) - # qasm output doesn't support parameterized gate yet. # param0 for "gate mcuq(param0) is not used inside the definition expected_qasm = """OPENQASM 2.0; From be4feb5ed15c06b6cd09d9c3bef4228b3a222915 Mon Sep 17 00:00:00 2001 From: ShellyGarion Date: Mon, 15 Jul 2024 03:01:55 -0500 Subject: [PATCH 09/17] fix qasm file in test_circuit_qasm_with_mcx_gate_variants --- test/python/circuit/test_circuit_qasm.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/test/python/circuit/test_circuit_qasm.py b/test/python/circuit/test_circuit_qasm.py index 89f7d07e4b4e..46d96011c227 100644 --- a/test/python/circuit/test_circuit_qasm.py +++ b/test/python/circuit/test_circuit_qasm.py @@ -418,16 +418,18 @@ def test_circuit_qasm_with_mcx_gate_variants(self): # param0 for "gate mcuq(param0) is not used inside the definition expected_qasm = """OPENQASM 2.0; include "qelib1.inc"; -gate mcu1(param0) q0,q1,q2,q3,q4,q5 { cu1(pi/16) q4,q5; cx q4,q3; cu1(-pi/16) q3,q5; cx q4,q3; cu1(pi/16) q3,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; } -gate mcx_gray q0,q1,q2,q3,q4,q5 { h q5; mcu1(pi) q0,q1,q2,q3,q4,q5; h q5; } -gate mcx q0,q1,q2,q3 { h q3; p(pi/8) q0; p(pi/8) q1; p(pi/8) q2; p(pi/8) q3; cx q0,q1; p(-pi/8) q1; cx q0,q1; cx q1,q2; p(-pi/8) q2; cx q0,q2; p(pi/8) q2; cx q1,q2; p(-pi/8) q2; cx q0,q2; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; h q3; } -gate mcx_recursive q0,q1,q2,q3,q4,q5,q6 { mcx q0,q1,q2,q6; mcx q3,q4,q6,q5; mcx q0,q1,q2,q6; mcx q3,q4,q6,q5; } -gate mcx_vchain q0,q1,q2,q3,q4,q5,q6,q7,q8 { rccx q0,q1,q6; rccx q2,q6,q7; rccx q3,q7,q8; ccx q4,q8,q5; rccx q3,q7,q8; rccx q2,q6,q7; rccx q0,q1,q6; } +gate mcu1(param0) q0,q1,q2,q3,q4,q5 {{ cu1(pi/16) q4,q5; cx q4,q3; cu1(-pi/16) q3,q5; cx q4,q3; cu1(pi/16) q3,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; }} +gate mcx_gray q0,q1,q2,q3,q4,q5 {{ h q5; mcu1(pi) q0,q1,q2,q3,q4,q5; h q5; }} +gate mcx q0,q1,q2,q3 {{ h q3; p(pi/8) q0; p(pi/8) q1; p(pi/8) q2; p(pi/8) q3; cx q0,q1; p(-pi/8) q1; cx q0,q1; cx q1,q2; p(-pi/8) q2; cx q0,q2; p(pi/8) q2; cx q1,q2; p(-pi/8) q2; cx q0,q2; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; h q3; }} +gate mcx_vchain q0,q1,q2,q3,q4 {{ mcx q0,q1,q2,q3; }} +gate mcx_recursive q0,q1,q2,q3,q4,q5,q6 {{ mcx_vchain q0,q1,q2,q6,q3; mcx_vchain q3,q4,q6,q5,q0; mcx_vchain q0,q1,q2,q6,q3; mcx_vchain q3,q4,q6,q5,q0; }} +gate mcx_vchain_{0} q0,q1,q2,q3,q4,q5,q6,q7,q8 {{ rccx q0,q1,q6; rccx q2,q6,q7; rccx q3,q7,q8; ccx q4,q8,q5; rccx q3,q7,q8; rccx q2,q6,q7; rccx q0,q1,q6; }} qreg q[9]; mcx_gray q[0],q[1],q[2],q[3],q[4],q[5]; mcx_recursive q[0],q[1],q[2],q[3],q[4],q[5],q[6]; -mcx_vchain q[0],q[1],q[2],q[3],q[4],q[5],q[6],q[7],q[8];""" - +mcx_vchain_{0} q[0],q[1],q[2],q[3],q[4],q[5],q[6],q[7],q[8];\n""".format( + mcx_vchain_id + ) self.assertEqual(dumps(qc), expected_qasm) def test_circuit_qasm_with_registerless_bits(self): From 1507e5cb87d0b1f648d94f60a493a3f8495d3b6a Mon Sep 17 00:00:00 2001 From: ShellyGarion Date: Mon, 15 Jul 2024 06:24:55 -0500 Subject: [PATCH 10/17] update the MCXRecursive class docstring --- qiskit/circuit/library/standard_gates/x.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/qiskit/circuit/library/standard_gates/x.py b/qiskit/circuit/library/standard_gates/x.py index a6d7f911ef83..b21fd393ff47 100644 --- a/qiskit/circuit/library/standard_gates/x.py +++ b/qiskit/circuit/library/standard_gates/x.py @@ -1320,9 +1320,14 @@ def _define(self): class MCXRecursive(MCXGate): """Implement the multi-controlled X gate using recursion. - Using a single ancilla qubit, the multi-controlled X gate is recursively split onto - four sub-registers. This is done until we reach the 3- or 4-controlled X gate since - for these we have a concrete implementation that do not require ancillas. + Using a single clean ancilla qubit, the multi-controlled X gate is split into + four sub-registers, each one of them uses the V-chain method. + + The method is based on Lemma 9 of [2], first shown in Lemma 7.3 of [1]. + + References: + [1] Barenco et al., 1995. https://arxiv.org/pdf/quant-ph/9503016.pdf + [2] Iten et al., 2015. https://arxiv.org/abs/1501.06911 """ def __init__( From 76199c942d5f73fea8c24d146c51ee2e9babc536 Mon Sep 17 00:00:00 2001 From: ShellyGarion Date: Mon, 15 Jul 2024 07:07:07 -0500 Subject: [PATCH 11/17] add a test of the upper bound limit of the number of CX gates --- test/python/circuit/test_controlled_gate.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/python/circuit/test_controlled_gate.py b/test/python/circuit/test_controlled_gate.py index e36ee04e2162..25fa55b62203 100644 --- a/test/python/circuit/test_controlled_gate.py +++ b/test/python/circuit/test_controlled_gate.py @@ -820,6 +820,22 @@ def test_mcxvchain_dirty_ancilla_cx_count(self, num_ctrl_qubits): self.assertLessEqual(cx_count, 8 * num_ctrl_qubits - 6) + @data(7, 10, 15) + def test_mcxrecursive_clean_ancilla_cx_count(self, num_ctrl_qubits): + """Test if cx count of the mcx with one clean ancilla + is less than upper bound.""" + from qiskit import transpile + + mcx_recursive = MCXRecursive(num_ctrl_qubits) + qc = QuantumCircuit(mcx_recursive.num_qubits) + + qc.append(mcx_recursive, list(range(mcx_recursive.num_qubits))) + + tr_mcx_rec = transpile(qc, basis_gates=["u", "cx"]) + cx_count = tr_mcx_rec.count_ops()["cx"] + + self.assertLessEqual(cx_count, 16 * num_ctrl_qubits - 8) + def test_mcxvchain_dirty_ancilla_action_only(self): """Test the v-chain mcx with dirty auxiliary qubits with gate cancelling with mirrored circuit.""" From 187994f76daa1fd6a6ff5ed27846b53cbe86e689 Mon Sep 17 00:00:00 2001 From: ShellyGarion Date: Mon, 15 Jul 2024 08:00:24 -0500 Subject: [PATCH 12/17] fix failing qasm test --- test/python/circuit/test_circuit_qasm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/python/circuit/test_circuit_qasm.py b/test/python/circuit/test_circuit_qasm.py index 46d96011c227..12bb9cd47016 100644 --- a/test/python/circuit/test_circuit_qasm.py +++ b/test/python/circuit/test_circuit_qasm.py @@ -427,7 +427,7 @@ def test_circuit_qasm_with_mcx_gate_variants(self): qreg q[9]; mcx_gray q[0],q[1],q[2],q[3],q[4],q[5]; mcx_recursive q[0],q[1],q[2],q[3],q[4],q[5],q[6]; -mcx_vchain_{0} q[0],q[1],q[2],q[3],q[4],q[5],q[6],q[7],q[8];\n""".format( +mcx_vchain_{0} q[0],q[1],q[2],q[3],q[4],q[5],q[6],q[7],q[8];""".format( mcx_vchain_id ) self.assertEqual(dumps(qc), expected_qasm) From 898b29d6332e665f25161e0f5b5042c720fe998c Mon Sep 17 00:00:00 2001 From: ShellyGarion Date: Tue, 16 Jul 2024 02:20:18 -0500 Subject: [PATCH 13/17] fix qasm file in test_export in qasm2 tests --- test/python/qasm2/test_export.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/test/python/qasm2/test_export.py b/test/python/qasm2/test_export.py index 85172ec3ce8f..1e54f3b3cb11 100644 --- a/test/python/qasm2/test_export.py +++ b/test/python/qasm2/test_export.py @@ -402,21 +402,25 @@ def test_mcx_gate_variants(self): qc.append(lib.MCXGrayCode(n), range(n + 1)) qc.append(lib.MCXRecursive(n), range(n + 2)) qc.append(lib.MCXVChain(n), range(2 * n - 1)) + mcx_vchain_id = id(qc.data[-1].operation) # qasm output doesn't support parameterized gate yet. # param0 for "gate mcuq(param0) is not used inside the definition expected_qasm = """\ OPENQASM 2.0; include "qelib1.inc"; -gate mcu1(param0) q0,q1,q2,q3,q4,q5 { cu1(pi/16) q4,q5; cx q4,q3; cu1(-pi/16) q3,q5; cx q4,q3; cu1(pi/16) q3,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; } -gate mcx_gray q0,q1,q2,q3,q4,q5 { h q5; mcu1(pi) q0,q1,q2,q3,q4,q5; h q5; } -gate mcx q0,q1,q2,q3 { h q3; p(pi/8) q0; p(pi/8) q1; p(pi/8) q2; p(pi/8) q3; cx q0,q1; p(-pi/8) q1; cx q0,q1; cx q1,q2; p(-pi/8) q2; cx q0,q2; p(pi/8) q2; cx q1,q2; p(-pi/8) q2; cx q0,q2; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; h q3; } -gate mcx_recursive q0,q1,q2,q3,q4,q5,q6 { mcx q0,q1,q2,q6; mcx q3,q4,q6,q5; mcx q0,q1,q2,q6; mcx q3,q4,q6,q5; } -gate mcx_vchain q0,q1,q2,q3,q4,q5,q6,q7,q8 { rccx q0,q1,q6; rccx q2,q6,q7; rccx q3,q7,q8; ccx q4,q8,q5; rccx q3,q7,q8; rccx q2,q6,q7; rccx q0,q1,q6; } +gate mcu1(param0) q0,q1,q2,q3,q4,q5 {{ cu1(pi/16) q4,q5; cx q4,q3; cu1(-pi/16) q3,q5; cx q4,q3; cu1(pi/16) q3,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; }} +gate mcx_gray q0,q1,q2,q3,q4,q5 {{ h q5; mcu1(pi) q0,q1,q2,q3,q4,q5; h q5; }} +gate mcx q0,q1,q2,q3 {{ h q3; p(pi/8) q0; p(pi/8) q1; p(pi/8) q2; p(pi/8) q3; cx q0,q1; p(-pi/8) q1; cx q0,q1; cx q1,q2; p(-pi/8) q2; cx q0,q2; p(pi/8) q2; cx q1,q2; p(-pi/8) q2; cx q0,q2; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; h q3; }} +gate mcx_vchain q0,q1,q2,q3,q4 {{ mcx q0,q1,q2,q3; }} +gate mcx_recursive q0,q1,q2,q3,q4,q5,q6 {{ mcx_vchain q0,q1,q2,q6,q3; mcx_vchain q3,q4,q6,q5,q0; mcx_vchain q0,q1,q2,q6,q3; mcx_vchain q3,q4,q6,q5,q0; }} +gate mcx_vchain_{0} q0,q1,q2,q3,q4,q5,q6,q7,q8 {{ rccx q0,q1,q6; rccx q2,q6,q7; rccx q3,q7,q8; ccx q4,q8,q5; rccx q3,q7,q8; rccx q2,q6,q7; rccx q0,q1,q6; }} qreg q[9]; mcx_gray q[0],q[1],q[2],q[3],q[4],q[5]; mcx_recursive q[0],q[1],q[2],q[3],q[4],q[5],q[6]; -mcx_vchain q[0],q[1],q[2],q[3],q[4],q[5],q[6],q[7],q[8];""" +mcx_vchain_{0} q[0],q[1],q[2],q[3],q[4],q[5],q[6],q[7],q[8];""".format( + mcx_vchain_id + ) self.assertEqual(qasm2.dumps(qc), expected_qasm) From 11dc6c956aa42b45925dd8abc427bc6ef6cc1623 Mon Sep 17 00:00:00 2001 From: ShellyGarion Date: Tue, 16 Jul 2024 02:51:15 -0500 Subject: [PATCH 14/17] fix format lint errors in qasm strings --- test/python/circuit/test_circuit_qasm.py | 9 ++++----- test/python/qasm2/test_export.py | 8 +++----- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/test/python/circuit/test_circuit_qasm.py b/test/python/circuit/test_circuit_qasm.py index 12bb9cd47016..5f01e5c647a6 100644 --- a/test/python/circuit/test_circuit_qasm.py +++ b/test/python/circuit/test_circuit_qasm.py @@ -416,20 +416,19 @@ def test_circuit_qasm_with_mcx_gate_variants(self): # qasm output doesn't support parameterized gate yet. # param0 for "gate mcuq(param0) is not used inside the definition - expected_qasm = """OPENQASM 2.0; + expected_qasm = f"""OPENQASM 2.0; include "qelib1.inc"; gate mcu1(param0) q0,q1,q2,q3,q4,q5 {{ cu1(pi/16) q4,q5; cx q4,q3; cu1(-pi/16) q3,q5; cx q4,q3; cu1(pi/16) q3,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; }} gate mcx_gray q0,q1,q2,q3,q4,q5 {{ h q5; mcu1(pi) q0,q1,q2,q3,q4,q5; h q5; }} gate mcx q0,q1,q2,q3 {{ h q3; p(pi/8) q0; p(pi/8) q1; p(pi/8) q2; p(pi/8) q3; cx q0,q1; p(-pi/8) q1; cx q0,q1; cx q1,q2; p(-pi/8) q2; cx q0,q2; p(pi/8) q2; cx q1,q2; p(-pi/8) q2; cx q0,q2; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; h q3; }} gate mcx_vchain q0,q1,q2,q3,q4 {{ mcx q0,q1,q2,q3; }} gate mcx_recursive q0,q1,q2,q3,q4,q5,q6 {{ mcx_vchain q0,q1,q2,q6,q3; mcx_vchain q3,q4,q6,q5,q0; mcx_vchain q0,q1,q2,q6,q3; mcx_vchain q3,q4,q6,q5,q0; }} -gate mcx_vchain_{0} q0,q1,q2,q3,q4,q5,q6,q7,q8 {{ rccx q0,q1,q6; rccx q2,q6,q7; rccx q3,q7,q8; ccx q4,q8,q5; rccx q3,q7,q8; rccx q2,q6,q7; rccx q0,q1,q6; }} +gate mcx_vchain_{mcx_vchain_id} q0,q1,q2,q3,q4,q5,q6,q7,q8 {{ rccx q0,q1,q6; rccx q2,q6,q7; rccx q3,q7,q8; ccx q4,q8,q5; rccx q3,q7,q8; rccx q2,q6,q7; rccx q0,q1,q6; }} qreg q[9]; mcx_gray q[0],q[1],q[2],q[3],q[4],q[5]; mcx_recursive q[0],q[1],q[2],q[3],q[4],q[5],q[6]; -mcx_vchain_{0} q[0],q[1],q[2],q[3],q[4],q[5],q[6],q[7],q[8];""".format( - mcx_vchain_id - ) +mcx_vchain_{mcx_vchain_id} q[0],q[1],q[2],q[3],q[4],q[5],q[6],q[7],q[8];""" + self.assertEqual(dumps(qc), expected_qasm) def test_circuit_qasm_with_registerless_bits(self): diff --git a/test/python/qasm2/test_export.py b/test/python/qasm2/test_export.py index 1e54f3b3cb11..0bba2f5c47e0 100644 --- a/test/python/qasm2/test_export.py +++ b/test/python/qasm2/test_export.py @@ -406,7 +406,7 @@ def test_mcx_gate_variants(self): # qasm output doesn't support parameterized gate yet. # param0 for "gate mcuq(param0) is not used inside the definition - expected_qasm = """\ + expected_qasm = f"""\ OPENQASM 2.0; include "qelib1.inc"; gate mcu1(param0) q0,q1,q2,q3,q4,q5 {{ cu1(pi/16) q4,q5; cx q4,q3; cu1(-pi/16) q3,q5; cx q4,q3; cu1(pi/16) q3,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q3,q2; cu1(-pi/16) q2,q5; cx q4,q2; cu1(pi/16) q2,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q2,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q3,q1; cu1(-pi/16) q1,q5; cx q4,q1; cu1(pi/16) q1,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q1,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q2,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; cx q3,q0; cu1(-pi/16) q0,q5; cx q4,q0; cu1(pi/16) q0,q5; }} @@ -414,13 +414,11 @@ def test_mcx_gate_variants(self): gate mcx q0,q1,q2,q3 {{ h q3; p(pi/8) q0; p(pi/8) q1; p(pi/8) q2; p(pi/8) q3; cx q0,q1; p(-pi/8) q1; cx q0,q1; cx q1,q2; p(-pi/8) q2; cx q0,q2; p(pi/8) q2; cx q1,q2; p(-pi/8) q2; cx q0,q2; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q1,q3; p(pi/8) q3; cx q2,q3; p(-pi/8) q3; cx q0,q3; h q3; }} gate mcx_vchain q0,q1,q2,q3,q4 {{ mcx q0,q1,q2,q3; }} gate mcx_recursive q0,q1,q2,q3,q4,q5,q6 {{ mcx_vchain q0,q1,q2,q6,q3; mcx_vchain q3,q4,q6,q5,q0; mcx_vchain q0,q1,q2,q6,q3; mcx_vchain q3,q4,q6,q5,q0; }} -gate mcx_vchain_{0} q0,q1,q2,q3,q4,q5,q6,q7,q8 {{ rccx q0,q1,q6; rccx q2,q6,q7; rccx q3,q7,q8; ccx q4,q8,q5; rccx q3,q7,q8; rccx q2,q6,q7; rccx q0,q1,q6; }} +gate mcx_vchain_{mcx_vchain_id} q0,q1,q2,q3,q4,q5,q6,q7,q8 {{ rccx q0,q1,q6; rccx q2,q6,q7; rccx q3,q7,q8; ccx q4,q8,q5; rccx q3,q7,q8; rccx q2,q6,q7; rccx q0,q1,q6; }} qreg q[9]; mcx_gray q[0],q[1],q[2],q[3],q[4],q[5]; mcx_recursive q[0],q[1],q[2],q[3],q[4],q[5],q[6]; -mcx_vchain_{0} q[0],q[1],q[2],q[3],q[4],q[5],q[6],q[7],q[8];""".format( - mcx_vchain_id - ) +mcx_vchain_{mcx_vchain_id} q[0],q[1],q[2],q[3],q[4],q[5],q[6],q[7],q[8];""" self.assertEqual(qasm2.dumps(qc), expected_qasm) From de55690b03d23e7a45e77f0167fa6685c8ab1c83 Mon Sep 17 00:00:00 2001 From: ShellyGarion Date: Tue, 16 Jul 2024 02:51:34 -0500 Subject: [PATCH 15/17] add release notes --- .../notes/mcx_recursive_clean_ancilla-2b0f6956e0f4cbbd.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 releasenotes/notes/mcx_recursive_clean_ancilla-2b0f6956e0f4cbbd.yaml diff --git a/releasenotes/notes/mcx_recursive_clean_ancilla-2b0f6956e0f4cbbd.yaml b/releasenotes/notes/mcx_recursive_clean_ancilla-2b0f6956e0f4cbbd.yaml new file mode 100644 index 000000000000..26c1772cef22 --- /dev/null +++ b/releasenotes/notes/mcx_recursive_clean_ancilla-2b0f6956e0f4cbbd.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + :class:`.MCXRecursive` with k controls and a single clean auxiliary qubits now requires at most + 16*k-8 cx gates. From ee273193cd66f470e3b0d2fd9e3987023175d22a Mon Sep 17 00:00:00 2001 From: ShellyGarion Date: Tue, 16 Jul 2024 10:44:39 -0500 Subject: [PATCH 16/17] update references format --- qiskit/circuit/library/standard_gates/x.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qiskit/circuit/library/standard_gates/x.py b/qiskit/circuit/library/standard_gates/x.py index b21fd393ff47..3688d376538a 100644 --- a/qiskit/circuit/library/standard_gates/x.py +++ b/qiskit/circuit/library/standard_gates/x.py @@ -952,8 +952,8 @@ class C4XGate(SingletonControlledGate): of the relative phase version of c3x, the rc3x [2]. References: - [1] Barenco et al., 1995. https://arxiv.org/pdf/quant-ph/9503016.pdf - [2] Maslov, 2015. https://arxiv.org/abs/1508.03273 + 1. Barenco et al., 1995. https://arxiv.org/pdf/quant-ph/9503016.pdf + 2. Maslov, 2015. https://arxiv.org/abs/1508.03273 """ def __init__( @@ -1326,8 +1326,8 @@ class MCXRecursive(MCXGate): The method is based on Lemma 9 of [2], first shown in Lemma 7.3 of [1]. References: - [1] Barenco et al., 1995. https://arxiv.org/pdf/quant-ph/9503016.pdf - [2] Iten et al., 2015. https://arxiv.org/abs/1501.06911 + 1. Barenco et al., 1995. https://arxiv.org/pdf/quant-ph/9503016.pdf + 2. Iten et al., 2015. https://arxiv.org/abs/1501.06911 """ def __init__( From e78a4c67d60ec1a625d7b0ab198109e83a9d9c15 Mon Sep 17 00:00:00 2001 From: ShellyGarion Date: Wed, 17 Jul 2024 06:55:08 -0500 Subject: [PATCH 17/17] update release notes after review --- .../notes/mcx_recursive_clean_ancilla-2b0f6956e0f4cbbd.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/releasenotes/notes/mcx_recursive_clean_ancilla-2b0f6956e0f4cbbd.yaml b/releasenotes/notes/mcx_recursive_clean_ancilla-2b0f6956e0f4cbbd.yaml index 26c1772cef22..12ccd09f6e12 100644 --- a/releasenotes/notes/mcx_recursive_clean_ancilla-2b0f6956e0f4cbbd.yaml +++ b/releasenotes/notes/mcx_recursive_clean_ancilla-2b0f6956e0f4cbbd.yaml @@ -1,5 +1,5 @@ --- -features: +features_synthesis: - | - :class:`.MCXRecursive` with k controls and a single clean auxiliary qubits now requires at most - 16*k-8 cx gates. + :class:`.MCXRecursive` with :math:`k` control qubits and a single clean auxiliary qubit + now requires at most :math:`16k-8` CX gates.