def test_state_handle() -> None: b = ForestStateBackend() c0 = Circuit(1) c1 = Circuit(1) c1.X(0) b.compile_circuit(c0) b.compile_circuit(c1) state0 = b.get_state(c0) state1 = b.get_state(c1) assert np.allclose(state0, np.asarray([1.0, 0.0])) assert np.allclose(state1, np.asarray([0.0, 1.0]))
def test_statevector(qvm: None, quilc: None) -> None: c = circuit_gen() b = ForestStateBackend() state = b.get_state(c) assert np.allclose(state, np.asarray([math.sqrt(0.5), 0, 0, math.sqrt(0.5)]), atol=1e-10) c.add_phase(0.5) state1 = b.get_state(c) assert np.allclose(state1, state * 1j, atol=1e-10)
def test_default_pass_2() -> None: b = ForestStateBackend() for ol in range(3): comp_pass = b.default_compilation_pass(ol) c = Circuit(3, 3) c.H(0) c.CX(0, 1) c.CSWAP(1, 0, 2) c.ZZPhase(0.84, 2, 0) comp_pass.apply(c) for pred in b.required_predicates: assert pred.verify(c)
def test_ilo(qvm: None, quilc: None) -> None: b = ForestBackend("9q-square") bs = ForestStateBackend() c = Circuit(2) c.CZ(0, 1) c.Rx(1.0, 1) assert np.allclose(bs.get_state(c), np.asarray([0, -1j, 0, 0])) assert np.allclose(bs.get_state(c, basis=BasisOrder.dlo), np.asarray([0, 0, -1j, 0])) c.rename_units({Qubit(0): Node(0), Qubit(1): Node(1)}) c.measure_all() assert (b.get_shots(c, 2) == np.asarray([[0, 1], [0, 1]])).all() assert (b.get_shots(c, 2, basis=BasisOrder.dlo) == np.asarray([[1, 0], [1, 0]])).all() assert b.get_counts(c, 2) == {(0, 1): 2} assert b.get_counts(c, 2, basis=BasisOrder.dlo) == {(1, 0): 2}
def test_pauli_statevector(qvm: None, quilc: None) -> None: c = Circuit(2, 2) c.Rz(0.5, 0) b = ForestStateBackend() zi = QubitPauliString(Qubit(0), Pauli.Z) assert get_pauli_expectation_value(c, zi, b) == 1 c.X(0) assert get_pauli_expectation_value(c, zi, b) == -1
def test_symbolic(qvm) -> None: pi2 = Symbol("pi2") pi3 = Symbol("pi3") tkc = Circuit(2).Rx(pi2, 1).Rx(-pi3, 1).CX(1, 0) RemoveRedundancies().apply(tkc) prog = tk_to_pyquil(tkc) tkc2 = pyquil_to_tk(prog) assert tkc2.free_symbols() == {pi2, pi3} tkc2.symbol_substitution({pi2: pi / 2, pi3: -pi / 3}) backend = ForestStateBackend() state1 = backend.get_state(tkc2) state0 = np.array( [-0.56468689 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.82530523j]) assert np.allclose(state0, state1)
def test_swaps_basisorder() -> None: # Check that implicit swaps can be corrected irrespective of BasisOrder b = ForestStateBackend() c = Circuit(4) c.X(0) c.CX(0, 1) c.CX(1, 0) CliffordSimp(True).apply(c) assert c.n_gates_of_type(OpType.CX) == 1 b.compile_circuit(c) s_ilo = b.get_state(c, basis=BasisOrder.ilo) s_dlo = b.get_state(c, basis=BasisOrder.dlo) correct_ilo = np.zeros((16, )) correct_ilo[4] = 1.0 assert np.allclose(s_ilo, correct_ilo) correct_dlo = np.zeros((16, )) correct_dlo[2] = 1.0 assert np.allclose(s_dlo, correct_dlo)
def test_operator_statevector(qvm: None, quilc: None) -> None: c = Circuit(2, 2) c.Rz(0.5, 0) b = ForestStateBackend() zi = QubitPauliString(Qubit(0), Pauli.Z) iz = QubitPauliString(Qubit(1), Pauli.Z) op = QubitPauliOperator({zi: 0.3, iz: -0.1}) assert get_operator_expectation_value(c, op, b) == pytest.approx(0.2) c.X(0) assert get_operator_expectation_value(c, op, b) == pytest.approx(-0.4)
optimise = SequencePass([KAKDecomposition(), CliffordSimp(False), SynthesiseIBM()]) optimise.apply(tk_circ) # Display the optimised circuit: print(tk_to_qiskit(tk_circ)) # The Backends in `pytket` abstract away the differences between different devices and simulators as much as possible, allowing painless switching between them. The `pytket_pyquil` package provides two Backends: `ForestBackend` encapsulates both running on physical devices via Rigetti QCS and simulating those devices on the QVM, and `ForestStateBackend` acts as a wrapper to the pyQuil Wavefunction Simulator. # # Both of these still have a few restrictions on the circuits that can be run. Each only supports a subset of the gate types available in `pytket`, and a real device or associated simulation will have restricted qubit connectivity. The Backend objects will contain a default compilation pass that will statisfy these constraints as much as possible, with minimal or no optimisation. # # The `ForestStateBackend` will allow us to view the full statevector (wavefunction) expected from a perfect execution of the circuit. from pytket.extensions.pyquil import ForestStateBackend state_backend = ForestStateBackend() state_backend.compile_circuit(tk_circ) state = state_backend.get_state(tk_circ) print(state) # For users who are familiar with the Forest SDK, the association of qubits to indices of bitstrings (and consequently the ordering of statevectors) used by default in `pytket` Backends differs from that described in the [Forest docs](http://docs.rigetti.com/en/stable/wavefunction_simulator.html#multi-qubit-basis-enumeration). You can recover the ordering used by the Forest systems with `state_backend.get_state(tk_circ, basis:pytket.BasisOrder.dlo)` (see our docs on the `BasisOrder` enum for more details). # Connecting to real devices works very similarly. Instead of obtaining the full statevector, we are only able to measure the quantum state and sample from the resulting distribution. Beyond that, the process is pretty much the same. # # The following shows how to run the circuit on the "9q-square" lattice. The `simulator` switch on the `ForestBackend` will switch between connecting to the real Aspen device and the QVM, allowing you to test your code with a simulator before you reserve your slot with the device. tk_circ.measure_all() from pytket.extensions.pyquil import ForestBackend