def __init__(self, backend: BaseBackend, optimisation_level: int = 1): """Identifies a Qiskit backend and provides the corresponding default compilation pass from pytket as a :py:class:`qiskit.transpiler.TransformationPass`. :param backend: The Qiskit backend to target. Accepts Aer or IBMQ backends. :type backend: BaseBackend :param optimisation_level: The level of optimisation to perform during compilation. Level 0 just solves the device constraints without optimising. Level 1 additionally performs some light optimisations. Level 2 adds more intensive optimisations that can increase compilation time for large circuits. Defaults to 1. :type optimisation_level: int, optional """ if not isinstance(backend, BaseBackend): raise ValueError("Requires BaseBackend instance") if isinstance(backend._provider, AerProvider): tk_backend = self._aer_backend_map[type(backend).__name__]() elif isinstance(backend._provider, AccountProvider): tk_backend = IBMQBackend(backend.name()) else: raise NotImplementedError( "This backend provider is not supported.") super().__init__( tk_backend.default_compilation_pass(optimisation_level))
def test_compile_x() -> None: # TKET-1028 b = IBMQBackend("ibmq_santiago", hub="ibm-q", group="open", project="main") c = Circuit(1).X(0) for ol in range(3): c1 = c.copy() b.compile_circuit(c1, optimisation_level=ol) assert c1.n_gates == 1
def test_default_pass() -> None: b = IBMQBackend("ibmq_santiago", hub="ibm-q", group="open", project="main") 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) c.measure_all() comp_pass.apply(c) for pred in b.required_predicates: assert pred.verify(c)
def test_remote_simulator() -> None: remote_qasm = IBMQBackend("ibmq_qasm_simulator", hub="ibm-q", group="open", project="main") c = Circuit(3).CX(0, 1) c.add_gate(OpType.ZZPhase, 0.1, [0, 1]) c.add_gate(OpType.CY, [0, 1]) c.add_gate(OpType.CCX, [0, 1, 2]) c.measure_all() assert remote_qasm.valid_circuit(c) assert sum(remote_qasm.get_counts(c, 10).values()) == 10
def test_cancellation_ibmq() -> None: b = IBMQBackend("ibmq_santiago", hub="ibm-q", group="open", project="main") c = circuit_gen(True) b.compile_circuit(c) h = b.process_circuit(c, 10) b.cancel(h) print(b.circuit_status(h))
def test_device() -> None: c = circuit_gen(False) b = IBMQBackend("ibmq_santiago", hub="ibm-q", group="open", project="main") assert b._max_per_job == 75 operator = QubitPauliOperator({ QubitPauliString(Qubit(0), Pauli.Z): 1.0, QubitPauliString(Qubit(0), Pauli.X): 0.5, }) val = get_operator_expectation_value(c, operator, b, 8000) print(val) c1 = circuit_gen(True) c2 = circuit_gen(True) b.compile_circuit(c1) b.compile_circuit(c2) print(b.get_shots(c1, n_shots=10)) print(b.get_shots(c2, n_shots=10))
def test_compilation_correctness() -> None: c = Circuit(5) c.H(0).H(1).H(2) c.CX(0, 1).CX(1, 2) c.Rx(0.25, 1).Ry(0.75, 1).Rz(0.5, 2) c.CCX(2, 1, 0) c.CY(1, 0).CY(2, 1) c.H(0).H(1).H(2) c.Rz(0.125, 0) c.X(1) c.Rz(0.125, 2).X(2).Rz(0.25, 2) c.SX(3).Rz(0.125, 3).SX(3) c.CX(0, 3).CX(0, 4) u_backend = AerUnitaryBackend() u = u_backend.get_unitary(c) ibm_backend = IBMQBackend("ibmq_santiago", hub="ibm-q", group="open", project="main") for ol in range(3): p = ibm_backend.default_compilation_pass(optimisation_level=ol) cu = CompilationUnit(c) p.apply(cu) c1 = cu.circuit compiled_u = u_backend.get_unitary(c1) # Adjust for placement imap = cu.initial_map fmap = cu.final_map c_idx = {c.qubits[i]: i for i in range(5)} c1_idx = {c1.qubits[i]: i for i in range(5)} ini = {c_idx[qb]: c1_idx[node] for qb, node in imap.items()} inv_fin = {c1_idx[node]: c_idx[qb] for qb, node in fmap.items()} m_ini = lift_perm(ini) m_inv_fin = lift_perm(inv_fin) assert compare_unitaries(u, m_inv_fin @ compiled_u @ m_ini)
def get_backend(provider, qpu): """ Get the backend instance by name :param provider: :param qpu: :return: """ if provider.lower() == "ibmq": try: return IBMQBackend(qpu) except NoIBMQAccountError: return None if provider.lower() == "rigetti": # Create a connection to the forest SDK connection = ForestConnection( sync_endpoint=f"http://{qvm_hostname}:{qvm_port}", compiler_endpoint=f"tcp://{quilc_hostname}:{quilc_port}") return ForestBackend(qpu, simulator=True, connection=connection) # Default if no provider matched return None
def test_machine_debug() -> None: backend = IBMQBackend("ibmq_santiago", hub="ibm-q", group="open", project="main") backend._MACHINE_DEBUG = True c = Circuit(2, 2).H(0).CX(0, 1).measure_all() with pytest.raises(CircuitNotValidError) as errorinfo: handles = backend.process_circuits([c, c.copy()], n_shots=2) assert "in submitted does not satisfy GateSetPredicate" in str( errorinfo.value) backend.compile_circuit(c) handles = backend.process_circuits([c, c.copy()], n_shots=4) from pytket.extensions.qiskit.backends.ibm import _DEBUG_HANDLE_PREFIX assert all( cast(str, hand[0]).startswith(_DEBUG_HANDLE_PREFIX) for hand in handles) correct_shots = np.zeros((4, 2)) correct_counts = {(0, 0): 4} shots = backend.get_shots(c, n_shots=4) assert np.all(shots == correct_shots) counts = backend.get_counts(c, n_shots=4) assert counts == correct_counts newshots = backend.get_shots(c, 4) assert np.all(newshots == correct_shots) newcounts = backend.get_counts(c, 4) assert newcounts == correct_counts
elif backend.supports_shots: syn_res_index = state_circuit.bit_readout[syn_res] pauli_circuits, coeffs, energy = gen_pauli_measurement_circuits( state_circuit, compiler_pass(backend), operator) handles = backend.process_circuits(pauli_circuits, n_shots=n_shots) for handle, coeff in zip(handles, coeffs): res = backend.get_result(handle) filtered = filter_shots(res, syn_res) energy += coeff * expectation_from_shots(filtered) backend.pop_result(handle) return energy else: raise NotImplementedError( "Implementation for state and counts to be written") # ...and then run it for our ansatz. `AerBackend` supports faster expectation value from snapshopts (using the `AerBackend.get_operator_expectation_value` method), but this only works when all the qubits in the circuit are default register qubits that go up from 0. So we will need to rename `synq`. from pytket.extensions.qiskit import IBMQBackend, AerBackend ansatz.rename_units({Qubit("synq", 0): Qubit("q", 4)}) print(expectation_value(ansatz, hamiltonian, AerBackend(), 8000)) print( expectation_value(ansatz, hamiltonian, IBMQBackend("ibmq_santiago"), 8000)) # For basic practice with using pytket backends and their results, try editing the code here to: # * Extend `expectation_value` to work with statevector backends (e.g. `AerStateBackend`) # * Remove the row filtering from `filter_shots` and see the effect on the expectation value on a noisy simulation/device # * Adapt `filter_shots` to be able to filter a counts dictionary and adapt `expectation_value` to calulate the result using the counts summary from the backend (`pytket.utils.expectation_from_counts` will be useful here)
ghz_invert_probabilities = probs_from_counts(ghz_invert_corrected_counts) print( "Jensen-Shannon Divergence between noiseless simulation probability distribution and Bayesian-corrected noisy simulation probability distribution: ", JSD(ghz_noiseless_probabilities, ghz_spam_corrected_probabilities), ) print( "Jensen-Shannon Divergence between noiseless simulation probability distribution and invert-corrected noisy simulation probability distribution: ", JSD(ghz_noiseless_probabilities, ghz_invert_probabilities), ) # Lets change from our simulator backend to the Santiago IBMQ device to see how SPAM correction performs on real results. from pytket.extensions.qiskit import IBMQBackend ibm_backend = IBMQBackend("ibmq_santiago") santiago_spam_real = SpamCorrecter([ibm_backend.device.nodes], ibm_backend) ibm_backend.compile_circuit(ghz_circuit) all_circuits = santiago_spam_real.calibration_circuits() + [ghz_circuit] ibm_handles = ibm_backend.process_circuits(all_circuits, n_shots) ibm_calibration_results = (ibm_backend.get_result(handle).get_counts() for handle in ibm_handles[:-1]) santiago_spam_real.calculate_matrices(ibm_calibration_results) ghz_santiago_counts = ibm_backend.get_result(ibm_handles[-1]).get_counts() ghz_santiago_probabilities = probs_from_counts(ghz_santiago_counts) # Finally we compare performance for our machine results: