From 0eb0bca87087a9c0d01f829ae9bb5592ed88aa27 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Tue, 11 Feb 2020 13:48:17 +0100 Subject: [PATCH 1/7] fix multiple += qc --- qiskit/circuit/quantumcircuit.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index 16d5810b773c..4bfa2cec9ca2 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -323,6 +323,7 @@ def extend(self, rhs): Raises: QiskitError: if the rhs circuit is not compatible """ + print('extend') # Check registers in LHS are compatible with RHS self._check_compatible_regs(rhs) @@ -334,8 +335,13 @@ def extend(self, rhs): if element not in self.cregs: self.cregs.append(element) + # copy the circuit data + # TODO only if rhs is self or if rhs is in self? + # data = rhs.data.copy() if rhs is self else rhs.data + data = rhs.data.copy() + # Add new gates - for instruction_context in rhs.data: + for instruction_context in data: self._append(*instruction_context) return self From e37a35ba1661958f16b8d29861f68a818a0eaed2 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Wed, 12 Feb 2020 10:12:07 +0100 Subject: [PATCH 2/7] add test --- qiskit/circuit/quantumcircuit.py | 8 +- test/python/circuit/test.ipynb | 233 ++++++++++++++++++ .../python/circuit/test_circuit_operations.py | 39 +++ 3 files changed, 275 insertions(+), 5 deletions(-) create mode 100644 test/python/circuit/test.ipynb diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index 4bfa2cec9ca2..6918a0a01805 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -323,7 +323,6 @@ def extend(self, rhs): Raises: QiskitError: if the rhs circuit is not compatible """ - print('extend') # Check registers in LHS are compatible with RHS self._check_compatible_regs(rhs) @@ -335,10 +334,9 @@ def extend(self, rhs): if element not in self.cregs: self.cregs.append(element) - # copy the circuit data - # TODO only if rhs is self or if rhs is in self? - # data = rhs.data.copy() if rhs is self else rhs.data - data = rhs.data.copy() + # Copy the circuit data if rhs and self are the same, otherwise the data of rhs is + # appended to both self and rhs resulting in an infinite loop + data = rhs.data.copy() if rhs is self else rhs.data # Add new gates for instruction_context in data: diff --git a/test/python/circuit/test.ipynb b/test/python/circuit/test.ipynb new file mode 100644 index 000000000000..d74ba5d77d04 --- /dev/null +++ b/test/python/circuit/test.ipynb @@ -0,0 +1,233 @@ +{ + "nbformat": 4, + "nbformat_minor": 2, + "metadata": { + "language_info": { + "name": "python", + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "version": "3.7.5-final" + }, + "orig_nbformat": 2, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "npconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": 3, + "kernelspec": { + "name": "python37564bitlatestvirtualenv76cfe9d7d3f749489cf2ff69593234af", + "display_name": "Python 3.7.5 64-bit ('latest': virtualenv)" + } + }, + "cells": [ + { + "source": [ + "import numpy\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "from qiskit import QuantumCircuit, execute, BasicAer\n", + "from qiskit.extensions.standard import RCCXGate, RCCCXGate\n", + "from qiskit.quantum_info import Operator\n", + "\n", + "from zrl.utils import to_qiskit_ordering" + ], + "cell_type": "code", + "outputs": [ + { + "output_type": "error", + "ename": "ModuleNotFoundError", + "evalue": "No module named 'zrl'", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mqiskit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mquantum_info\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mOperator\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 9\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mzrl\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mutils\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mto_qiskit_ordering\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'zrl'" + ] + } + ], + "metadata": {}, + "execution_count": 1 + }, + { + "source": [ + "def _compute_control_matrix(base_mat, num_ctrl_qubits):\n", + " \"\"\"\n", + " Compute the controlled version of the input matrix with qiskit ordering.\n", + "\n", + " Args:\n", + " base_mat (ndarray): unitary to be controlled\n", + " num_ctrl_qubits (int): number of controls for new unitary\n", + "\n", + " Returns:\n", + " ndarray: controlled version of base matrix.\n", + " \"\"\"\n", + " num_target = int(np.log2(base_mat.shape[0]))\n", + " ctrl_dim = 2**num_ctrl_qubits\n", + " ctrl_grnd = np.repeat([[1], [0]], [1, ctrl_dim-1])\n", + " full_mat_dim = ctrl_dim * base_mat.shape[0]\n", + " full_mat = np.zeros((full_mat_dim, full_mat_dim), dtype=base_mat.dtype)\n", + " ctrl_proj = np.diag(np.roll(ctrl_grnd, ctrl_dim - 1))\n", + " full_mat = (np.kron(np.eye(2**num_target),\n", + " np.eye(ctrl_dim) - ctrl_proj)\n", + " + np.kron(base_mat, ctrl_proj))\n", + " return full_mat" + ], + "cell_type": "code", + "outputs": [], + "metadata": {}, + "execution_count": 0 + }, + { + "source": [ + "def _compute_control_matrix(base_mat, num_ctrl_qubits, ctrl_state=None):\n", + " \"\"\"\n", + " Compute the controlled version of the input matrix with qiskit ordering.\n", + " Args:\n", + " base_mat (ndarray): unitary to be controlled\n", + " num_ctrl_qubits (int): number of controls for new unitary\n", + " ctrl_state (int or str or None): The control state in decimal or as\n", + " a bitstring (e.g. '111'). If None, use 2**num_ctrl_qubits-1.\n", + " Returns:\n", + " ndarray: controlled version of base matrix.\n", + " Raises:\n", + " QiskitError: unrecognized mode or invalid ctrl_state\n", + " \"\"\"\n", + " num_target = int(numpy.log2(base_mat.shape[0]))\n", + " ctrl_dim = 2**num_ctrl_qubits\n", + " ctrl_grnd = numpy.repeat([[1], [0]], [1, ctrl_dim-1])\n", + " if ctrl_state is None:\n", + " ctrl_state = ctrl_dim - 1\n", + " elif isinstance(ctrl_state, str):\n", + " ctrl_state = int(ctrl_state, 2)\n", + " if isinstance(ctrl_state, int):\n", + " if not 0 <= ctrl_state < ctrl_dim:\n", + " raise QiskitError('Invalid control state value specified.')\n", + " else:\n", + " raise QiskitError('Invalid control state type specified.')\n", + " full_mat_dim = ctrl_dim * base_mat.shape[0]\n", + " full_mat = numpy.zeros((full_mat_dim, full_mat_dim), dtype=base_mat.dtype)\n", + " ctrl_proj = numpy.diag(numpy.roll(ctrl_grnd, ctrl_state))\n", + " full_mat = (numpy.kron(numpy.eye(2**num_target),\n", + " numpy.eye(ctrl_dim) - ctrl_proj)\n", + " + numpy.kron(base_mat, ctrl_proj))\n", + " return full_mat" + ], + "cell_type": "code", + "outputs": [], + "metadata": {}, + "execution_count": 0 + }, + { + "source": [ + "B = np.eye(8, dtype=complex)\n", + "B[5, 5] = -1\n", + "B[6:, 6:] = np.array([[0, -1j], [1j, 0]])\n", + "\n", + "CB = np.eye(16, 16, dtype=complex)\n", + "CB[8:, 8:] = B\n", + "\n", + "cb = to_qiskit_ordering(CB)" + ], + "cell_type": "code", + "outputs": [], + "metadata": {}, + "execution_count": 0 + }, + { + "source": [ + "plt.figure()\n", + "plt.imshow(np.abs(CB))\n", + "plt.figure()\n", + "plt.imshow(np.abs(cb))\n", + "" + ], + "cell_type": "code", + "outputs": [], + "metadata": {}, + "execution_count": 0 + }, + { + "source": [ + "ctrl = _compute_control_matrix(RCCXGate().to_matrix(), 1)\n", + "plt.imshow(np.abs(ctrl - cb))" + ], + "cell_type": "code", + "outputs": [], + "metadata": {}, + "execution_count": 0 + }, + { + "source": [ + "num_ctrl_qubits = 1\n", + "for gate in [RCCXGate()]:\n", + " cgate = gate.control(num_ctrl_qubits)\n", + " base_mat = Operator(gate).data\n", + " ctrl_mat = Operator(cgate).data\n", + " target_mat = _compute_control_matrix(base_mat, num_ctrl_qubits)\n", + " print(gate.name)\n", + "\n", + " diff = np.abs(ctrl_mat - target_mat)\n", + " plt.figure()\n", + " plt.imshow(np.abs(ctrl_mat))\n", + " plt.colorbar()\n", + "\n", + " plt.figure()\n", + " plt.imshow(diff)\n", + " plt.colorbar()\n", + "" + ], + "cell_type": "code", + "outputs": [], + "metadata": {}, + "execution_count": 0 + }, + { + "source": [ + "cgate = RCCXGate().control()\n", + "qc = QuantumCircuit(cgate.num_qubits)\n", + "qc.append(cgate, list(range(cgate.num_qubits)), [])\n", + "qc.draw()" + ], + "cell_type": "code", + "outputs": [], + "metadata": {}, + "execution_count": 0 + }, + { + "source": [ + "unitary = execute(qc, BasicAer.get_backend('unitary_simulator')).result().get_unitary()" + ], + "cell_type": "code", + "outputs": [], + "metadata": {}, + "execution_count": 0 + }, + { + "source": [ + "plt.imshow(np.abs(unitary))\n", + "plt.imshow(np.abs(unitary - ctrl))\n", + "\n", + "atol = 1e-10\n", + "for i in range(2**cgate.num_qubits):\n", + " for j in range(2**cgate.num_qubits):\n", + " if np.abs(ctrl[i, j] - unitary[i, j]) >= atol:\n", + " print(i, j, ctrl[i, j], unitary[i, j])" + ], + "cell_type": "code", + "outputs": [], + "metadata": {}, + "execution_count": 0 + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ] +} \ No newline at end of file diff --git a/test/python/circuit/test_circuit_operations.py b/test/python/circuit/test_circuit_operations.py index 4afc9d59ddf2..371e329f54bc 100644 --- a/test/python/circuit/test_circuit_operations.py +++ b/test/python/circuit/test_circuit_operations.py @@ -18,6 +18,7 @@ from qiskit import BasicAer from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit from qiskit import execute +from qiskit.circuit import Instruction from qiskit.circuit.exceptions import CircuitError from qiskit.test import QiskitTestCase @@ -25,6 +26,44 @@ class TestCircuitOperations(QiskitTestCase): """QuantumCircuit Operations tests.""" + def test_adding_self(self): + """Test qc += qc which can be prone to infinite while-loops. + """ + qc = QuantumCircuit(1) + qc.x(0) # must contain at least one operation to end up in a infinite while-loop + + # modify _append to detect the issue + qc._call_count = 0 + + def mock_append(self, instruction, qargs, cargs): + if self._call_count > 0: + raise CircuitError('The circuit must be added as copy!') + + self._call_count += 1 + + # the original _append method: + if not isinstance(instruction, Instruction): + raise CircuitError('object is not an Instruction.') + + # do some compatibility checks + self._check_dups(qargs) + self._check_qargs(qargs) + self._check_cargs(cargs) + + # add the instruction onto the given wires + instruction_context = instruction, qargs, cargs + self._data.append(instruction_context) + + self._update_parameter_table(instruction) + + return instruction + + # monkey-patch the instance method + qc._append = mock_append.__get__(qc, QuantumCircuit) + + # attempt addition + qc += qc + def test_combine_circuit_common(self): """Test combining two circuits with same registers. """ From 50fc6ec4585001c25b94e1e02b9ada2f99911486 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Fri, 14 Feb 2020 11:58:48 +0100 Subject: [PATCH 3/7] use timeout as test failure - patching _append might not catch future implementations where += is done differently - also other tests with timeout already exist - this is cleaner than before --- .../python/circuit/test_circuit_operations.py | 37 +++---------------- 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/test/python/circuit/test_circuit_operations.py b/test/python/circuit/test_circuit_operations.py index 371e329f54bc..1bc707f1e6ab 100644 --- a/test/python/circuit/test_circuit_operations.py +++ b/test/python/circuit/test_circuit_operations.py @@ -27,41 +27,16 @@ class TestCircuitOperations(QiskitTestCase): """QuantumCircuit Operations tests.""" def test_adding_self(self): - """Test qc += qc which can be prone to infinite while-loops. + """Test that qc += qc finishes, which can be prone to infinite while-loops. + + This can occur e.g. when a user tries + >>> other_qc = qc + >>> other_qc += qc # or qc2.extend(qc) """ qc = QuantumCircuit(1) qc.x(0) # must contain at least one operation to end up in a infinite while-loop - # modify _append to detect the issue - qc._call_count = 0 - - def mock_append(self, instruction, qargs, cargs): - if self._call_count > 0: - raise CircuitError('The circuit must be added as copy!') - - self._call_count += 1 - - # the original _append method: - if not isinstance(instruction, Instruction): - raise CircuitError('object is not an Instruction.') - - # do some compatibility checks - self._check_dups(qargs) - self._check_qargs(qargs) - self._check_cargs(cargs) - - # add the instruction onto the given wires - instruction_context = instruction, qargs, cargs - self._data.append(instruction_context) - - self._update_parameter_table(instruction) - - return instruction - - # monkey-patch the instance method - qc._append = mock_append.__get__(qc, QuantumCircuit) - - # attempt addition + # attempt addition, times out if qc is added via reference qc += qc def test_combine_circuit_common(self): From d43349b2672819ffd9828855eaec0a1c49539f19 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Fri, 14 Feb 2020 12:00:32 +0100 Subject: [PATCH 4/7] remove accidentially tracked file --- test/python/circuit/test.ipynb | 233 --------------------------------- 1 file changed, 233 deletions(-) delete mode 100644 test/python/circuit/test.ipynb diff --git a/test/python/circuit/test.ipynb b/test/python/circuit/test.ipynb deleted file mode 100644 index d74ba5d77d04..000000000000 --- a/test/python/circuit/test.ipynb +++ /dev/null @@ -1,233 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 2, - "metadata": { - "language_info": { - "name": "python", - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "version": "3.7.5-final" - }, - "orig_nbformat": 2, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "npconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": 3, - "kernelspec": { - "name": "python37564bitlatestvirtualenv76cfe9d7d3f749489cf2ff69593234af", - "display_name": "Python 3.7.5 64-bit ('latest': virtualenv)" - } - }, - "cells": [ - { - "source": [ - "import numpy\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from qiskit import QuantumCircuit, execute, BasicAer\n", - "from qiskit.extensions.standard import RCCXGate, RCCCXGate\n", - "from qiskit.quantum_info import Operator\n", - "\n", - "from zrl.utils import to_qiskit_ordering" - ], - "cell_type": "code", - "outputs": [ - { - "output_type": "error", - "ename": "ModuleNotFoundError", - "evalue": "No module named 'zrl'", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mqiskit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mquantum_info\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mOperator\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 9\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mzrl\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mutils\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mto_qiskit_ordering\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'zrl'" - ] - } - ], - "metadata": {}, - "execution_count": 1 - }, - { - "source": [ - "def _compute_control_matrix(base_mat, num_ctrl_qubits):\n", - " \"\"\"\n", - " Compute the controlled version of the input matrix with qiskit ordering.\n", - "\n", - " Args:\n", - " base_mat (ndarray): unitary to be controlled\n", - " num_ctrl_qubits (int): number of controls for new unitary\n", - "\n", - " Returns:\n", - " ndarray: controlled version of base matrix.\n", - " \"\"\"\n", - " num_target = int(np.log2(base_mat.shape[0]))\n", - " ctrl_dim = 2**num_ctrl_qubits\n", - " ctrl_grnd = np.repeat([[1], [0]], [1, ctrl_dim-1])\n", - " full_mat_dim = ctrl_dim * base_mat.shape[0]\n", - " full_mat = np.zeros((full_mat_dim, full_mat_dim), dtype=base_mat.dtype)\n", - " ctrl_proj = np.diag(np.roll(ctrl_grnd, ctrl_dim - 1))\n", - " full_mat = (np.kron(np.eye(2**num_target),\n", - " np.eye(ctrl_dim) - ctrl_proj)\n", - " + np.kron(base_mat, ctrl_proj))\n", - " return full_mat" - ], - "cell_type": "code", - "outputs": [], - "metadata": {}, - "execution_count": 0 - }, - { - "source": [ - "def _compute_control_matrix(base_mat, num_ctrl_qubits, ctrl_state=None):\n", - " \"\"\"\n", - " Compute the controlled version of the input matrix with qiskit ordering.\n", - " Args:\n", - " base_mat (ndarray): unitary to be controlled\n", - " num_ctrl_qubits (int): number of controls for new unitary\n", - " ctrl_state (int or str or None): The control state in decimal or as\n", - " a bitstring (e.g. '111'). If None, use 2**num_ctrl_qubits-1.\n", - " Returns:\n", - " ndarray: controlled version of base matrix.\n", - " Raises:\n", - " QiskitError: unrecognized mode or invalid ctrl_state\n", - " \"\"\"\n", - " num_target = int(numpy.log2(base_mat.shape[0]))\n", - " ctrl_dim = 2**num_ctrl_qubits\n", - " ctrl_grnd = numpy.repeat([[1], [0]], [1, ctrl_dim-1])\n", - " if ctrl_state is None:\n", - " ctrl_state = ctrl_dim - 1\n", - " elif isinstance(ctrl_state, str):\n", - " ctrl_state = int(ctrl_state, 2)\n", - " if isinstance(ctrl_state, int):\n", - " if not 0 <= ctrl_state < ctrl_dim:\n", - " raise QiskitError('Invalid control state value specified.')\n", - " else:\n", - " raise QiskitError('Invalid control state type specified.')\n", - " full_mat_dim = ctrl_dim * base_mat.shape[0]\n", - " full_mat = numpy.zeros((full_mat_dim, full_mat_dim), dtype=base_mat.dtype)\n", - " ctrl_proj = numpy.diag(numpy.roll(ctrl_grnd, ctrl_state))\n", - " full_mat = (numpy.kron(numpy.eye(2**num_target),\n", - " numpy.eye(ctrl_dim) - ctrl_proj)\n", - " + numpy.kron(base_mat, ctrl_proj))\n", - " return full_mat" - ], - "cell_type": "code", - "outputs": [], - "metadata": {}, - "execution_count": 0 - }, - { - "source": [ - "B = np.eye(8, dtype=complex)\n", - "B[5, 5] = -1\n", - "B[6:, 6:] = np.array([[0, -1j], [1j, 0]])\n", - "\n", - "CB = np.eye(16, 16, dtype=complex)\n", - "CB[8:, 8:] = B\n", - "\n", - "cb = to_qiskit_ordering(CB)" - ], - "cell_type": "code", - "outputs": [], - "metadata": {}, - "execution_count": 0 - }, - { - "source": [ - "plt.figure()\n", - "plt.imshow(np.abs(CB))\n", - "plt.figure()\n", - "plt.imshow(np.abs(cb))\n", - "" - ], - "cell_type": "code", - "outputs": [], - "metadata": {}, - "execution_count": 0 - }, - { - "source": [ - "ctrl = _compute_control_matrix(RCCXGate().to_matrix(), 1)\n", - "plt.imshow(np.abs(ctrl - cb))" - ], - "cell_type": "code", - "outputs": [], - "metadata": {}, - "execution_count": 0 - }, - { - "source": [ - "num_ctrl_qubits = 1\n", - "for gate in [RCCXGate()]:\n", - " cgate = gate.control(num_ctrl_qubits)\n", - " base_mat = Operator(gate).data\n", - " ctrl_mat = Operator(cgate).data\n", - " target_mat = _compute_control_matrix(base_mat, num_ctrl_qubits)\n", - " print(gate.name)\n", - "\n", - " diff = np.abs(ctrl_mat - target_mat)\n", - " plt.figure()\n", - " plt.imshow(np.abs(ctrl_mat))\n", - " plt.colorbar()\n", - "\n", - " plt.figure()\n", - " plt.imshow(diff)\n", - " plt.colorbar()\n", - "" - ], - "cell_type": "code", - "outputs": [], - "metadata": {}, - "execution_count": 0 - }, - { - "source": [ - "cgate = RCCXGate().control()\n", - "qc = QuantumCircuit(cgate.num_qubits)\n", - "qc.append(cgate, list(range(cgate.num_qubits)), [])\n", - "qc.draw()" - ], - "cell_type": "code", - "outputs": [], - "metadata": {}, - "execution_count": 0 - }, - { - "source": [ - "unitary = execute(qc, BasicAer.get_backend('unitary_simulator')).result().get_unitary()" - ], - "cell_type": "code", - "outputs": [], - "metadata": {}, - "execution_count": 0 - }, - { - "source": [ - "plt.imshow(np.abs(unitary))\n", - "plt.imshow(np.abs(unitary - ctrl))\n", - "\n", - "atol = 1e-10\n", - "for i in range(2**cgate.num_qubits):\n", - " for j in range(2**cgate.num_qubits):\n", - " if np.abs(ctrl[i, j] - unitary[i, j]) >= atol:\n", - " print(i, j, ctrl[i, j], unitary[i, j])" - ], - "cell_type": "code", - "outputs": [], - "metadata": {}, - "execution_count": 0 - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ] -} \ No newline at end of file From ac7d004be8f55d00f283dc1fec87e67536a76b3c Mon Sep 17 00:00:00 2001 From: Cryoris Date: Fri, 14 Feb 2020 13:05:31 +0100 Subject: [PATCH 5/7] remove unused import --- test/python/circuit/test_circuit_operations.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/python/circuit/test_circuit_operations.py b/test/python/circuit/test_circuit_operations.py index 1bc707f1e6ab..e5e8b1baf269 100644 --- a/test/python/circuit/test_circuit_operations.py +++ b/test/python/circuit/test_circuit_operations.py @@ -18,7 +18,6 @@ from qiskit import BasicAer from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit from qiskit import execute -from qiskit.circuit import Instruction from qiskit.circuit.exceptions import CircuitError from qiskit.test import QiskitTestCase From d6eff50ad3d8937cd81221b0bef5e70ecc969288 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Fri, 14 Feb 2020 15:03:00 +0100 Subject: [PATCH 6/7] add reno --- .../notes/copy-rhs-on-extending-qc-9e65804b6b0ab4da.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 releasenotes/notes/copy-rhs-on-extending-qc-9e65804b6b0ab4da.yaml diff --git a/releasenotes/notes/copy-rhs-on-extending-qc-9e65804b6b0ab4da.yaml b/releasenotes/notes/copy-rhs-on-extending-qc-9e65804b6b0ab4da.yaml new file mode 100644 index 000000000000..9a822a74c2e4 --- /dev/null +++ b/releasenotes/notes/copy-rhs-on-extending-qc-9e65804b6b0ab4da.yaml @@ -0,0 +1,8 @@ +--- +fixes: + - | + When extending a `QuantumCircuit` instance (extendee) with another circuit (extension), + the circuit is taken via reference. If a circuit is extended with itself that + leads to an infinite loop as extendee and extension are the same. + This bug is resolved by copying the extension if it is the same object as + the extendee. \ No newline at end of file From 0577b2384f7ab3b700b3f3dccef7c1af019e8a7c Mon Sep 17 00:00:00 2001 From: Cryoris Date: Fri, 14 Feb 2020 15:41:19 +0100 Subject: [PATCH 7/7] test circuit ops after extension --- test/python/circuit/test_circuit_operations.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/python/circuit/test_circuit_operations.py b/test/python/circuit/test_circuit_operations.py index e5e8b1baf269..4f00778aa492 100644 --- a/test/python/circuit/test_circuit_operations.py +++ b/test/python/circuit/test_circuit_operations.py @@ -38,6 +38,9 @@ def test_adding_self(self): # attempt addition, times out if qc is added via reference qc += qc + # finally, qc should contain two X gates + self.assertEqual(['x', 'x'], [x[0].name for x in qc.data]) + def test_combine_circuit_common(self): """Test combining two circuits with same registers. """