From 7080d257b7d302df5da1ae6855bbe0e9c834d79f Mon Sep 17 00:00:00 2001 From: Theodor Isacsson Date: Wed, 9 Mar 2022 15:40:00 -0500 Subject: [PATCH 1/8] use deep copy instead of shallow copy --- .github/CHANGELOG.md | 4 ++++ strawberryfields/program.py | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 890279201..e0ace1a7c 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -44,6 +44,10 @@ instead of `phi = np.pi / 2`) for the phase shift of the beamsplitters. [(#674)](https://github.com/XanaduAI/strawberryfields/pull/674) +* `Program.compile()` returns a deep copy of the program, instead of a shallow copy, while still keeping + the same register references. + [(#675)](https://github.com/XanaduAI/strawberryfields/pull/675) +

Documentation

Contributors

diff --git a/strawberryfields/program.py b/strawberryfields/program.py index 21e21e5a3..e8777d7c1 100644 --- a/strawberryfields/program.py +++ b/strawberryfields/program.py @@ -546,7 +546,9 @@ def _linked_copy(self): Program: a copy of the Program """ self.lock() - p = copy.copy(self) # shares RegRefs with the source + p = copy.deepcopy(self) + p.reg_refs = self.reg_refs # shares RegRefs with the source + # link to the original source Program if self.source is None: p.source = self From 78fb248cfe5aeafcf43c736d61f1741a2679d5cb Mon Sep 17 00:00:00 2001 From: Theodor Isacsson Date: Wed, 9 Mar 2022 15:50:29 -0500 Subject: [PATCH 2/8] rename test --- tests/frontend/test_program.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/frontend/test_program.py b/tests/frontend/test_program.py index 4667fc4d3..c331b06c7 100644 --- a/tests/frontend/test_program.py +++ b/tests/frontend/test_program.py @@ -227,7 +227,7 @@ def test_eq_symmetric_bsgate(self, compare_params): assert prog_2.equivalence(prog_1, compare_params=compare_params) @pytest.mark.parametrize("compare_params", [True, False]) - def test_neq_operator_equivalent(self, compare_params): + def test_equivalence_different_circuits(self, compare_params): """Programs with differnet, but equivalent, circuits.""" prog_1 = sf.Program(3) prog_2 = sf.Program(3) From 8f2907347c86eea73b1249afdb43fc0026afd1ae Mon Sep 17 00:00:00 2001 From: Theodor Isacsson Date: Wed, 9 Mar 2022 16:15:50 -0500 Subject: [PATCH 3/8] add tests --- tests/frontend/test_program.py | 17 +++++++++++++++++ tests/frontend/test_tdmprogram.py | 26 ++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/tests/frontend/test_program.py b/tests/frontend/test_program.py index c331b06c7..7e96b34eb 100644 --- a/tests/frontend/test_program.py +++ b/tests/frontend/test_program.py @@ -534,6 +534,23 @@ def test_has_feed_forward(self): assert prog_2.has_feed_forward is False assert prog_2.has_post_selection is False + def test_linked_copy(self, prog): + """Check that the ``_linked_copy`` method copies a program correctly.""" + + with prog.context as q: + ops.Fock(2) | q[0] + ops.BSgate() | (q[0], q[1]) + ops.MeasureFock() | q[1] + + prog_copy = prog._linked_copy() + for i, regref in prog_copy.reg_refs.items(): + assert regref is prog.reg_refs[i] + + for i, cmd in enumerate(prog_copy.circuit): + assert cmd is not prog.circuit[i] + + assert prog_copy.source is prog + class TestRegRefs: """Testing register references.""" diff --git a/tests/frontend/test_tdmprogram.py b/tests/frontend/test_tdmprogram.py index cf9d16f49..c4814c728 100644 --- a/tests/frontend/test_tdmprogram.py +++ b/tests/frontend/test_tdmprogram.py @@ -505,6 +505,32 @@ def singleloop_program(r, alpha, phi, theta): device = Device(device_spec) +def test_linked_copy(): + """Check that the ``_linked_copy`` method copies a TDM program correctly.""" + sq_r = 0.5643 + c = 2 + alpha = [np.pi / 4, 0] * c + phi = [0, np.pi / 2] * c + theta = [0, 0, np.pi / 2, np.pi / 2] + prog = singleloop_program(sq_r, alpha, phi, theta) + + prog_copy = prog._linked_copy() + assert prog_copy.circuit + assert prog.circuit + + for i, regref in prog_copy.reg_refs.items(): + assert regref is prog.reg_refs[i] + + for i, cmd in enumerate(prog_copy.circuit): + assert cmd is not prog.circuit[i] + + # tdm_params should be equal, but not the same + assert prog_copy.tdm_params is not prog.tdm_params + assert prog_copy.tdm_params == prog.tdm_params + + assert prog_copy.source is prog + + class TestTDMcompiler: """Test class for checking error messages from the compiler""" From 7b80047e86e09836f6994d708284081fc4d2512c Mon Sep 17 00:00:00 2001 From: Theodor Isacsson Date: Wed, 9 Mar 2022 20:38:56 -0500 Subject: [PATCH 4/8] fix program copying --- strawberryfields/program.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/strawberryfields/program.py b/strawberryfields/program.py index e8777d7c1..d270843b7 100644 --- a/strawberryfields/program.py +++ b/strawberryfields/program.py @@ -546,8 +546,14 @@ def _linked_copy(self): Program: a copy of the Program """ self.lock() - p = copy.deepcopy(self) - p.reg_refs = self.reg_refs # shares RegRefs with the source + p = copy.copy(self) + + for name, val in self.__dict__.items(): + # Deep-copy all attributes except 'circuit' and 'reg_refs', since the programs + # should share the same register references. Program.circuit potentially + # contains FreeParameters/MeasuredParameters, which contain RegRefs. + if name not in ("circuit", "reg_refs", "init_reg_refs"): + setattr(name, val, copy.deepcopy(val)) # link to the original source Program if self.source is None: From d3f2526d28af3e9502237ed6758c6e5d6c6b6d1c Mon Sep 17 00:00:00 2001 From: Theodor Isacsson Date: Wed, 9 Mar 2022 20:40:28 -0500 Subject: [PATCH 5/8] fix mistake --- strawberryfields/program.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strawberryfields/program.py b/strawberryfields/program.py index d270843b7..3e0c05cab 100644 --- a/strawberryfields/program.py +++ b/strawberryfields/program.py @@ -553,7 +553,7 @@ def _linked_copy(self): # should share the same register references. Program.circuit potentially # contains FreeParameters/MeasuredParameters, which contain RegRefs. if name not in ("circuit", "reg_refs", "init_reg_refs"): - setattr(name, val, copy.deepcopy(val)) + setattr(p, name, copy.deepcopy(val)) # link to the original source Program if self.source is None: From e15059646e63f667b1c3662056402b1cef5c8da2 Mon Sep 17 00:00:00 2001 From: Theodor Isacsson Date: Wed, 9 Mar 2022 23:38:14 -0500 Subject: [PATCH 6/8] fix tests (again) --- tests/frontend/test_program.py | 4 +++- tests/frontend/test_tdmprogram.py | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/frontend/test_program.py b/tests/frontend/test_program.py index 7e96b34eb..096f9d88d 100644 --- a/tests/frontend/test_program.py +++ b/tests/frontend/test_program.py @@ -543,11 +543,13 @@ def test_linked_copy(self, prog): ops.MeasureFock() | q[1] prog_copy = prog._linked_copy() + + # registers should be the same for i, regref in prog_copy.reg_refs.items(): assert regref is prog.reg_refs[i] for i, cmd in enumerate(prog_copy.circuit): - assert cmd is not prog.circuit[i] + assert cmd is prog.circuit[i] assert prog_copy.source is prog diff --git a/tests/frontend/test_tdmprogram.py b/tests/frontend/test_tdmprogram.py index c4814c728..e550531d9 100644 --- a/tests/frontend/test_tdmprogram.py +++ b/tests/frontend/test_tdmprogram.py @@ -518,11 +518,12 @@ def test_linked_copy(): assert prog_copy.circuit assert prog.circuit + # registers should be the same for i, regref in prog_copy.reg_refs.items(): assert regref is prog.reg_refs[i] for i, cmd in enumerate(prog_copy.circuit): - assert cmd is not prog.circuit[i] + assert cmd is prog.circuit[i] # tdm_params should be equal, but not the same assert prog_copy.tdm_params is not prog.tdm_params From ade5319b68184bc5c75a3c63795bb5f0352b598e Mon Sep 17 00:00:00 2001 From: Theodor Isacsson Date: Wed, 9 Mar 2022 23:57:33 -0500 Subject: [PATCH 7/8] update changelog --- .github/CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index e0ace1a7c..60ed3db8a 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -44,9 +44,9 @@ instead of `phi = np.pi / 2`) for the phase shift of the beamsplitters. [(#674)](https://github.com/XanaduAI/strawberryfields/pull/674) -* `Program.compile()` returns a deep copy of the program, instead of a shallow copy, while still keeping - the same register references. - [(#675)](https://github.com/XanaduAI/strawberryfields/pull/675) +* `Program.compile()` returns a deep copy of the program attributes, except for the circuit and + the register references. + [(#688)](https://github.com/XanaduAI/strawberryfields/pull/688)

Documentation

From 33fa11d8d4d582eb325364c902f8526c6c7c05d4 Mon Sep 17 00:00:00 2001 From: Theodor Date: Thu, 10 Mar 2022 16:24:27 -0500 Subject: [PATCH 8/8] Update tests/frontend/test_program.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Duque Mesa <675763+sduquemesa@users.noreply.github.com> --- tests/frontend/test_program.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/frontend/test_program.py b/tests/frontend/test_program.py index 096f9d88d..db966d0c9 100644 --- a/tests/frontend/test_program.py +++ b/tests/frontend/test_program.py @@ -228,7 +228,7 @@ def test_eq_symmetric_bsgate(self, compare_params): @pytest.mark.parametrize("compare_params", [True, False]) def test_equivalence_different_circuits(self, compare_params): - """Programs with differnet, but equivalent, circuits.""" + """Programs with different, but equivalent, circuits.""" prog_1 = sf.Program(3) prog_2 = sf.Program(3)