def qnode(x1, x2, params, **kwargs): if self.noise_application_level == 'per_gate': add_noise_channel( ansatz(x1, params, **kwargs), self.noise_channel_mapped, self.idling_gate_noise_channel, ) else: ansatz(x1, params, **kwargs) if self.noise_application_level == 'per_embedding': # Invoke noise channel with default kwarg data. self.noise_channel(*self.args_noise_channel, wires=device.wires) elif self.noise_application_level == 'per_gate': add_noise_channel( ansatz(x2, params, **kwargs), self.noise_channel_mapped, self.idling_gate_noise_channel, adjoint=True, ) else: qml.adjoint(ansatz)(x2, params, **kwargs) if self.noise_application_level in ('per_embedding', 'global'): # Invoke noise channel with default kwarg data. self.noise_channel(*self.args_noise_channel, wires=device.wires) return qml.probs(wires=device.wires)
def test_adjoint_of_control(): """Test adjoint(ctrl(fn)) and ctrl(adjoint(fn))""" def my_op(a, b, c): qml.RX(a, wires=2) qml.RY(b, wires=3) qml.RZ(c, wires=0) with QuantumTape() as tape1: cmy_op_dagger = qml.adjoint(ctrl(my_op, 5)) # Execute controlled and adjointed version of my_op. cmy_op_dagger(0.789, 0.123, c=0.456) with QuantumTape() as tape2: cmy_op_dagger = ctrl(qml.adjoint(my_op), 5) # Execute adjointed and controlled version of my_op. cmy_op_dagger(0.789, 0.123, c=0.456) expected = [ qml.CRZ(-0.456, wires=[5, 0]), qml.CRY(-0.123, wires=[5, 3]), qml.CRX(-0.789, wires=[5, 2]), ] for tape in [tape1, tape2]: assert len(tape.operations) == 1 ctrl_op = tape.operations[0] assert isinstance(ctrl_op, ControlledOperation) expanded = ctrl_op.expand() assert_equal_operations(expanded.operations, expected)
def circuit(phi): qml.PauliX(wires=0) qml.PauliX(wires=1) qml.OrbitalRotation(phi, wires=[0, 1, 2, 3]) qml.adjoint(qml.OrbitalRotation)(phi, wires=[0, 1, 2, 3]) qml.PauliX(wires=0) qml.PauliX(wires=1) return qml.state()
def test_adjoint_with_decomposition(op_builder): """Tests the ``QubitCarry`` op under adjoint and decomposition.""" op = op_builder() decomposed_ops = op.decompose() with qml.tape.QuantumTape() as adjoint_tape: qml.adjoint(op_builder)() for a, b in zip(decomposed_ops, reversed(adjoint_tape.operations)): np.testing.assert_allclose(a.matrix, np.conj(b.matrix).T)
def qfunc(theta): qml.Hadamard(wires=0) qml.PauliX(wires=1) qml.S(wires=1) qml.adjoint(qml.S)(wires=1) qml.Hadamard(wires=0) qml.CNOT(wires=[0, 1]) qml.RZ(theta[0], wires=2) qml.PauliX(wires=1) qml.CZ(wires=[1, 0]) qml.RY(theta[1], wires=2) qml.CZ(wires=[0, 1]) return qml.expval(qml.PauliX(0) @ qml.PauliX(2))
def test_single_op_non_param_adjoint(self, op, wires): """Test that the adjoint correctly inverts non-parametrized operations""" op_adjoint = qml.adjoint(op)(wires=wires) expected = op(wires=wires).adjoint() assert type(op_adjoint) == type(expected) assert op_adjoint.wires == expected.wires
def test_single_op_param_adjoint(self, op, par, wires): """Test that the adjoint correctly inverts operations with a single parameter""" param_op_adjoint = qml.adjoint(op)(*par, wires=wires) expected = op(*par, wires=wires).adjoint() assert type(param_op_adjoint) == type(expected) assert param_op_adjoint.parameters == expected.parameters assert param_op_adjoint.wires == expected.wires
def qpe_circuit(): qml.Hadamard(wires=0) qml.PauliX(wires=1) qml.QuantumPhaseEstimation( qml.PauliX.matrix, target_wires=[0], estimation_wires=[1, 2], ) qml.adjoint(qml.QuantumPhaseEstimation)( qml.PauliX.matrix, target_wires=[0], estimation_wires=[1, 2], ) qml.Hadamard(wires=0) qml.PauliX(wires=1) return qml.state()
def test_cv_template_adjoint(self): """Test that the adjoint correctly inverts CV templates""" template, par, wires = qml.templates.Interferometer, [[1], [0.3], [0.2, 0.3]], [2, 3] result = qml.adjoint(template)(*par, wires=wires) expected_ops = template(*par, wires=wires) for o1, o2 in zip(result, reversed(expected_ops)): o2 = o2.adjoint() assert type(o1) == type(o2) assert o1.parameters == o2.parameters assert o1.wires == o2.wires
def test_templates_adjoint(self, template, par, wires): """Test that the adjoint correctly inverts templates""" res = qml.adjoint(template)(*par, wires=wires) result = res if hasattr( res, "__iter__") else [res] # handle single operation case expected_ops = template(*par, wires=wires) expected_ops = expected_ops.expand().operations for o1, o2 in zip(result, reversed(expected_ops)): o2 = o2.adjoint() assert type(o1) == type(o2) assert o1.parameters == o2.parameters assert o1.wires == o2.wires
def test_single_par_op(self): """Test a single parametrized operation for the adjoint method of ControlledOperation""" op, par, control_wires, wires = qml.RY, np.array(0.3), qml.wires.Wires(1), [2] adjoint_of_controlled_op = qml.ctrl(op, control=control_wires)(par, wires=wires).adjoint() assert adjoint_of_controlled_op.control_wires == control_wires res_ops = adjoint_of_controlled_op.subtape.operations op1 = res_ops[0] op2 = qml.adjoint(op)(par, wires=wires) assert type(op1) == type(op2) assert op1.parameters == op2.parameters assert op1.wires == op2.wires
def test_template(self): """Test a template for the adjoint method of ControlledOperation""" op, par = qml.templates.StronglyEntanglingLayers, np.ones((1, 2, 3)) control_wires, wires = qml.wires.Wires(1), [2, 3] adjoint_of_controlled_op = qml.ctrl(op, control=control_wires)(par, wires=wires).adjoint() assert adjoint_of_controlled_op.control_wires == control_wires res_ops = adjoint_of_controlled_op.subtape.operations[0].operations expected = qml.adjoint(op)(par, wires=wires) for op1, op2 in zip(res_ops, expected): assert type(op1) == type(op2) assert op1.parameters == op2.parameters assert op1.wires == op2.wires
def test_cv_template(self): """Test a CV template that returns a list of operations for the adjoint method of ControlledOperation""" op, par = qml.templates.Interferometer, [[1], [0.3], [0.2, 0.3]] control_wires, wires = qml.wires.Wires(1), [2, 3] adjoint_of_controlled_op = qml.ctrl(op, control=control_wires)(*par, wires=wires).adjoint() assert adjoint_of_controlled_op.control_wires == control_wires res_ops = adjoint_of_controlled_op.subtape.operations[0].expand().operations expected = qml.adjoint(op)(*par, wires=wires).expand().operations for op1, op2 in zip(res_ops, expected): assert type(op1) == type(op2) assert op1.parameters == op2.parameters assert op1.wires == op2.wires
def adjoint(self): # pylint: disable=arguments-differ return qml.adjoint(qml.MottonenStatePreparation)(self.parameters[0], wires=self.wires)
def circuit(): qml.CVNeuralNetLayers(*weights, wires=[0, 1]) qml.adjoint(qml.CVNeuralNetLayers)(*weights, wires=[0, 1]) return qml.expval(qml.X(0))
i += inc qml.RY(params[0, j], wires=[wire]) qml.broadcast(unitary=qml.CRZ, pattern="ring", wires=wires, parameters=params[1]) def ansatz(x, params, wires): """The embedding ansatz""" for j, layer_params in enumerate(params): layer(x, layer_params, wires, i0=j * len(wires)) adjoint_ansatz = qml.adjoint(ansatz) def random_params(num_wires, num_layers): """Generate random variational parameters in the shape for the ansatz.""" return np.random.uniform(0, 2 * np.pi, (num_layers, 2, num_wires)) # The kernel function itself is now obtained by looking at the probability # of observing the all-zero state at the end of the kernel circuit – # because of the ordering in qml.probs, this is the first entry: def kernel(x1, x2, params): return kernel_circuit(x1, x2, params)[0] # ## Init QEK
def circuit(): # Adjoint is RX(-0.2), so expect RY(-0.2) H qml.adjoint(qml.RX)(0.2, wires="a") return qml.expval(qml.PauliZ("a"))
def mitigated_qnode(w1, w2): qml.SimplifiedTwoDesign(w1, w2, wires=range(2)) qml.adjoint(qml.SimplifiedTwoDesign)(w1, w2, wires=range(2)) return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1))
def my_circuit(): qml.adjoint(qml.Barrier)(wires=0) return qml.state()
def kernel_circuit(x1, x2): qml.templates.AngleEmbedding(x1, wires=wires) qml.adjoint(qml.templates.AngleEmbedding)(x2, wires=wires) return qml.probs(wires)
def circuit(): identity() qml.adjoint(identity)() return qml.state()
def adjoint_evolution_circuit(time): for i in range(n_wires): qml.Hadamard(i) qml.adjoint(qml.CommutingEvolution)(hamiltonian, time, frequencies) return qml.expval(qml.PauliZ(1))
def circuit(): barrier() qml.adjoint(barrier)() return qml.state()
def circ(n_qubits): qml.adjoint(qml.templates.QFT)(wires=range(n_qubits)) qml.templates.QFT(wires=range(n_qubits)) return qml.state()
def kernel(x1, x2): """The quantum kernel.""" AngleEmbedding(x1, wires=range(n_qubits)) qml.adjoint(AngleEmbedding)(x2, wires=range(n_qubits)) return qml.expval(qml.Hermitian(projector, wires=range(n_qubits)))
def kernel(x1, x2, params): ansatz(x1, params, wires) qml.adjoint(ansatz)(x2, params, wires) return qml.expval(qml.Projector([0] * width, wires=wires))
def kernel_circuit(x1, x2, params): ansatz(x1, params, wires=wires) qml.adjoint(ansatz(x2, params, wires=wires)) return qml.probs(wires=wires)
def inv(operation_list): """Invert a list of operations or a :doc:`template </introduction/templates>`. If the inversion happens inside a QNode, the operations are removed and requeued in the reversed order for proper inversion. **Example:** The following example illuminates the inversion of a template: .. code-block:: python3 @qml.template def ansatz(weights, wires): for idx, wire in enumerate(wires): qml.RX(weights[idx], wires=[wire]) for idx in range(len(wires) - 1): qml.CNOT(wires=[wires[idx], wires[idx + 1]]) dev = qml.device('default.qubit', wires=2) @qml.qnode(dev) def circuit(weights): qml.inv(ansatz(weights, wires=[0, 1])) return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) We may also invert an operation sequence: .. code-block:: python3 dev = qml.device('default.qubit', wires=2) @qml.qnode(dev) def circuit1(): qml.T(wires=[0]).inv() qml.Hadamard(wires=[0]).inv() qml.S(wires=[0]).inv() return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) @qml.qnode(dev) def circuit2(): qml.inv([qml.S(wires=[0]), qml.Hadamard(wires=[0]), qml.T(wires=[0])]) return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)) Double checking that both circuits produce the same output: >>> ZZ1 = circuit1() >>> ZZ2 = circuit2() >>> assert ZZ1 == ZZ2 True Args: operation_list (Iterable[~.Operation]): An iterable of operations Returns: List[~.Operation]: The inverted list of operations """ if isinstance(operation_list, qml.operation.Operation): operation_list = [operation_list] elif operation_list is None: raise ValueError( "None was passed as an argument to inv. " "This could happen if inversion of a template without the template decorator is attempted." ) elif callable(operation_list): raise ValueError( "A function was passed as an argument to inv. " "This could happen if inversion of a template function is attempted. " "Please use inv on the function including its arguments, as in inv(template(args))." ) elif isinstance(operation_list, qml.tape.QuantumTape): new_tape = operation_list.adjoint() return new_tape elif not isinstance(operation_list, Iterable): raise ValueError("The provided operation_list is not iterable.") non_ops = [ (idx, op) for idx, op in enumerate(operation_list) if not isinstance(op, qml.operation.Operation) ] if non_ops: string_reps = [" operation_list[{}] = {}".format(idx, op) for idx, op in non_ops] raise ValueError( "The given operation_list does not only contain Operations." + "The following elements of the iterable were not Operations:" + ",".join(string_reps) ) for op in operation_list: try: # remove the queued operation to be inverted # from the existing queuing context qml.QueuingContext.remove(op) except KeyError: # operation to be inverted does not # exist on the queuing context pass def qfunc(): for o in operation_list: o.queue() with qml.tape.QuantumTape() as tape: qml.adjoint(qfunc)() return tape
def circuit(w1, w2): qml.SimplifiedTwoDesign(w1, w2, wires=range(2)) qml.adjoint(qml.SimplifiedTwoDesign)(w1, w2, wires=range(2)) return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1))
def f(state): qml.QubitStateVector(state, wires=range(3)) qml.adjoint(qml.QubitSum)(wires=range(3)) return qml.probs(wires=range(3))