From 95327909366d8a4350125c29c608114226926440 Mon Sep 17 00:00:00 2001 From: Aaryan Mehta <73230976+blazingphoenix7@users.noreply.github.com> Date: Sun, 12 Jul 2026 18:04:19 -0400 Subject: [PATCH 1/2] Avoid deepcopy in SymbolicOperator arithmetic __add__, __sub__, __mul__ and accumulate copied the operand with copy.deepcopy before mutating it in place. Term keys are tuples of tuples and coefficients are numbers or sympy expressions, all immutable, so copying the terms dictionary is enough to keep the result independent of the operand. Add a small _clone helper that does this and use it in place of deepcopy. --- .../ops/operators/symbolic_operator.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/openfermion/ops/operators/symbolic_operator.py b/src/openfermion/ops/operators/symbolic_operator.py index 595f773bf..e304e9266 100644 --- a/src/openfermion/ops/operators/symbolic_operator.py +++ b/src/openfermion/ops/operators/symbolic_operator.py @@ -12,7 +12,6 @@ """SymbolicOperator is the base class for FermionOperator and QubitOperator""" import abc -import copy import itertools import re import warnings @@ -354,6 +353,16 @@ def __str__(self): def __repr__(self): return str(self) + def _clone(self): + """Returns a copy of self. + + Term keys and coefficients are immutable, so copying the terms + dictionary yields a result independent of self without a deep copy. + """ + cloned = self.__class__() + cloned.terms = dict(self.terms) + return cloned + def __imul__(self, multiplier): """In-place multiply (*=) with scalar or operator of the same type. @@ -415,7 +424,7 @@ def __mul__(self, multiplier): TypeError: Invalid type cannot be multiply with SymbolicOperator. """ if isinstance(multiplier, COEFFICIENT_TYPES + (type(self),)): - product = copy.deepcopy(self) + product = self._clone() product *= multiplier return product else: @@ -454,7 +463,7 @@ def __add__(self, addend): Returns: sum (SymbolicOperator) """ - summand = copy.deepcopy(self) + summand = self._clone() summand += addend return summand @@ -500,7 +509,7 @@ def __sub__(self, subtrahend): Returns: difference (SymbolicOperator) """ - minuend = copy.deepcopy(self) + minuend = self._clone() minuend -= subtrahend return minuend @@ -753,7 +762,7 @@ def many_body_order(self): @classmethod def accumulate(cls, operators, start=None): """Sums over SymbolicOperators.""" - total = copy.deepcopy(start or cls.zero()) + total = (start or cls.zero())._clone() for operator in operators: total += operator return total From f2120de201a319eb8b8fee8a96a4e065789fee7d Mon Sep 17 00:00:00 2001 From: Aaryan Mehta <73230976+blazingphoenix7@users.noreply.github.com> Date: Tue, 14 Jul 2026 19:26:07 -0400 Subject: [PATCH 2/2] Use explicit None check in accumulate --- src/openfermion/ops/operators/symbolic_operator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openfermion/ops/operators/symbolic_operator.py b/src/openfermion/ops/operators/symbolic_operator.py index e304e9266..613930160 100644 --- a/src/openfermion/ops/operators/symbolic_operator.py +++ b/src/openfermion/ops/operators/symbolic_operator.py @@ -762,7 +762,7 @@ def many_body_order(self): @classmethod def accumulate(cls, operators, start=None): """Sums over SymbolicOperators.""" - total = (start or cls.zero())._clone() + total = start._clone() if start is not None else cls.zero() for operator in operators: total += operator return total