def test_decomposition(self, tol): """Test decomposition onto a device's supported gate set""" dev = qml.device("default.qubit", wires=1) with QuantumTape() as tape: qml.U3(0.1, 0.2, 0.3, wires=[0]) qml.expval(qml.PauliZ(0)) tape = tape.expand(stop_at=lambda obj: obj.name in dev.operations) res = tape.execute(dev) assert np.allclose(res, np.cos(0.1), atol=tol, rtol=0)
def test_no_decomposition_defined(): """Test that a controlled gate that has no control transform defined, as well as no decomposition transformed defined, still works correctly""" with QuantumTape() as tape: ctrl(qml.CZ, 0)(wires=[1, 2]) tape = expand_tape(tape) assert len(tape.operations) == 1 assert tape.operations[0].name == "ControlledQubitUnitary"
def test_nested_control(): """Test nested use of control""" with QuantumTape() as tape: CCX = ctrl(ctrl(qml.PauliX, 7), 3) CCX(wires=0) assert len(tape.operations) == 1 op = tape.operations[0] assert isinstance(op, ControlledOperation) new_tape = expand_tape(tape, 2) assert_equal_operations(new_tape.operations, [qml.Toffoli(wires=[7, 3, 0])])
def test_multi_control(): """Test control with a list of wires.""" with QuantumTape() as tape: CCX = ctrl(qml.PauliX, control=[3, 7]) CCX(wires=0) assert len(tape.operations) == 1 op = tape.operations[0] assert isinstance(op, ControlledOperation) new_tape = expand_tape(tape, 1) assert_equal_operations(new_tape.operations, [qml.Toffoli(wires=[7, 3, 0])])
def test_CRX_decimals(self): """Test a controlled parametric operation with specified decimals.""" with QuantumTape() as tape: qml.CRX(1.234, wires=(0, 1)) _, ax = tape_mpl(tape, decimals=2) # two wire labels, so CRX is third text object assert ax.texts[2].get_text() == "RX\n(1.23)" plt.close()
def test_no_control_defined(): """Test a custom operation with no control transform defined.""" # QFT has no control rule defined. with QuantumTape() as tape: ctrl(qml.QFT, 2)(wires=[0, 1]) tape = expand_tape(tape) assert len(tape.operations) == 12 # Check that all operations are updated to their controlled version. for op in tape.operations: assert type(op) in { qml.ControlledPhaseShift, qml.Toffoli, qml.CRX, qml.CSWAP }
def make_tape(self): params = [0.432, 0.123, 0.546, 0.32, 0.76] with QuantumTape() as tape: qml.RX(params[0], wires=0) qml.Rot(*params[1:4], wires=0) qml.CNOT(wires=[0, "a"]) qml.RX(params[4], wires=4) qml.expval(qml.PauliX(wires="a")) qml.probs(wires=[0, "a"]) return tape, params
def test_stopping_criterion(self): """Test that gates specified in the stop_at argument are not expanded.""" with QuantumTape() as tape: qml.U3(0, 1, 2, wires=0) qml.Rot(3, 4, 5, wires=0) qml.probs(wires=0), qml.probs(wires="a") new_tape = tape.expand(stop_at=lambda obj: obj.name in ["Rot"]) assert len(new_tape.operations) == 4 assert "Rot" in [i.name for i in new_tape.operations] assert not "U3" in [i.name for i in new_tape.operations]
def test_expand_tape_multiple_wires_non_commuting(self, ret): """Test if a QuantumFunctionError is raised during tape expansion if non-commuting observables are on the same wire""" with QuantumTape() as tape: qml.RX(0.3, wires=0) qml.RY(0.4, wires=1) qml.expval(qml.PauliX(0)) ret(qml.PauliZ(0)) with pytest.raises(qml.QuantumFunctionError, match="Only observables that are qubit-wise"): tape.expand(expand_measurements=True)
def test_general_operations_decimals(self, op): """Check that the decimals argument affects text strings when applicable.""" with QuantumTape() as tape: qml.apply(op) _, ax = tape_mpl(tape, decimals=2) num_wires = len(op.wires) assert ax.texts[num_wires].get_text() == op.label(decimals=2) plt.close()
def test_state_preparation(self): """Test that state preparations are correctly processed""" params = [np.array([1, 0, 1, 0]) / np.sqrt(2), 1] with QuantumTape() as tape: A = qml.QubitStateVector(params[0], wires=[0, 1]) B = qml.RX(params[1], wires=0) qml.expval(qml.PauliZ(wires=1)) assert tape.operations == [A, B] assert tape._prep == [A] assert tape.get_parameters() == params
def wrapper(*args, **kwargs): with get_active_tape().stop_recording(), QuantumTape() as tape: fn(*args, **kwargs) for op in reversed(tape.queue): try: op.adjoint() except NotImplementedError: # Expand the operation and adjoint the result. # We do not do anything with the output since # calling adjoint on the expansion will automatically # queue the new operations. adjoint(op.expand)()
def test_controlled_template(): """Test that a controlled template correctly expands on a device that doesn't support it""" weights = np.ones([3, 2]) with QuantumTape() as tape: ctrl(qml.templates.BasicEntanglerLayers, 0)(weights, wires=[1, 2]) tape = expand_tape(tape) assert len(tape.operations) == 9 assert all(o.name in {"CRX", "Toffoli"} for o in tape.operations)
def test_active_wire_notches_False(self): """Test active wire notches are disable with active_wire_notches=False.""" with QuantumTape() as tape: qml.QFT(wires=(0, 3)) _, ax = tape_mpl(tape, show_all_wires=True, wire_order=[0, 1, 2, 3], active_wire_notches=False) assert len(ax.patches) == 1
def test_batch_execute_partial_fail_parallel_tracker(mock_run_batch): """Asserts tracker updates during a partial failure of parallel execution""" FAIL_TASK = Mock() FAIL_TASK.result.return_value = None type(FAIL_TASK).id = PropertyMock(return_value="failed_task_arn") FAIL_TASK.state.return_value = "FAILED" FAIL_BATCH = Mock() FAIL_BATCH.results.side_effect = RuntimeError("tasks failed to complete") type(FAIL_BATCH).tasks = PropertyMock(return_value=[SIM_TASK, FAIL_TASK]) type(FAIL_BATCH).unsuccessful = PropertyMock( return_value={"failed_task_arn"}) mock_run_batch.return_value = FAIL_BATCH dev = _aws_device(wires=1, foo="bar", parallel=True) with QuantumTape() as circuit: qml.Hadamard(wires=0) qml.probs(wires=(0, )) circuits = [circuit, circuit] callback = Mock() try: with qml.Tracker(dev, callback=callback) as tracker: dev.batch_execute(circuits) dev.batch_execute(circuits) except RuntimeError: pass latest = {"batches": 1, "executions": 1, "shots": 1 * SHOTS} history = { "batches": [1], "executions": [1], "shots": [1 * SHOTS], "braket_task_id": ["task_arn"], "braket_failed_task_id": ["failed_task_arn"], "braket_simulator_ms": [1234], "braket_simulator_billed_ms": [3000], } totals = { "batches": 1, "executions": 1, "shots": 1 * SHOTS, "braket_simulator_ms": 1234, "braket_simulator_billed_ms": 3000, } assert tracker.latest == latest assert tracker.history == history assert tracker.totals == totals callback.assert_called_with(latest=latest, history=history, totals=totals)
def test_Barrier(self): """Test Barrier gets correct special call.""" with QuantumTape() as tape: qml.Barrier(wires=(0, 1, 2)) _, ax = tape_mpl(tape) layer = 0 assert len(ax.lines) == 3 assert len(ax.collections) == 2 plt.close()
def test_no_output_execute(self): """Test that tapes with no measurement process return an empty list.""" dev = qml.device("default.qubit", wires=2) params = [0.1, 0.2] with QuantumTape() as tape: qml.RX(params[0], wires=[0]) qml.RY(params[1], wires=[1]) res = tape.execute(dev) assert res.size == 0 assert np.all(res == np.array([]))
def adjoint(self): """Returns a new ControlledOperation that is equal to the adjoint of `self`""" active_tape = get_active_tape() if active_tape is not None: with get_active_tape().stop_recording(), QuantumTape() as new_tape: # Execute all ops adjointed. adjoint(requeue_ops_in_tape)(self.subtape) else: # Not within a queuing context with QuantumTape() as new_tape: # Execute all ops adjointed. ops = adjoint(requeue_ops_in_tape)(self.subtape) if not new_tape.operations: with qml.tape.QuantumTape() as new_tape: for op in ops: op.queue() return ControlledOperation(new_tape, self.control_wires)
def test_expand_tape_multiple_wires(self): """Test the expand() method when measurements with more than one observable on the same wire are used""" with QuantumTape() as tape1: qml.RX(0.3, wires=0) qml.RY(0.4, wires=1) qml.expval(qml.PauliX(0)) qml.var(qml.PauliX(0) @ qml.PauliX(1)) qml.expval(qml.PauliX(2)) with QuantumTape() as tape2: qml.RX(0.3, wires=0) qml.RY(0.4, wires=1) qml.RY(-np.pi / 2, wires=0) qml.RY(-np.pi / 2, wires=1) qml.expval(qml.PauliZ(0)) qml.var(qml.PauliZ(0) @ qml.PauliZ(1)) qml.expval(qml.PauliX(2)) tape1_exp = tape1.expand() assert tape1_exp.graph.hash == tape2.graph.hash
def test_WireCut(self): """Test WireCut gets correct special call.""" with QuantumTape() as tape: qml.WireCut(wires=(0, 1)) _, ax = tape_mpl(tape) layer = 0 assert len(ax.lines) == 2 assert len(ax.collections) == 2 plt.close()
def test_tensor_process_queuing(self): """Test that tensors are correctly queued""" with QuantumTape() as tape: A = qml.PauliX(wires=0) B = qml.PauliZ(wires=1) C = A @ B D = qml.expval(C) assert len(tape.queue) == 4 assert not tape.operations assert tape.measurements == [D] assert tape.observables == [C] assert tape.output_dim == 1
def expand_with_control(tape, control_wire): """Expand a tape to include a control wire on all queued operations. Args: tape (.QuantumTape): quantum tape to be controlled control_wire (int): a single wire to use as the control wire Returns: .QuantumTape: A new QuantumTape with the controlled operations. """ with QuantumTape(do_queue=False) as new_tape: for op in tape.operations: if hasattr(op, "_controlled"): # Execute the controlled version of the operation # and add that the to the tape context. # pylint: disable=protected-access op._controlled(control_wire) else: # Attempt to decompose the operation and apply # controls to each gate in the decomposition. with new_tape.stop_recording(): try: tmp_tape = op.expand() except NotImplementedError: # No decomposition is defined. Create a # ControlledQubitUnitary gate using the operation # matrix representation. with QuantumTape() as tmp_tape: qml.ControlledQubitUnitary( op.matrix, control_wires=control_wire, wires=op.wires) tmp_tape = expand_with_control(tmp_tape, control_wire) requeue_ops_in_tape(tmp_tape) return new_tape
def test_sampling(self): """Test sampling works as expected""" dev = qml.device("default.qubit", wires=2, shots=10) with TorchInterface.apply(QuantumTape()) as tape: qml.Hadamard(wires=[0]) qml.CNOT(wires=[0, 1]) qml.sample(qml.PauliZ(0)) qml.sample(qml.PauliX(1)) res = tape.execute(dev) assert res.shape == (2, 10) assert isinstance(res, torch.Tensor)
def test_tensor_observables_matmul(self): """Test that tensor observables are correctly processed from the annotated queue. Here, we test multiple tensor observables constructed via matmul.""" with QuantumTape() as tape: op = qml.RX(1.0, wires=0) t_obs1 = qml.PauliZ(0) @ qml.PauliX(1) t_obs2 = t_obs1 @ qml.PauliZ(3) m = qml.expval(t_obs2) assert tape.operations == [op] assert tape.observables == [t_obs2] assert tape.measurements[0].return_type is qml.operation.Expectation assert tape.measurements[0].obs is t_obs2
def make_tape(self): ops = [] obs = [] with QuantumTape() as tape: ops += [qml.RX(0.432, wires=0)] ops += [qml.Rot(0.543, 0, 0.23, wires=0)] ops += [qml.CNOT(wires=[0, "a"])] ops += [qml.RX(0.133, wires=4)] obs += [qml.PauliX(wires="a")] qml.expval(obs[0]) obs += [qml.probs(wires=[0, "a"])] return tape, ops, obs
def test_multiple_observables_same_wire(self): """Test if an error is raised when multiple observables are evaluated on the same wire without first running tape.expand().""" dev = qml.device("default.qubit", wires=2) with QuantumTape() as tape: qml.expval(qml.PauliX(0) @ qml.PauliZ(1)) qml.expval(qml.PauliX(0)) with pytest.raises(qml.QuantumFunctionError, match="Multiple observables are being"): tape.execute(dev) new_tape = tape.expand() new_tape.execute(dev)
def test_empty_tape_wire_order(self): """Test situation with empty tape but specified wires and show_all_wires still draws wires.""" _, ax = tape_mpl(QuantumTape(), wire_order=[0, 1, 2], show_all_wires=True) assert len(ax.lines) == 3 for wire, line in enumerate(ax.lines): assert line.get_xdata() == (-1, 1) # from -1 to number of layers assert line.get_ydata() == (wire, wire) plt.close()
def test_decomposition_removing_parameters(self): """Test that decompositions which reduce the number of parameters on the tape retain tape consistency.""" with QuantumTape() as tape: qml.BasisState(np.array([1]), wires=0) new_tape = tape.expand() assert len(new_tape.operations) == 1 assert new_tape.operations[0].name == "PauliX" assert new_tape.operations[0].wires.tolist() == [0] assert new_tape.num_params == 0 assert new_tape.get_parameters() == [] assert isinstance(new_tape.operations[0], qml.PauliX)
def test_single_mode_sample(self): """Test that there is only one array of values returned for a single wire qml.sample""" dev = qml.device("default.qubit", wires=2, shots=10) x = 0.543 y = -0.654 with QuantumTape() as tape: qml.RX(x, wires=[0]) qml.RY(y, wires=[1]) qml.CNOT(wires=[0, 1]) qml.sample(qml.PauliZ(0) @ qml.PauliX(1)) res = tape.execute(dev) assert res.shape == (1, 10)
def test_same_hash(self): """Test that executing the same tape twice produces the same circuit hash.""" dev = qml.device("default.qubit", wires=2) with QuantumTape() as tape0: qml.RZ(0.3, wires=[0]) qml.expval(qml.PauliX(0)) tape0.execute(dev) orig_hash = dev.circuit_hash tape0.execute(dev) new_hash = dev.circuit_hash assert orig_hash == new_hash