From 1a49ff0831e31b56bd95bd496aba8afcc95f7c7c Mon Sep 17 00:00:00 2001 From: mhucka Date: Tue, 28 Apr 2026 02:44:46 +0000 Subject: [PATCH 1/4] Fix 2 problems in `_multitensor.py` The `dual_basis` parameter to the `MultiTensor` class constructor was defaulted to `DualBasis()`. In Python, default arguments are evaluated only once at definition time, meaning every `MultiTensor` instance created without an explicit basis shared the same global `DualBasis` object. When tests were run in parallel or repeated, data from one test would leak into others, leading to errors. In addition, `MultiTensor.add_dual_elements` used `list.extend()` instead of `list.append()` when adding `DualBasisElement` objects. Since `DualBasisElement` is iterable (yielding its internal terms), using `extend()` incorrectly decomposed the object into its constituent tuples instead of adding the object as a single unit. This caused `MultiTensor.synthesize_dual_basis()` to fail in some cases. --- src/openfermion/contrib/representability/_multitensor.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/openfermion/contrib/representability/_multitensor.py b/src/openfermion/contrib/representability/_multitensor.py index e63b0805b..bf56353e7 100644 --- a/src/openfermion/contrib/representability/_multitensor.py +++ b/src/openfermion/contrib/representability/_multitensor.py @@ -23,7 +23,7 @@ def __iter__(self): class MultiTensor(object): - def __init__(self, tensors, dual_basis=DualBasis()): + def __init__(self, tensors, dual_basis=None): """ A collection of tensor objects with maps from name to tensor @@ -46,6 +46,8 @@ def __init__(self, tensors, dual_basis=DualBasis()): self.off_set_map = self.make_offset_dict(self.tensors) # An iterable object that provides access to the dual basis elements + if dual_basis is None: + dual_basis = DualBasis() self.dual_basis = dual_basis self.vec_dim = sum([vec.size for vec in self.tensors]) @@ -82,7 +84,7 @@ def add_dual_elements(self, dual_element): raise TypeError("dual_element variable needs to be a DualBasisElement type") # we should extend TMap to add - self.dual_basis.elements.extend(dual_element) + self.dual_basis.elements.append(dual_element) def synthesize_dual_basis(self): """ From 5627b53407615ded35c2384fe06a1386be5f5641 Mon Sep 17 00:00:00 2001 From: mhucka Date: Tue, 28 Apr 2026 02:47:59 +0000 Subject: [PATCH 2/4] Add unit tests for `Multitensor` dual basis arg --- .../representability/_multitensor_test.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/openfermion/contrib/representability/_multitensor_test.py b/src/openfermion/contrib/representability/_multitensor_test.py index 620fa07e3..40fb398c1 100644 --- a/src/openfermion/contrib/representability/_multitensor_test.py +++ b/src/openfermion/contrib/representability/_multitensor_test.py @@ -94,6 +94,33 @@ def test_add_dualelement(): mt.add_dual_elements(dbe) assert len(mt.dual_basis) == 1 + dbe2 = DualBasisElement() + dbe2.add_element('b', (0, 1, 2), 5) + mt.add_dual_elements(dbe2) + assert len(mt.dual_basis) == 2 + + A, bias, scalar = mt.synthesize_dual_basis() + assert A.shape[0] == 2 + # Verify that the elements are correctly added as DualBasisElements + # and not as their internal tuples (which would cause synthesis to fail). + assert isinstance(mt.dual_basis[0], DualBasisElement) + assert isinstance(mt.dual_basis[1], DualBasisElement) + + +def test_multitensor_init_isolation(): + # Test that different MultiTensor instances don't share the same dual_basis. + a = np.random.random((2, 2)) + at = Tensor(tensor=a, name='a') + mt1 = MultiTensor([at]) + mt2 = MultiTensor([at]) + + dbe = DualBasisElement() + dbe.add_element('a', (0, 0), 1.0) + mt1.add_dual_elements(dbe) + + assert len(mt1.dual_basis) == 1 + assert len(mt2.dual_basis) == 0 + def test_synthesis_element(): a = np.random.random((5, 5)) From c187cab9928d5dd8def97b9a41a2b5a9ab7e9345 Mon Sep 17 00:00:00 2001 From: mhucka Date: Tue, 28 Apr 2026 03:09:44 +0000 Subject: [PATCH 3/4] Fix typo --- src/openfermion/contrib/representability/_multitensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openfermion/contrib/representability/_multitensor.py b/src/openfermion/contrib/representability/_multitensor.py index bf56353e7..8f7c61d8b 100644 --- a/src/openfermion/contrib/representability/_multitensor.py +++ b/src/openfermion/contrib/representability/_multitensor.py @@ -95,7 +95,7 @@ def synthesize_dual_basis(self): :returns: sparse matrix """ - # go throught the dual basis list and synthesize each element + # go through the dual basis list and synthesize each element dual_row_indices = [] dual_col_indices = [] dual_data_values = [] From 8665b930e49668c9dbec5f9426eed86f7a06c85e Mon Sep 17 00:00:00 2001 From: mhucka Date: Tue, 28 Apr 2026 23:18:57 +0000 Subject: [PATCH 4/4] Remove no-longer-accurate comment --- src/openfermion/contrib/representability/_multitensor.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/openfermion/contrib/representability/_multitensor.py b/src/openfermion/contrib/representability/_multitensor.py index 8f7c61d8b..53f77e13d 100644 --- a/src/openfermion/contrib/representability/_multitensor.py +++ b/src/openfermion/contrib/representability/_multitensor.py @@ -83,7 +83,6 @@ def add_dual_elements(self, dual_element): if not isinstance(dual_element, DualBasisElement): raise TypeError("dual_element variable needs to be a DualBasisElement type") - # we should extend TMap to add self.dual_basis.elements.append(dual_element) def synthesize_dual_basis(self):