From fb4bb485fc1c6f19ac539e0a1b6a7e0f4463f206 Mon Sep 17 00:00:00 2001 From: Josh Izaac Date: Wed, 21 Apr 2021 15:11:51 +0800 Subject: [PATCH 01/17] fix inversion of templates --- pennylane/tape/tape.py | 17 +++++++++++++++++ pennylane/templates/embeddings/angle.py | 3 +++ pennylane/templates/embeddings/displacement.py | 3 +++ pennylane/templates/embeddings/iqp.py | 3 +++ pennylane/templates/embeddings/qaoa.py | 3 +++ pennylane/templates/embeddings/squeezing.py | 3 +++ pennylane/templates/layers/basic_entangler.py | 3 +++ pennylane/templates/layers/cv_neural_net.py | 3 +++ .../templates/layers/particle_conserving_u1.py | 4 ++++ .../templates/layers/particle_conserving_u2.py | 4 ++++ pennylane/templates/layers/random.py | 4 ++++ .../templates/layers/simplified_two_design.py | 3 +++ .../templates/layers/strongly_entangling.py | 3 +++ .../arbitrary_state_preparation.py | 3 +++ .../templates/state_preparations/mottonen.py | 3 +++ .../subroutines/approx_time_evolution.py | 3 +++ .../templates/subroutines/arbitrary_unitary.py | 3 +++ .../subroutines/double_excitation_unitary.py | 3 +++ pennylane/templates/subroutines/permute.py | 4 ++++ pennylane/templates/subroutines/qmc.py | 3 +++ pennylane/templates/subroutines/qpe.py | 3 +++ .../subroutines/single_excitation_unitary.py | 3 +++ pennylane/templates/subroutines/uccsd.py | 3 +++ pennylane/transforms/adjoint.py | 7 ++++--- 24 files changed, 91 insertions(+), 3 deletions(-) diff --git a/pennylane/tape/tape.py b/pennylane/tape/tape.py index 3c1585c00c9..9351044c015 100644 --- a/pennylane/tape/tape.py +++ b/pennylane/tape/tape.py @@ -653,6 +653,23 @@ def inv(self): self._ops = list(reversed(self._ops)) + def adjoint(self): + new_tape = self.copy(copy_operations=True) + new_tape.inv() + + # the current implementation of the adjoint + # method requires that the returned inverted object + # is automatically queued. + QuantumTape._lock.acquire() + try: + QueuingContext.append(new_tape) + except Exception as _: + QuantumTape._lock.release() + raise + QuantumTape._lock.release() + + return new_tape + # ======================================================== # Parameter handling # ======================================================== diff --git a/pennylane/templates/embeddings/angle.py b/pennylane/templates/embeddings/angle.py index 7d03f52ce76..73d7d7bbfb5 100644 --- a/pennylane/templates/embeddings/angle.py +++ b/pennylane/templates/embeddings/angle.py @@ -77,4 +77,7 @@ def expand(self): for i in range(len(self.wires)): self.rotation(features[i], wires=self.wires[i]) + if self.inverse: + tape.inv() + return tape diff --git a/pennylane/templates/embeddings/displacement.py b/pennylane/templates/embeddings/displacement.py index 981699bea12..8963335edba 100644 --- a/pennylane/templates/embeddings/displacement.py +++ b/pennylane/templates/embeddings/displacement.py @@ -82,4 +82,7 @@ def expand(self): for i in range(len(self.wires)): qml.Displacement(pars[i, 0], pars[i, 1], wires=self.wires[i : i + 1]) + if self.inverse: + tape.inv() + return tape diff --git a/pennylane/templates/embeddings/iqp.py b/pennylane/templates/embeddings/iqp.py index 5e7e59039d1..8ae625383c3 100644 --- a/pennylane/templates/embeddings/iqp.py +++ b/pennylane/templates/embeddings/iqp.py @@ -205,4 +205,7 @@ def expand(self): # apply product of two features as entangler qml.MultiRZ(features[idx1] * features[idx2], wires=wire_pair) + if self.inverse: + tape.inv() + return tape diff --git a/pennylane/templates/embeddings/qaoa.py b/pennylane/templates/embeddings/qaoa.py index 37631986449..4236db420e3 100644 --- a/pennylane/templates/embeddings/qaoa.py +++ b/pennylane/templates/embeddings/qaoa.py @@ -234,6 +234,9 @@ def expand(self): # repeat the feature encoding once more at the end qaoa_feature_encoding_hamiltonian(features, self.wires) + if self.inverse: + tape.inv() + return tape @staticmethod diff --git a/pennylane/templates/embeddings/squeezing.py b/pennylane/templates/embeddings/squeezing.py index 6fdd3c49a1d..ad5c442a5b3 100644 --- a/pennylane/templates/embeddings/squeezing.py +++ b/pennylane/templates/embeddings/squeezing.py @@ -83,4 +83,7 @@ def expand(self): for i in range(len(self.wires)): qml.Squeezing(pars[i, 0], pars[i, 1], wires=self.wires[i : i + 1]) + if self.inverse: + tape.inv() + return tape diff --git a/pennylane/templates/layers/basic_entangler.py b/pennylane/templates/layers/basic_entangler.py index 78e55d8c6bb..bb423a8e736 100644 --- a/pennylane/templates/layers/basic_entangler.py +++ b/pennylane/templates/layers/basic_entangler.py @@ -161,6 +161,9 @@ def expand(self): w = self.wires.subset([i, i + 1], periodic_boundary=True) qml.CNOT(wires=w) + if self.inverse: + tape.inv() + return tape @staticmethod diff --git a/pennylane/templates/layers/cv_neural_net.py b/pennylane/templates/layers/cv_neural_net.py index c17404da2d2..3b0f9b79974 100644 --- a/pennylane/templates/layers/cv_neural_net.py +++ b/pennylane/templates/layers/cv_neural_net.py @@ -170,6 +170,9 @@ def expand(self): for i in range(len(self.wires)): qml.Kerr(self.parameters[10][l, i], wires=self.wires[i]) + if self.inverse: + tape.inv() + return tape @staticmethod diff --git a/pennylane/templates/layers/particle_conserving_u1.py b/pennylane/templates/layers/particle_conserving_u1.py index 03008d6be01..c0718d1e1cf 100644 --- a/pennylane/templates/layers/particle_conserving_u1.py +++ b/pennylane/templates/layers/particle_conserving_u1.py @@ -273,6 +273,10 @@ def expand(self): u1_ex_gate( self.parameters[0][l, i, 0], self.parameters[0][l, i, 1], wires=wires_ ) + + if self.inverse: + tape.inv() + return tape @staticmethod diff --git a/pennylane/templates/layers/particle_conserving_u2.py b/pennylane/templates/layers/particle_conserving_u2.py index 940e0c32089..f2eddf5ca33 100644 --- a/pennylane/templates/layers/particle_conserving_u2.py +++ b/pennylane/templates/layers/particle_conserving_u2.py @@ -192,6 +192,10 @@ def expand(self): for i, wires_ in enumerate(nm_wires): u2_ex_gate(self.parameters[0][l, len(self.wires) + i], wires=wires_) + + if self.inverse: + tape.inv() + return tape @staticmethod diff --git a/pennylane/templates/layers/random.py b/pennylane/templates/layers/random.py index 5a700260bd2..9bbfce7edc2 100644 --- a/pennylane/templates/layers/random.py +++ b/pennylane/templates/layers/random.py @@ -228,6 +228,10 @@ def expand(self): if len(self.wires) > 1: rnd_wires = self.wires.select_random(2) self.imprimitive(wires=rnd_wires) + + if self.inverse: + tape.inv() + return tape @staticmethod diff --git a/pennylane/templates/layers/simplified_two_design.py b/pennylane/templates/layers/simplified_two_design.py index cddb6facd3c..943ec32f467 100644 --- a/pennylane/templates/layers/simplified_two_design.py +++ b/pennylane/templates/layers/simplified_two_design.py @@ -155,6 +155,9 @@ def expand(self): self.parameters[1][layer, len(self.wires) // 2 + i, 1], wires=wire_pair[1] ) + if self.inverse: + tape.inv() + return tape @staticmethod diff --git a/pennylane/templates/layers/strongly_entangling.py b/pennylane/templates/layers/strongly_entangling.py index 98a1aa66249..4b81ae48c9e 100644 --- a/pennylane/templates/layers/strongly_entangling.py +++ b/pennylane/templates/layers/strongly_entangling.py @@ -116,6 +116,9 @@ def expand(self): act_on = self.wires.subset([i, i + self.ranges[l]], periodic_boundary=True) self.imprimitive(wires=act_on) + if self.inverse: + tape.inv() + return tape @staticmethod diff --git a/pennylane/templates/state_preparations/arbitrary_state_preparation.py b/pennylane/templates/state_preparations/arbitrary_state_preparation.py index aa23dc3b2ba..8f3f4a8cc94 100644 --- a/pennylane/templates/state_preparations/arbitrary_state_preparation.py +++ b/pennylane/templates/state_preparations/arbitrary_state_preparation.py @@ -99,6 +99,9 @@ def expand(self): for i, pauli_word in enumerate(_state_preparation_pauli_words(len(self.wires))): qml.PauliRot(self.parameters[0][i], pauli_word, wires=self.wires) + if self.inverse: + tape.inv() + return tape @staticmethod diff --git a/pennylane/templates/state_preparations/mottonen.py b/pennylane/templates/state_preparations/mottonen.py index 860eeb80f50..cd4d080dd8c 100644 --- a/pennylane/templates/state_preparations/mottonen.py +++ b/pennylane/templates/state_preparations/mottonen.py @@ -291,4 +291,7 @@ def expand(self): if len(alpha_z_k) > 0: _uniform_rotation_dagger(qml.RZ, alpha_z_k, control, target) + if self.inverse: + tape.inv() + return tape diff --git a/pennylane/templates/subroutines/approx_time_evolution.py b/pennylane/templates/subroutines/approx_time_evolution.py index 0bc5e2e8daa..6aa70e7f11e 100644 --- a/pennylane/templates/subroutines/approx_time_evolution.py +++ b/pennylane/templates/subroutines/approx_time_evolution.py @@ -156,4 +156,7 @@ def expand(self): for j, term in enumerate(pauli_words): PauliRot(theta[j], term, wires=wires[j]) + if self.inverse: + tape.inv() + return tape diff --git a/pennylane/templates/subroutines/arbitrary_unitary.py b/pennylane/templates/subroutines/arbitrary_unitary.py index 835ae34701f..96539f0e9e2 100644 --- a/pennylane/templates/subroutines/arbitrary_unitary.py +++ b/pennylane/templates/subroutines/arbitrary_unitary.py @@ -115,6 +115,9 @@ def expand(self): for i, pauli_word in enumerate(_all_pauli_words_but_identity(len(self.wires))): PauliRot(weights[i], pauli_word, wires=self.wires) + if self.inverse: + tape.inv() + return tape @staticmethod diff --git a/pennylane/templates/subroutines/double_excitation_unitary.py b/pennylane/templates/subroutines/double_excitation_unitary.py index a35fe29a25c..0fc04cfe82e 100644 --- a/pennylane/templates/subroutines/double_excitation_unitary.py +++ b/pennylane/templates/subroutines/double_excitation_unitary.py @@ -525,4 +525,7 @@ def expand(self): _layer7(weight, s, r, q, p, set_cnot_wires) _layer8(weight, s, r, q, p, set_cnot_wires) + if self.inverse: + tape.inv() + return tape diff --git a/pennylane/templates/subroutines/permute.py b/pennylane/templates/subroutines/permute.py index 1666c022871..eabd6180785 100644 --- a/pennylane/templates/subroutines/permute.py +++ b/pennylane/templates/subroutines/permute.py @@ -186,4 +186,8 @@ def expand(self): working_order[idx_there], working_order[idx_here], ) + + if self.inverse: + tape.inv() + return tape diff --git a/pennylane/templates/subroutines/qmc.py b/pennylane/templates/subroutines/qmc.py index b1e246b8f1d..abdfa348061 100644 --- a/pennylane/templates/subroutines/qmc.py +++ b/pennylane/templates/subroutines/qmc.py @@ -367,4 +367,7 @@ def expand(self): Q, target_wires=self.target_wires, estimation_wires=self.estimation_wires ) + if self.inverse: + tape.inv() + return tape diff --git a/pennylane/templates/subroutines/qpe.py b/pennylane/templates/subroutines/qpe.py index 0391e15139d..a37a02c0ed4 100644 --- a/pennylane/templates/subroutines/qpe.py +++ b/pennylane/templates/subroutines/qpe.py @@ -137,4 +137,7 @@ def expand(self): QFT(wires=self.estimation_wires).inv() + if self.inverse: + tape.inv() + return tape diff --git a/pennylane/templates/subroutines/single_excitation_unitary.py b/pennylane/templates/subroutines/single_excitation_unitary.py index f02e2c8a7e5..69aa37f589f 100644 --- a/pennylane/templates/subroutines/single_excitation_unitary.py +++ b/pennylane/templates/subroutines/single_excitation_unitary.py @@ -183,4 +183,7 @@ def expand(self): Hadamard(wires=r) RX(np.pi / 2, wires=p) + if self.inverse: + tape.inv() + return tape diff --git a/pennylane/templates/subroutines/uccsd.py b/pennylane/templates/subroutines/uccsd.py index e21bc13cc82..a4851b812c1 100644 --- a/pennylane/templates/subroutines/uccsd.py +++ b/pennylane/templates/subroutines/uccsd.py @@ -196,4 +196,7 @@ def expand(self): for j, s_wires_ in enumerate(self.s_wires): qml.templates.SingleExcitationUnitary(weights[j], wires=s_wires_) + if self.inverse: + tape.inv() + return tape diff --git a/pennylane/transforms/adjoint.py b/pennylane/transforms/adjoint.py index ea8908c2b94..35d7a44fec9 100644 --- a/pennylane/transforms/adjoint.py +++ b/pennylane/transforms/adjoint.py @@ -102,9 +102,10 @@ def wrapper(*args, **kwargs): try: op.adjoint() except NotImplementedError: - # Decompose the operation and adjoint the result. + # Expand the operation and adjoint the result. # We do not do anything with the output since - # decomposition will automatically queue the new operations. - adjoint(op.decomposition)(wires=op.wires) + # calling adjoint on the expansion will automatically + # queue the new operations. + adjoint(op.expand)() return wrapper From 272d32ff3aa62a2b8aaec89bcf1054edf7fac006 Mon Sep 17 00:00:00 2001 From: Josh Izaac Date: Wed, 21 Apr 2021 19:53:16 +0800 Subject: [PATCH 02/17] fix --- pennylane/tape/tape.py | 9 +- pennylane/templates/embeddings/amplitude.py | 11 +- pennylane/templates/embeddings/basis.py | 3 + tests/transforms/test_adjoint.py | 128 +++++++++++++++++++- 4 files changed, 146 insertions(+), 5 deletions(-) diff --git a/pennylane/tape/tape.py b/pennylane/tape/tape.py index 9351044c015..f1cac0c59b2 100644 --- a/pennylane/tape/tape.py +++ b/pennylane/tape/tape.py @@ -648,14 +648,17 @@ def inv(self): self.trainable_params = {parameter_mapping[i] for i in self.trainable_params} self._par_info = {parameter_mapping[k]: v for k, v in self._par_info.items()} - for op in self._ops: - op.inverse = not op.inverse + for idx, op in enumerate(self._ops): + try: + self._ops[idx] = op.adjoint() + except NotImplementedError: + op.inverse = not op.inverse self._ops = list(reversed(self._ops)) def adjoint(self): new_tape = self.copy(copy_operations=True) - new_tape.inv() + qml.transforms.invisible(new_tape.inv)() # the current implementation of the adjoint # method requires that the returned inverted object diff --git a/pennylane/templates/embeddings/amplitude.py b/pennylane/templates/embeddings/amplitude.py index f85c18dae7c..93a2fe0a2fb 100644 --- a/pennylane/templates/embeddings/amplitude.py +++ b/pennylane/templates/embeddings/amplitude.py @@ -143,10 +143,19 @@ def __init__(self, features, wires, pad_with=None, normalize=False, pad=None, do features = self._preprocess(features, wires, pad_with, normalize) super().__init__(features, wires=wires, do_queue=do_queue) + def adjoint(self): + return qml.templates.MottonenStatePreparation(self.parameters[0], wires=self.wires) + def expand(self): with qml.tape.QuantumTape() as tape: - QubitStateVector(self.parameters[0], wires=self.wires) + if self.inverse: + self.adjoint() + else: + QubitStateVector(self.parameters[0], wires=self.wires) + + if self.inverse: + tape.inv() return tape diff --git a/pennylane/templates/embeddings/basis.py b/pennylane/templates/embeddings/basis.py index 94ea09eac61..2fa25dce6c7 100644 --- a/pennylane/templates/embeddings/basis.py +++ b/pennylane/templates/embeddings/basis.py @@ -70,4 +70,7 @@ def expand(self): if bit == 1: qml.PauliX(wire) + if self.inverse: + tape.inv() + return tape diff --git a/tests/transforms/test_adjoint.py b/tests/transforms/test_adjoint.py index 00156dc83f2..04033631bb5 100644 --- a/tests/transforms/test_adjoint.py +++ b/tests/transforms/test_adjoint.py @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - +import pytest import numpy as np import pennylane as qml @@ -85,3 +85,129 @@ def my_circuit(): np.testing.assert_allclose( my_circuit(), np.array([-0.995707, 0.068644 + 6.209710e-02j]), atol=1e-6, rtol=1e-6 ) + + +test_functions = [ + lambda fn, *args, **kwargs: adjoint(fn)(*args, **kwargs), + lambda fn, *args, **kwargs: qml.inv(fn(*args, **kwargs)), +] + + +@pytest.mark.parametrize("fn", test_functions) +class TestTemplateIntegration: + """Test that templates work correctly with the adjoint transform""" + + def test_angle_embedding(self, fn): + """Test that the adjoint correctly inverts angle embedding""" + dev = qml.device("default.qubit", wires=3) + template = qml.templates.AngleEmbedding + + @qml.qnode(dev) + def circuit(weights): + template(features=weights, wires=[0, 1, 2]) + fn(template, features=weights, wires=[0, 1, 2]) + return qml.state() + + weights = np.array([0.2, 0.5, 0.8]) + res = circuit(weights) + assert len(np.nonzero(res)) == 1 + + def test_amplitude_embedding(self, fn): + """Test that the adjoint correctly inverts amplitude embedding""" + dev = qml.device("default.qubit", wires=3) + template = qml.templates.AmplitudeEmbedding + + @qml.qnode(dev) + def circuit(weights): + template(features=weights, wires=[0, 1, 2]) + fn(template, features=weights, wires=[0, 1, 2]) + return qml.state() + + weights = np.array([0.2, 0.5, 0.8, 0.6, 0.1, 0.6, 0.1, 0.5]) / np.sqrt(1.92) + res = circuit(weights) + assert len(np.nonzero(res)) == 1 + + def test_basis_embedding(self, fn): + """Test that the adjoint correctly inverts basis embedding""" + dev = qml.device("default.qubit", wires=3) + template = qml.templates.BasisEmbedding + + @qml.qnode(dev) + def circuit(weights): + template(features=weights, wires=[0, 1, 2]) + fn(template, features=weights, wires=[0, 1, 2]) + return qml.state() + + weights = np.array([1, 0, 1]) + res = circuit(weights) + expected = np.zeros([2 ** 3]) + expected[0] = 1.0 + assert np.allclose(res, expected) + + def test_displacement_embedding(self, fn): + """Test that the adjoint correctly inverts displacement embedding""" + dev = qml.device("default.gaussian", wires=3) + template = qml.templates.DisplacementEmbedding + + @qml.qnode(dev) + def circuit(weights): + template(features=weights, wires=[0, 1, 2]) + fn(template, features=weights, wires=[0, 1, 2]) + return qml.expval(qml.NumberOperator(0)) + + weights = np.array([0.6, 0.2, 0.1]) + res = circuit(weights) + assert np.allclose(res, 0.0) + + def test_squeezing_embedding(self, fn): + """Test that the adjoint correctly inverts squeezing embedding""" + dev = qml.device("default.gaussian", wires=3) + template = qml.templates.SqueezingEmbedding + + @qml.qnode(dev) + def circuit(weights): + template(features=weights, wires=[0, 1, 2]) + fn(template, features=weights, wires=[0, 1, 2]) + return qml.expval(qml.NumberOperator(0)) + + weights = np.array([0.6, 0.2, 0.1]) + res = circuit(weights) + assert np.allclose(res, 0.0) + + def test_qaoa_embedding(self, fn): + """Test that the adjoint correctly inverts qaoa embedding""" + dev = qml.device("default.qubit", wires=3) + template = qml.templates.QAOAEmbedding + + @qml.qnode(dev) + def circuit(features, weights): + template(features=features, weights=weights, wires=[0, 1, 2]) + fn(template, features=features, weights=weights, wires=[0, 1, 2]) + return qml.probs(wires=[0, 1, 2]) + + features = np.array([1.0, 2.0, 3.0]) + weights = np.random.random(template.shape(2, 3)) + + res = circuit(features, weights) + expected = np.zeros([2 ** 3]) + expected[0] = 1.0 + + assert np.allclose(res, expected) + + def test_iqp_embedding(self, fn): + """Test that the adjoint correctly inverts iqp embedding""" + dev = qml.device("default.qubit", wires=3) + template = qml.templates.IQPEmbedding + + @qml.qnode(dev) + def circuit(features): + template(features=features, wires=[0, 1, 2]) + fn(template, features=features, wires=[0, 1, 2]) + return qml.probs(wires=[0, 1, 2]) + + features = np.array([1.0, 2.0, 3.0]) + res = circuit(features) + expected = np.zeros([2 ** 3]) + expected[0] = 1.0 + + assert np.allclose(res, expected) From afcfef79a74852b0104fd220f610b283c3ac04bc Mon Sep 17 00:00:00 2001 From: Josh Izaac Date: Wed, 21 Apr 2021 19:55:02 +0800 Subject: [PATCH 03/17] linting --- pennylane/tape/tape.py | 11 ++++++++++- pennylane/templates/embeddings/amplitude.py | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/pennylane/tape/tape.py b/pennylane/tape/tape.py index f1cac0c59b2..a557370c5fa 100644 --- a/pennylane/tape/tape.py +++ b/pennylane/tape/tape.py @@ -657,11 +657,20 @@ def inv(self): self._ops = list(reversed(self._ops)) def adjoint(self): + """Create a tape that is the adjoint of this one. + + Adjointed tapes are the conjugated and transposed version of the + original tapes. Adjointed ops are equivalent to the inverted operation for unitary + gates. + + Returns: + ~.QuantumTape: the adjointed tape + """ new_tape = self.copy(copy_operations=True) qml.transforms.invisible(new_tape.inv)() # the current implementation of the adjoint - # method requires that the returned inverted object + # transform requires that the returned inverted object # is automatically queued. QuantumTape._lock.acquire() try: diff --git a/pennylane/templates/embeddings/amplitude.py b/pennylane/templates/embeddings/amplitude.py index 93a2fe0a2fb..d4568e4849e 100644 --- a/pennylane/templates/embeddings/amplitude.py +++ b/pennylane/templates/embeddings/amplitude.py @@ -143,7 +143,7 @@ def __init__(self, features, wires, pad_with=None, normalize=False, pad=None, do features = self._preprocess(features, wires, pad_with, normalize) super().__init__(features, wires=wires, do_queue=do_queue) - def adjoint(self): + def adjoint(self, do_queue=False): return qml.templates.MottonenStatePreparation(self.parameters[0], wires=self.wires) def expand(self): From 48150ab53777074c4a8404cb77edd6b0f6e54328 Mon Sep 17 00:00:00 2001 From: Josh Izaac Date: Wed, 21 Apr 2021 20:06:25 +0800 Subject: [PATCH 04/17] more tests --- .../layers/particle_conserving_u1.py | 2 +- .../layers/particle_conserving_u2.py | 2 +- tests/transforms/test_adjoint.py | 50 +++++++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/pennylane/templates/layers/particle_conserving_u1.py b/pennylane/templates/layers/particle_conserving_u1.py index c0718d1e1cf..f61c5583110 100644 --- a/pennylane/templates/layers/particle_conserving_u1.py +++ b/pennylane/templates/layers/particle_conserving_u1.py @@ -266,7 +266,7 @@ def expand(self): with qml.tape.QuantumTape() as tape: - qml.BasisState(self.init_state, wires=self.wires) + qml.templates.BasisEmbedding(self.init_state, wires=self.wires) for l in range(self.n_layers): for i, wires_ in enumerate(nm_wires): diff --git a/pennylane/templates/layers/particle_conserving_u2.py b/pennylane/templates/layers/particle_conserving_u2.py index f2eddf5ca33..9e295bbbee5 100644 --- a/pennylane/templates/layers/particle_conserving_u2.py +++ b/pennylane/templates/layers/particle_conserving_u2.py @@ -183,7 +183,7 @@ def expand(self): with qml.tape.QuantumTape() as tape: - qml.BasisState(self.init_state, wires=self.wires) + qml.templates.BasisEmbedding(self.init_state, wires=self.wires) for l in range(self.n_layers): diff --git a/tests/transforms/test_adjoint.py b/tests/transforms/test_adjoint.py index 04033631bb5..ea028ca8e07 100644 --- a/tests/transforms/test_adjoint.py +++ b/tests/transforms/test_adjoint.py @@ -211,3 +211,53 @@ def circuit(features): expected[0] = 1.0 assert np.allclose(res, expected) + + @pytest.mark.parametrize( + "template", + [ + qml.templates.BasicEntanglerLayers, + qml.templates.StronglyEntanglingLayers, + qml.templates.RandomLayers, + ], + ) + def test_layers(self, fn, template): + """Test that the adjoint correctly inverts layers""" + dev = qml.device("default.qubit", wires=3) + + @qml.qnode(dev) + def circuit(weights): + template(weights=weights, wires=[0, 1, 2]) + fn(template, weights=weights, wires=[0, 1, 2]) + return qml.probs(wires=[0, 1, 2]) + + weights = np.random.random(template.shape(2, 3)) + res = circuit(weights) + expected = np.zeros([2 ** 3]) + expected[0] = 1.0 + + assert np.allclose(res, expected) + + @pytest.mark.parametrize( + "template", + [ + qml.templates.ParticleConservingU1, + qml.templates.ParticleConservingU2, + ], + ) + def test_particle_conserving(self, fn, template): + """Test that the adjoint correctly inverts particle conserving layers""" + dev = qml.device("default.qubit", wires=3) + init_state = np.array([0, 1, 1]) + + @qml.qnode(dev) + def circuit(weights): + template(weights=weights, init_state=init_state, wires=[0, 1, 2]) + fn(template, weights=weights, init_state=init_state, wires=[0, 1, 2]) + return qml.probs(wires=[0, 1, 2]) + + weights = np.random.random(template.shape(2, 3)) + res = circuit(weights) + expected = np.zeros([2 ** 3]) + expected[0] = 1.0 + + assert np.allclose(res, expected) From ee955d76fe71379f8c195c7142faf252f576aa5b Mon Sep 17 00:00:00 2001 From: Josh Izaac Date: Wed, 21 Apr 2021 20:15:45 +0800 Subject: [PATCH 05/17] fix tests --- pennylane/utils.py | 2 +- tests/test_utils.py | 58 ++++++++++++++++++++++----------------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/pennylane/utils.py b/pennylane/utils.py index a2b15e094f4..46fa454738c 100644 --- a/pennylane/utils.py +++ b/pennylane/utils.py @@ -340,7 +340,7 @@ def circuit2(): if o.inverse: o.inv() - tape.inv() + qml.transforms.invisible(tape.inv)() return tape diff --git a/tests/test_utils.py b/tests/test_utils.py index 4e48a46018e..ab886069f21 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -463,8 +463,8 @@ def inverted_dummy_template_operations(wires): ops = [] for wire in reversed(wires): - ops.append(qml.RY(-1, wires=[wire]).inv()) - ops.append(qml.RX(1, wires=[wire]).inv()) + ops.append(qml.RY(1, wires=[wire])) + ops.append(qml.RX(-1, wires=[wire])) return ops @@ -475,7 +475,7 @@ class TestInv: def test_inversion_without_context(self): """Test that a sequence of operations is properly inverted.""" op_queue = [qml.PauliX(0), qml.PauliY(0).inv(), qml.PauliZ(0)] - inv_queue = [qml.PauliZ(0).inv(), qml.PauliY(0), qml.PauliX(0).inv()] + inv_queue = [qml.PauliZ(0), qml.PauliY(0), qml.PauliX(0)] inv_ops = pu.inv(op_queue).operations @@ -527,9 +527,9 @@ def test_inversion_with_context(self): inv_queue = [ qml.Hadamard(wires=[0]), qml.CNOT(wires=[0, 1]), - qml.RZ(3, wires=[0]).inv(), - qml.RY(2, wires=[0]).inv(), - qml.RX(1, wires=[0]).inv(), + qml.RZ(-3, wires=[0]), + qml.RY(-2, wires=[0]), + qml.RX(-1, wires=[0]), qml.CNOT(wires=[0, 1]), qml.Hadamard(wires=[0]), ] @@ -554,9 +554,9 @@ def test_non_queued_inversion_with_context(self): inv_queue = [ qml.Hadamard(wires=[0]), qml.CNOT(wires=[0, 1]), - qml.RZ(3, wires=[0]).inv(), - qml.RY(2, wires=[0]).inv(), - qml.RX(1, wires=[0]).inv(), + qml.RZ(-3, wires=[0]), + qml.RY(-2, wires=[0]), + qml.RX(-1, wires=[0]), qml.CNOT(wires=[0, 1]), qml.Hadamard(wires=[0]), ] @@ -582,10 +582,10 @@ def test_mixed_inversion_with_context(self): inv_queue = [ qml.Hadamard(wires=[0]), qml.CNOT(wires=[0, 1]), - qml.RY(2, wires=[0]).inv(), - qml.PauliZ(0).inv(), - qml.RX(1, wires=[0]).inv(), - qml.PauliX(0).inv(), + qml.RY(-2, wires=[0]), + qml.PauliZ(0), + qml.RX(-1, wires=[0]), + qml.PauliX(0), qml.CNOT(wires=[0, 1]), qml.Hadamard(wires=[0]), ] @@ -612,10 +612,10 @@ def test_mixed_inversion_with_nested_context(self): inv_queue = [ qml.Hadamard(wires=[0]), qml.CNOT(wires=[0, 1]), - qml.RY(2, wires=[0]).inv(), - qml.PauliZ(0).inv(), - qml.RX(1, wires=[0]).inv(), - qml.PauliX(0).inv(), + qml.RY(-2, wires=[0]), + qml.PauliZ(0), + qml.RX(-1, wires=[0]), + qml.PauliX(0), qml.CNOT(wires=[0, 1]), qml.Hadamard(wires=[0]), ] @@ -669,9 +669,9 @@ def qfunc(): inv_queue = [ qml.Hadamard(wires=[0]), qml.CNOT(wires=[0, 1]), - qml.RZ(3, wires=[0]).inv(), - qml.RY(2, wires=[0]).inv(), - qml.RX(1, wires=[0]).inv(), + qml.RZ(-3, wires=[0]), + qml.RY(-2, wires=[0]), + qml.RX(-1, wires=[0]), qml.CNOT(wires=[0, 1]), qml.Hadamard(wires=[0]), ] @@ -703,9 +703,9 @@ def qfunc(): inv_queue = [ qml.Hadamard(wires=[0]), qml.CNOT(wires=[0, 1]), - qml.RZ(3, wires=[0]).inv(), - qml.RY(2, wires=[0]).inv(), - qml.RX(1, wires=[0]).inv(), + qml.RZ(-3, wires=[0]), + qml.RY(-2, wires=[0]), + qml.RX(-1, wires=[0]), qml.CNOT(wires=[0, 1]), qml.Hadamard(wires=[0]), ] @@ -737,10 +737,10 @@ def qfunc(): inv_queue = [ qml.Hadamard(wires=[0]), qml.CNOT(wires=[0, 1]), - qml.RY(2, wires=[0]).inv(), - qml.PauliZ(0).inv(), - qml.RX(1, wires=[0]).inv(), - qml.PauliX(0).inv(), + qml.RY(-2, wires=[0]), + qml.PauliZ(0), + qml.RX(-1, wires=[0]), + qml.PauliX(0), qml.CNOT(wires=[0, 1]), qml.Hadamard(wires=[0]), ] @@ -783,8 +783,8 @@ def qfunc(): def test_argument_wrapping(self): """Test that a single operation can be given to inv and is properly inverted.""" - op = qml.PauliX(0) - exp_op = qml.PauliX(0).inv() + op = qml.RX(0.1, wires=0) + exp_op = qml.RX(-0.1, wires=0) inv_ops = pu.inv(op).operations From bcfaa85eafdfe1c638946fbc8cce6164bf570b0c Mon Sep 17 00:00:00 2001 From: Josh Izaac Date: Wed, 21 Apr 2021 20:40:19 +0800 Subject: [PATCH 06/17] fix failing tests --- pennylane/templates/state_preparations/basis.py | 4 ++++ tests/devices/test_default_qubit.py | 2 +- tests/tape/test_tape.py | 10 +++++----- .../test_layers/test_particle_conserving_u1.py | 2 +- .../test_layers/test_particle_conserving_u2.py | 2 +- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/pennylane/templates/state_preparations/basis.py b/pennylane/templates/state_preparations/basis.py index 5b326e938e5..9911f1c3066 100644 --- a/pennylane/templates/state_preparations/basis.py +++ b/pennylane/templates/state_preparations/basis.py @@ -77,4 +77,8 @@ def expand(self): for wire, state in zip(self.wires, self.parameters[0]): if state == 1: qml.PauliX(wire) + + if self.inverse: + tape.inv() + return tape diff --git a/tests/devices/test_default_qubit.py b/tests/devices/test_default_qubit.py index 741b50d11ed..0051a476f85 100644 --- a/tests/devices/test_default_qubit.py +++ b/tests/devices/test_default_qubit.py @@ -2493,7 +2493,7 @@ def test_s_inverse(): test_s_inverse() operations = test_s_inverse.qtape.operations assert "S.inv" not in [i.name for i in operations] - assert "PhaseShift.inv" in [i.name for i in operations] + assert "PhaseShift" in [i.name for i in operations] expected = np.array([1.0, -1.0j]) / np.sqrt(2) assert np.allclose(dev.state, expected, atol=tol, rtol=0) diff --git a/tests/tape/test_tape.py b/tests/tape/test_tape.py index d39f4b87f42..0a11bcbee22 100644 --- a/tests/tape/test_tape.py +++ b/tests/tape/test_tape.py @@ -604,12 +604,12 @@ def test_inverse(self): tape.inv() # check that operation order is reversed - assert tape.operations == [prep] + ops[::-1] + assert [o.name for o in tape.operations] == [ + o.name.replace(".inv", "") for o in [prep] + ops[::-1] + ] # check that operations are inverted - assert ops[0].inverse - assert not ops[1].inverse - assert ops[2].inverse + assert np.allclose(tape.operations[2].parameters, -np.array(p[-1:0:-1])) # check that parameter order has reversed assert tape.get_parameters() == [init_state, p[1], p[2], p[3], p[0]] @@ -636,7 +636,7 @@ def test_parameter_transforms(self): tape.inv() assert tape.trainable_params == {1, 2} assert tape.get_parameters() == [p[0], p[1]] - assert tape._ops == ops + assert [o.name for o in tape._ops] == [o.name.replace(".inv", "") for o in ops] class TestExpand: diff --git a/tests/templates/test_layers/test_particle_conserving_u1.py b/tests/templates/test_layers/test_particle_conserving_u1.py index a7d64976dcf..d65936b1836 100644 --- a/tests/templates/test_layers/test_particle_conserving_u1.py +++ b/tests/templates/test_layers/test_particle_conserving_u1.py @@ -84,7 +84,7 @@ def test_operations(self): assert gate_count == len(queue) # check initialization of the qubit register - assert isinstance(queue[0], qml.BasisState) + assert isinstance(queue[0], qml.templates.BasisEmbedding) # check all quantum operations idx_CRot = 8 diff --git a/tests/templates/test_layers/test_particle_conserving_u2.py b/tests/templates/test_layers/test_particle_conserving_u2.py index f741956a521..3a05f8e2d37 100644 --- a/tests/templates/test_layers/test_particle_conserving_u2.py +++ b/tests/templates/test_layers/test_particle_conserving_u2.py @@ -50,7 +50,7 @@ def test_operations(self, layers, qubits, init_state): assert len(queue) == n_gates # initialization - assert isinstance(queue[0], qml.BasisState) + assert isinstance(queue[0], qml.templates.BasisEmbedding) # order of gates for op1, op2 in zip(queue[1:], exp_gates): From 5d7cedcf8339c541608483b6a394ffe656326b25 Mon Sep 17 00:00:00 2001 From: Josh Izaac Date: Wed, 21 Apr 2021 20:41:52 +0800 Subject: [PATCH 07/17] changelog --- .github/CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index c516f4d340f..b2d5ec100bd 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -43,13 +43,17 @@

