Skip to content

Commit

Permalink
Fix: Ensure adding programs doesn't mutate the first
Browse files Browse the repository at this point in the history
Closes #1476

As noted in #1476, adding programs (like `p1 + p2`) currently mutates
the first program (i.e. `p1` would change). This PR ensures that
calibrations et. al. are copied rather than just assigned, and adds a
new test case to `unit/test_program.py` to ensure against regression:

```shell
$ poetry run pytest test/unit/test_program.py --verbose
==================================== test session starts =====================================
platform darwin -- Python 3.9.13, pytest-6.2.4, py-1.10.0, pluggy-0.13.1 -- /Users/genos/rc/repos/pyquil/.venv/bin/python
cachedir: .pytest_cache
rootdir: /Users/genos/rc/repos/pyquil
plugins: cov-2.12.1, freezegun-0.4.2, rerunfailures-9.1.1, xdist-2.3.0, mock-3.6.1, timeout-1.4.2, forked-1.3.0
collected 5 items

test/unit/test_program.py::test_measure_qubits PASSED                                  [ 20%]
test/unit/test_program.py::test_parameterized_single_qubit_measurement_basis PASSED    [ 40%]
test/unit/test_program.py::test_parameterized_single_qubit_state_preparation PASSED    [ 60%]
test/unit/test_program.py::test_parameterized_readout_symmetrization PASSED            [ 80%]
test/unit/test_program.py::test_adding_does_not_mutate PASSED                          [100%]
```
  • Loading branch information
Graham Enos committed Sep 20, 2022
1 parent 57f0501 commit ea258fe
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 3 deletions.
6 changes: 3 additions & 3 deletions pyquil/quil.py
Original file line number Diff line number Diff line change
Expand Up @@ -874,9 +874,9 @@ def __add__(self, other: InstructionDesignator) -> "Program":
p = Program()
p.inst(self)
p.inst(other)
p._calibrations = self.calibrations
p._waveforms = self.waveforms
p._frames = self.frames
p._calibrations = self.calibrations.copy()
p._waveforms = self.waveforms.copy()
p._frames = self.frames.copy()
p._memory = self._memory.copy()
if isinstance(other, Program):
p.calibrations.extend(other.calibrations)
Expand Down
28 changes: 28 additions & 0 deletions test/unit/test_program.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,31 @@ def test_parameterized_readout_symmetrization():
p += RX(symmetrization[0], 0)
p += RX(symmetrization[1], 1)
assert parameterized_readout_symmetrization([0, 1]).out() == p.out()


def test_adding_does_not_mutate():
# https://github.com/rigetti/pyquil/issues/1476
p1 = Program(
"""
DEFCAL RX(pi/2) 32:
FENCE 32
NONBLOCKING PULSE 32 "rf" drag_gaussian(duration: 3.2e-08, fwhm: 8e-09, t0: 1.6e-08, anh: -190000000.0, alpha: -1.8848698349348032, scale: 0.30631340170943533, phase: 0.0, detuning: 1622438.2425563578)
FENCE 32
RX(pi/2) 32
"""
)
original_p1 = p1.copy()
p2 = Program(
"""
DEFCAL RX(pi/2) 33:
FENCE 33
NONBLOCKING PULSE 33 "rf" drag_gaussian(duration: 2e-08, fwhm: 5e-09, t0: 1e-08, anh: -190000000.0, alpha: -0.9473497322033984, scale: 0.25680107985232403, phase: 0.0, detuning: 1322130.5458282642)
FENCE 33
RX(pi/2) 33
"""
)
p_all = p1 + p2
assert p1 == original_p1
assert p1.calibrations != p_all.calibrations
Empty file modified test/unit/test_quil.py
100755 → 100644
Empty file.

0 comments on commit ea258fe

Please sign in to comment.