From e0faed120b8b2421ccdd92d04ca414b5c4963a2a Mon Sep 17 00:00:00 2001 From: Luciano Bello Date: Tue, 12 May 2020 02:07:29 -0400 Subject: [PATCH 1/3] label support for controlled unitary (#4429) Co-authored-by: Ali Javadi-Abhari --- qiskit/extensions/unitary.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/qiskit/extensions/unitary.py b/qiskit/extensions/unitary.py index ac02b3a82ba4..ffc2e9aa04b7 100644 --- a/qiskit/extensions/unitary.py +++ b/qiskit/extensions/unitary.py @@ -133,8 +133,10 @@ def control(self, num_ctrl_qubits=1, label=None, ctrl_state=None): """ cmat = _compute_control_matrix(self.to_matrix(), num_ctrl_qubits) iso = isometry.Isometry(cmat, 0, 0) - return ControlledGate('c-unitary', self.num_qubits + num_ctrl_qubits, cmat, - definition=iso.definition, label=label) + cunitary = ControlledGate('c-unitary', self.num_qubits + num_ctrl_qubits, cmat, + definition=iso.definition, label=label) + cunitary.base_gate.label = self.label + return cunitary def qasm(self): """ The qasm for a custom unitary gate From 607bdf52cc1cb676daec6ee5c079adc1a87f1512 Mon Sep 17 00:00:00 2001 From: SooluThomas Date: Tue, 12 May 2020 03:24:26 -0400 Subject: [PATCH 2/3] Bugfix: Hz -> GHz conversion for SetFrequency -> PulseQobjInstruction (#4399) * Hz -> GHz conversion for SetFrequency -> PulseQobjInstruction * Reno * Logic Fixes * Review suggestions * few more corrections Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- qiskit/qobj/converters/pulse_instruction.py | 4 ++-- .../notes/bugfix-set-frequency-29608d213a8cbece.yaml | 6 ++++++ test/python/qobj/test_pulse_converter.py | 4 ++-- test/python/qobj/test_qobj.py | 4 ++-- 4 files changed, 12 insertions(+), 6 deletions(-) create mode 100644 releasenotes/notes/bugfix-set-frequency-29608d213a8cbece.yaml diff --git a/qiskit/qobj/converters/pulse_instruction.py b/qiskit/qobj/converters/pulse_instruction.py index c89ed8245766..661127b67eae 100644 --- a/qiskit/qobj/converters/pulse_instruction.py +++ b/qiskit/qobj/converters/pulse_instruction.py @@ -269,7 +269,7 @@ def convert_set_frequency(self, shift, instruction): 'name': 'setf', 't0': shift+instruction.start_time, 'ch': instruction.channel.name, - 'frequency': instruction.frequency + 'frequency': instruction.frequency / 1e9 } return self._qobj_model(**command_dict) @@ -532,7 +532,7 @@ def convert_set_frequency(self, instruction): """ t0 = instruction.t0 channel = self.get_channel(instruction.ch) - frequency = instruction.frequency + frequency = instruction.frequency * 1e9 if isinstance(frequency, str): frequency_expr = parse_string_expr(frequency, partial_binding=False) diff --git a/releasenotes/notes/bugfix-set-frequency-29608d213a8cbece.yaml b/releasenotes/notes/bugfix-set-frequency-29608d213a8cbece.yaml new file mode 100644 index 000000000000..360e5339509a --- /dev/null +++ b/releasenotes/notes/bugfix-set-frequency-29608d213a8cbece.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Fixed the SI unit conversion for :py:class:`qiskit.pulse.SetFrequency`. The + ``SetFrequency`` instruction should be in Hz on the frontend and has to be + converted to GHz when ``SetFrequency`` is converted to ``PulseQobjInstruction``. diff --git a/test/python/qobj/test_pulse_converter.py b/test/python/qobj/test_pulse_converter.py index e000a78ee167..d8f082c95e34 100644 --- a/test/python/qobj/test_pulse_converter.py +++ b/test/python/qobj/test_pulse_converter.py @@ -146,7 +146,7 @@ def test_frame_change(self): def test_set_frequency(self): """Test converted qobj from SetFrequency.""" converter = InstructionToQobjConverter(PulseQobjInstruction, meas_level=2) - instruction = SetFrequency(8.0, DriveChannel(0)) + instruction = SetFrequency(8.0e9, DriveChannel(0)) valid_qobj = PulseQobjInstruction( name='setf', @@ -302,7 +302,7 @@ def test_frame_change(self): def test_set_frequency(self): """Test converted qobj from FrameChangeInstruction.""" - instruction = SetFrequency(8.0, DriveChannel(0)) + instruction = SetFrequency(8.0e9, DriveChannel(0)) qobj = PulseQobjInstruction(name='setf', ch='d0', t0=0, frequency=8.0) converted_instruction = self.converter(qobj) diff --git a/test/python/qobj/test_qobj.py b/test/python/qobj/test_qobj.py index 930882cf5438..b1b0622e64d8 100644 --- a/test/python/qobj/test_qobj.py +++ b/test/python/qobj/test_qobj.py @@ -231,7 +231,7 @@ def setUp(self): PulseQobjInstruction(name='fc', t0=5, ch='d0', phase='P1'), PulseQobjInstruction(name='pv', t0=10, ch='d0', val=0.1 + 0.0j), PulseQobjInstruction(name='pv', t0=10, ch='d0', val='P1'), - PulseQobjInstruction(name='sf', t0=10, ch='d0', frequency=8.), + PulseQobjInstruction(name='setf', t0=10, ch='d0', frequency=8.0), PulseQobjInstruction(name='acquire', t0=15, duration=5, qubits=[0], memory_slot=[0], kernels=[ @@ -265,7 +265,7 @@ def setUp(self): {'name': 'fc', 't0': 5, 'ch': 'd0', 'phase': 'P1'}, {'name': 'pv', 't0': 10, 'ch': 'd0', 'val': 0.1+0j}, {'name': 'pv', 't0': 10, 'ch': 'd0', 'val': 'P1'}, - {'name': 'sf', 't0': 10, 'ch': 'd0', 'frequency': 8.0}, + {'name': 'setf', 't0': 10, 'ch': 'd0', 'frequency': 8.0}, {'name': 'acquire', 't0': 15, 'duration': 5, 'qubits': [0], 'memory_slot': [0], 'kernels': [{'name': 'boxcar', From c74f87f47cb91192e77bfb3d123740157f5cc55c Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Tue, 12 May 2020 12:44:19 -0400 Subject: [PATCH 3/3] Fix randomized test failures for test_clifford (#4435) np.inv can return invalid output for larger matrices which sometimes causes random_clifford to fail. This can be avoided by manually block inverting the required matrices. This PR lowers the threshold for block diagonalization from 150 qubits to 50 qubit Clifford to hopefully fix this issue. --- .../operators/symplectic/random.py | 19 ++++++++++++------- .../quantum_info/operators/test_random.py | 2 +- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/qiskit/quantum_info/operators/symplectic/random.py b/qiskit/quantum_info/operators/symplectic/random.py index d3ad58409d91..f5f3c8fd5389 100644 --- a/qiskit/quantum_info/operators/symplectic/random.py +++ b/qiskit/quantum_info/operators/symplectic/random.py @@ -107,12 +107,18 @@ def random_clifford(num_qubits, seed=None): _fill_tril(delta1, rng) _fill_tril(delta2, rng) + # For large num_qubits numpy.inv function called below can + # return invalid output leading to a non-symplectic Clifford + # being generated. This can be prevented by manually forcing + # block inversion of the matrix. + block_inverse_threshold = 50 + # Compute stabilizer table zero = np.zeros((num_qubits, num_qubits), dtype=np.int8) prod1 = np.matmul(gamma1, delta1) % 2 prod2 = np.matmul(gamma2, delta2) % 2 - inv1 = _inverse_tril(delta1).transpose() - inv2 = _inverse_tril(delta2).transpose() + inv1 = _inverse_tril(delta1, block_inverse_threshold).transpose() + inv2 = _inverse_tril(delta2, block_inverse_threshold).transpose() table1 = np.block([[delta1, zero], [prod1, inv1]]) table2 = np.block([[delta2, zero], [prod2, inv2]]) @@ -197,7 +203,7 @@ def _fill_tril(mat, rng, symmetric=False): mat[(cols, rows)] = vals -def _inverse_tril(mat): +def _inverse_tril(mat, block_inverse_threshold): """Invert a lower-triangular matrix with unit diagonal.""" # Optimized inversion function for low dimensions dim = mat.shape[0] @@ -221,8 +227,7 @@ def _inverse_tril(mat): # For higher dimensions we use Numpy's inverse function # however this function tends to fail and result in a non-symplectic # final matrix if n is too large. - max_np_inv = 150 - if dim <= max_np_inv: + if dim <= block_inverse_threshold: return np.linalg.inv(mat).astype(np.int8) % 2 # For very large matrices we divide the matrix into 4 blocks of @@ -232,8 +237,8 @@ def _inverse_tril(mat): # call the inverse function recursively to compute inv(A) and invD dim1 = dim // 2 - mat_a = _inverse_tril(mat[0:dim1, 0:dim1]) - mat_d = _inverse_tril(mat[dim1:dim, dim1:dim]) + mat_a = _inverse_tril(mat[0:dim1, 0:dim1], block_inverse_threshold) + mat_d = _inverse_tril(mat[dim1:dim, dim1:dim], block_inverse_threshold) mat_c = np.matmul(np.matmul(mat_d, mat[dim1:dim, 0:dim1]), mat_a) inv = np.block([[mat_a, np.zeros((dim1, dim - dim1), dtype=int)], [mat_c, mat_d]]) return inv % 2 diff --git a/test/python/quantum_info/operators/test_random.py b/test/python/quantum_info/operators/test_random.py index e126729369f2..ea8cbd9bbc47 100644 --- a/test/python/quantum_info/operators/test_random.py +++ b/test/python/quantum_info/operators/test_random.py @@ -167,7 +167,7 @@ class TestRandomClifford(QiskitTestCase): @combine(num_qubits=[1, 2, 3, 4, 5, 10, 50, 100, 150, 211]) def test_valid(self, num_qubits): """Test random_clifford {num_qubits}-qubits.""" - seed = 42 + seed = 213 value = random_clifford(num_qubits, seed=seed) with self.subTest(msg='Test type'): self.assertIsInstance(value, Clifford)