Bug fixes

+* A bug which resulted in `qml.adjoint()` and `qml.inv()` failing to work with + templates has been fixed. + [(#1243)](https://github.com/PennyLaneAI/pennylane/pull/1243) +

Documentation

Contributors

This release contains contributions from: -Thomas Bromley, Diego Guala, Anthony Hayes +Thomas Bromley, Diego Guala, Anthony Hayes, Josh Izaac # Release 0.15.0 (current release) From d7de2a5f9f4993059e86b5c06c2ec4bcf48b9877 Mon Sep 17 00:00:00 2001 From: Josh Izaac Date: Fri, 23 Apr 2021 23:14:47 +0800 Subject: [PATCH 08/17] suggested changes --- pennylane/transforms/adjoint.py | 43 ++++++++---- tests/transforms/test_adjoint.py | 113 +++++++++++++++++++++++++++++++ 2 files changed, 143 insertions(+), 13 deletions(-) diff --git a/pennylane/transforms/adjoint.py b/pennylane/transforms/adjoint.py index 35d7a44fec9..1427155b2c8 100644 --- a/pennylane/transforms/adjoint.py +++ b/pennylane/transforms/adjoint.py @@ -18,34 +18,51 @@ def adjoint(fn): - """Create a function that applies the adjoint of the provided operation or template. + """Create a function that applies the adjoint (inverse) of the provided operation or template. This transform can be used to apply the adjoint of an arbitrary sequence of operations. Args: - fn (function): Any python function that applies pennylane operations. + fn (function): A quantum function that applies quantum operations. Returns: function: A new function that will apply the same operations but adjointed and in reverse order. **Example** + The adjoint transforms can be used within a QNode to apply the adjoint of + any quantum function. Consider the following quantum function, that applies two + operations: + .. code-block:: python3 - def my_ops(): - qml.RX(0.123, wires=0) - qml.RY(0.456, wires=0) + def my_ops(a, b, wire): + qml.RX(a, wires=wire) + qml.RY(b, wires=wire) + + We can create a QNode that applies this quantum function, + followed by the adjoint of this function: + + .. code-black:: python3 + + dev = qml.device('default.qubit', wires=1) + + @qml.qnode(dev) + def circuit(a, b): + my_ops(a, b, wire=0) + qml.adjoint(my_ops)(a, b, wire=0) + return qml.expval(qml.PauliZ(0)) + + Printing this out, we can see that the inverse quantum + function has indeed been applied: - with qml.tape.QuantumTape() as tape: - my_ops() + >>> print(qml.draw(circuit)(0.2, 0.5)) + 0: ──RX(0.2)──RY(0.5)──RY(-0.5)──RX(-0.2)──┤ ⟨Z⟩ - with qml.tape.QuantumTape() as tape_adj: - qml.adjoint(my_ops)() + The adjoint function can also be applied directly to templates and operations: - >>> print(tape.operations) - [RX(0.123, wires=[0]), RY(0.456, wires=[0])] - >>> print(tape_adj.operatioins) - [RY(-0.456, wires=[0]), RX(-0.123, wires=[0])] + >>> qml.adjoint(qml.RX)(0.123, wires=0) + >>> qml.adjoint(qml.templates.StronglyEntanglingLayers)(weights, wires=[0, 1]) .. UsageDetails:: diff --git a/tests/transforms/test_adjoint.py b/tests/transforms/test_adjoint.py index ea028ca8e07..92cbc14321d 100644 --- a/tests/transforms/test_adjoint.py +++ b/tests/transforms/test_adjoint.py @@ -261,3 +261,116 @@ def circuit(weights): expected[0] = 1.0 assert np.allclose(res, expected) + + def test_simplified_two_design(self, fn): + """Test that the adjoint correctly inverts the simplified two design""" + dev = qml.device("default.qubit", wires=3) + template = qml.templates.SimplifiedTwoDesign + + @qml.qnode(dev) + def circuit(data, weights): + template(initial_layer_weights=data, weights=weights, wires=[0, 1, 2]) + fn(template, initial_layer_weights=data, weights=weights, wires=[0, 1, 2]) + return qml.probs(wires=[0, 1, 2]) + + weights = [np.random.random(s) for s in template.shape(2, 3)] + res = circuit(weights[0], *weights[1:]) + expected = np.zeros([2 ** 3]) + expected[0] = 1.0 + + assert np.allclose(res, expected) + + def test_approx_time_evolution(self, fn): + """Test that the adjoint correctly inverts the approx time evolution""" + dev = qml.device("default.qubit", wires=3) + template = qml.templates.ApproxTimeEvolution + + coeffs = [1, 1] + obs = [qml.PauliX(0), qml.PauliX(1)] + H = qml.Hamiltonian(coeffs, obs) + + @qml.qnode(dev) + def circuit(t): + template(H, t, 1) + fn(template, H, t, 1) + return qml.probs(wires=[0, 1, 2]) + + res = circuit(0.5) + expected = np.zeros([2 ** 3]) + expected[0] = 1.0 + assert np.allclose(res, expected) + + def test_arbitrary_unitary(self, fn): + """Test that the adjoint correctly inverts the arbitrary unitary""" + dev = qml.device("default.qubit", wires=3) + template = qml.templates.ArbitraryUnitary + + @qml.qnode(dev) + def circuit(weights): + template(weights=weights, wires=[0, 1, 2]) + fn(template, weights=weights, wires=[0, 1, 2]) + return qml.probs(wires=[0, 1, 2]) + + weights = np.random.random(template.shape(3)) + res = circuit(weights) + expected = np.zeros([2 ** 3]) + expected[0] = 1.0 + + assert np.allclose(res, expected) + + def test_single_excitation(self, fn): + """Test that the adjoint correctly inverts the single excitation unitary""" + dev = qml.device("default.qubit", wires=3) + template = qml.templates.SingleExcitationUnitary + + @qml.qnode(dev) + def circuit(weights): + template(weight=weights, wires=[0, 1, 2]) + fn(template, weight=weights, wires=[0, 1, 2]) + return qml.probs(wires=[0, 1, 2]) + + res = circuit(0.6) + expected = np.zeros([2 ** 3]) + expected[0] = 1.0 + + assert np.allclose(res, expected) + + def test_double_excitation(self, fn): + """Test that the adjoint correctly inverts the double excitation unitary""" + dev = qml.device("default.qubit", wires=4) + template = qml.templates.DoubleExcitationUnitary + + @qml.qnode(dev) + def circuit(weights): + template(weight=weights, wires1=[0, 1], wires2=[2, 3]) + fn(template, weight=weights, wires1=[0, 1], wires2=[2, 3]) + return qml.probs(wires=[0, 1, 2, 3]) + + res = circuit(0.6) + expected = np.zeros([2 ** 4]) + expected[0] = 1.0 + + assert np.allclose(res, expected) + + def test_interferometer(self, fn): + """Test that the adjoint correctly inverts squeezing embedding""" + dev = qml.device("default.gaussian", wires=3) + template = qml.templates.Interferometer + r = 1.5 + + @qml.qnode(dev) + def circuit(weights): + qml.Squeezing(r, 0, wires=0) + qml.Squeezing(r, 0, wires=1) + qml.Squeezing(r, 0, wires=2) + template(*weights, wires=[0, 1, 2]) + fn(template, *weights, wires=[0, 1, 2]) + return qml.expval(qml.NumberOperator(0)) + + weights = [ + np.random.random([3 * (3 - 1) // 2]), + np.random.random([3 * (3 - 1) // 2]), + np.random.random([3]), + ] + res = circuit(weights) + assert np.allclose(res, np.sinh(r) ** 2) From 3210ee9ad69b2822442ee0c3d8e9798942c9f18e Mon Sep 17 00:00:00 2001 From: Josh Izaac Date: Fri, 23 Apr 2021 23:21:31 +0800 Subject: [PATCH 09/17] fix sphinx --- pennylane/transforms/adjoint.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane/transforms/adjoint.py b/pennylane/transforms/adjoint.py index 1427155b2c8..fbdb6e578f8 100644 --- a/pennylane/transforms/adjoint.py +++ b/pennylane/transforms/adjoint.py @@ -43,7 +43,7 @@ def my_ops(a, b, wire): We can create a QNode that applies this quantum function, followed by the adjoint of this function: - .. code-black:: python3 + .. code-block:: python3 dev = qml.device('default.qubit', wires=1) From cb75162426c56674cb235d9c5fbfaab99ffe71f5 Mon Sep 17 00:00:00 2001 From: Josh Izaac Date: Sat, 24 Apr 2021 00:50:20 +0800 Subject: [PATCH 10/17] update --- pennylane/ops/qubit.py | 2 +- pennylane/templates/embeddings/amplitude.py | 14 +++++--------- pennylane/templates/embeddings/angle.py | 3 --- pennylane/templates/embeddings/basis.py | 3 --- pennylane/templates/embeddings/displacement.py | 3 --- pennylane/templates/embeddings/iqp.py | 3 --- pennylane/templates/embeddings/qaoa.py | 3 --- pennylane/templates/embeddings/squeezing.py | 3 --- pennylane/templates/layers/basic_entangler.py | 3 --- pennylane/templates/layers/cv_neural_net.py | 3 --- .../templates/layers/particle_conserving_u1.py | 3 --- .../templates/layers/particle_conserving_u2.py | 3 --- pennylane/templates/layers/random.py | 3 --- .../templates/layers/simplified_two_design.py | 3 --- pennylane/templates/layers/strongly_entangling.py | 3 --- .../arbitrary_state_preparation.py | 3 --- pennylane/templates/state_preparations/basis.py | 3 --- pennylane/templates/state_preparations/mottonen.py | 3 --- .../templates/subroutines/approx_time_evolution.py | 3 --- .../templates/subroutines/arbitrary_unitary.py | 3 --- .../subroutines/double_excitation_unitary.py | 3 --- pennylane/templates/subroutines/permute.py | 3 --- pennylane/templates/subroutines/qmc.py | 3 --- pennylane/templates/subroutines/qpe.py | 3 --- .../subroutines/single_excitation_unitary.py | 3 --- pennylane/templates/subroutines/uccsd.py | 3 --- pennylane/utils.py | 13 +++++++------ 27 files changed, 13 insertions(+), 88 deletions(-) diff --git a/pennylane/ops/qubit.py b/pennylane/ops/qubit.py index 2c930598c50..ad5ecd347d7 100644 --- a/pennylane/ops/qubit.py +++ b/pennylane/ops/qubit.py @@ -2465,7 +2465,7 @@ def decomposition(state, wires): return MottonenStatePreparation(state, wires) def adjoint(self): - raise AdjointError("No adjoint exists for QubitStateVector operations.") + return qml.adjoint(MottonenStatePreparation)(self.parameters[0], wires=self.wires) # ============================================================================= diff --git a/pennylane/templates/embeddings/amplitude.py b/pennylane/templates/embeddings/amplitude.py index d4568e4849e..063bd497d73 100644 --- a/pennylane/templates/embeddings/amplitude.py +++ b/pennylane/templates/embeddings/amplitude.py @@ -143,19 +143,15 @@ def __init__(self, features, wires, pad_with=None, normalize=False, pad=None, do features = self._preprocess(features, wires, pad_with, normalize) super().__init__(features, wires=wires, do_queue=do_queue) - def adjoint(self, do_queue=False): - return qml.templates.MottonenStatePreparation(self.parameters[0], wires=self.wires) + def adjoint(self): + return qml.adjoint(qml.templates.MottonenStatePreparation)( + self.parameters[0], wires=self.wires + ) def expand(self): with qml.tape.QuantumTape() as tape: - if self.inverse: - self.adjoint() - else: - QubitStateVector(self.parameters[0], wires=self.wires) - - if self.inverse: - tape.inv() + QubitStateVector(self.parameters[0], wires=self.wires) return tape diff --git a/pennylane/templates/embeddings/angle.py b/pennylane/templates/embeddings/angle.py index 73d7d7bbfb5..7d03f52ce76 100644 --- a/pennylane/templates/embeddings/angle.py +++ b/pennylane/templates/embeddings/angle.py @@ -77,7 +77,4 @@ def expand(self): for i in range(len(self.wires)): self.rotation(features[i], wires=self.wires[i]) - if self.inverse: - tape.inv() - return tape diff --git a/pennylane/templates/embeddings/basis.py b/pennylane/templates/embeddings/basis.py index 2fa25dce6c7..94ea09eac61 100644 --- a/pennylane/templates/embeddings/basis.py +++ b/pennylane/templates/embeddings/basis.py @@ -70,7 +70,4 @@ def expand(self): if bit == 1: qml.PauliX(wire) - if self.inverse: - tape.inv() - return tape diff --git a/pennylane/templates/embeddings/displacement.py b/pennylane/templates/embeddings/displacement.py index 8963335edba..981699bea12 100644 --- a/pennylane/templates/embeddings/displacement.py +++ b/pennylane/templates/embeddings/displacement.py @@ -82,7 +82,4 @@ def expand(self): for i in range(len(self.wires)): qml.Displacement(pars[i, 0], pars[i, 1], wires=self.wires[i : i + 1]) - if self.inverse: - tape.inv() - return tape diff --git a/pennylane/templates/embeddings/iqp.py b/pennylane/templates/embeddings/iqp.py index 8ae625383c3..5e7e59039d1 100644 --- a/pennylane/templates/embeddings/iqp.py +++ b/pennylane/templates/embeddings/iqp.py @@ -205,7 +205,4 @@ def expand(self): # apply product of two features as entangler qml.MultiRZ(features[idx1] * features[idx2], wires=wire_pair) - if self.inverse: - tape.inv() - return tape diff --git a/pennylane/templates/embeddings/qaoa.py b/pennylane/templates/embeddings/qaoa.py index 4236db420e3..37631986449 100644 --- a/pennylane/templates/embeddings/qaoa.py +++ b/pennylane/templates/embeddings/qaoa.py @@ -234,9 +234,6 @@ def expand(self): # repeat the feature encoding once more at the end qaoa_feature_encoding_hamiltonian(features, self.wires) - if self.inverse: - tape.inv() - return tape @staticmethod diff --git a/pennylane/templates/embeddings/squeezing.py b/pennylane/templates/embeddings/squeezing.py index ad5c442a5b3..6fdd3c49a1d 100644 --- a/pennylane/templates/embeddings/squeezing.py +++ b/pennylane/templates/embeddings/squeezing.py @@ -83,7 +83,4 @@ def expand(self): for i in range(len(self.wires)): qml.Squeezing(pars[i, 0], pars[i, 1], wires=self.wires[i : i + 1]) - if self.inverse: - tape.inv() - return tape diff --git a/pennylane/templates/layers/basic_entangler.py b/pennylane/templates/layers/basic_entangler.py index bb423a8e736..78e55d8c6bb 100644 --- a/pennylane/templates/layers/basic_entangler.py +++ b/pennylane/templates/layers/basic_entangler.py @@ -161,9 +161,6 @@ def expand(self): w = self.wires.subset([i, i + 1], periodic_boundary=True) qml.CNOT(wires=w) - if self.inverse: - tape.inv() - return tape @staticmethod diff --git a/pennylane/templates/layers/cv_neural_net.py b/pennylane/templates/layers/cv_neural_net.py index 3b0f9b79974..c17404da2d2 100644 --- a/pennylane/templates/layers/cv_neural_net.py +++ b/pennylane/templates/layers/cv_neural_net.py @@ -170,9 +170,6 @@ def expand(self): for i in range(len(self.wires)): qml.Kerr(self.parameters[10][l, i], wires=self.wires[i]) - if self.inverse: - tape.inv() - return tape @staticmethod diff --git a/pennylane/templates/layers/particle_conserving_u1.py b/pennylane/templates/layers/particle_conserving_u1.py index f61c5583110..097f1bfd5e9 100644 --- a/pennylane/templates/layers/particle_conserving_u1.py +++ b/pennylane/templates/layers/particle_conserving_u1.py @@ -274,9 +274,6 @@ def expand(self): self.parameters[0][l, i, 0], self.parameters[0][l, i, 1], wires=wires_ ) - if self.inverse: - tape.inv() - return tape @staticmethod diff --git a/pennylane/templates/layers/particle_conserving_u2.py b/pennylane/templates/layers/particle_conserving_u2.py index 9e295bbbee5..de2a4e4f62e 100644 --- a/pennylane/templates/layers/particle_conserving_u2.py +++ b/pennylane/templates/layers/particle_conserving_u2.py @@ -193,9 +193,6 @@ def expand(self): for i, wires_ in enumerate(nm_wires): u2_ex_gate(self.parameters[0][l, len(self.wires) + i], wires=wires_) - if self.inverse: - tape.inv() - return tape @staticmethod diff --git a/pennylane/templates/layers/random.py b/pennylane/templates/layers/random.py index 9bbfce7edc2..1ff792960a8 100644 --- a/pennylane/templates/layers/random.py +++ b/pennylane/templates/layers/random.py @@ -229,9 +229,6 @@ def expand(self): rnd_wires = self.wires.select_random(2) self.imprimitive(wires=rnd_wires) - if self.inverse: - tape.inv() - return tape @staticmethod diff --git a/pennylane/templates/layers/simplified_two_design.py b/pennylane/templates/layers/simplified_two_design.py index 943ec32f467..cddb6facd3c 100644 --- a/pennylane/templates/layers/simplified_two_design.py +++ b/pennylane/templates/layers/simplified_two_design.py @@ -155,9 +155,6 @@ def expand(self): self.parameters[1][layer, len(self.wires) // 2 + i, 1], wires=wire_pair[1] ) - if self.inverse: - tape.inv() - return tape @staticmethod diff --git a/pennylane/templates/layers/strongly_entangling.py b/pennylane/templates/layers/strongly_entangling.py index 4b81ae48c9e..98a1aa66249 100644 --- a/pennylane/templates/layers/strongly_entangling.py +++ b/pennylane/templates/layers/strongly_entangling.py @@ -116,9 +116,6 @@ def expand(self): act_on = self.wires.subset([i, i + self.ranges[l]], periodic_boundary=True) self.imprimitive(wires=act_on) - if self.inverse: - tape.inv() - return tape @staticmethod diff --git a/pennylane/templates/state_preparations/arbitrary_state_preparation.py b/pennylane/templates/state_preparations/arbitrary_state_preparation.py index 8f3f4a8cc94..aa23dc3b2ba 100644 --- a/pennylane/templates/state_preparations/arbitrary_state_preparation.py +++ b/pennylane/templates/state_preparations/arbitrary_state_preparation.py @@ -99,9 +99,6 @@ def expand(self): for i, pauli_word in enumerate(_state_preparation_pauli_words(len(self.wires))): qml.PauliRot(self.parameters[0][i], pauli_word, wires=self.wires) - if self.inverse: - tape.inv() - return tape @staticmethod diff --git a/pennylane/templates/state_preparations/basis.py b/pennylane/templates/state_preparations/basis.py index 9911f1c3066..a78e1ffe19f 100644 --- a/pennylane/templates/state_preparations/basis.py +++ b/pennylane/templates/state_preparations/basis.py @@ -78,7 +78,4 @@ def expand(self): if state == 1: qml.PauliX(wire) - if self.inverse: - tape.inv() - return tape diff --git a/pennylane/templates/state_preparations/mottonen.py b/pennylane/templates/state_preparations/mottonen.py index cd4d080dd8c..860eeb80f50 100644 --- a/pennylane/templates/state_preparations/mottonen.py +++ b/pennylane/templates/state_preparations/mottonen.py @@ -291,7 +291,4 @@ def expand(self): if len(alpha_z_k) > 0: _uniform_rotation_dagger(qml.RZ, alpha_z_k, control, target) - if self.inverse: - tape.inv() - return tape diff --git a/pennylane/templates/subroutines/approx_time_evolution.py b/pennylane/templates/subroutines/approx_time_evolution.py index 6aa70e7f11e..0bc5e2e8daa 100644 --- a/pennylane/templates/subroutines/approx_time_evolution.py +++ b/pennylane/templates/subroutines/approx_time_evolution.py @@ -156,7 +156,4 @@ def expand(self): for j, term in enumerate(pauli_words): PauliRot(theta[j], term, wires=wires[j]) - if self.inverse: - tape.inv() - return tape diff --git a/pennylane/templates/subroutines/arbitrary_unitary.py b/pennylane/templates/subroutines/arbitrary_unitary.py index 96539f0e9e2..835ae34701f 100644 --- a/pennylane/templates/subroutines/arbitrary_unitary.py +++ b/pennylane/templates/subroutines/arbitrary_unitary.py @@ -115,9 +115,6 @@ def expand(self): for i, pauli_word in enumerate(_all_pauli_words_but_identity(len(self.wires))): PauliRot(weights[i], pauli_word, wires=self.wires) - if self.inverse: - tape.inv() - return tape @staticmethod diff --git a/pennylane/templates/subroutines/double_excitation_unitary.py b/pennylane/templates/subroutines/double_excitation_unitary.py index 0fc04cfe82e..a35fe29a25c 100644 --- a/pennylane/templates/subroutines/double_excitation_unitary.py +++ b/pennylane/templates/subroutines/double_excitation_unitary.py @@ -525,7 +525,4 @@ def expand(self): _layer7(weight, s, r, q, p, set_cnot_wires) _layer8(weight, s, r, q, p, set_cnot_wires) - if self.inverse: - tape.inv() - return tape diff --git a/pennylane/templates/subroutines/permute.py b/pennylane/templates/subroutines/permute.py index eabd6180785..cdab13a0c57 100644 --- a/pennylane/templates/subroutines/permute.py +++ b/pennylane/templates/subroutines/permute.py @@ -187,7 +187,4 @@ def expand(self): working_order[idx_here], ) - if self.inverse: - tape.inv() - return tape diff --git a/pennylane/templates/subroutines/qmc.py b/pennylane/templates/subroutines/qmc.py index abdfa348061..b1e246b8f1d 100644 --- a/pennylane/templates/subroutines/qmc.py +++ b/pennylane/templates/subroutines/qmc.py @@ -367,7 +367,4 @@ def expand(self): Q, target_wires=self.target_wires, estimation_wires=self.estimation_wires ) - if self.inverse: - tape.inv() - return tape diff --git a/pennylane/templates/subroutines/qpe.py b/pennylane/templates/subroutines/qpe.py index a37a02c0ed4..0391e15139d 100644 --- a/pennylane/templates/subroutines/qpe.py +++ b/pennylane/templates/subroutines/qpe.py @@ -137,7 +137,4 @@ def expand(self): QFT(wires=self.estimation_wires).inv() - if self.inverse: - tape.inv() - return tape diff --git a/pennylane/templates/subroutines/single_excitation_unitary.py b/pennylane/templates/subroutines/single_excitation_unitary.py index 69aa37f589f..f02e2c8a7e5 100644 --- a/pennylane/templates/subroutines/single_excitation_unitary.py +++ b/pennylane/templates/subroutines/single_excitation_unitary.py @@ -183,7 +183,4 @@ def expand(self): Hadamard(wires=r) RX(np.pi / 2, wires=p) - if self.inverse: - tape.inv() - return tape diff --git a/pennylane/templates/subroutines/uccsd.py b/pennylane/templates/subroutines/uccsd.py index a4851b812c1..e21bc13cc82 100644 --- a/pennylane/templates/subroutines/uccsd.py +++ b/pennylane/templates/subroutines/uccsd.py @@ -196,7 +196,4 @@ def expand(self): for j, s_wires_ in enumerate(self.s_wires): qml.templates.SingleExcitationUnitary(weights[j], wires=s_wires_) - if self.inverse: - tape.inv() - return tape diff --git a/pennylane/utils.py b/pennylane/utils.py index 46fa454738c..258b7f6bf06 100644 --- a/pennylane/utils.py +++ b/pennylane/utils.py @@ -305,8 +305,9 @@ def circuit2(): "Please use inv on the function including its arguments, as in inv(template(args))." ) elif isinstance(operation_list, qml.tape.QuantumTape): - operation_list.inv() - return operation_list + new_tape = operation_list.adjoint() + return new_tape + elif not isinstance(operation_list, Iterable): raise ValueError("The provided operation_list is not iterable.") @@ -334,13 +335,13 @@ def circuit2(): # exist on the queuing context pass - with qml.tape.QuantumTape() as tape: + def qfunc(): for o in operation_list: o.queue() - if o.inverse: - o.inv() - qml.transforms.invisible(tape.inv)() + with qml.tape.QuantumTape() as tape: + qml.adjoint(qfunc)() + return tape From 16fb9dcd1c58705cc64de04e88c9c39b0840dc33 Mon Sep 17 00:00:00 2001 From: Josh Izaac Date: Sat, 24 Apr 2021 00:55:25 +0800 Subject: [PATCH 11/17] update --- pennylane/operation.py | 5 +---- tests/ops/test_qubit_ops.py | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/pennylane/operation.py b/pennylane/operation.py index 3289d49f25a..58c8a77d6f4 100644 --- a/pennylane/operation.py +++ b/pennylane/operation.py @@ -589,16 +589,13 @@ def inverse(self): """Boolean determining if the inverse of the operation was requested.""" return self._inverse - def adjoint(self, do_queue=False): + def adjoint(self): """Create an operation that is the adjoint of this one. Adjointed operations are the conjugated and transposed version of the original operation. Adjointed ops are equivalent to the inverted operation for unitary gates. - Args: - do_queue: Whether to add the adjointed gate to the context queue. - Returns: The adjointed operation. """ diff --git a/tests/ops/test_qubit_ops.py b/tests/ops/test_qubit_ops.py index bcf0b2ff3c0..392324ac8ad 100644 --- a/tests/ops/test_qubit_ops.py +++ b/tests/ops/test_qubit_ops.py @@ -421,7 +421,6 @@ def test_adjoint_with_decomposition(self, op_builder): "op", [ qml.BasisState(np.array([0, 1]), wires=0), - qml.QubitStateVector(np.array([1.0, 0.0]), wires=0), ], ) def test_adjoint_error_exception(self, op, tol): From 89d2891028812ebbdb98ad18fc27d85e48591ec6 Mon Sep 17 00:00:00 2001 From: Josh Izaac Date: Sat, 24 Apr 2021 00:59:00 +0800 Subject: [PATCH 12/17] Apply suggestions from code review --- pennylane/templates/layers/particle_conserving_u2.py | 1 - pennylane/templates/layers/random.py | 1 - pennylane/templates/state_preparations/basis.py | 1 - pennylane/templates/subroutines/permute.py | 1 - 4 files changed, 4 deletions(-) diff --git a/pennylane/templates/layers/particle_conserving_u2.py b/pennylane/templates/layers/particle_conserving_u2.py index de2a4e4f62e..e0ac00a8a17 100644 --- a/pennylane/templates/layers/particle_conserving_u2.py +++ b/pennylane/templates/layers/particle_conserving_u2.py @@ -192,7 +192,6 @@ def expand(self): for i, wires_ in enumerate(nm_wires): u2_ex_gate(self.parameters[0][l, len(self.wires) + i], wires=wires_) - return tape @staticmethod diff --git a/pennylane/templates/layers/random.py b/pennylane/templates/layers/random.py index 1ff792960a8..5a700260bd2 100644 --- a/pennylane/templates/layers/random.py +++ b/pennylane/templates/layers/random.py @@ -228,7 +228,6 @@ def expand(self): if len(self.wires) > 1: rnd_wires = self.wires.select_random(2) self.imprimitive(wires=rnd_wires) - return tape @staticmethod diff --git a/pennylane/templates/state_preparations/basis.py b/pennylane/templates/state_preparations/basis.py index a78e1ffe19f..5b326e938e5 100644 --- a/pennylane/templates/state_preparations/basis.py +++ b/pennylane/templates/state_preparations/basis.py @@ -77,5 +77,4 @@ def expand(self): for wire, state in zip(self.wires, self.parameters[0]): if state == 1: qml.PauliX(wire) - return tape diff --git a/pennylane/templates/subroutines/permute.py b/pennylane/templates/subroutines/permute.py index cdab13a0c57..1666c022871 100644 --- a/pennylane/templates/subroutines/permute.py +++ b/pennylane/templates/subroutines/permute.py @@ -186,5 +186,4 @@ def expand(self): working_order[idx_there], working_order[idx_here], ) - return tape From 6245c7125631f9a1c47197e058ed1408d4325a00 Mon Sep 17 00:00:00 2001 From: Josh Izaac Date: Sat, 24 Apr 2021 01:11:02 +0800 Subject: [PATCH 13/17] rever --- pennylane/ops/qubit.py | 2 +- tests/ops/test_qubit_ops.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pennylane/ops/qubit.py b/pennylane/ops/qubit.py index ad5ecd347d7..f98a3113833 100644 --- a/pennylane/ops/qubit.py +++ b/pennylane/ops/qubit.py @@ -2465,7 +2465,7 @@ def decomposition(state, wires): return MottonenStatePreparation(state, wires) def adjoint(self): - return qml.adjoint(MottonenStatePreparation)(self.parameters[0], wires=self.wires) + raise AdjointError("No adjoint exists for BasisState operations.") # ============================================================================= diff --git a/tests/ops/test_qubit_ops.py b/tests/ops/test_qubit_ops.py index 392324ac8ad..bcf0b2ff3c0 100644 --- a/tests/ops/test_qubit_ops.py +++ b/tests/ops/test_qubit_ops.py @@ -421,6 +421,7 @@ def test_adjoint_with_decomposition(self, op_builder): "op", [ qml.BasisState(np.array([0, 1]), wires=0), + qml.QubitStateVector(np.array([1.0, 0.0]), wires=0), ], ) def test_adjoint_error_exception(self, op, tol): From 9ee8f7379328b4bfe31d444146cdbb3293896185 Mon Sep 17 00:00:00 2001 From: Josh Izaac Date: Sat, 24 Apr 2021 01:12:50 +0800 Subject: [PATCH 14/17] typo --- pennylane/ops/qubit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pennylane/ops/qubit.py b/pennylane/ops/qubit.py index f98a3113833..2c930598c50 100644 --- a/pennylane/ops/qubit.py +++ b/pennylane/ops/qubit.py @@ -2465,7 +2465,7 @@ def decomposition(state, wires): return MottonenStatePreparation(state, wires) def adjoint(self): - raise AdjointError("No adjoint exists for BasisState operations.") + raise AdjointError("No adjoint exists for QubitStateVector operations.") # ============================================================================= From 0f65b615d8db15e1b189dfc8f6b7ddf0367153a9 Mon Sep 17 00:00:00 2001 From: Josh Izaac Date: Sat, 24 Apr 2021 01:24:16 +0800 Subject: [PATCH 15/17] typo --- pennylane/operation.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pennylane/operation.py b/pennylane/operation.py index 58c8a77d6f4..3289d49f25a 100644 --- a/pennylane/operation.py +++ b/pennylane/operation.py @@ -589,13 +589,16 @@ def inverse(self): """Boolean determining if the inverse of the operation was requested.""" return self._inverse - def adjoint(self): + def adjoint(self, do_queue=False): """Create an operation that is the adjoint of this one. Adjointed operations are the conjugated and transposed version of the original operation. Adjointed ops are equivalent to the inverted operation for unitary gates. + Args: + do_queue: Whether to add the adjointed gate to the context queue. + Returns: The adjointed operation. """ From f6dce731e099f0719bf7330f97872e3a0389bca1 Mon Sep 17 00:00:00 2001 From: Josh Izaac Date: Wed, 28 Apr 2021 20:50:00 +0800 Subject: [PATCH 16/17] Update tests/tape/test_tape.py Co-authored-by: antalszava --- tests/tape/test_tape.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/tape/test_tape.py b/tests/tape/test_tape.py index 0a11bcbee22..e1ccea41b3c 100644 --- a/tests/tape/test_tape.py +++ b/tests/tape/test_tape.py @@ -604,9 +604,7 @@ def test_inverse(self): tape.inv() # check that operation order is reversed - assert [o.name for o in tape.operations] == [ - o.name.replace(".inv", "") for o in [prep] + ops[::-1] - ] + assert [o.name for o in tape.operations] == ["BasisState", "CNOT", "Rot", "RX"] # check that operations are inverted assert np.allclose(tape.operations[2].parameters, -np.array(p[-1:0:-1])) From ffa9b20c2828bcef2ec90d21276163ffdc826f12 Mon Sep 17 00:00:00 2001 From: Josh Izaac Date: Wed, 28 Apr 2021 20:55:16 +0800 Subject: [PATCH 17/17] Apply suggestions from code review Co-authored-by: antalszava --- pennylane/templates/embeddings/amplitude.py | 2 +- tests/tape/test_tape.py | 2 +- tests/transforms/test_adjoint.py | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/pennylane/templates/embeddings/amplitude.py b/pennylane/templates/embeddings/amplitude.py index 063bd497d73..4c750c8de74 100644 --- a/pennylane/templates/embeddings/amplitude.py +++ b/pennylane/templates/embeddings/amplitude.py @@ -143,7 +143,7 @@ def __init__(self, features, wires, pad_with=None, normalize=False, pad=None, do features = self._preprocess(features, wires, pad_with, normalize) super().__init__(features, wires=wires, do_queue=do_queue) - def adjoint(self): + def adjoint(self): # pylint: disable=arguments-differ return qml.adjoint(qml.templates.MottonenStatePreparation)( self.parameters[0], wires=self.wires ) diff --git a/tests/tape/test_tape.py b/tests/tape/test_tape.py index e1ccea41b3c..5b78ea4da9c 100644 --- a/tests/tape/test_tape.py +++ b/tests/tape/test_tape.py @@ -634,7 +634,7 @@ def test_parameter_transforms(self): tape.inv() assert tape.trainable_params == {1, 2} assert tape.get_parameters() == [p[0], p[1]] - assert [o.name for o in tape._ops] == [o.name.replace(".inv", "") for o in ops] + assert [o.name for o in tape._ops] == ["RX", "Rot", "CNOT"] class TestExpand: diff --git a/tests/transforms/test_adjoint.py b/tests/transforms/test_adjoint.py index 92cbc14321d..a111df0ba93 100644 --- a/tests/transforms/test_adjoint.py +++ b/tests/transforms/test_adjoint.py @@ -183,7 +183,7 @@ def test_qaoa_embedding(self, fn): def circuit(features, weights): template(features=features, weights=weights, wires=[0, 1, 2]) fn(template, features=features, weights=weights, wires=[0, 1, 2]) - return qml.probs(wires=[0, 1, 2]) + return qml.state() features = np.array([1.0, 2.0, 3.0]) weights = np.random.random(template.shape(2, 3)) @@ -203,7 +203,7 @@ def test_iqp_embedding(self, fn): def circuit(features): template(features=features, wires=[0, 1, 2]) fn(template, features=features, wires=[0, 1, 2]) - return qml.probs(wires=[0, 1, 2]) + return qml.state() features = np.array([1.0, 2.0, 3.0]) res = circuit(features) @@ -228,7 +228,7 @@ def test_layers(self, fn, template): def circuit(weights): template(weights=weights, wires=[0, 1, 2]) fn(template, weights=weights, wires=[0, 1, 2]) - return qml.probs(wires=[0, 1, 2]) + return qml.state() weights = np.random.random(template.shape(2, 3)) res = circuit(weights) @@ -253,7 +253,7 @@ def test_particle_conserving(self, fn, template): def circuit(weights): template(weights=weights, init_state=init_state, wires=[0, 1, 2]) fn(template, weights=weights, init_state=init_state, wires=[0, 1, 2]) - return qml.probs(wires=[0, 1, 2]) + return qml.state() weights = np.random.random(template.shape(2, 3)) res = circuit(weights) @@ -271,7 +271,7 @@ def test_simplified_two_design(self, fn): def circuit(data, weights): template(initial_layer_weights=data, weights=weights, wires=[0, 1, 2]) fn(template, initial_layer_weights=data, weights=weights, wires=[0, 1, 2]) - return qml.probs(wires=[0, 1, 2]) + return qml.state() weights = [np.random.random(s) for s in template.shape(2, 3)] res = circuit(weights[0], *weights[1:]) @@ -293,7 +293,7 @@ def test_approx_time_evolution(self, fn): def circuit(t): template(H, t, 1) fn(template, H, t, 1) - return qml.probs(wires=[0, 1, 2]) + return qml.state() res = circuit(0.5) expected = np.zeros([2 ** 3]) @@ -309,7 +309,7 @@ def test_arbitrary_unitary(self, fn): def circuit(weights): template(weights=weights, wires=[0, 1, 2]) fn(template, weights=weights, wires=[0, 1, 2]) - return qml.probs(wires=[0, 1, 2]) + return qml.state() weights = np.random.random(template.shape(3)) res = circuit(weights) @@ -327,7 +327,7 @@ def test_single_excitation(self, fn): def circuit(weights): template(weight=weights, wires=[0, 1, 2]) fn(template, weight=weights, wires=[0, 1, 2]) - return qml.probs(wires=[0, 1, 2]) + return qml.state() res = circuit(0.6) expected = np.zeros([2 ** 3]) @@ -344,7 +344,7 @@ def test_double_excitation(self, fn): def circuit(weights): template(weight=weights, wires1=[0, 1], wires2=[2, 3]) fn(template, weight=weights, wires1=[0, 1], wires2=[2, 3]) - return qml.probs(wires=[0, 1, 2, 3]) + return qml.state() res = circuit(0.6) expected = np.zeros([2 ** 4])