This is an automated email from the ASF dual-hosted git repository.
hcr pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/mahout.git
The following commit(s) were added to refs/heads/main by this push:
new 6eb7063b6 Fix Cirq backend circuit mutation when adding measurements
(#1072)
6eb7063b6 is described below
commit 6eb7063b65074618efbbaf602c411b4732640fe3
Author: Shivam Mittal <[email protected]>
AuthorDate: Sat Feb 21 17:55:49 2026 +0530
Fix Cirq backend circuit mutation when adding measurements (#1072)
* Fix Cirq backend circuit mutation when adding measurements
* reformated
* test added for it
* test precommt issue fixed
---
qumat/cirq_backend.py | 15 +++++---
testing/qumat/test_create_circuit.py | 69 ++++++++++++++++++++++++++++++++++++
2 files changed, 80 insertions(+), 4 deletions(-)
diff --git a/qumat/cirq_backend.py b/qumat/cirq_backend.py
index 3c2a3e3fb..bb89a4bcc 100644
--- a/qumat/cirq_backend.py
+++ b/qumat/cirq_backend.py
@@ -14,6 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+import copy
import cirq
import sympy
@@ -106,23 +107,29 @@ def execute_circuit(circuit, backend, backend_config):
shots = backend_config["backend_options"].get("shots", 1)
return [{0: shots}]
+ # Create a working copy to avoid mutating the original circuit
+ working_circuit = copy.deepcopy(circuit)
+
# Ensure measurement is added to capture the results
- if not circuit.has_measurements():
- circuit.append(cirq.measure(*circuit.all_qubits(), key="result"))
+ if not working_circuit.has_measurements():
+ working_circuit.append(
+ cirq.measure(*working_circuit.all_qubits(), key="result")
+ )
simulator = cirq.Simulator()
parameter_values = backend_config.get("parameter_values", None)
if parameter_values:
# Convert parameter_values to applicable resolvers
res = [cirq.ParamResolver(parameter_values)]
results = simulator.run_sweep(
- circuit,
+ working_circuit,
repetitions=backend_config["backend_options"].get("shots", 1),
params=res,
)
return [result.histogram(key="result") for result in results]
else:
result = simulator.run(
- circuit,
repetitions=backend_config["backend_options"].get("shots", 1)
+ working_circuit,
+ repetitions=backend_config["backend_options"].get("shots", 1),
)
return [result.histogram(key="result")]
diff --git a/testing/qumat/test_create_circuit.py
b/testing/qumat/test_create_circuit.py
index 869f5bcab..dc48c20c7 100644
--- a/testing/qumat/test_create_circuit.py
+++ b/testing/qumat/test_create_circuit.py
@@ -103,6 +103,75 @@ class TestDefaultShotsParameter:
assert result is not None
[email protected]("backend_name", TESTING_BACKENDS)
+class TestCircuitMutationPrevention:
+ """Test that circuits are not mutated during execution."""
+
+ def test_execute_circuit_multiple_times_no_mutation(self, backend_name):
+ """Test that executing a circuit multiple times doesn't mutate it"""
+ backend_config = get_backend_config(backend_name)
+ qumat = QuMat(backend_config)
+ qumat.create_empty_circuit(num_qubits=2)
+ qumat.apply_hadamard_gate(0)
+ qumat.apply_cnot_gate(0, 1)
+
+ assert qumat.circuit is not None
+ circuit = qumat.circuit
+
+ # Record initial circuit state
+ if backend_name == "cirq":
+ initial_length = len(circuit)
+ initial_has_measurements = circuit.has_measurements()
+ elif backend_name == "qiskit":
+ initial_length = len(circuit.data)
+ else:
+ initial_length = len(circuit.instructions)
+
+ # Execute circuit multiple times
+ result1 = qumat.execute_circuit()
+ result2 = qumat.execute_circuit()
+ result3 = qumat.execute_circuit()
+
+ # Verify circuit hasn't been mutated
+ assert qumat.circuit is not None
+ circuit_after = qumat.circuit
+ if backend_name == "cirq":
+ final_length = len(circuit_after)
+ final_has_measurements = circuit_after.has_measurements()
+ assert initial_length == final_length, (
+ f"Circuit length changed from {initial_length} to
{final_length}. "
+ "Circuit was mutated!"
+ )
+ assert initial_has_measurements == final_has_measurements, (
+ "Circuit measurement state changed. Circuit was mutated!"
+ )
+ elif backend_name == "qiskit":
+ final_length = len(circuit_after.data)
+ assert initial_length == final_length, (
+ f"Circuit length changed from {initial_length} to
{final_length}. "
+ "Circuit was mutated!"
+ )
+ else:
+ final_length = len(circuit_after.instructions)
+ assert initial_length == final_length, (
+ f"Circuit length changed from {initial_length} to
{final_length}. "
+ "Circuit was mutated!"
+ )
+
+ # Verify results are consistent (all should have same structure)
+ if isinstance(result1, list):
+ result1 = result1[0]
+ if isinstance(result2, list):
+ result2 = result2[0]
+ if isinstance(result3, list):
+ result3 = result3[0]
+
+ # All results should have the same keys (measurement states)
+ assert set(result1.keys()) == set(result2.keys()) ==
set(result3.keys()), (
+ "Results have different states after multiple executions"
+ )
+
+
class TestBackendConfigValidation:
"""Test class for backend configuration validation."""