From 65b173f6858f516161a08061c5eee3aa634f8429 Mon Sep 17 00:00:00 2001 From: SaashaJoshi Date: Wed, 20 Jul 2022 10:00:39 -0400 Subject: [PATCH 01/23] adding PolynomialTensor class --- .../second_q/operators/polynomial_tensor.py | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 qiskit_nature/second_q/operators/polynomial_tensor.py diff --git a/qiskit_nature/second_q/operators/polynomial_tensor.py b/qiskit_nature/second_q/operators/polynomial_tensor.py new file mode 100644 index 0000000000..e603c714c5 --- /dev/null +++ b/qiskit_nature/second_q/operators/polynomial_tensor.py @@ -0,0 +1,74 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2022. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +"""Polynomial Tensor class""" + +from __future__ import annotations +import numpy as np +from typing import Dict +from qiskit.opflow.mixins import StarAlgebraMixin +from qiskit.quantum_info.operators.mixins import TolerancesMixin + + +class PolynomialTensor(StarAlgebraMixin, TolerancesMixin): + """Polynomial Tensor class""" + + def __init__(self, data: Dict[str, np.ndarray]): + self._data = data + + for key, value in self._data.items(): + if len(np.shape(value)) == len(key): + pass + else: + raise ValueError( + f"data key length {len(key)} and number of value dimensions {np.shape(value)} do not match" + ) + + def mul(self, other: complex): + """scalar multiplication of PolynomialTensor with complex""" + + # other might be float, int or etc. quantum info - typing is Number (check) + prod_dict = {} + + for key, matrix in self._data.items(): + prod_dict[key] = matrix * other + return PolynomialTensor(prod_dict) + + def add(self, other: PolynomialTensor): + """addition of PolynomialTensors""" + + # Polynomial tensor immutable! + sum_dict = self._data # or try empty dict {} + + if other is not isinstance(other, PolynomialTensor): + raise TypeError("Incorrect argument type: other should be PolynomialTensor") + + for key, value in other.items(): + if key in self._data.keys(): + if np.shape(value) == np.shape(self._data[key]): + print(f"key {key} of same dimension present in both") + sum_dict[key] = np.add(value, self._data[key]) + else: + raise ValueError( + f"Dictionary value dimensions {np.shape(value)} and {np.shape(self._data[key])} do not match" + ) + else: + print(f"adding a new key {key}") + sum_dict[key] = value + + return PolynomialTensor(sum_dict) + + def compose(self, other): + pass + + def adjoint(self): + pass From 71c359138be2bf5b5cc904d33501a8ee0df16db7 Mon Sep 17 00:00:00 2001 From: SaashaJoshi Date: Thu, 21 Jul 2022 11:35:52 -0400 Subject: [PATCH 02/23] adding unittest corresponding PolynomialTensor class; making changes to the class as suggested --- qiskit_nature/second_q/operators/__init__.py | 3 + .../second_q/operators/polynomial_tensor.py | 66 +++--- .../operators/test_polynomial_tensor.py | 193 ++++++++++++++++++ 3 files changed, 238 insertions(+), 24 deletions(-) create mode 100644 test/second_q/operators/test_polynomial_tensor.py diff --git a/qiskit_nature/second_q/operators/__init__.py b/qiskit_nature/second_q/operators/__init__.py index 2606c4550f..aa72221568 100644 --- a/qiskit_nature/second_q/operators/__init__.py +++ b/qiskit_nature/second_q/operators/__init__.py @@ -25,16 +25,19 @@ SpinOp SecondQuantizedOp VibrationalOp + PolynomialTensor """ from .fermionic_op import FermionicOp from .second_quantized_op import SecondQuantizedOp from .spin_op import SpinOp from .vibrational_op import VibrationalOp +from .polynomial_tensor import PolynomialTensor __all__ = [ "FermionicOp", "SecondQuantizedOp", "SpinOp", "VibrationalOp", + "PolynomialTensor", ] diff --git a/qiskit_nature/second_q/operators/polynomial_tensor.py b/qiskit_nature/second_q/operators/polynomial_tensor.py index e603c714c5..4441bb487f 100644 --- a/qiskit_nature/second_q/operators/polynomial_tensor.py +++ b/qiskit_nature/second_q/operators/polynomial_tensor.py @@ -13,13 +13,17 @@ """Polynomial Tensor class""" from __future__ import annotations -import numpy as np from typing import Dict -from qiskit.opflow.mixins import StarAlgebraMixin -from qiskit.quantum_info.operators.mixins import TolerancesMixin +from numbers import Number +import numpy as np +from qiskit.quantum_info.operators.mixins import ( + LinearMixin, + AdjointMixin, + TolerancesMixin, +) -class PolynomialTensor(StarAlgebraMixin, TolerancesMixin): +class PolynomialTensor(LinearMixin, AdjointMixin, TolerancesMixin): """Polynomial Tensor class""" def __init__(self, data: Dict[str, np.ndarray]): @@ -30,45 +34,59 @@ def __init__(self, data: Dict[str, np.ndarray]): pass else: raise ValueError( - f"data key length {len(key)} and number of value dimensions {np.shape(value)} do not match" + f"data key {key} of length {len(key)} does not match " + f"data value of dimensions {np.shape(value)}" ) def mul(self, other: complex): - """scalar multiplication of PolynomialTensor with complex""" + """Scalar multiplication of PolynomialTensor with complex""" - # other might be float, int or etc. quantum info - typing is Number (check) prod_dict = {} + if not isinstance(other, Number): + raise TypeError(f"other {other} must be a number") + for key, matrix in self._data.items(): prod_dict[key] = matrix * other return PolynomialTensor(prod_dict) + def _multiply(self, other): + return self.mul(other) + def add(self, other: PolynomialTensor): - """addition of PolynomialTensors""" + """Addition of PolynomialTensors""" - # Polynomial tensor immutable! - sum_dict = self._data # or try empty dict {} + sum_dict = {} - if other is not isinstance(other, PolynomialTensor): + if not isinstance(other, PolynomialTensor): raise TypeError("Incorrect argument type: other should be PolynomialTensor") - for key, value in other.items(): - if key in self._data.keys(): - if np.shape(value) == np.shape(self._data[key]): - print(f"key {key} of same dimension present in both") - sum_dict[key] = np.add(value, self._data[key]) - else: - raise ValueError( - f"Dictionary value dimensions {np.shape(value)} and {np.shape(self._data[key])} do not match" - ) + for key, value in self._data.items(): + sum_dict[key] = value + if key in other._data.keys() and np.shape(value) == np.shape(other._data[key]): + sum_dict[key] = np.add(value, other._data[key]) else: - print(f"adding a new key {key}") - sum_dict[key] = value + raise ValueError( + f"Data value of shape {np.shape(value)} " + f"does not match other value of shape {np.shape(other._data[key])}" + ) return PolynomialTensor(sum_dict) - def compose(self, other): + def _add(self, other, qargs=None): + return self.add(other) + + def __eq__(self, other): + """Check equality of PolynomialTensors""" + if self._data.keys() == other._data.keys(): + for key in self._data.keys(): + if np.allclose(self._data[key], other._data[key], atol=self.atol, rtol=self.rtol): + return isinstance(other, PolynomialTensor) + + def conjugate(self, other): + """Conjugate of PolynomialTensors""" pass - def adjoint(self): + def transpose(self): + """Transpose of PolynomialTensor""" pass diff --git a/test/second_q/operators/test_polynomial_tensor.py b/test/second_q/operators/test_polynomial_tensor.py new file mode 100644 index 0000000000..1889605161 --- /dev/null +++ b/test/second_q/operators/test_polynomial_tensor.py @@ -0,0 +1,193 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2022. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +"""Test for Polynomial Tensor""" + +import unittest +import warnings +import numpy as np +from functools import lru_cache +from test import QiskitNatureTestCase +from qiskit_nature.second_q.operators import PolynomialTensor +from qiskit_nature.drivers import UnitsType +from qiskit_nature.second_q.drivers import PySCFDriver +from qiskit_nature.second_q.properties.bases.electronic_basis import ElectronicBasis + +@lru_cache +def driver_results(): + _driver = PySCFDriver( + atom="H .0 .0 .0; H .0 .0 0.735", unit=UnitsType.ANGSTROM, basis="sto3g" + ) + _elec_energy = _driver.run().get_property("ElectronicEnergy") + + _one = _elec_energy.get_electronic_integral(ElectronicBasis.MO, 1) + one_matrix = _one.to_spin() + + _two = _elec_energy.get_electronic_integral(ElectronicBasis.MO, 2) + two_matrix = np.einsum("ijkl->iklj", _two.to_spin()) + + og_poly = { + "+-": one_matrix, + "++--": two_matrix + } + + return og_poly + +class TestPolynomialTensor(QiskitNatureTestCase): + """Tests for PolynomialTensor class""" + + def setUp(self) -> None: + super().setUp() + + self.og_poly = driver_results() + + self.expected_poly = { + "+-": np.array( + [ + [-2.51267815, 0.0, 0.0, 0.0], + [0.0, -0.94379201, 0.0, 0.0], + [0.0, 0.0, -2.51267815, 0.0], + [0.0, 0.0, 0.0, -0.94379201], + ] + ), + "++--": np.array( + [ + [ + [ + [-0.67571015, 0.0, 0.0, 0.0], + [0.0, -0.1809312, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ], + [ + [0.0, -0.66458173, 0.0, 0.0], + [-0.1809312, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ], + [ + [0.0, 0.0, -0.67571015, 0.0], + [0.0, 0.0, 0.0, -0.1809312], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ], + [ + [0.0, 0.0, 0.0, -0.66458173], + [0.0, 0.0, -0.1809312, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ], + ], + [ + [ + [0.0, -0.1809312, 0.0, 0.0], + [-0.66458173, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ], + [ + [-0.1809312, 0.0, 0.0, 0.0], + [0.0, -0.69857372, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ], + [ + [0.0, 0.0, 0.0, -0.1809312], + [0.0, 0.0, -0.66458173, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ], + [ + [0.0, 0.0, -0.1809312, 0.0], + [0.0, 0.0, 0.0, -0.69857372], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + ], + ], + [ + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [-0.67571015, 0.0, 0.0, 0.0], + [0.0, -0.1809312, 0.0, 0.0], + ], + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, -0.66458173, 0.0, 0.0], + [-0.1809312, 0.0, 0.0, 0.0], + ], + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, -0.67571015, 0.0], + [0.0, 0.0, 0.0, -0.1809312], + ], + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, -0.66458173], + [0.0, 0.0, -0.1809312, 0.0], + ], + ], + [ + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, -0.1809312, 0.0, 0.0], + [-0.66458173, 0.0, 0.0, 0.0], + ], + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [-0.1809312, 0.0, 0.0, 0.0], + [0.0, -0.69857372, 0.0, 0.0], + ], + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, -0.1809312], + [0.0, 0.0, -0.66458173, 0.0], + ], + [ + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, -0.1809312, 0.0], + [0.0, 0.0, 0.0, -0.69857372], + ], + ], + ] + ), + } + + def test_mul(self): + """Test for scalar multiplication""" + + result = PolynomialTensor(self.og_poly).mul(2) + self.assertEqual(result, PolynomialTensor(self.expected_poly)) + + def test_add(self): + """Test for addition of Polynomial Tensors""" + + result = PolynomialTensor(self.og_poly).add(PolynomialTensor(self.og_poly)) + self.assertEqual(result, PolynomialTensor(self.expected_poly)) + + def test_conjugate(self): + """Test for conjugate of Polynomial Tensor""" + pass + + def transpose(self): + """Test for transpose of Polynomial Tensor""" + pass + +if __name__ == "__main__": + unittest.main() From 91d1f89a8c94935413998e1c2aad5d89e1286e28 Mon Sep 17 00:00:00 2001 From: SaashaJoshi Date: Thu, 21 Jul 2022 16:45:08 -0400 Subject: [PATCH 03/23] adding conjugate and transpose functions --- .../second_q/operators/polynomial_tensor.py | 43 +++++++++++++------ .../operators/test_polynomial_tensor.py | 16 +++---- 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/qiskit_nature/second_q/operators/polynomial_tensor.py b/qiskit_nature/second_q/operators/polynomial_tensor.py index 4441bb487f..88be9a8db4 100644 --- a/qiskit_nature/second_q/operators/polynomial_tensor.py +++ b/qiskit_nature/second_q/operators/polynomial_tensor.py @@ -56,20 +56,24 @@ def _multiply(self, other): def add(self, other: PolynomialTensor): """Addition of PolynomialTensors""" - sum_dict = {} + sum_dict = self._data.copy() if not isinstance(other, PolynomialTensor): raise TypeError("Incorrect argument type: other should be PolynomialTensor") - for key, value in self._data.items(): - sum_dict[key] = value - if key in other._data.keys() and np.shape(value) == np.shape(other._data[key]): - sum_dict[key] = np.add(value, other._data[key]) - else: - raise ValueError( - f"Data value of shape {np.shape(value)} " - f"does not match other value of shape {np.shape(other._data[key])}" + for other_key, other_value in other._data.items(): + if other_key in sum_dict.keys(): + if np.shape(other_value) == np.shape(sum_dict[other_key]): + sum_dict[other_key] = np.add(other_value, sum_dict[other_key]) + else: + print("not same shape", np.shape(other_value), np.shape(sum_dict[other_key])) + raise ValueError( + f"For key {other_key} " + f"corresponding data value of shape {np.shape(sum_dict[other_key])} " + f"does not match value of shape {np.shape(other_value)}" ) + else: + sum_dict[other_key] = other_value return PolynomialTensor(sum_dict) @@ -82,11 +86,26 @@ def __eq__(self, other): for key in self._data.keys(): if np.allclose(self._data[key], other._data[key], atol=self.atol, rtol=self.rtol): return isinstance(other, PolynomialTensor) + else: + return False + else: + return False - def conjugate(self, other): + def conjugate(self): """Conjugate of PolynomialTensors""" - pass + conj_dict = {} + + for key, value in self._data.items(): + conj_dict[key] = np.conjugate(value) + + return PolynomialTensor(conj_dict) def transpose(self): """Transpose of PolynomialTensor""" - pass + + transpose_dict = {} + + for key, value in self._data.items(): + transpose_dict[key] = np.transpose(value) + + return PolynomialTensor(transpose_dict) diff --git a/test/second_q/operators/test_polynomial_tensor.py b/test/second_q/operators/test_polynomial_tensor.py index 1889605161..fc166badac 100644 --- a/test/second_q/operators/test_polynomial_tensor.py +++ b/test/second_q/operators/test_polynomial_tensor.py @@ -13,20 +13,19 @@ """Test for Polynomial Tensor""" import unittest -import warnings -import numpy as np from functools import lru_cache from test import QiskitNatureTestCase +import numpy as np from qiskit_nature.second_q.operators import PolynomialTensor from qiskit_nature.drivers import UnitsType from qiskit_nature.second_q.drivers import PySCFDriver from qiskit_nature.second_q.properties.bases.electronic_basis import ElectronicBasis + @lru_cache def driver_results(): - _driver = PySCFDriver( - atom="H .0 .0 .0; H .0 .0 0.735", unit=UnitsType.ANGSTROM, basis="sto3g" - ) + """Caching driver results""" + _driver = PySCFDriver(atom="H .0 .0 .0; H .0 .0 0.735", unit=UnitsType.ANGSTROM, basis="sto3g") _elec_energy = _driver.run().get_property("ElectronicEnergy") _one = _elec_energy.get_electronic_integral(ElectronicBasis.MO, 1) @@ -35,13 +34,11 @@ def driver_results(): _two = _elec_energy.get_electronic_integral(ElectronicBasis.MO, 2) two_matrix = np.einsum("ijkl->iklj", _two.to_spin()) - og_poly = { - "+-": one_matrix, - "++--": two_matrix - } + og_poly = {"+-": one_matrix, "++--": two_matrix} return og_poly + class TestPolynomialTensor(QiskitNatureTestCase): """Tests for PolynomialTensor class""" @@ -189,5 +186,6 @@ def transpose(self): """Test for transpose of Polynomial Tensor""" pass + if __name__ == "__main__": unittest.main() From 5d094840940cfce8f47e7e3bc32d751f3b760384 Mon Sep 17 00:00:00 2001 From: SaashaJoshi Date: Tue, 2 Aug 2022 10:47:24 -0400 Subject: [PATCH 04/23] made changes to polynomial_tensor and test_polyomial_tensor files --- .../second_q/operators/polynomial_tensor.py | 34 +-- .../operators/test_polynomial_tensor.py | 207 ++++++------------ 2 files changed, 87 insertions(+), 154 deletions(-) diff --git a/qiskit_nature/second_q/operators/polynomial_tensor.py b/qiskit_nature/second_q/operators/polynomial_tensor.py index 88be9a8db4..a8ad4f7d4e 100644 --- a/qiskit_nature/second_q/operators/polynomial_tensor.py +++ b/qiskit_nature/second_q/operators/polynomial_tensor.py @@ -27,25 +27,34 @@ class PolynomialTensor(LinearMixin, AdjointMixin, TolerancesMixin): """Polynomial Tensor class""" def __init__(self, data: Dict[str, np.ndarray]): + if not isinstance(data, Dict): + raise TypeError(f"data {data} must be a Dictionary") + self._data = data + shapes = () for key, value in self._data.items(): - if len(np.shape(value)) == len(key): - pass - else: + shapes += value.shape + if len(value.shape) != len(key): raise ValueError( f"data key {key} of length {len(key)} does not match " - f"data value of dimensions {np.shape(value)}" + f"data value matrix of dimensions {value.shape}" + ) + if len(set(value.shape)) != 1: + raise ValueError( + f"For key {key}: dimensions of value matrix are not identical {value.shape}" ) + if len(set(shapes)) != 1: + raise ValueError("Dimensions of value matrices in data dictionary are not identical.") + def mul(self, other: complex): """Scalar multiplication of PolynomialTensor with complex""" - prod_dict = {} - if not isinstance(other, Number): raise TypeError(f"other {other} must be a number") + prod_dict = {} for key, matrix in self._data.items(): prod_dict[key] = matrix * other return PolynomialTensor(prod_dict) @@ -56,21 +65,20 @@ def _multiply(self, other): def add(self, other: PolynomialTensor): """Addition of PolynomialTensors""" - sum_dict = self._data.copy() - if not isinstance(other, PolynomialTensor): raise TypeError("Incorrect argument type: other should be PolynomialTensor") + sum_dict = self._data.copy() for other_key, other_value in other._data.items(): if other_key in sum_dict.keys(): - if np.shape(other_value) == np.shape(sum_dict[other_key]): + if other_value.shape == np.shape(sum_dict[other_key]): sum_dict[other_key] = np.add(other_value, sum_dict[other_key]) else: - print("not same shape", np.shape(other_value), np.shape(sum_dict[other_key])) + print("not same shape", other_value.shape, np.shape(sum_dict[other_key])) raise ValueError( f"For key {other_key} " f"corresponding data value of shape {np.shape(sum_dict[other_key])} " - f"does not match value of shape {np.shape(other_value)}" + f"does not match other value matrix of shape {other_value.shape}" ) else: sum_dict[other_key] = other_value @@ -82,6 +90,7 @@ def _add(self, other, qargs=None): def __eq__(self, other): """Check equality of PolynomialTensors""" + if self._data.keys() == other._data.keys(): for key in self._data.keys(): if np.allclose(self._data[key], other._data[key], atol=self.atol, rtol=self.rtol): @@ -93,8 +102,8 @@ def __eq__(self, other): def conjugate(self): """Conjugate of PolynomialTensors""" - conj_dict = {} + conj_dict = {} for key, value in self._data.items(): conj_dict[key] = np.conjugate(value) @@ -104,7 +113,6 @@ def transpose(self): """Transpose of PolynomialTensor""" transpose_dict = {} - for key, value in self._data.items(): transpose_dict[key] = np.transpose(value) diff --git a/test/second_q/operators/test_polynomial_tensor.py b/test/second_q/operators/test_polynomial_tensor.py index fc166badac..0fcfcfa820 100644 --- a/test/second_q/operators/test_polynomial_tensor.py +++ b/test/second_q/operators/test_polynomial_tensor.py @@ -13,178 +13,103 @@ """Test for Polynomial Tensor""" import unittest -from functools import lru_cache +from typing import Dict from test import QiskitNatureTestCase +from ddt import ddt, data import numpy as np from qiskit_nature.second_q.operators import PolynomialTensor -from qiskit_nature.drivers import UnitsType -from qiskit_nature.second_q.drivers import PySCFDriver -from qiskit_nature.second_q.properties.bases.electronic_basis import ElectronicBasis -@lru_cache -def driver_results(): - """Caching driver results""" - _driver = PySCFDriver(atom="H .0 .0 .0; H .0 .0 0.735", unit=UnitsType.ANGSTROM, basis="sto3g") - _elec_energy = _driver.run().get_property("ElectronicEnergy") +def gen_expected_prod_poly(og_poly, dim_size, other): + """Generate expected product Polynomial Tensors""" - _one = _elec_energy.get_electronic_integral(ElectronicBasis.MO, 1) - one_matrix = _one.to_spin() + expected_poly = {} + for key, value in og_poly.items(): + num_dim = len(key) + expected_poly[key] = (np.arange(1, dim_size ** num_dim + 1) * other).reshape((dim_size,) * num_dim) - _two = _elec_energy.get_electronic_integral(ElectronicBasis.MO, 2) - two_matrix = np.einsum("ijkl->iklj", _two.to_spin()) + return expected_poly - og_poly = {"+-": one_matrix, "++--": two_matrix} +def gen_expected_transpose_poly(og_poly, dim_size): + """Generate expected transpose of Polynomial Tensor""" - return og_poly + expected_poly = {} + for key, value in og_poly.items(): + num_dim = len(key) + expected_poly[key] = np.arange(1, dim_size ** num_dim + 1).reshape((dim_size,) * num_dim).transpose() + return expected_poly +def gen_expected_conjugate_poly(og_poly, dim_size): + """Generate expected transpose of Polynomial Tensor""" + + expected_poly = {} + for key, value in og_poly.items(): + num_dim = len(key) + expected_poly[key] = np.arange(1, dim_size ** num_dim + 1).reshape((dim_size,) * num_dim).conjugate() + + return expected_poly + +@ddt class TestPolynomialTensor(QiskitNatureTestCase): """Tests for PolynomialTensor class""" def setUp(self) -> None: super().setUp() - self.og_poly = driver_results() - - self.expected_poly = { - "+-": np.array( - [ - [-2.51267815, 0.0, 0.0, 0.0], - [0.0, -0.94379201, 0.0, 0.0], - [0.0, 0.0, -2.51267815, 0.0], - [0.0, 0.0, 0.0, -0.94379201], - ] - ), - "++--": np.array( - [ - [ - [ - [-0.67571015, 0.0, 0.0, 0.0], - [0.0, -0.1809312, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - ], - [ - [0.0, -0.66458173, 0.0, 0.0], - [-0.1809312, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - ], - [ - [0.0, 0.0, -0.67571015, 0.0], - [0.0, 0.0, 0.0, -0.1809312], - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - ], - [ - [0.0, 0.0, 0.0, -0.66458173], - [0.0, 0.0, -0.1809312, 0.0], - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - ], - ], - [ - [ - [0.0, -0.1809312, 0.0, 0.0], - [-0.66458173, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - ], - [ - [-0.1809312, 0.0, 0.0, 0.0], - [0.0, -0.69857372, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - ], - [ - [0.0, 0.0, 0.0, -0.1809312], - [0.0, 0.0, -0.66458173, 0.0], - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - ], - [ - [0.0, 0.0, -0.1809312, 0.0], - [0.0, 0.0, 0.0, -0.69857372], - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - ], - ], - [ - [ - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - [-0.67571015, 0.0, 0.0, 0.0], - [0.0, -0.1809312, 0.0, 0.0], - ], - [ - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - [0.0, -0.66458173, 0.0, 0.0], - [-0.1809312, 0.0, 0.0, 0.0], - ], - [ - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, -0.67571015, 0.0], - [0.0, 0.0, 0.0, -0.1809312], - ], - [ - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, -0.66458173], - [0.0, 0.0, -0.1809312, 0.0], - ], - ], - [ - [ - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - [0.0, -0.1809312, 0.0, 0.0], - [-0.66458173, 0.0, 0.0, 0.0], - ], - [ - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - [-0.1809312, 0.0, 0.0, 0.0], - [0.0, -0.69857372, 0.0, 0.0], - ], - [ - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, -0.1809312], - [0.0, 0.0, -0.66458173, 0.0], - ], - [ - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, 0.0, 0.0], - [0.0, 0.0, -0.1809312, 0.0], - [0.0, 0.0, 0.0, -0.69857372], - ], - ], - ] - ), + self.og_poly: Dict[str, np.ndarray] = { + "+-": np.arange(1, 17).reshape(4, 4), + "+++-": np.arange(1, 257).reshape(4, 4, 4, 4), } - def test_mul(self): + for value in self.og_poly.values(): + self.dim_size = np.shape(value) + + self.expected_sum_poly: Dict[str, np.ndarray] = { + "+-": (np.arange(1, 17) * 2).reshape(4, 4), + "+++-": (np.arange(1, 257) * 2).reshape(4, 4, 4, 4), + } + + + def test_init_dict(self): + """Test for input type in Polynomial Tensor class""" + + if self.assertRaises(TypeError): + PolynomialTensor(self.og_poly) + + def test_init_dimensions(self): + """Test for input matrix dimensions in Polynomial Tensor""" + + if self.assertRaisesRegex(ValueError, "Dimensions of value matrices in data dictionary are not identical."): + PolynomialTensor(self.og_poly) + + @data(2, 3, 4) + def test_mul(self, other): """Test for scalar multiplication""" - result = PolynomialTensor(self.og_poly).mul(2) - self.assertEqual(result, PolynomialTensor(self.expected_poly)) + result = PolynomialTensor(self.og_poly).mul(other) + expected_prod_poly = gen_expected_prod_poly(self.og_poly, self.dim_size[0], other) + self.assertEqual(result, PolynomialTensor(expected_prod_poly)) def test_add(self): """Test for addition of Polynomial Tensors""" result = PolynomialTensor(self.og_poly).add(PolynomialTensor(self.og_poly)) - self.assertEqual(result, PolynomialTensor(self.expected_poly)) + self.assertEqual(result, PolynomialTensor(self.expected_sum_poly)) def test_conjugate(self): """Test for conjugate of Polynomial Tensor""" - pass - def transpose(self): + result = PolynomialTensor(self.og_poly).conjugate() + expected_conjugate_poly = gen_expected_conjugate_poly(self.og_poly, self.dim_size[0]) + self.assertEqual(result, PolynomialTensor(expected_conjugate_poly)) + + def test_transpose(self): """Test for transpose of Polynomial Tensor""" - pass + + result = PolynomialTensor(self.og_poly).transpose() + expected_transpose_poly = gen_expected_transpose_poly(self.og_poly, self.dim_size[0]) + self.assertEqual(result, PolynomialTensor(expected_transpose_poly)) if __name__ == "__main__": From 679d3409a4ab6c3ac44f191377bbf742baf48ac0 Mon Sep 17 00:00:00 2001 From: Saasha Joshi <32019413+SaashaJoshi@users.noreply.github.com> Date: Mon, 8 Aug 2022 09:29:11 -0400 Subject: [PATCH 05/23] Update qiskit_nature/second_q/operators/polynomial_tensor.py Co-authored-by: Max Rossmannek --- .../second_q/operators/polynomial_tensor.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/qiskit_nature/second_q/operators/polynomial_tensor.py b/qiskit_nature/second_q/operators/polynomial_tensor.py index a8ad4f7d4e..3c7fae1a20 100644 --- a/qiskit_nature/second_q/operators/polynomial_tensor.py +++ b/qiskit_nature/second_q/operators/polynomial_tensor.py @@ -32,20 +32,24 @@ def __init__(self, data: Dict[str, np.ndarray]): self._data = data - shapes = () + shapes = set() for key, value in self._data.items(): - shapes += value.shape if len(value.shape) != len(key): raise ValueError( f"data key {key} of length {len(key)} does not match " f"data value matrix of dimensions {value.shape}" ) - if len(set(value.shape)) != 1: + + shape = set(value.shape) + + if len(shape) != 1: raise ValueError( f"For key {key}: dimensions of value matrix are not identical {value.shape}" ) - if len(set(shapes)) != 1: + shapes.update(shape) + + if len(shapes) != 1: raise ValueError("Dimensions of value matrices in data dictionary are not identical.") def mul(self, other: complex): From 2d32bf8c6f7dcf8847802d535184b47b1571ab2e Mon Sep 17 00:00:00 2001 From: SaashaJoshi Date: Wed, 10 Aug 2022 15:17:53 -0400 Subject: [PATCH 06/23] updating polynomial_tensor and unittest --- .../second_q/operators/polynomial_tensor.py | 41 ++++--- .../operators/test_polynomial_tensor.py | 112 +++++++++--------- 2 files changed, 81 insertions(+), 72 deletions(-) diff --git a/qiskit_nature/second_q/operators/polynomial_tensor.py b/qiskit_nature/second_q/operators/polynomial_tensor.py index 3c7fae1a20..659fde90f9 100644 --- a/qiskit_nature/second_q/operators/polynomial_tensor.py +++ b/qiskit_nature/second_q/operators/polynomial_tensor.py @@ -13,7 +13,7 @@ """Polynomial Tensor class""" from __future__ import annotations -from typing import Dict +from typing import Dict, Mapping from numbers import Number import numpy as np from qiskit.quantum_info.operators.mixins import ( @@ -26,41 +26,45 @@ class PolynomialTensor(LinearMixin, AdjointMixin, TolerancesMixin): """Polynomial Tensor class""" - def __init__(self, data: Dict[str, np.ndarray]): - if not isinstance(data, Dict): - raise TypeError(f"data {data} must be a Dictionary") - - self._data = data + def __init__(self, data: Mapping[str, np.ndarray | Number]): + copy_dict: Dict[str, np.ndarray] = {} shapes = set() - for key, value in self._data.items(): + for key, value in data.items(): + if isinstance(value, Number): + value = np.asarray(value) + if len(value.shape) != len(key): raise ValueError( - f"data key {key} of length {len(key)} does not match " + f"Data key {key} of length {len(key)} does not match " f"data value matrix of dimensions {value.shape}" ) - shape = set(value.shape) + dims = set(value.shape) - if len(shape) != 1: + if len(dims) > 1: raise ValueError( f"For key {key}: dimensions of value matrix are not identical {value.shape}" ) - shapes.update(shape) + shapes.update(dims) + copy_dict[key] = value if len(shapes) != 1: + print(shapes) raise ValueError("Dimensions of value matrices in data dictionary are not identical.") + self._data = copy_dict + def mul(self, other: complex): """Scalar multiplication of PolynomialTensor with complex""" if not isinstance(other, Number): raise TypeError(f"other {other} must be a number") - prod_dict = {} + prod_dict: Dict[str, np.ndarray] = {} for key, matrix in self._data.items(): - prod_dict[key] = matrix * other + prod_dict[key] = np.multiply(matrix, other) return PolynomialTensor(prod_dict) def _multiply(self, other): @@ -72,7 +76,8 @@ def add(self, other: PolynomialTensor): if not isinstance(other, PolynomialTensor): raise TypeError("Incorrect argument type: other should be PolynomialTensor") - sum_dict = self._data.copy() + # Copy values from data to sum dict one by one. + sum_dict: Dict[str, np.ndarray] = self._data.copy() for other_key, other_value in other._data.items(): if other_key in sum_dict.keys(): if other_value.shape == np.shape(sum_dict[other_key]): @@ -96,8 +101,8 @@ def __eq__(self, other): """Check equality of PolynomialTensors""" if self._data.keys() == other._data.keys(): - for key in self._data.keys(): - if np.allclose(self._data[key], other._data[key], atol=self.atol, rtol=self.rtol): + for key, value in self._data.items(): + if np.allclose(value, other._data[key], atol=self.atol, rtol=self.rtol): return isinstance(other, PolynomialTensor) else: return False @@ -107,7 +112,7 @@ def __eq__(self, other): def conjugate(self): """Conjugate of PolynomialTensors""" - conj_dict = {} + conj_dict: Dict[str, np.ndarray] = {} for key, value in self._data.items(): conj_dict[key] = np.conjugate(value) @@ -116,7 +121,7 @@ def conjugate(self): def transpose(self): """Transpose of PolynomialTensor""" - transpose_dict = {} + transpose_dict: Dict[str, np.ndarray] = {} for key, value in self._data.items(): transpose_dict[key] = np.transpose(value) diff --git a/test/second_q/operators/test_polynomial_tensor.py b/test/second_q/operators/test_polynomial_tensor.py index 0fcfcfa820..9de3258101 100644 --- a/test/second_q/operators/test_polynomial_tensor.py +++ b/test/second_q/operators/test_polynomial_tensor.py @@ -12,44 +12,14 @@ """Test for Polynomial Tensor""" +from __future__ import annotations import unittest -from typing import Dict from test import QiskitNatureTestCase -from ddt import ddt, data +from ddt import ddt, idata import numpy as np from qiskit_nature.second_q.operators import PolynomialTensor -def gen_expected_prod_poly(og_poly, dim_size, other): - """Generate expected product Polynomial Tensors""" - - expected_poly = {} - for key, value in og_poly.items(): - num_dim = len(key) - expected_poly[key] = (np.arange(1, dim_size ** num_dim + 1) * other).reshape((dim_size,) * num_dim) - - return expected_poly - -def gen_expected_transpose_poly(og_poly, dim_size): - """Generate expected transpose of Polynomial Tensor""" - - expected_poly = {} - for key, value in og_poly.items(): - num_dim = len(key) - expected_poly[key] = np.arange(1, dim_size ** num_dim + 1).reshape((dim_size,) * num_dim).transpose() - - return expected_poly - -def gen_expected_conjugate_poly(og_poly, dim_size): - """Generate expected transpose of Polynomial Tensor""" - - expected_poly = {} - for key, value in og_poly.items(): - num_dim = len(key) - expected_poly[key] = np.arange(1, dim_size ** num_dim + 1).reshape((dim_size,) * num_dim).conjugate() - - return expected_poly - @ddt class TestPolynomialTensor(QiskitNatureTestCase): """Tests for PolynomialTensor class""" @@ -57,38 +27,74 @@ class TestPolynomialTensor(QiskitNatureTestCase): def setUp(self) -> None: super().setUp() - self.og_poly: Dict[str, np.ndarray] = { - "+-": np.arange(1, 17).reshape(4, 4), - "+++-": np.arange(1, 257).reshape(4, 4, 4, 4), + self.og_poly = { + "": 1.0, + "+": self.build_matrix(4, 1), + "+-": self.build_matrix(4, 2), + "++--": self.build_matrix(4, 4), } - for value in self.og_poly.values(): - self.dim_size = np.shape(value) + self.expected_conjugate_poly = { + "": 1.0, + "+": self.build_matrix(4, 1).conjugate(), + "+-": self.build_matrix(4, 2).conjugate(), + "++--": self.build_matrix(4, 4).conjugate(), + } + + self.expected_transpose_poly = { + "": 1.0, + "+": self.build_matrix(4, 1).transpose(), + "+-": self.build_matrix(4, 2).transpose(), + "++--": self.build_matrix(4, 4).transpose(), + } - self.expected_sum_poly: Dict[str, np.ndarray] = { - "+-": (np.arange(1, 17) * 2).reshape(4, 4), - "+++-": (np.arange(1, 257) * 2).reshape(4, 4, 4, 4), + self.expected_sum_poly = { + "": 2.0, + "+": np.add(self.build_matrix(4, 1), self.build_matrix(4, 1)), + "+-": np.add(self.build_matrix(4, 2), self.build_matrix(4, 2)), + "++--": np.add(self.build_matrix(4, 4), self.build_matrix(4, 4)), } + @staticmethod + def build_matrix(dim_size, num_dim, val=1): + """Build dictionary value matrix""" + + return (np.arange(1, dim_size**num_dim + 1) * val).reshape((dim_size,) * num_dim) - def test_init_dict(self): - """Test for input type in Polynomial Tensor class""" + def test_init_val_dimen(self): + """Test for value dimensions of data input""" - if self.assertRaises(TypeError): - PolynomialTensor(self.og_poly) + self.assertRaisesRegex( + ValueError, r"For key .* dimensions of value matrix are not identical \d+" + ) - def test_init_dimensions(self): - """Test for input matrix dimensions in Polynomial Tensor""" + def test_init_key_len(self): + """Test for key length and value dimensions of data input""" - if self.assertRaisesRegex(ValueError, "Dimensions of value matrices in data dictionary are not identical."): - PolynomialTensor(self.og_poly) + self.assertRaisesRegex( + ValueError, + r"Data key .* of length \d does not match data value matrix of dimensions \((\d+), (\d+)\)", + ) - @data(2, 3, 4) + def test_init_all_val_dimen(self): + """Test for dimesnions of all values of data input""" + + self.assertRaisesRegex( + ValueError, r"Dimensions of value matrices in data dictionary are not identical." + ) + + @idata(np.linspace(2, 3, 5)) def test_mul(self, other): """Test for scalar multiplication""" + expected_prod_poly = { + "": 1.0 * other, + "+": self.build_matrix(4, 1, other), + "+-": self.build_matrix(4, 2, other), + "++--": self.build_matrix(4, 4, other), + } + result = PolynomialTensor(self.og_poly).mul(other) - expected_prod_poly = gen_expected_prod_poly(self.og_poly, self.dim_size[0], other) self.assertEqual(result, PolynomialTensor(expected_prod_poly)) def test_add(self): @@ -101,15 +107,13 @@ def test_conjugate(self): """Test for conjugate of Polynomial Tensor""" result = PolynomialTensor(self.og_poly).conjugate() - expected_conjugate_poly = gen_expected_conjugate_poly(self.og_poly, self.dim_size[0]) - self.assertEqual(result, PolynomialTensor(expected_conjugate_poly)) + self.assertEqual(result, PolynomialTensor(self.expected_conjugate_poly)) def test_transpose(self): """Test for transpose of Polynomial Tensor""" result = PolynomialTensor(self.og_poly).transpose() - expected_transpose_poly = gen_expected_transpose_poly(self.og_poly, self.dim_size[0]) - self.assertEqual(result, PolynomialTensor(expected_transpose_poly)) + self.assertEqual(result, PolynomialTensor(self.expected_transpose_poly)) if __name__ == "__main__": From 0d275e6178263d5d42cdac8120e6016ac2406696 Mon Sep 17 00:00:00 2001 From: SaashaJoshi Date: Thu, 11 Aug 2022 11:58:19 -0400 Subject: [PATCH 07/23] updating polynomial tensor and unittest --- .../second_q/operators/polynomial_tensor.py | 13 ++++----- .../operators/test_polynomial_tensor.py | 29 ++++++++++--------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/qiskit_nature/second_q/operators/polynomial_tensor.py b/qiskit_nature/second_q/operators/polynomial_tensor.py index 659fde90f9..feaf5d6c0f 100644 --- a/qiskit_nature/second_q/operators/polynomial_tensor.py +++ b/qiskit_nature/second_q/operators/polynomial_tensor.py @@ -76,7 +76,6 @@ def add(self, other: PolynomialTensor): if not isinstance(other, PolynomialTensor): raise TypeError("Incorrect argument type: other should be PolynomialTensor") - # Copy values from data to sum dict one by one. sum_dict: Dict[str, np.ndarray] = self._data.copy() for other_key, other_value in other._data.items(): if other_key in sum_dict.keys(): @@ -100,14 +99,12 @@ def _add(self, other, qargs=None): def __eq__(self, other): """Check equality of PolynomialTensors""" - if self._data.keys() == other._data.keys(): - for key, value in self._data.items(): - if np.allclose(value, other._data[key], atol=self.atol, rtol=self.rtol): - return isinstance(other, PolynomialTensor) - else: - return False - else: + if self._data.keys() != other._data.keys(): return False + for key, value in self._data.items(): + if not np.allclose(value, other._data[key], atol=self.atol, rtol=self.rtol): + return False + return True def conjugate(self): """Conjugate of PolynomialTensors""" diff --git a/test/second_q/operators/test_polynomial_tensor.py b/test/second_q/operators/test_polynomial_tensor.py index 9de3258101..b84a08ba43 100644 --- a/test/second_q/operators/test_polynomial_tensor.py +++ b/test/second_q/operators/test_polynomial_tensor.py @@ -61,27 +61,30 @@ def build_matrix(dim_size, num_dim, val=1): return (np.arange(1, dim_size**num_dim + 1) * val).reshape((dim_size,) * num_dim) - def test_init_val_dimen(self): - """Test for value dimensions of data input""" - - self.assertRaisesRegex( - ValueError, r"For key .* dimensions of value matrix are not identical \d+" - ) - def test_init_key_len(self): """Test for key length and value dimensions of data input""" - self.assertRaisesRegex( + with self.assertRaisesRegex( ValueError, - r"Data key .* of length \d does not match data value matrix of dimensions \((\d+), (\d+)\)", - ) + r"Data key (.*?) of length (.*?) does not match data value matrix of dimensions (.*?)", + ): + poly_tensor = PolynomialTensor(self.og_poly) + + def test_init_val_dimen(self): + """Test for value dimensions of data input""" + + with self.assertRaisesRegex( + ValueError, r"For key (.*?) dimensions of value matrix are not identical (.*?)" + ): + poly_tensor = PolynomialTensor(self.og_poly) def test_init_all_val_dimen(self): - """Test for dimesnions of all values of data input""" + """Test for dimensions of all values of data input""" - self.assertRaisesRegex( + with self.assertRaisesRegex( ValueError, r"Dimensions of value matrices in data dictionary are not identical." - ) + ): + poly_tensor = PolynomialTensor(self.og_poly) @idata(np.linspace(2, 3, 5)) def test_mul(self, other): From 5b771b2c9f16cc7df3f9c2d2b4ab2b311f15e686 Mon Sep 17 00:00:00 2001 From: SaashaJoshi Date: Fri, 12 Aug 2022 10:04:06 -0400 Subject: [PATCH 08/23] update unittest --- .../second_q/operators/polynomial_tensor.py | 4 +- .../operators/test_polynomial_tensor.py | 63 +++++++++++++++---- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/qiskit_nature/second_q/operators/polynomial_tensor.py b/qiskit_nature/second_q/operators/polynomial_tensor.py index feaf5d6c0f..074be52f28 100644 --- a/qiskit_nature/second_q/operators/polynomial_tensor.py +++ b/qiskit_nature/second_q/operators/polynomial_tensor.py @@ -51,7 +51,6 @@ def __init__(self, data: Mapping[str, np.ndarray | Number]): copy_dict[key] = value if len(shapes) != 1: - print(shapes) raise ValueError("Dimensions of value matrices in data dictionary are not identical.") self._data = copy_dict @@ -82,9 +81,8 @@ def add(self, other: PolynomialTensor): if other_value.shape == np.shape(sum_dict[other_key]): sum_dict[other_key] = np.add(other_value, sum_dict[other_key]) else: - print("not same shape", other_value.shape, np.shape(sum_dict[other_key])) raise ValueError( - f"For key {other_key} " + f"For key {other_key}: " f"corresponding data value of shape {np.shape(sum_dict[other_key])} " f"does not match other value matrix of shape {other_value.shape}" ) diff --git a/test/second_q/operators/test_polynomial_tensor.py b/test/second_q/operators/test_polynomial_tensor.py index b84a08ba43..dd88a5f41c 100644 --- a/test/second_q/operators/test_polynomial_tensor.py +++ b/test/second_q/operators/test_polynomial_tensor.py @@ -34,6 +34,34 @@ def setUp(self) -> None: "++--": self.build_matrix(4, 4), } + self.sample_poly_1 = { + "": 1.0, + "++": self.build_matrix(4, 1), + "+-": self.build_matrix(4, 2), + "++--": self.build_matrix(4, 4), + } + + self.sample_poly_2 = { + "": 1.0, + "+": self.build_matrix(4, 1), + "+-": self.build_matrix(4, 2), + "++--": np.arange(1, 13).reshape(1, 2, 3, 2), + } + + self.sample_poly_3 = { + "": 1.0, + "+": self.build_matrix(4, 1), + "+-": self.build_matrix(2, 2), + "++--": self.build_matrix(4, 4), + } + + self.sample_poly_4 = { + "": 1.0, + "+": self.build_matrix(2, 1), + "+-": self.build_matrix(2, 2), + "++--": self.build_matrix(2, 4), + } + self.expected_conjugate_poly = { "": 1.0, "+": self.build_matrix(4, 1).conjugate(), @@ -61,30 +89,24 @@ def build_matrix(dim_size, num_dim, val=1): return (np.arange(1, dim_size**num_dim + 1) * val).reshape((dim_size,) * num_dim) - def test_init_key_len(self): - """Test for key length and value dimensions of data input""" + def test_init(self): + """Test for errors in constructor for Polynomial Tensor""" with self.assertRaisesRegex( ValueError, - r"Data key (.*?) of length (.*?) does not match data value matrix of dimensions (.*?)", + r"Data key .* of length \d does not match data value matrix of dimensions \(\d+, *\)", ): - poly_tensor = PolynomialTensor(self.og_poly) - - def test_init_val_dimen(self): - """Test for value dimensions of data input""" + _ = PolynomialTensor(self.sample_poly_1) with self.assertRaisesRegex( - ValueError, r"For key (.*?) dimensions of value matrix are not identical (.*?)" + ValueError, r"For key (.*): dimensions of value matrix are not identical \(\d+, .*\)" ): - poly_tensor = PolynomialTensor(self.og_poly) - - def test_init_all_val_dimen(self): - """Test for dimensions of all values of data input""" + _ = PolynomialTensor(self.sample_poly_2) with self.assertRaisesRegex( ValueError, r"Dimensions of value matrices in data dictionary are not identical." ): - poly_tensor = PolynomialTensor(self.og_poly) + _ = PolynomialTensor(self.sample_poly_3) @idata(np.linspace(2, 3, 5)) def test_mul(self, other): @@ -100,12 +122,27 @@ def test_mul(self, other): result = PolynomialTensor(self.og_poly).mul(other) self.assertEqual(result, PolynomialTensor(expected_prod_poly)) + with self.assertRaisesRegex(TypeError, r"other .* must be a number"): + _ = PolynomialTensor(self.og_poly).mul(PolynomialTensor(self.og_poly)) + def test_add(self): """Test for addition of Polynomial Tensors""" result = PolynomialTensor(self.og_poly).add(PolynomialTensor(self.og_poly)) self.assertEqual(result, PolynomialTensor(self.expected_sum_poly)) + with self.assertRaisesRegex( + TypeError, "Incorrect argument type: other should be PolynomialTensor" + ): + _ = PolynomialTensor(self.og_poly).add(5) + + with self.assertRaisesRegex( + ValueError, + r"For key (.*): corresponding data value of shape \(\d+, *\) " + r"does not match other value matrix of shape \(\d+, *\)", + ): + _ = PolynomialTensor(self.og_poly).add(PolynomialTensor(self.sample_poly_4)) + def test_conjugate(self): """Test for conjugate of Polynomial Tensor""" From 326ac9b46640bd2d24706e660e2c8c6d877b8365 Mon Sep 17 00:00:00 2001 From: SaashaJoshi Date: Tue, 23 Aug 2022 09:38:39 -0700 Subject: [PATCH 09/23] updating polynomial_tensor file --- qiskit_nature/second_q/operators/polynomial_tensor.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/qiskit_nature/second_q/operators/polynomial_tensor.py b/qiskit_nature/second_q/operators/polynomial_tensor.py index 074be52f28..5f61e49dde 100644 --- a/qiskit_nature/second_q/operators/polynomial_tensor.py +++ b/qiskit_nature/second_q/operators/polynomial_tensor.py @@ -97,6 +97,9 @@ def _add(self, other, qargs=None): def __eq__(self, other): """Check equality of PolynomialTensors""" + if not isinstance(other, PolynomialTensor): + raise TypeError("Incorrect argument type: other should be PolynomialTensor") + if self._data.keys() != other._data.keys(): return False for key, value in self._data.items(): From 8bdfefc54fcd22dcdae18de037d253e486c5aae9 Mon Sep 17 00:00:00 2001 From: Saasha Joshi <32019413+SaashaJoshi@users.noreply.github.com> Date: Wed, 31 Aug 2022 22:39:32 -0700 Subject: [PATCH 10/23] Update qiskit_nature/second_q/operators/polynomial_tensor.py Co-authored-by: Max Rossmannek --- qiskit_nature/second_q/operators/polynomial_tensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_nature/second_q/operators/polynomial_tensor.py b/qiskit_nature/second_q/operators/polynomial_tensor.py index 5f61e49dde..40252edeca 100644 --- a/qiskit_nature/second_q/operators/polynomial_tensor.py +++ b/qiskit_nature/second_q/operators/polynomial_tensor.py @@ -116,7 +116,7 @@ def conjugate(self): return PolynomialTensor(conj_dict) - def transpose(self): + def transpose(self) -> PolynomialTensor: """Transpose of PolynomialTensor""" transpose_dict: Dict[str, np.ndarray] = {} From 094c6efaaace546f68f39b7aa5ae15b3b36e3a9b Mon Sep 17 00:00:00 2001 From: Saasha Joshi <32019413+SaashaJoshi@users.noreply.github.com> Date: Wed, 31 Aug 2022 22:39:40 -0700 Subject: [PATCH 11/23] Update qiskit_nature/second_q/operators/polynomial_tensor.py Co-authored-by: Max Rossmannek --- qiskit_nature/second_q/operators/polynomial_tensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_nature/second_q/operators/polynomial_tensor.py b/qiskit_nature/second_q/operators/polynomial_tensor.py index 40252edeca..7ce914bf3b 100644 --- a/qiskit_nature/second_q/operators/polynomial_tensor.py +++ b/qiskit_nature/second_q/operators/polynomial_tensor.py @@ -107,7 +107,7 @@ def __eq__(self, other): return False return True - def conjugate(self): + def conjugate(self) -> PolynomialTensor: """Conjugate of PolynomialTensors""" conj_dict: Dict[str, np.ndarray] = {} From 42732053c3991c6d7b6c9b8255d9cb2e4dc66729 Mon Sep 17 00:00:00 2001 From: Saasha Joshi <32019413+SaashaJoshi@users.noreply.github.com> Date: Wed, 31 Aug 2022 22:39:58 -0700 Subject: [PATCH 12/23] Update qiskit_nature/second_q/operators/polynomial_tensor.py Co-authored-by: Max Rossmannek --- qiskit_nature/second_q/operators/polynomial_tensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_nature/second_q/operators/polynomial_tensor.py b/qiskit_nature/second_q/operators/polynomial_tensor.py index 7ce914bf3b..4d3b611edc 100644 --- a/qiskit_nature/second_q/operators/polynomial_tensor.py +++ b/qiskit_nature/second_q/operators/polynomial_tensor.py @@ -98,7 +98,7 @@ def __eq__(self, other): """Check equality of PolynomialTensors""" if not isinstance(other, PolynomialTensor): - raise TypeError("Incorrect argument type: other should be PolynomialTensor") + return False if self._data.keys() != other._data.keys(): return False From 497ae60578eadc10bdf841a6777a3a3b1302c823 Mon Sep 17 00:00:00 2001 From: Saasha Joshi <32019413+SaashaJoshi@users.noreply.github.com> Date: Wed, 31 Aug 2022 22:40:28 -0700 Subject: [PATCH 13/23] Update qiskit_nature/second_q/operators/polynomial_tensor.py Co-authored-by: Max Rossmannek --- qiskit_nature/second_q/operators/polynomial_tensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_nature/second_q/operators/polynomial_tensor.py b/qiskit_nature/second_q/operators/polynomial_tensor.py index 4d3b611edc..8acbd5ce33 100644 --- a/qiskit_nature/second_q/operators/polynomial_tensor.py +++ b/qiskit_nature/second_q/operators/polynomial_tensor.py @@ -26,7 +26,7 @@ class PolynomialTensor(LinearMixin, AdjointMixin, TolerancesMixin): """Polynomial Tensor class""" - def __init__(self, data: Mapping[str, np.ndarray | Number]): + def __init__(self, data: Mapping[str, np.ndarray | Number]) -> None: copy_dict: Dict[str, np.ndarray] = {} shapes = set() From ab551e99067095466f37f630100ac1a489ec0cdd Mon Sep 17 00:00:00 2001 From: SaashaJoshi Date: Sat, 3 Sep 2022 20:07:53 -0700 Subject: [PATCH 14/23] update polynomial_tensor and test_polynomial_tensor --- .../second_q/operators/polynomial_tensor.py | 72 +++++++++++++++---- .../operators/test_polynomial_tensor.py | 12 ++-- 2 files changed, 64 insertions(+), 20 deletions(-) diff --git a/qiskit_nature/second_q/operators/polynomial_tensor.py b/qiskit_nature/second_q/operators/polynomial_tensor.py index 8acbd5ce33..f909d9f3f6 100644 --- a/qiskit_nature/second_q/operators/polynomial_tensor.py +++ b/qiskit_nature/second_q/operators/polynomial_tensor.py @@ -13,7 +13,8 @@ """Polynomial Tensor class""" from __future__ import annotations -from typing import Dict, Mapping +from typing import Dict, Iterator +from collections.abc import Mapping from numbers import Number import numpy as np from qiskit.quantum_info.operators.mixins import ( @@ -23,10 +24,18 @@ ) -class PolynomialTensor(LinearMixin, AdjointMixin, TolerancesMixin): +class PolynomialTensor(LinearMixin, AdjointMixin, TolerancesMixin, Mapping): """Polynomial Tensor class""" def __init__(self, data: Mapping[str, np.ndarray | Number]) -> None: + """ + Args: + data: coefficient container; mapping of string-based operator keys to coefficient matrix values. + Raises: + ValueError: when length of operator key does not match dimensions of value matrix. + ValueError: when value matrix does not have consistent dimensions. + ValueError: when some or all value matrices in ``data`` have different dimensions. + """ copy_dict: Dict[str, np.ndarray] = {} shapes = set() @@ -55,8 +64,25 @@ def __init__(self, data: Mapping[str, np.ndarray | Number]) -> None: self._data = copy_dict - def mul(self, other: complex): - """Scalar multiplication of PolynomialTensor with complex""" + def __getitem__(self, __k: str) -> (np.ndarray | Number): + return self._data.__getitem__(__k) + + def __len__(self) -> int: + return self._data.__len__() + + def __iter__(self) -> Iterator[str]: + return self._data.__iter__() + + def _multiply(self, other: complex): + """Scalar multiplication of PolynomialTensor with complex + + Args: + other: scalar to be multiplied with the ``Polynomial Tensor`` object. + Returns: + the new ``Polynomial Tensor`` product object. + Raises: + TypeError: if ``other`` is not a ``Number``. + """ if not isinstance(other, Number): raise TypeError(f"other {other} must be a number") @@ -66,11 +92,18 @@ def mul(self, other: complex): prod_dict[key] = np.multiply(matrix, other) return PolynomialTensor(prod_dict) - def _multiply(self, other): - return self.mul(other) + def _add(self, other: PolynomialTensor, qargs=None): + """Addition of PolynomialTensors - def add(self, other: PolynomialTensor): - """Addition of PolynomialTensors""" + Args: + other: second``Polynomial Tensor`` object to be added to the first. + Returns: + the new summed ``Polynomial Tensor`` object. + Raises: + TypeError: when ``other`` is not a ``Polynomial Tensor`` object. + ValueError: when values corresponding to keys in ``other`` and + the first ``Polynomial Tensor`` object do not match. + """ if not isinstance(other, PolynomialTensor): raise TypeError("Incorrect argument type: other should be PolynomialTensor") @@ -91,11 +124,14 @@ def add(self, other: PolynomialTensor): return PolynomialTensor(sum_dict) - def _add(self, other, qargs=None): - return self.add(other) - def __eq__(self, other): - """Check equality of PolynomialTensors""" + """Check equality of PolynomialTensors + + Args: + other: second``Polynomial Tensor`` object to be compared with the first. + Returns: + True when ``Polynomial Tensor`` objects are equal, False when unequal. + """ if not isinstance(other, PolynomialTensor): return False @@ -108,7 +144,11 @@ def __eq__(self, other): return True def conjugate(self) -> PolynomialTensor: - """Conjugate of PolynomialTensors""" + """Conjugate of PolynomialTensors + + Returns: + the complex conjugate of the ``Polynomial Tensor`` object. + """ conj_dict: Dict[str, np.ndarray] = {} for key, value in self._data.items(): @@ -117,7 +157,11 @@ def conjugate(self) -> PolynomialTensor: return PolynomialTensor(conj_dict) def transpose(self) -> PolynomialTensor: - """Transpose of PolynomialTensor""" + """Transpose of PolynomialTensor + + Returns: + the transpose of the ``Polynomial Tensor`` object. + """ transpose_dict: Dict[str, np.ndarray] = {} for key, value in self._data.items(): diff --git a/test/second_q/operators/test_polynomial_tensor.py b/test/second_q/operators/test_polynomial_tensor.py index dd88a5f41c..10a9e134bd 100644 --- a/test/second_q/operators/test_polynomial_tensor.py +++ b/test/second_q/operators/test_polynomial_tensor.py @@ -108,7 +108,7 @@ def test_init(self): ): _ = PolynomialTensor(self.sample_poly_3) - @idata(np.linspace(2, 3, 5)) + @idata(np.linspace(0, 3, 5)) def test_mul(self, other): """Test for scalar multiplication""" @@ -119,29 +119,29 @@ def test_mul(self, other): "++--": self.build_matrix(4, 4, other), } - result = PolynomialTensor(self.og_poly).mul(other) + result = PolynomialTensor(self.og_poly) * other self.assertEqual(result, PolynomialTensor(expected_prod_poly)) with self.assertRaisesRegex(TypeError, r"other .* must be a number"): - _ = PolynomialTensor(self.og_poly).mul(PolynomialTensor(self.og_poly)) + _ = PolynomialTensor(self.og_poly) * PolynomialTensor(self.og_poly) def test_add(self): """Test for addition of Polynomial Tensors""" - result = PolynomialTensor(self.og_poly).add(PolynomialTensor(self.og_poly)) + result = PolynomialTensor(self.og_poly) + PolynomialTensor(self.og_poly) self.assertEqual(result, PolynomialTensor(self.expected_sum_poly)) with self.assertRaisesRegex( TypeError, "Incorrect argument type: other should be PolynomialTensor" ): - _ = PolynomialTensor(self.og_poly).add(5) + _ = PolynomialTensor(self.og_poly) + 5 with self.assertRaisesRegex( ValueError, r"For key (.*): corresponding data value of shape \(\d+, *\) " r"does not match other value matrix of shape \(\d+, *\)", ): - _ = PolynomialTensor(self.og_poly).add(PolynomialTensor(self.sample_poly_4)) + _ = PolynomialTensor(self.og_poly) + PolynomialTensor(self.sample_poly_4) def test_conjugate(self): """Test for conjugate of Polynomial Tensor""" From 5c9d00b5e81e58fb6b1c482283110c89bb718c70 Mon Sep 17 00:00:00 2001 From: SaashaJoshi Date: Tue, 6 Sep 2022 13:48:56 -0700 Subject: [PATCH 15/23] adding register_length to polynomial tensor --- .../second_q/operators/polynomial_tensor.py | 38 ++++++++++++++---- .../operators/test_polynomial_tensor.py | 40 ++++++++++++------- 2 files changed, 57 insertions(+), 21 deletions(-) diff --git a/qiskit_nature/second_q/operators/polynomial_tensor.py b/qiskit_nature/second_q/operators/polynomial_tensor.py index f909d9f3f6..0bc1f68485 100644 --- a/qiskit_nature/second_q/operators/polynomial_tensor.py +++ b/qiskit_nature/second_q/operators/polynomial_tensor.py @@ -27,10 +27,11 @@ class PolynomialTensor(LinearMixin, AdjointMixin, TolerancesMixin, Mapping): """Polynomial Tensor class""" - def __init__(self, data: Mapping[str, np.ndarray | Number]) -> None: + def __init__(self, data: Mapping[str, np.ndarray | Number], register_length: int) -> None: """ Args: - data: coefficient container; mapping of string-based operator keys to coefficient matrix values. + data: coefficient container; + mapping of string-based operator keys to coefficient matrix values. Raises: ValueError: when length of operator key does not match dimensions of value matrix. ValueError: when value matrix does not have consistent dimensions. @@ -63,14 +64,38 @@ def __init__(self, data: Mapping[str, np.ndarray | Number]) -> None: raise ValueError("Dimensions of value matrices in data dictionary are not identical.") self._data = copy_dict + self._register_length = register_length + + @property + def register_length(self) -> int: + """ Returns register length of the operator key in `Polynomial Tensor` object """ + + return self._register_length def __getitem__(self, __k: str) -> (np.ndarray | Number): + """ + Returns value matrix in the `Polynomial Tensor` object. + + Args: + __k: operator key string in the `Polynomial Tensor` object + Returns: + Value matrix corresponding to the operator key `__k` + """ + return self._data.__getitem__(__k) def __len__(self) -> int: + """ + Returns length of `Polynomial Tensor` object + """ + return self._data.__len__() def __iter__(self) -> Iterator[str]: + """ + Returns iterator of the `Polynomial Tensor` object + """ + return self._data.__iter__() def _multiply(self, other: complex): @@ -90,7 +115,7 @@ def _multiply(self, other: complex): prod_dict: Dict[str, np.ndarray] = {} for key, matrix in self._data.items(): prod_dict[key] = np.multiply(matrix, other) - return PolynomialTensor(prod_dict) + return PolynomialTensor(prod_dict, self._register_length) def _add(self, other: PolynomialTensor, qargs=None): """Addition of PolynomialTensors @@ -121,8 +146,7 @@ def _add(self, other: PolynomialTensor, qargs=None): ) else: sum_dict[other_key] = other_value - - return PolynomialTensor(sum_dict) + return PolynomialTensor(sum_dict, self._register_length) def __eq__(self, other): """Check equality of PolynomialTensors @@ -154,7 +178,7 @@ def conjugate(self) -> PolynomialTensor: for key, value in self._data.items(): conj_dict[key] = np.conjugate(value) - return PolynomialTensor(conj_dict) + return PolynomialTensor(conj_dict, self._register_length) def transpose(self) -> PolynomialTensor: """Transpose of PolynomialTensor @@ -167,4 +191,4 @@ def transpose(self) -> PolynomialTensor: for key, value in self._data.items(): transpose_dict[key] = np.transpose(value) - return PolynomialTensor(transpose_dict) + return PolynomialTensor(transpose_dict, self._register_length) diff --git a/test/second_q/operators/test_polynomial_tensor.py b/test/second_q/operators/test_polynomial_tensor.py index 10a9e134bd..440dc3b97c 100644 --- a/test/second_q/operators/test_polynomial_tensor.py +++ b/test/second_q/operators/test_polynomial_tensor.py @@ -96,17 +96,29 @@ def test_init(self): ValueError, r"Data key .* of length \d does not match data value matrix of dimensions \(\d+, *\)", ): - _ = PolynomialTensor(self.sample_poly_1) + _ = PolynomialTensor(self.sample_poly_1, register_length=4) with self.assertRaisesRegex( ValueError, r"For key (.*): dimensions of value matrix are not identical \(\d+, .*\)" ): - _ = PolynomialTensor(self.sample_poly_2) + _ = PolynomialTensor(self.sample_poly_2, register_length=4) with self.assertRaisesRegex( ValueError, r"Dimensions of value matrices in data dictionary are not identical." ): - _ = PolynomialTensor(self.sample_poly_3) + _ = PolynomialTensor(self.sample_poly_3, register_length=4) + + def test_get_item(self): + pass + + def test_len(self): + pass + + def test_iter(self): + pass + + def test_register_length(self): + pass @idata(np.linspace(0, 3, 5)) def test_mul(self, other): @@ -119,41 +131,41 @@ def test_mul(self, other): "++--": self.build_matrix(4, 4, other), } - result = PolynomialTensor(self.og_poly) * other - self.assertEqual(result, PolynomialTensor(expected_prod_poly)) + result = PolynomialTensor(self.og_poly, 4) * other + self.assertEqual(result, PolynomialTensor(expected_prod_poly, 4)) with self.assertRaisesRegex(TypeError, r"other .* must be a number"): - _ = PolynomialTensor(self.og_poly) * PolynomialTensor(self.og_poly) + _ = PolynomialTensor(self.og_poly, 4) * PolynomialTensor(self.og_poly, 4) def test_add(self): """Test for addition of Polynomial Tensors""" - result = PolynomialTensor(self.og_poly) + PolynomialTensor(self.og_poly) - self.assertEqual(result, PolynomialTensor(self.expected_sum_poly)) + result = PolynomialTensor(self.og_poly, 4) + PolynomialTensor(self.og_poly, 4) + self.assertEqual(result, PolynomialTensor(self.expected_sum_poly, 4)) with self.assertRaisesRegex( TypeError, "Incorrect argument type: other should be PolynomialTensor" ): - _ = PolynomialTensor(self.og_poly) + 5 + _ = PolynomialTensor(self.og_poly, 4) + 5 with self.assertRaisesRegex( ValueError, r"For key (.*): corresponding data value of shape \(\d+, *\) " r"does not match other value matrix of shape \(\d+, *\)", ): - _ = PolynomialTensor(self.og_poly) + PolynomialTensor(self.sample_poly_4) + _ = PolynomialTensor(self.og_poly, 4) + PolynomialTensor(self.sample_poly_4, 4) def test_conjugate(self): """Test for conjugate of Polynomial Tensor""" - result = PolynomialTensor(self.og_poly).conjugate() - self.assertEqual(result, PolynomialTensor(self.expected_conjugate_poly)) + result = PolynomialTensor(self.og_poly, 4).conjugate() + self.assertEqual(result, PolynomialTensor(self.expected_conjugate_poly, 4)) def test_transpose(self): """Test for transpose of Polynomial Tensor""" - result = PolynomialTensor(self.og_poly).transpose() - self.assertEqual(result, PolynomialTensor(self.expected_transpose_poly)) + result = PolynomialTensor(self.og_poly, 4).transpose() + self.assertEqual(result, PolynomialTensor(self.expected_transpose_poly, 4)) if __name__ == "__main__": From 0371db1bec7b7bad961ba8cbcd987f755d22c0ce Mon Sep 17 00:00:00 2001 From: Saasha Joshi <32019413+SaashaJoshi@users.noreply.github.com> Date: Wed, 7 Sep 2022 11:33:20 -0700 Subject: [PATCH 16/23] Update qiskit_nature/second_q/operators/polynomial_tensor.py Co-authored-by: Max Rossmannek --- qiskit_nature/second_q/operators/polynomial_tensor.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qiskit_nature/second_q/operators/polynomial_tensor.py b/qiskit_nature/second_q/operators/polynomial_tensor.py index 0bc1f68485..e48cefc829 100644 --- a/qiskit_nature/second_q/operators/polynomial_tensor.py +++ b/qiskit_nature/second_q/operators/polynomial_tensor.py @@ -68,8 +68,7 @@ def __init__(self, data: Mapping[str, np.ndarray | Number], register_length: int @property def register_length(self) -> int: - """ Returns register length of the operator key in `Polynomial Tensor` object """ - + """Returns the register length of the operator stored in this `PolynomialTensor`.""" return self._register_length def __getitem__(self, __k: str) -> (np.ndarray | Number): From 01b8d50b36bb32b0c1e09950a51bced3f9ba7515 Mon Sep 17 00:00:00 2001 From: SaashaJoshi Date: Mon, 12 Sep 2022 14:41:31 -0700 Subject: [PATCH 17/23] changes to polynomial_tensor - adding register_length --- .../second_q/operators/polynomial_tensor.py | 44 ++++++++++--------- .../operators/test_polynomial_tensor.py | 8 ++-- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/qiskit_nature/second_q/operators/polynomial_tensor.py b/qiskit_nature/second_q/operators/polynomial_tensor.py index e48cefc829..72188d3f70 100644 --- a/qiskit_nature/second_q/operators/polynomial_tensor.py +++ b/qiskit_nature/second_q/operators/polynomial_tensor.py @@ -30,8 +30,8 @@ class PolynomialTensor(LinearMixin, AdjointMixin, TolerancesMixin, Mapping): def __init__(self, data: Mapping[str, np.ndarray | Number], register_length: int) -> None: """ Args: - data: coefficient container; - mapping of string-based operator keys to coefficient matrix values. + data: mapping of string-based operator keys to coefficient matrix values. + register_length: dimensions of the value matrices in data mapping. Raises: ValueError: when length of operator key does not match dimensions of value matrix. ValueError: when value matrix does not have consistent dimensions. @@ -56,27 +56,29 @@ def __init__(self, data: Mapping[str, np.ndarray | Number], register_length: int raise ValueError( f"For key {key}: dimensions of value matrix are not identical {value.shape}" ) + elif len(dims) == 1 and list(dims)[0] != register_length: + raise ValueError( + f"Dimensions of value matrices in data dictionary do not match the provided " + f"register length, {register_length}" + ) - shapes.update(dims) copy_dict[key] = value - if len(shapes) != 1: - raise ValueError("Dimensions of value matrices in data dictionary are not identical.") - self._data = copy_dict self._register_length = register_length @property def register_length(self) -> int: - """Returns the register length of the operator stored in this `PolynomialTensor`.""" + """ Returns register length of the operator key in `PolynomialTensor`.""" + return self._register_length def __getitem__(self, __k: str) -> (np.ndarray | Number): """ - Returns value matrix in the `Polynomial Tensor` object. + Returns value matrix in the `PolynomialTensor`. Args: - __k: operator key string in the `Polynomial Tensor` object + __k: operator key string in the `PolynomialTensor`. Returns: Value matrix corresponding to the operator key `__k` """ @@ -85,14 +87,14 @@ def __getitem__(self, __k: str) -> (np.ndarray | Number): def __len__(self) -> int: """ - Returns length of `Polynomial Tensor` object + Returns length of `PolynomialTensor`. """ return self._data.__len__() def __iter__(self) -> Iterator[str]: """ - Returns iterator of the `Polynomial Tensor` object + Returns iterator of the `PolynomialTensor`. """ return self._data.__iter__() @@ -101,9 +103,9 @@ def _multiply(self, other: complex): """Scalar multiplication of PolynomialTensor with complex Args: - other: scalar to be multiplied with the ``Polynomial Tensor`` object. + other: scalar to be multiplied with the ``PolynomialTensor``. Returns: - the new ``Polynomial Tensor`` product object. + the new ``PolynomialTensor`` product object. Raises: TypeError: if ``other`` is not a ``Number``. """ @@ -120,13 +122,13 @@ def _add(self, other: PolynomialTensor, qargs=None): """Addition of PolynomialTensors Args: - other: second``Polynomial Tensor`` object to be added to the first. + other: second``PolynomialTensor`` object to be added to the first. Returns: - the new summed ``Polynomial Tensor`` object. + the new summed ``PolynomialTensor``. Raises: - TypeError: when ``other`` is not a ``Polynomial Tensor`` object. + TypeError: when ``other`` is not a ``PolynomialTensor``. ValueError: when values corresponding to keys in ``other`` and - the first ``Polynomial Tensor`` object do not match. + the first ``PolynomialTensor`` object do not match. """ if not isinstance(other, PolynomialTensor): @@ -151,9 +153,9 @@ def __eq__(self, other): """Check equality of PolynomialTensors Args: - other: second``Polynomial Tensor`` object to be compared with the first. + other: second``PolynomialTensor`` object to be compared with the first. Returns: - True when ``Polynomial Tensor`` objects are equal, False when unequal. + True when ``PolynomialTensor`` objects are equal, False when unequal. """ if not isinstance(other, PolynomialTensor): @@ -170,7 +172,7 @@ def conjugate(self) -> PolynomialTensor: """Conjugate of PolynomialTensors Returns: - the complex conjugate of the ``Polynomial Tensor`` object. + the complex conjugate of the ``PolynomialTensor``. """ conj_dict: Dict[str, np.ndarray] = {} @@ -183,7 +185,7 @@ def transpose(self) -> PolynomialTensor: """Transpose of PolynomialTensor Returns: - the transpose of the ``Polynomial Tensor`` object. + the transpose of the ``PolynomialTensor``. """ transpose_dict: Dict[str, np.ndarray] = {} diff --git a/test/second_q/operators/test_polynomial_tensor.py b/test/second_q/operators/test_polynomial_tensor.py index 440dc3b97c..6f42108a24 100644 --- a/test/second_q/operators/test_polynomial_tensor.py +++ b/test/second_q/operators/test_polynomial_tensor.py @@ -99,12 +99,14 @@ def test_init(self): _ = PolynomialTensor(self.sample_poly_1, register_length=4) with self.assertRaisesRegex( - ValueError, r"For key (.*): dimensions of value matrix are not identical \(\d+, .*\)" + ValueError, + r"For key (.*): dimensions of value matrix are not identical \(\d+, .*\)" ): _ = PolynomialTensor(self.sample_poly_2, register_length=4) with self.assertRaisesRegex( - ValueError, r"Dimensions of value matrices in data dictionary are not identical." + ValueError, + r"Dimensions of value matrices in data dictionary do not match the provided register length, \d" ): _ = PolynomialTensor(self.sample_poly_3, register_length=4) @@ -153,7 +155,7 @@ def test_add(self): r"For key (.*): corresponding data value of shape \(\d+, *\) " r"does not match other value matrix of shape \(\d+, *\)", ): - _ = PolynomialTensor(self.og_poly, 4) + PolynomialTensor(self.sample_poly_4, 4) + _ = PolynomialTensor(self.og_poly, 4) + PolynomialTensor(self.sample_poly_4, 2) def test_conjugate(self): """Test for conjugate of Polynomial Tensor""" From 468a1c3ee20268ebb7637e345db5194279fc6231 Mon Sep 17 00:00:00 2001 From: SaashaJoshi Date: Mon, 12 Sep 2022 22:32:40 -0700 Subject: [PATCH 18/23] adding equiv method to polynomial_tensor. adding unittests for dunders --- .../second_q/operators/polynomial_tensor.py | 35 ++++++++++++---- .../operators/test_polynomial_tensor.py | 40 +++++++++++++------ 2 files changed, 55 insertions(+), 20 deletions(-) diff --git a/qiskit_nature/second_q/operators/polynomial_tensor.py b/qiskit_nature/second_q/operators/polynomial_tensor.py index 72188d3f70..680216c149 100644 --- a/qiskit_nature/second_q/operators/polynomial_tensor.py +++ b/qiskit_nature/second_q/operators/polynomial_tensor.py @@ -10,7 +10,7 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -"""Polynomial Tensor class""" +"""PolynomialTensor class""" from __future__ import annotations from typing import Dict, Iterator @@ -25,7 +25,7 @@ class PolynomialTensor(LinearMixin, AdjointMixin, TolerancesMixin, Mapping): - """Polynomial Tensor class""" + """PolynomialTensor class""" def __init__(self, data: Mapping[str, np.ndarray | Number], register_length: int) -> None: """ @@ -39,7 +39,6 @@ def __init__(self, data: Mapping[str, np.ndarray | Number], register_length: int """ copy_dict: Dict[str, np.ndarray] = {} - shapes = set() for key, value in data.items(): if isinstance(value, Number): value = np.asarray(value) @@ -56,7 +55,7 @@ def __init__(self, data: Mapping[str, np.ndarray | Number], register_length: int raise ValueError( f"For key {key}: dimensions of value matrix are not identical {value.shape}" ) - elif len(dims) == 1 and list(dims)[0] != register_length: + if len(dims) == 1 and list(dims)[0] != register_length: raise ValueError( f"Dimensions of value matrices in data dictionary do not match the provided " f"register length, {register_length}" @@ -69,7 +68,7 @@ def __init__(self, data: Mapping[str, np.ndarray | Number], register_length: int @property def register_length(self) -> int: - """ Returns register length of the operator key in `PolynomialTensor`.""" + """Returns register length of the operator key in `PolynomialTensor`.""" return self._register_length @@ -149,8 +148,8 @@ def _add(self, other: PolynomialTensor, qargs=None): sum_dict[other_key] = other_value return PolynomialTensor(sum_dict, self._register_length) - def __eq__(self, other): - """Check equality of PolynomialTensors + def __eq__(self, other: object) -> bool: + """Check equality of first PolynomialTensor with other Args: other: second``PolynomialTensor`` object to be compared with the first. @@ -161,8 +160,30 @@ def __eq__(self, other): if not isinstance(other, PolynomialTensor): return False + if self._register_length == other._register_length: + return True + + if self._data.keys() == other._data.keys() and self._data.values() == other._data.values(): + return True + + def equiv(self, other: object) -> bool: + """Check equivalence of first PolynomialTensor with other + + Args: + other: second``PolynomialTensor`` object to be compared with the first. + Returns: + True when ``PolynomialTensor`` objects are equivalent, False when not. + """ + + if not isinstance(other, PolynomialTensor): + return False + + if self._register_length != other._register_length: + return False + if self._data.keys() != other._data.keys(): return False + for key, value in self._data.items(): if not np.allclose(value, other._data[key], atol=self.atol, rtol=self.rtol): return False diff --git a/test/second_q/operators/test_polynomial_tensor.py b/test/second_q/operators/test_polynomial_tensor.py index 6f42108a24..3ca821650d 100644 --- a/test/second_q/operators/test_polynomial_tensor.py +++ b/test/second_q/operators/test_polynomial_tensor.py @@ -10,7 +10,7 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -"""Test for Polynomial Tensor""" +"""Test for PolynomialTensor class""" from __future__ import annotations import unittest @@ -62,6 +62,12 @@ def setUp(self) -> None: "++--": self.build_matrix(2, 4), } + self.sample_poly_5 = { + "": 1.0, + "+": self.build_matrix(2, 1), + "+-": self.build_matrix(2, 2), + } + self.expected_conjugate_poly = { "": 1.0, "+": self.build_matrix(4, 1).conjugate(), @@ -90,7 +96,7 @@ def build_matrix(dim_size, num_dim, val=1): return (np.arange(1, dim_size**num_dim + 1) * val).reshape((dim_size,) * num_dim) def test_init(self): - """Test for errors in constructor for Polynomial Tensor""" + """Test for errors in constructor for PolynomialTensor""" with self.assertRaisesRegex( ValueError, @@ -99,28 +105,36 @@ def test_init(self): _ = PolynomialTensor(self.sample_poly_1, register_length=4) with self.assertRaisesRegex( - ValueError, - r"For key (.*): dimensions of value matrix are not identical \(\d+, .*\)" + ValueError, r"For key (.*): dimensions of value matrix are not identical \(\d+, .*\)" ): _ = PolynomialTensor(self.sample_poly_2, register_length=4) with self.assertRaisesRegex( ValueError, - r"Dimensions of value matrices in data dictionary do not match the provided register length, \d" + r"Dimensions of value matrices in data dictionary " + r"do not match the provided register length, \d", ): _ = PolynomialTensor(self.sample_poly_3, register_length=4) def test_get_item(self): - pass + """Test for getting value matrices corresponding to keys in PolynomialTensor""" + + og_poly_tensor = PolynomialTensor(self.og_poly, 4) + self.assertEqual(self.og_poly["+"].all(), og_poly_tensor["+"].all()) def test_len(self): - pass + """Test for the length of PolynomialTensor""" + + length = len(PolynomialTensor(self.sample_poly_4, 2)) + exp_len = 4 + self.assertEqual(exp_len, length) def test_iter(self): - pass + """Test for the iterator of PolynomialTensor""" - def test_register_length(self): - pass + og_poly_tensor = PolynomialTensor(self.og_poly, 4) + exp_iter = [key for key, _ in self.og_poly.items()] + self.assertEqual(exp_iter, list(iter(og_poly_tensor))) @idata(np.linspace(0, 3, 5)) def test_mul(self, other): @@ -140,7 +154,7 @@ def test_mul(self, other): _ = PolynomialTensor(self.og_poly, 4) * PolynomialTensor(self.og_poly, 4) def test_add(self): - """Test for addition of Polynomial Tensors""" + """Test for addition of PolynomialTensor""" result = PolynomialTensor(self.og_poly, 4) + PolynomialTensor(self.og_poly, 4) self.assertEqual(result, PolynomialTensor(self.expected_sum_poly, 4)) @@ -158,13 +172,13 @@ def test_add(self): _ = PolynomialTensor(self.og_poly, 4) + PolynomialTensor(self.sample_poly_4, 2) def test_conjugate(self): - """Test for conjugate of Polynomial Tensor""" + """Test for conjugate of PolynomialTensor""" result = PolynomialTensor(self.og_poly, 4).conjugate() self.assertEqual(result, PolynomialTensor(self.expected_conjugate_poly, 4)) def test_transpose(self): - """Test for transpose of Polynomial Tensor""" + """Test for transpose of PolynomialTensor""" result = PolynomialTensor(self.og_poly, 4).transpose() self.assertEqual(result, PolynomialTensor(self.expected_transpose_poly, 4)) From 5ab41ee42b5bbf780f727d5bdf1ab03e6cff0f8d Mon Sep 17 00:00:00 2001 From: SaashaJoshi Date: Mon, 12 Sep 2022 22:38:14 -0700 Subject: [PATCH 19/23] lint and mypy update --- qiskit_nature/second_q/operators/polynomial_tensor.py | 1 + 1 file changed, 1 insertion(+) diff --git a/qiskit_nature/second_q/operators/polynomial_tensor.py b/qiskit_nature/second_q/operators/polynomial_tensor.py index 680216c149..745a1be2ee 100644 --- a/qiskit_nature/second_q/operators/polynomial_tensor.py +++ b/qiskit_nature/second_q/operators/polynomial_tensor.py @@ -165,6 +165,7 @@ def __eq__(self, other: object) -> bool: if self._data.keys() == other._data.keys() and self._data.values() == other._data.values(): return True + return False def equiv(self, other: object) -> bool: """Check equivalence of first PolynomialTensor with other From 807eb1a401a2e7476fa548536eb315dcf197c56c Mon Sep 17 00:00:00 2001 From: Saasha Joshi <32019413+SaashaJoshi@users.noreply.github.com> Date: Tue, 13 Sep 2022 11:33:08 -0700 Subject: [PATCH 20/23] Update qiskit_nature/second_q/operators/polynomial_tensor.py Co-authored-by: Max Rossmannek --- qiskit_nature/second_q/operators/polynomial_tensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_nature/second_q/operators/polynomial_tensor.py b/qiskit_nature/second_q/operators/polynomial_tensor.py index 745a1be2ee..d631b9cdeb 100644 --- a/qiskit_nature/second_q/operators/polynomial_tensor.py +++ b/qiskit_nature/second_q/operators/polynomial_tensor.py @@ -55,7 +55,7 @@ def __init__(self, data: Mapping[str, np.ndarray | Number], register_length: int raise ValueError( f"For key {key}: dimensions of value matrix are not identical {value.shape}" ) - if len(dims) == 1 and list(dims)[0] != register_length: + if len(dims) == 1 and dims.pop() != register_length: raise ValueError( f"Dimensions of value matrices in data dictionary do not match the provided " f"register length, {register_length}" From db03648ee2f34795b58eeffa5d08fa4f45a2e50c Mon Sep 17 00:00:00 2001 From: SaashaJoshi Date: Tue, 13 Sep 2022 12:51:21 -0700 Subject: [PATCH 21/23] updating polynomial_tensor --- .pylintdict | 1 + .../second_q/operators/polynomial_tensor.py | 28 ++++++++----------- .../operators/test_polynomial_tensor.py | 12 ++------ 3 files changed, 14 insertions(+), 27 deletions(-) diff --git a/.pylintdict b/.pylintdict index 72b7ab6fde..978c65f70d 100644 --- a/.pylintdict +++ b/.pylintdict @@ -381,6 +381,7 @@ physrevd physik plesset pmatrix +polynomialtensor polypeptides popovas pos diff --git a/qiskit_nature/second_q/operators/polynomial_tensor.py b/qiskit_nature/second_q/operators/polynomial_tensor.py index d631b9cdeb..b1f4d8c5a8 100644 --- a/qiskit_nature/second_q/operators/polynomial_tensor.py +++ b/qiskit_nature/second_q/operators/polynomial_tensor.py @@ -69,7 +69,6 @@ def __init__(self, data: Mapping[str, np.ndarray | Number], register_length: int @property def register_length(self) -> int: """Returns register length of the operator key in `PolynomialTensor`.""" - return self._register_length def __getitem__(self, __k: str) -> (np.ndarray | Number): @@ -81,24 +80,21 @@ def __getitem__(self, __k: str) -> (np.ndarray | Number): Returns: Value matrix corresponding to the operator key `__k` """ - return self._data.__getitem__(__k) def __len__(self) -> int: """ Returns length of `PolynomialTensor`. """ - return self._data.__len__() def __iter__(self) -> Iterator[str]: """ Returns iterator of the `PolynomialTensor`. """ - return self._data.__iter__() - def _multiply(self, other: complex): + def _multiply(self, other: complex) -> PolynomialTensor: """Scalar multiplication of PolynomialTensor with complex Args: @@ -108,7 +104,6 @@ def _multiply(self, other: complex): Raises: TypeError: if ``other`` is not a ``Number``. """ - if not isinstance(other, Number): raise TypeError(f"other {other} must be a number") @@ -117,7 +112,7 @@ def _multiply(self, other: complex): prod_dict[key] = np.multiply(matrix, other) return PolynomialTensor(prod_dict, self._register_length) - def _add(self, other: PolynomialTensor, qargs=None): + def _add(self, other: PolynomialTensor, qargs=None) -> PolynomialTensor: """Addition of PolynomialTensors Args: @@ -129,7 +124,6 @@ def _add(self, other: PolynomialTensor, qargs=None): ValueError: when values corresponding to keys in ``other`` and the first ``PolynomialTensor`` object do not match. """ - if not isinstance(other, PolynomialTensor): raise TypeError("Incorrect argument type: other should be PolynomialTensor") @@ -156,16 +150,19 @@ def __eq__(self, other: object) -> bool: Returns: True when ``PolynomialTensor`` objects are equal, False when unequal. """ - if not isinstance(other, PolynomialTensor): return False - if self._register_length == other._register_length: - return True + if self._register_length != other._register_length: + return False + + if self._data.keys() != other._data.keys(): + return False - if self._data.keys() == other._data.keys() and self._data.values() == other._data.values(): - return True - return False + for key, value in self._data.items(): + if not np.array_equal(value, other._data[key]): + return False + return True def equiv(self, other: object) -> bool: """Check equivalence of first PolynomialTensor with other @@ -175,7 +172,6 @@ def equiv(self, other: object) -> bool: Returns: True when ``PolynomialTensor`` objects are equivalent, False when not. """ - if not isinstance(other, PolynomialTensor): return False @@ -196,7 +192,6 @@ def conjugate(self) -> PolynomialTensor: Returns: the complex conjugate of the ``PolynomialTensor``. """ - conj_dict: Dict[str, np.ndarray] = {} for key, value in self._data.items(): conj_dict[key] = np.conjugate(value) @@ -209,7 +204,6 @@ def transpose(self) -> PolynomialTensor: Returns: the transpose of the ``PolynomialTensor``. """ - transpose_dict: Dict[str, np.ndarray] = {} for key, value in self._data.items(): transpose_dict[key] = np.transpose(value) diff --git a/test/second_q/operators/test_polynomial_tensor.py b/test/second_q/operators/test_polynomial_tensor.py index 3ca821650d..275a2684a6 100644 --- a/test/second_q/operators/test_polynomial_tensor.py +++ b/test/second_q/operators/test_polynomial_tensor.py @@ -92,12 +92,10 @@ def setUp(self) -> None: @staticmethod def build_matrix(dim_size, num_dim, val=1): """Build dictionary value matrix""" - return (np.arange(1, dim_size**num_dim + 1) * val).reshape((dim_size,) * num_dim) def test_init(self): """Test for errors in constructor for PolynomialTensor""" - with self.assertRaisesRegex( ValueError, r"Data key .* of length \d does not match data value matrix of dimensions \(\d+, *\)", @@ -118,20 +116,18 @@ def test_init(self): def test_get_item(self): """Test for getting value matrices corresponding to keys in PolynomialTensor""" - og_poly_tensor = PolynomialTensor(self.og_poly, 4) - self.assertEqual(self.og_poly["+"].all(), og_poly_tensor["+"].all()) + for key, value in self.og_poly.items(): + np.testing.assert_array_equal(value, og_poly_tensor[key]) def test_len(self): """Test for the length of PolynomialTensor""" - length = len(PolynomialTensor(self.sample_poly_4, 2)) exp_len = 4 self.assertEqual(exp_len, length) def test_iter(self): """Test for the iterator of PolynomialTensor""" - og_poly_tensor = PolynomialTensor(self.og_poly, 4) exp_iter = [key for key, _ in self.og_poly.items()] self.assertEqual(exp_iter, list(iter(og_poly_tensor))) @@ -139,7 +135,6 @@ def test_iter(self): @idata(np.linspace(0, 3, 5)) def test_mul(self, other): """Test for scalar multiplication""" - expected_prod_poly = { "": 1.0 * other, "+": self.build_matrix(4, 1, other), @@ -155,7 +150,6 @@ def test_mul(self, other): def test_add(self): """Test for addition of PolynomialTensor""" - result = PolynomialTensor(self.og_poly, 4) + PolynomialTensor(self.og_poly, 4) self.assertEqual(result, PolynomialTensor(self.expected_sum_poly, 4)) @@ -173,13 +167,11 @@ def test_add(self): def test_conjugate(self): """Test for conjugate of PolynomialTensor""" - result = PolynomialTensor(self.og_poly, 4).conjugate() self.assertEqual(result, PolynomialTensor(self.expected_conjugate_poly, 4)) def test_transpose(self): """Test for transpose of PolynomialTensor""" - result = PolynomialTensor(self.og_poly, 4).transpose() self.assertEqual(result, PolynomialTensor(self.expected_transpose_poly, 4)) From 7619b159002ec6a79eaad98ed9d84ad377945d9f Mon Sep 17 00:00:00 2001 From: Saasha Joshi <32019413+SaashaJoshi@users.noreply.github.com> Date: Tue, 13 Sep 2022 12:54:57 -0700 Subject: [PATCH 22/23] Update qiskit_nature/second_q/operators/polynomial_tensor.py Co-authored-by: Max Rossmannek --- .../second_q/operators/polynomial_tensor.py | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/qiskit_nature/second_q/operators/polynomial_tensor.py b/qiskit_nature/second_q/operators/polynomial_tensor.py index b1f4d8c5a8..4ade0a39da 100644 --- a/qiskit_nature/second_q/operators/polynomial_tensor.py +++ b/qiskit_nature/second_q/operators/polynomial_tensor.py @@ -127,19 +127,15 @@ def _add(self, other: PolynomialTensor, qargs=None) -> PolynomialTensor: if not isinstance(other, PolynomialTensor): raise TypeError("Incorrect argument type: other should be PolynomialTensor") - sum_dict: Dict[str, np.ndarray] = self._data.copy() - for other_key, other_value in other._data.items(): - if other_key in sum_dict.keys(): - if other_value.shape == np.shape(sum_dict[other_key]): - sum_dict[other_key] = np.add(other_value, sum_dict[other_key]) - else: - raise ValueError( - f"For key {other_key}: " - f"corresponding data value of shape {np.shape(sum_dict[other_key])} " - f"does not match other value matrix of shape {other_value.shape}" - ) - else: - sum_dict[other_key] = other_value + if self.register_length != other.register_length: + raise ValueError( + "The dimensions of the PolynomialTensors which are to be added together, do not " + f"match: {self.register_length} != {other.register_length}" + ) + + sum_dict = {key: np.value + other._data.get(key, 0) for key, value in self._data.items()} + other_unique = {key: other._data[key] for key in other._data.keys() - self._data.keys()} + sum_dict.update(other_unique) return PolynomialTensor(sum_dict, self._register_length) def __eq__(self, other: object) -> bool: From 8344b6054f5897a5714baec6fe6d8db4b816db5e Mon Sep 17 00:00:00 2001 From: SaashaJoshi Date: Tue, 13 Sep 2022 13:06:38 -0700 Subject: [PATCH 23/23] update polynomial_tensor --- qiskit_nature/second_q/operators/polynomial_tensor.py | 7 ++++--- test/second_q/operators/test_polynomial_tensor.py | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/qiskit_nature/second_q/operators/polynomial_tensor.py b/qiskit_nature/second_q/operators/polynomial_tensor.py index 4ade0a39da..f04a2fa1de 100644 --- a/qiskit_nature/second_q/operators/polynomial_tensor.py +++ b/qiskit_nature/second_q/operators/polynomial_tensor.py @@ -127,15 +127,16 @@ def _add(self, other: PolynomialTensor, qargs=None) -> PolynomialTensor: if not isinstance(other, PolynomialTensor): raise TypeError("Incorrect argument type: other should be PolynomialTensor") - if self.register_length != other.register_length: + if self._register_length != other._register_length: raise ValueError( "The dimensions of the PolynomialTensors which are to be added together, do not " - f"match: {self.register_length} != {other.register_length}" + f"match: {self._register_length} != {other._register_length}" ) - sum_dict = {key: np.value + other._data.get(key, 0) for key, value in self._data.items()} + sum_dict = {key: value + other._data.get(key, 0) for key, value in self._data.items()} other_unique = {key: other._data[key] for key in other._data.keys() - self._data.keys()} sum_dict.update(other_unique) + return PolynomialTensor(sum_dict, self._register_length) def __eq__(self, other: object) -> bool: diff --git a/test/second_q/operators/test_polynomial_tensor.py b/test/second_q/operators/test_polynomial_tensor.py index 275a2684a6..3ac3ba99ea 100644 --- a/test/second_q/operators/test_polynomial_tensor.py +++ b/test/second_q/operators/test_polynomial_tensor.py @@ -160,8 +160,8 @@ def test_add(self): with self.assertRaisesRegex( ValueError, - r"For key (.*): corresponding data value of shape \(\d+, *\) " - r"does not match other value matrix of shape \(\d+, *\)", + r"The dimensions of the PolynomialTensors which are to be added together, do not " + r"match: \d+ != \d+", ): _ = PolynomialTensor(self.og_poly, 4) + PolynomialTensor(self.sample_poly_4, 2)