From 9848f90ac0d473de2b6f994b5f727c687907bb51 Mon Sep 17 00:00:00 2001 From: Daiki Murata Date: Sun, 1 May 2022 23:49:42 +0900 Subject: [PATCH 1/7] add left multiplication --- qiskit/quantum_info/operators/mixins/multiply.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/qiskit/quantum_info/operators/mixins/multiply.py b/qiskit/quantum_info/operators/mixins/multiply.py index 2ae3ec3e2f4d..1eaf483ce007 100644 --- a/qiskit/quantum_info/operators/mixins/multiply.py +++ b/qiskit/quantum_info/operators/mixins/multiply.py @@ -35,6 +35,9 @@ class MultiplyMixin(ABC): def __rmul__(self, other): return self._multiply(other) + def __mul__(self, other): + return self.__rmul__(other) + def __truediv__(self, other): return self._multiply(1 / other) From 4d22a4fde07151a1e398e7f021e9e556b5e1919d Mon Sep 17 00:00:00 2001 From: Daiki Murata Date: Mon, 2 May 2022 07:00:24 +0900 Subject: [PATCH 2/7] add tests --- test/python/quantum_info/operators/channel/test_chi.py | 2 ++ .../python/quantum_info/operators/channel/test_choi.py | 2 ++ .../quantum_info/operators/channel/test_kraus.py | 3 +++ test/python/quantum_info/operators/channel/test_ptm.py | 2 ++ .../quantum_info/operators/channel/test_stinespring.py | 4 ++++ .../quantum_info/operators/channel/test_superop.py | 2 ++ .../quantum_info/operators/symplectic/test_pauli.py | 3 +++ .../operators/symplectic/test_sparse_pauli_op.py | 10 ++++++++-- test/python/quantum_info/operators/test_operator.py | 1 + test/python/quantum_info/operators/test_scalar_op.py | 3 +++ 10 files changed, 30 insertions(+), 2 deletions(-) diff --git a/test/python/quantum_info/operators/channel/test_chi.py b/test/python/quantum_info/operators/channel/test_chi.py index 66240f7ce4a3..2bd5613510e1 100644 --- a/test/python/quantum_info/operators/channel/test_chi.py +++ b/test/python/quantum_info/operators/channel/test_chi.py @@ -363,6 +363,8 @@ def test_multiply(self): targ = Chi(val * self.chiI) self.assertEqual(chan._multiply(val), targ) self.assertEqual(val * chan, targ) + targ = Chi(self.chiI * val) + self.assertEqual(chan * val, targ) def test_multiply_except(self): """Test multiply method raises exceptions.""" diff --git a/test/python/quantum_info/operators/channel/test_choi.py b/test/python/quantum_info/operators/channel/test_choi.py index 1ef859a9a0f1..daa1a1cd18ac 100644 --- a/test/python/quantum_info/operators/channel/test_choi.py +++ b/test/python/quantum_info/operators/channel/test_choi.py @@ -450,6 +450,8 @@ def test_multiply(self): targ = Choi(val * self.choiI) self.assertEqual(chan._multiply(val), targ) self.assertEqual(val * chan, targ) + targ = Choi(self.choiI * val) + self.assertEqual(chan * val, targ) def test_multiply_except(self): """Test multiply method raises exceptions.""" diff --git a/test/python/quantum_info/operators/channel/test_kraus.py b/test/python/quantum_info/operators/channel/test_kraus.py index 5e589878d0bf..5d50ee9b4759 100644 --- a/test/python/quantum_info/operators/channel/test_kraus.py +++ b/test/python/quantum_info/operators/channel/test_kraus.py @@ -419,6 +419,9 @@ def test_multiply(self): self.assertEqual(rho & chan, targ) chan = val * chan1 self.assertEqual(rho & chan, targ) + targ = (rho & chan1) * val + chan = chan1 * val + self.assertEqual(rho & chan, targ) # Double Kraus set chan2 = Kraus((kraus1, kraus2)) diff --git a/test/python/quantum_info/operators/channel/test_ptm.py b/test/python/quantum_info/operators/channel/test_ptm.py index 51660e495a0c..bca1d4173071 100644 --- a/test/python/quantum_info/operators/channel/test_ptm.py +++ b/test/python/quantum_info/operators/channel/test_ptm.py @@ -356,6 +356,8 @@ def test_multiply(self): targ = PTM(val * self.ptmI) self.assertEqual(chan._multiply(val), targ) self.assertEqual(val * chan, targ) + targ = PTM(self.ptmI * val) + self.assertEqual(chan * val, targ) def test_multiply_except(self): """Test multiply method raises exceptions.""" diff --git a/test/python/quantum_info/operators/channel/test_stinespring.py b/test/python/quantum_info/operators/channel/test_stinespring.py index d809009c23cf..69179161dbd0 100644 --- a/test/python/quantum_info/operators/channel/test_stinespring.py +++ b/test/python/quantum_info/operators/channel/test_stinespring.py @@ -411,6 +411,10 @@ def test_multiply(self): self.assertEqual(rho_init.evolve(chan), rho_targ) chan = val * chan1 self.assertEqual(rho_init.evolve(chan), rho_targ) + rho_targ = (rho_init & chan1) * val + chan = chan1 * val + self.assertEqual(rho_init.evolve(chan), rho_targ) + # Double Stinespring set chan2 = Stinespring((stine1, stine2), input_dims=2, output_dims=4) diff --git a/test/python/quantum_info/operators/channel/test_superop.py b/test/python/quantum_info/operators/channel/test_superop.py index 50297eaf73bf..0d79af03d931 100644 --- a/test/python/quantum_info/operators/channel/test_superop.py +++ b/test/python/quantum_info/operators/channel/test_superop.py @@ -647,6 +647,8 @@ def test_multiply(self): targ = SuperOp(val * self.sopI) self.assertEqual(chan._multiply(val), targ) self.assertEqual(val * chan, targ) + targ = SuperOp(self.sopI * val) + self.assertEqual(chan * val, targ) def test_multiply_except(self): """Test multiply method raises exceptions.""" diff --git a/test/python/quantum_info/operators/symplectic/test_pauli.py b/test/python/quantum_info/operators/symplectic/test_pauli.py index ba08b453c6a4..c952a3a8fb93 100644 --- a/test/python/quantum_info/operators/symplectic/test_pauli.py +++ b/test/python/quantum_info/operators/symplectic/test_pauli.py @@ -336,6 +336,9 @@ def test_multiply(self, val): op = val * Pauli(([True, True], [False, False], 0)) phase = (-1j) ** op.phase self.assertEqual(phase, val) + op = Pauli(([True, True], [False, False], 0)) * val + phase = (-1j) ** op.phase + self.assertEqual(phase, val) def test_multiply_except(self): """Test multiply method raises exceptions.""" diff --git a/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py b/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py index 81a9a0d103c6..f56bcc5e0ba6 100644 --- a/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py +++ b/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py @@ -13,6 +13,7 @@ """Tests for SparsePauliOp class.""" import itertools as it +from tokenize import Number import unittest from test import combine @@ -450,8 +451,13 @@ def test_mul(self, num_qubits, value): spp_op = self.random_spp_op(num_qubits, 2**num_qubits) target = value * Operator(spp_op) op = value * spp_op - value = op.to_operator() - self.assertEqual(value, target) + value_mat = op.to_operator() + self.assertEqual(value_mat, target) + np.testing.assert_array_equal(op.paulis.phase, np.zeros(op.size)) + target = Operator(spp_op) * value + op = spp_op * value + value_mat = op.to_operator() + self.assertEqual(value_mat, target) np.testing.assert_array_equal(op.paulis.phase, np.zeros(op.size)) @combine(num_qubits=[1, 2, 3], value=[1, 1j, -3 + 4.4j]) diff --git a/test/python/quantum_info/operators/test_operator.py b/test/python/quantum_info/operators/test_operator.py index 847e816385c6..365b33f1ac9a 100644 --- a/test/python/quantum_info/operators/test_operator.py +++ b/test/python/quantum_info/operators/test_operator.py @@ -635,6 +635,7 @@ def test_multiply(self): op = Operator(mat) self.assertEqual(op._multiply(val), Operator(val * mat)) self.assertEqual(val * op, Operator(val * mat)) + self.assertEqual(op * val, Operator(mat * val)) def test_multiply_except(self): """Test multiply method raises exceptions.""" diff --git a/test/python/quantum_info/operators/test_scalar_op.py b/test/python/quantum_info/operators/test_scalar_op.py index e6a2171b78e9..45079f8d0cc6 100644 --- a/test/python/quantum_info/operators/test_scalar_op.py +++ b/test/python/quantum_info/operators/test_scalar_op.py @@ -152,6 +152,9 @@ def test_multiply(self, coeff1, coeff2): val = coeff2 * ScalarOp(dims, coeff=coeff1) target = coeff1 * coeff2 self.assertScalarOp(val, dims, target) + val = ScalarOp(dims, coeff=coeff1) * coeff2 + target = coeff2 * coeff1 + self.assertScalarOp(val, dims, target) @combine(coeff1=[0, 1, -3.1, 1 + 3j], coeff2=[-1, -5.1 - 2j]) def test_add(self, coeff1, coeff2): From 46b69e0397779e1445f3c86ec6c308d3f9b7b160 Mon Sep 17 00:00:00 2001 From: Daiki Murata Date: Mon, 2 May 2022 07:12:25 +0900 Subject: [PATCH 3/7] add releasenote --- ...scaler-multiplication-left-side-7bea0d73f9afabe2.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 releasenotes/notes/scaler-multiplication-left-side-7bea0d73f9afabe2.yaml diff --git a/releasenotes/notes/scaler-multiplication-left-side-7bea0d73f9afabe2.yaml b/releasenotes/notes/scaler-multiplication-left-side-7bea0d73f9afabe2.yaml new file mode 100644 index 000000000000..8ff9195fc9a2 --- /dev/null +++ b/releasenotes/notes/scaler-multiplication-left-side-7bea0d73f9afabe2.yaml @@ -0,0 +1,9 @@ +--- +features: + - | + Introduced a left side scaler multiplication to :class:`.Operator` objects. + It can be used by using * decorator, + for example:: + + from qiskit.quantum_info import Pauli + Pauli("X") * -1j From b76867d67302417d0be20beeb35717313ac6f046 Mon Sep 17 00:00:00 2001 From: Daiki Murata Date: Mon, 2 May 2022 11:38:59 +0900 Subject: [PATCH 4/7] fix incorrectly mixed module --- .../quantum_info/operators/symplectic/test_sparse_pauli_op.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py b/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py index f56bcc5e0ba6..4cb9d50b9d72 100644 --- a/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py +++ b/test/python/quantum_info/operators/symplectic/test_sparse_pauli_op.py @@ -13,7 +13,6 @@ """Tests for SparsePauliOp class.""" import itertools as it -from tokenize import Number import unittest from test import combine From 31ea9fedc4f78274c5262cf26e0e3ab164efbe17 Mon Sep 17 00:00:00 2001 From: Daiki Murata Date: Mon, 2 May 2022 11:45:07 +0900 Subject: [PATCH 5/7] change method of __mul__ --- qiskit/quantum_info/operators/mixins/multiply.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/quantum_info/operators/mixins/multiply.py b/qiskit/quantum_info/operators/mixins/multiply.py index 1eaf483ce007..ad3de1f1c6a5 100644 --- a/qiskit/quantum_info/operators/mixins/multiply.py +++ b/qiskit/quantum_info/operators/mixins/multiply.py @@ -36,7 +36,7 @@ def __rmul__(self, other): return self._multiply(other) def __mul__(self, other): - return self.__rmul__(other) + return self._multiply(other) def __truediv__(self, other): return self._multiply(1 / other) From df490f76272d2e1465c4800900e3abf82ff51c28 Mon Sep 17 00:00:00 2001 From: Daiki Murata Date: Mon, 2 May 2022 12:28:58 +0900 Subject: [PATCH 6/7] fix lint --- test/python/quantum_info/operators/channel/test_stinespring.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/python/quantum_info/operators/channel/test_stinespring.py b/test/python/quantum_info/operators/channel/test_stinespring.py index 69179161dbd0..9bcc886a026c 100644 --- a/test/python/quantum_info/operators/channel/test_stinespring.py +++ b/test/python/quantum_info/operators/channel/test_stinespring.py @@ -415,7 +415,6 @@ def test_multiply(self): chan = chan1 * val self.assertEqual(rho_init.evolve(chan), rho_targ) - # Double Stinespring set chan2 = Stinespring((stine1, stine2), input_dims=2, output_dims=4) rho_targ = val * (rho_init & chan2) From 7ba19df0a949e7bb9bb4ccdeaba48c499d71c964 Mon Sep 17 00:00:00 2001 From: Jake Lishman Date: Tue, 3 May 2022 11:44:22 +0100 Subject: [PATCH 7/7] Reword release note --- ...scaler-multiplication-left-side-7bea0d73f9afabe2.yaml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/releasenotes/notes/scaler-multiplication-left-side-7bea0d73f9afabe2.yaml b/releasenotes/notes/scaler-multiplication-left-side-7bea0d73f9afabe2.yaml index 8ff9195fc9a2..11727a657785 100644 --- a/releasenotes/notes/scaler-multiplication-left-side-7bea0d73f9afabe2.yaml +++ b/releasenotes/notes/scaler-multiplication-left-side-7bea0d73f9afabe2.yaml @@ -1,9 +1,6 @@ --- features: - | - Introduced a left side scaler multiplication to :class:`.Operator` objects. - It can be used by using * decorator, - for example:: - - from qiskit.quantum_info import Pauli - Pauli("X") * -1j + Classes in the :mod:`.quantum_info` module that support scalar multiplication + can now be multiplied by a scalar from either the left or the right. + Previously, they would only accept scalar multipliers from the left.