def __init__( self, noise_model: Optional[NoiseModel] = None, simulation_method: str = "automatic", ): """Backend for running simulations on the Qiskit Aer QASM simulator. :param noise_model: Noise model to apply during simulation. Defaults to None. :type noise_model: Optional[NoiseModel], optional :param simulation_method: Simulation method, see https://qiskit.org/documentation/stubs/qiskit.providers.aer.QasmSimulator.html for available values. Defaults to "automatic". :type simulation_method: str """ super().__init__("qasm_simulator") if not noise_model or all(value == [] for value in noise_model.to_dict().values()): self._noise_model = None else: self._noise_model = noise_model self._characterisation = _process_model(noise_model, self._gate_set) self._device = Device( self._characterisation.get("NodeErrors", {}), self._characterisation.get("EdgeErrors", {}), self._characterisation.get("Architecture", Architecture([])), ) self._memory = True self._backend.set_options(method=simulation_method)
def __init__(self, qc_name: str, simulator: bool = True, connection: ForestConnection = None): """Backend for running circuits on a Rigetti QCS device or simulating with the QVM. :param qc_name: The name of the particular QuantumComputer to use. See the pyQuil docs for more details. :type qc_name: str :param simulator: Simulate the device with the QVM (True), or run on the QCS (False). Defaults to True. :type simulator: bool, optional :param connection: Customized connection to the rigetti backend :type """ # skip the constructor of BaseForestBackend super(Backend, self).__init__() self._cache = {} self._qc: QuantumComputer = get_qc(qc_name, as_qvm=simulator, connection=connection) self._characterisation: dict = process_characterisation(self._qc) averaged_errors = get_avg_characterisation(self._characterisation) self._backend_info: BackendInfo = BackendInfo( name=type(self).__name__, device_name=qc_name, version="0.14.0", architecture=self._characterisation.get("Architecture", Architecture([])), gate_set=self._GATE_SET, all_node_gate_errors=self._characterisation.get("NodeErrors", {}), all_edge_gate_errors=self._characterisation.get("EdgeErrors", {}), averaged_node_gate_errors=averaged_errors["node_errors"], averaged_edge_gate_errors=averaged_errors["link_errors"])
def test_device() -> None: fox = Foxtail char = process_characterisation(fox) dev = Device( char.get("NodeErrors", {}), char.get("EdgeErrors", {}), char.get("Architecture", Architecture([])), ) arc = dev.architecture assert str(arc) == "<tket::Architecture, nodes=22>"
def test_characterisation(qvm: None, quilc: None) -> None: b = ForestBackend("9q-square") char = b.characterisation assert char dev = Device( char.get("NodeErrors", {}), char.get("EdgeErrors", {}), char.get("Architecture", Architecture([])), ) assert dev
def test_routing_no_cx() -> None: circ = Circuit(2, 2) circ.H(1) # c.CX(1, 2) circ.Rx(0.2, 0) circ.measure_all() coupling = [[1, 0], [2, 0], [2, 1], [3, 2], [3, 4], [4, 2]] arc = Architecture(coupling) physical_c = route(circ, arc) assert len(physical_c.get_commands()) == 4
def test_routing_measurements() -> None: qc = get_test_circuit(True) circ = qiskit_to_tk(qc) sim = AerBackend() original_results = sim.get_shots(circ, 10, seed=4) coupling = [[1, 0], [2, 0], [2, 1], [3, 2], [3, 4], [4, 2]] arc = Architecture(coupling) physical_c = route(circ, arc) Transform.DecomposeSWAPtoCX().apply(physical_c) Transform.DecomposeCXDirected(arc).apply(physical_c) Transform.OptimisePostRouting().apply(physical_c) assert (sim.get_shots(physical_c, 10) == original_results).all()
def tket_run(file_name, device_name): connection_list = qcdevice(device_name).connection_list circ = circuit_from_qasm(file_name) circ.measure_all() arc = Architecture(connection_list) dev = Device(arc) routed_circ = route(circ, arc) # cu = CompilationUnit(routed_circ) Transform.DecomposeBRIDGE().apply(routed_circ) # pass1 = DecomposeSwapsToCXs(dev) # pass1.apply(cu) # circ2 = cu.circuit return routed_circ
def generate_architecture(environment): coupling_map = [] a = environment.adjacency_matrix for i in range(len(a)): for j in range(len(a[0])): if a[i][j] == 1: coupling_map.append((i, j)) architecture = Architecture(coupling_map) return architecture
def process_characterisation(qc: QuantumComputer) -> dict: """Convert a :py:class:`pyquil.api.QuantumComputer` to a dictionary containing Rigetti device Characteristics :param qc: A quantum computer to be converted :type qc: QuantumComputer :return: A dictionary containing Rigetti device characteristics """ specs = qc.device.get_specs() coupling_map = [[n, ni] for n, neigh_dict in qc.qubit_topology().adjacency() for ni, _ in neigh_dict.items()] node_ers_dict = {} link_ers_dict = {} t1_times_dict = {} t2_times_dict = {} device_node_fidelities = specs.f1QRBs() # type: ignore device_link_fidelities = specs.fCZs() # type: ignore device_fROs = specs.fROs() # type: ignore device_t1s = specs.T1s() # type: ignore device_t2s = specs.T2s() # type: ignore for index in qc.qubits(): error_cont = QubitErrorContainer({OpType.Rx, OpType.Rz}) error_cont.add_readout(1 - device_fROs[index]) # type: ignore t1_times_dict[index] = device_t1s[index] t2_times_dict[index] = device_t2s[index] error_cont.add_error( (OpType.Rx, 1 - device_node_fidelities[index])) # type: ignore # Rigetti use frame changes for Rz, so they effectively have no error. node_ers_dict[Node(index)] = error_cont for (a, b), fid in device_link_fidelities.items(): error_cont = QubitErrorContainer({OpType.CZ}) error_cont.add_error((OpType.CZ, 1 - fid)) # type: ignore link_ers_dict[(Node(a), Node(b))] = error_cont link_ers_dict[(Node(b), Node(a))] = error_cont arc = Architecture(coupling_map) characterisation = dict() characterisation["NodeErrors"] = node_ers_dict characterisation["EdgeErrors"] = link_ers_dict characterisation["Architecture"] = arc characterisation["t1times"] = t1_times_dict characterisation["t2times"] = t2_times_dict return characterisation
def test_process_characterisation_complete_noise_model() -> None: my_noise_model = NoiseModel() readout_error_0 = 0.2 readout_error_1 = 0.3 my_noise_model.add_readout_error( [ [1 - readout_error_0, readout_error_0], [readout_error_0, 1 - readout_error_0], ], [0], ) my_noise_model.add_readout_error( [ [1 - readout_error_1, readout_error_1], [readout_error_1, 1 - readout_error_1], ], [1], ) my_noise_model.add_quantum_error(depolarizing_error(0.6, 2), ["cx"], [0, 1]) my_noise_model.add_quantum_error(depolarizing_error(0.5, 1), ["u3"], [0]) my_noise_model.add_quantum_error(pauli_error([("X", 0.35), ("Z", 0.65)]), ["u2"], [0]) my_noise_model.add_quantum_error(pauli_error([("X", 0.35), ("Y", 0.65)]), ["u1"], [0]) back = AerBackend(my_noise_model) char = cast(Dict[str, Any], back.characterisation) dev = Device( char.get("NodeErrors", {}), char.get("EdgeErrors", {}), char.get("Architecture", Architecture([])), ) assert char["GenericTwoQubitQErrors"][(0, 1)][0][1][0] == 0.0375 assert char["GenericTwoQubitQErrors"][(0, 1)][0][1][15] == 0.4375 assert char["GenericOneQubitQErrors"][0][0][1][0] == 0.125 assert char["GenericOneQubitQErrors"][0][0][1][3] == 0.625 assert char["GenericOneQubitQErrors"][0][1][1][0] == 0.35 assert char["GenericOneQubitQErrors"][0][1][1][1] == 0.65 assert char["GenericOneQubitQErrors"][0][2][1][0] == 0.35 assert char["GenericOneQubitQErrors"][0][2][1][1] == 0.65 assert dev.get_error(OpType.U3, dev.nodes[0]) == 0.375 assert dev.get_error(OpType.CX, (dev.nodes[0], dev.nodes[1])) == 0.5625 assert dev.get_error(OpType.CX, (dev.nodes[1], dev.nodes[0])) == 0.80859375 assert char["ReadoutErrors"][0] == [[0.8, 0.2], [0.2, 0.8]] assert char["ReadoutErrors"][1] == [[0.7, 0.3], [0.3, 0.7]]
def test_process_characterisation() -> None: if not IBMQ.active_account(): IBMQ.load_account() provider = IBMQ.providers(hub="ibm-q", group="open")[0] back = provider.get_backend("ibmq_santiago") char = process_characterisation(back) dev = Device( char.get("NodeErrors", {}), char.get("EdgeErrors", {}), char.get("Architecture", Architecture([])), ) assert len(dev.nodes) == 5 assert len(dev.errors_by_node) == 5 assert len(dev.coupling) == 8
def __init__(self, qc_name: str, simulator: bool = True): """Backend for running circuits on a Rigetti QCS device or simulating with the QVM. :param qc_name: The name of the particular QuantumComputer to use. See the pyQuil docs for more details. :type qc_name: str :param simulator: Simulate the device with the QVM (True), or run on the QCS (False). Defaults to True. :type simulator: bool, optional """ super().__init__() self._qc: QuantumComputer = get_qc(qc_name, as_qvm=simulator) self._characterisation: dict = process_characterisation(self._qc) self._device: Device = Device( self._characterisation.get("NodeErrors", {}), self._characterisation.get("EdgeErrors", {}), self._characterisation.get("Architecture", Architecture([])), )
def route_circuit(tk_circuit, architecture_map): """Route the circuit to a given architecture map Parameters ---------- tk_circuit : pytket Circuit A pytket circuit architecture_map : list A list of qubit pairings, which are in the form of tuples Returns ------- pytket Circuit A pytket circuit routed for the given architecture Notes ----- IBMQ architectures are provided in the IBMLayouts module, accessible with ALALI.ibm""" architecture = Architecture(architecture_map) routed_circuit = route(tk_circuit, architecture) return routed_circuit
def test_process_characterisation_incomplete_noise_model() -> None: my_noise_model = NoiseModel() my_noise_model.add_quantum_error(depolarizing_error(0.6, 2), ["cx"], [0, 1]) my_noise_model.add_quantum_error(depolarizing_error(0.5, 1), ["u3"], [1]) my_noise_model.add_quantum_error(depolarizing_error(0.1, 1), ["u3"], [3]) my_noise_model.add_quantum_error(pauli_error([("X", 0.35), ("Z", 0.65)]), ["u2"], [0]) my_noise_model.add_quantum_error(pauli_error([("X", 0.35), ("Y", 0.65)]), ["u1"], [2]) back = AerBackend(my_noise_model) char = cast(Dict[str, Any], back.characterisation) c = Circuit(4).CX(0, 1).H(2).CX(2, 1).H(3).CX(0, 3).H(1).X(0).measure_all() back.compile_circuit(c) assert back.valid_circuit(c) dev = Device( char.get("NodeErrors", {}), char.get("EdgeErrors", {}), char.get("Architecture", Architecture([])), ) nodes = dev.nodes assert set(dev.architecture.coupling) == set([ (nodes[0], nodes[1]), (nodes[0], nodes[2]), (nodes[0], nodes[3]), (nodes[1], nodes[2]), (nodes[1], nodes[3]), (nodes[2], nodes[0]), (nodes[2], nodes[1]), (nodes[2], nodes[3]), (nodes[3], nodes[0]), (nodes[3], nodes[1]), (nodes[3], nodes[2]), ])
def process_characterisation(xmon: XmonDevice) -> dict: """Generates a tket dictionary containing device characteristics for a Cirq :py:class:`XmonDevice`. :param xmon: The device to convert :return: A dictionary containing device characteristics """ qb_map = {q: Node("q", q.row, q.col) for q in xmon.qubits} indexed_qubits = _sort_row_col(xmon.qubits) coupling_map = [] for qb in indexed_qubits: neighbours = xmon.neighbors_of(qb) for x in neighbours: coupling_map.append((qb_map[qb], qb_map[x])) arc = Architecture(coupling_map) node_ers_dict = {} link_ers_dict = {} for qb in xmon.qubits: error_cont = QubitErrorContainer({OpType.PhasedX, OpType.Rz}) error_cont.add_error((OpType.PhasedX, 0.0)) error_cont.add_error((OpType.Rz, 0.0)) node_ers_dict[qb_map[qb]] = error_cont for a, b in coupling_map: error_cont = QubitErrorContainer({OpType.CZ}) error_cont.add_error((OpType.CZ, 0.0)) link_ers_dict[(a, b)] = error_cont link_ers_dict[(b, a)] = error_cont characterisation = dict() characterisation["NodeErrors"] = node_ers_dict characterisation["EdgeErrors"] = link_ers_dict characterisation["Architecture"] = arc return characterisation
qasm_file = 'path to your qasm file' q_circ = QuantumCircuit.from_qasm_file(qasm_file) tk_circ = qiskit_to_tk(q_circ) backend = FakeMelbourne() coupling_list = backend.configuration().coupling_map coupling_map = CouplingMap(coupling_list) characterisation = process_characterisation(backend) directed_arc = Device( characterisation.get("NodeErrors", {}), characterisation.get("EdgeErrors", {}), characterisation.get("Architecture", Architecture([])), ) comp_tk = tk_circ.copy() DecomposeBoxes().apply(comp_tk) FullPeepholeOptimise().apply(comp_tk) CXMappingPass(directed_arc, NoiseAwarePlacement(directed_arc), directed_cx=True, delay_measures=True).apply(comp_tk) DecomposeSwapsToCXs(directed_arc).apply(comp_tk) cost = lambda c: c.n_gates_of_type(OpType.CX) comp = RepeatWithMetricPass( SequencePass( [CommuteThroughMultis(),
M = int(sys.argv[1]) graph = nx.random_regular_graph(3, M) edges = list(graph.edges()) print(edges) connection_list = [(0, 2), (1, 2), (2, 3), (1, 5), (2, 6), (3, 7), (4, 5), (5, 6), (6, 7), (7, 8), (4, 10), (5, 11), (6, 12), (7, 13), (9, 10), (10, 11), (11, 12), (12, 13), (9, 15), (10, 16), (11, 17), (12, 18), (14, 15), (15, 16), (16, 17), (17, 18), (15, 19), (16, 20), (17, 21), (19, 20), (20, 21), (20, 22)] circ = pytket.Circuit(23, 0) for edge in edges: circ.ZZPhase(angle=0.75, qubit0=edge[0], qubit1=edge[1]) routed_circ = route(circ, Architecture(connection_list), decompose_swaps=False) Transform.DecomposeBRIDGE().apply(routed_circ) cirq_circuit = tk_to_cirq(routed_circ) num_swap = 0 for layer in cirq_circuit: for gate in layer: if gate.__str__().startswith('SWAP'): num_swap += 1 tket_depth = len(cirq_circuit) print("num_swap", num_swap, " depth", tket_depth) for layer in cirq_circuit: print(layer) [our_depth, our_swap] = qaoa_exp_smt(M, edges)
def _process_model(noise_model: NoiseModel, gate_set: Set[OpType]) -> dict: # obtain approximations for gate errors from noise model by using probability of # "identity" error assert OpType.CX in gate_set # TODO explicitly check for and separate 1 and 2 qubit gates supported_single_optypes = gate_set.difference({OpType.CX}) supported_single_optypes.add(OpType.Reset) errors = [ e for e in noise_model.to_dict()["errors"] if e["type"] == "qerror" or e["type"] == "roerror" ] link_ers_dict: dict = {} node_ers_dict: dict = defaultdict( lambda: QubitErrorContainer(supported_single_optypes)) readout_errors_dict: dict = {} generic_single_qerrors_dict: dict = defaultdict(lambda: list()) generic_2q_qerrors_dict: dict = defaultdict(lambda: list()) node_ers_qubits: set = set() link_ers_qubits: set = set() coupling_map = [] for error in errors: name = error["operations"] if len(name) > 1: raise RuntimeWarning("Error applies to multiple gates.") if "gate_qubits" not in error: raise RuntimeWarning(("Please define NoiseModel without using the" " add_all_qubit_quantum_error()" " or add_all_qubit_readout_error() method.")) name = name[0] qubits = error["gate_qubits"][0] node_ers_qubits.add(qubits[0]) gate_fid = error["probabilities"][-1] if len(qubits) == 1: if error["type"] == "qerror": node_ers_dict[qubits[0]].add_error( (_gate_str_2_optype[name], 1 - gate_fid)) generic_single_qerrors_dict[qubits[0]].append( (error["instructions"], error["probabilities"])) elif error["type"] == "roerror": node_ers_dict[qubits[0]].add_readout( error["probabilities"][0][1]) readout_errors_dict[qubits[0]] = error["probabilities"] else: raise RuntimeWarning("Error type not 'qerror' or 'roerror'.") elif len(qubits) == 2: # note that if multiple multi-qubit errors are added to the CX gate, # the resulting noise channel is composed and reflected in probabilities error_cont = QubitErrorContainer( {_gate_str_2_optype[name]: 1 - gate_fid}) link_ers_qubits.add(qubits[0]) link_ers_qubits.add(qubits[1]) link_ers_dict[tuple(qubits)] = error_cont # to simulate a worse reverse direction square the fidelity rev_error_cont = QubitErrorContainer( {_gate_str_2_optype[name]: 1 - gate_fid**2}) link_ers_dict[tuple(qubits[::-1])] = rev_error_cont generic_2q_qerrors_dict[tuple(qubits)].append( (error["instructions"], error["probabilities"])) coupling_map.append(qubits) free_qubits = node_ers_qubits - link_ers_qubits for q in free_qubits: for lq in link_ers_qubits: coupling_map.append([q, lq]) coupling_map.append([lq, q]) for pair in itertools.permutations(free_qubits, 2): coupling_map.append(pair) # convert qubits to architecture Nodes characterisation = {} node_ers_dict = { Node(q_index): ers for q_index, ers in node_ers_dict.items() } link_ers_dict = {(Node(q_indices[0]), Node(q_indices[1])): ers for q_indices, ers in link_ers_dict.items()} characterisation["NodeErrors"] = node_ers_dict characterisation["EdgeErrors"] = link_ers_dict characterisation["ReadoutErrors"] = readout_errors_dict characterisation["GenericOneQubitQErrors"] = generic_single_qerrors_dict characterisation["GenericTwoQubitQErrors"] = generic_2q_qerrors_dict characterisation["Architecture"] = Architecture(coupling_map) return characterisation
cu = CompilationUnit(circ) pass2.apply(cu) print(cu.circuit.get_commands()) # ## Targeting devices and architectures # If we are given a target architecture, we can generate passes tailored to it. # # In `pytket` an architecture is defined by a connectivity graph, i.e. a list of pairs of qubits capable of executing two-qubit operations. For example, we can represent a 5-qubit linear architecture, with qubits labelled `n[i]`, as follows: from pytket.routing import Architecture from pytket.circuit import Node n = [Node("n", i) for i in range(5)] arc = Architecture([[n[0], n[1]], [n[1], n[2]], [n[2], n[3]], [n[3], n[4]]]) # A `Device` is a model of a physical device, which encapsulates both its `Architecture` and its gate noise characteristics. Ignoring the latter, we can construct a 'noise-free' `Device` directly from an `Architecture`: from pytket.device import Device dev = Device(arc) # Suppose we have a circuit that we wish to run on this device: circ = Circuit(5) circ.CX(0, 1) circ.H(0) circ.Z(1) circ.CX(0, 3) circ.Rx(1.5, 3)
def __init__( self, local: bool = False, s3_bucket: str = "", s3_folder: str = "", device_type: str = "quantum-simulator", provider: str = "amazon", device: str = "sv1", ): """ Construct a new braket backend. If `local=True`, other parameters are ignored. :param local: use simulator running on local machine :param s3_bucket: name of S3 bucket to store results :param s3_folder: name of folder ("key") in S3 bucket to store results in :param device_type: device type from device ARN (e.g. "qpu") :param provider: provider name from device ARN (e.g. "ionq", "rigetti", ...) :paran device: device name from device ARN (e.g. "ionQdevice", "Aspen-8", ...) """ super().__init__() if local: self._device = LocalSimulator() self._device_type = _DeviceType.LOCAL else: self._device = AwsDevice( "arn:aws:braket:::" + "/".join(["device", device_type, provider, device])) self._s3_dest = (s3_bucket, s3_folder) aws_device_type = self._device.type if aws_device_type == AwsDeviceType.SIMULATOR: self._device_type = _DeviceType.SIMULATOR elif aws_device_type == AwsDeviceType.QPU: self._device_type = _DeviceType.QPU else: raise ValueError(f"Unsupported device type {aws_device_type}") props = self._device.properties.dict() paradigm = props["paradigm"] n_qubits = paradigm["qubitCount"] connectivity_graph = None # None means "fully connected" if self._device_type == _DeviceType.QPU: connectivity = paradigm["connectivity"] if connectivity["fullyConnected"]: self._all_qubits: List = list(range(n_qubits)) else: connectivity_graph = connectivity["connectivityGraph"] # Convert strings to ints connectivity_graph = dict( (int(k), [int(v) for v in l]) for k, l in connectivity_graph.items()) self._all_qubits = sorted(connectivity_graph.keys()) if n_qubits < len(self._all_qubits): # This can happen, at least on rigetti devices, and causes errors. # As a kludgy workaround, remove some qubits from the architecture. self._all_qubits = self._all_qubits[:( n_qubits - len(self._all_qubits))] connectivity_graph = dict( (k, [v for v in l if v in self._all_qubits]) for k, l in connectivity_graph.items() if k in self._all_qubits) self._characteristics: Optional[Dict] = props["provider"] else: self._all_qubits = list(range(n_qubits)) self._characteristics = None device_info = props["action"][DeviceActionType.JAQCD] supported_ops = set(op.lower() for op in device_info["supportedOperations"]) supported_result_types = device_info["supportedResultTypes"] self._result_types = set() for rt in supported_result_types: rtname = rt["name"] rtminshots = rt["minShots"] rtmaxshots = rt["maxShots"] self._result_types.add(rtname) if rtname == "StateVector": self._supports_state = True # Always use n_shots = 0 for StateVector elif rtname == "Amplitude": pass # Always use n_shots = 0 for Amplitude elif rtname == "Probability": self._probability_min_shots = rtminshots self._probability_max_shots = rtmaxshots elif rtname == "Expectation": self._supports_expectation = True self._expectation_allows_nonhermitian = False self._expectation_min_shots = rtminshots self._expectation_max_shots = rtmaxshots elif rtname == "Sample": self._supports_shots = True self._supports_counts = True self._sample_min_shots = rtminshots self._sample_max_shots = rtmaxshots elif rtname == "Variance": self._variance_min_shots = rtminshots self._variance_max_shots = rtmaxshots self._multiqs = set() self._singleqs = set() if not {"cnot", "rx", "rz"} <= supported_ops: # This is so that we can define RebaseCustom without prior knowledge of the # gate set. We could do better than this, by having a few different options # for the CX- and tk1-replacement circuits. But it seems all existing # backends support these gates. raise NotImplementedError( "Device must support cnot, rx and rz gates.") for t in supported_ops: tkt = _gate_types[t] if tkt is not None: if t in _multiq_gate_types: if self._device_type == _DeviceType.QPU and t in [ "ccnot", "cswap" ]: # FullMappingPass can't handle 3-qubit gates, so ignore them. continue self._multiqs.add(tkt) else: self._singleqs.add(tkt) self._req_preds = [ NoClassicalControlPredicate(), NoFastFeedforwardPredicate(), NoMidMeasurePredicate(), NoSymbolsPredicate(), GateSetPredicate(self._multiqs | self._singleqs), MaxNQubitsPredicate(n_qubits), ] if connectivity_graph is None: arch = FullyConnected(n_qubits) else: arch = Architecture([(k, v) for k, l in connectivity_graph.items() for v in l]) if self._device_type == _DeviceType.QPU: assert self._characteristics is not None node_errs = {} edge_errs = {} schema = self._characteristics["braketSchemaHeader"] if schema == IONQ_SCHEMA: fid = self._characteristics["fidelity"] mean_1q_err = 1 - fid["1Q"]["mean"] mean_2q_err = 1 - fid["2Q"]["mean"] err_1q_cont = QubitErrorContainer(self._singleqs) for optype in self._singleqs: err_1q_cont.add_error((optype, mean_1q_err)) err_2q_cont = QubitErrorContainer(self._multiqs) for optype in self._multiqs: err_2q_cont.add_error((optype, mean_2q_err)) for node in arch.nodes: node_errs[node] = err_1q_cont for coupling in arch.coupling: edge_errs[coupling] = err_2q_cont elif schema == RIGETTI_SCHEMA: specs = self._characteristics["specs"] specs1q, specs2q = specs["1Q"], specs["2Q"] for node in arch.nodes: nodespecs = specs1q[f"{node.index[0]}"] err_1q_cont = QubitErrorContainer(self._singleqs) for optype in self._singleqs: err_1q_cont.add_error( (optype, 1 - nodespecs.get("f1QRB", 1))) err_1q_cont.add_readout(nodespecs.get("fRO", 1)) node_errs[node] = err_1q_cont for coupling in arch.coupling: node0, node1 = coupling n0, n1 = node0.index[0], node1.index[0] couplingspecs = specs2q[f"{min(n0,n1)}-{max(n0,n1)}"] err_2q_cont = QubitErrorContainer({OpType.CZ}) err_2q_cont.add_error( (OpType.CZ, 1 - couplingspecs.get("fCZ", 1))) edge_errs[coupling] = err_2q_cont self._tket_device = Device(node_errs, edge_errs, arch) if connectivity_graph is not None: self._req_preds.append(ConnectivityPredicate( self._tket_device)) else: self._tket_device = None self._rebase_pass = RebaseCustom( self._multiqs, Circuit(), self._singleqs, lambda a, b, c: Circuit(1).Rz(c, 0).Rx(b, 0).Rz(a, 0), ) self._squash_pass = SquashCustom( self._singleqs, lambda a, b, c: Circuit(1).Rz(c, 0).Rx(b, 0).Rz(a, 0), )
def __init__( self, backend_name: str, hub: Optional[str] = None, group: Optional[str] = None, project: Optional[str] = None, monitor: bool = True, ): """A backend for running circuits on remote IBMQ devices. :param backend_name: Name of the IBMQ device, e.g. `ibmqx4`, `ibmq_16_melbourne`. :type backend_name: str :param hub: Name of the IBMQ hub to use for the provider. If None, just uses the first hub found. Defaults to None. :type hub: Optional[str], optional :param group: Name of the IBMQ group to use for the provider. Defaults to None. :type group: Optional[str], optional :param project: Name of the IBMQ project to use for the provider. Defaults to None. :type project: Optional[str], optional :param monitor: Use the IBM job monitor. Defaults to True. :type monitor: bool, optional :raises ValueError: If no IBMQ account is loaded and none exists on the disk. """ super().__init__() if not IBMQ.active_account(): if IBMQ.stored_account(): IBMQ.load_account() else: raise NoIBMQAccountError() provider_kwargs = {} if hub: provider_kwargs["hub"] = hub if group: provider_kwargs["group"] = group if project: provider_kwargs["project"] = project try: if provider_kwargs: provider = IBMQ.get_provider(**provider_kwargs) else: provider = IBMQ.providers()[0] except qiskit.providers.ibmq.exceptions.IBMQProviderError as err: logging.warn( ("Provider was not specified enough, specify hub," "group and project correctly (check your IBMQ account).")) raise err self._backend: "_QiskIBMQBackend" = provider.get_backend(backend_name) self._config: "QasmBackendConfiguration" = self._backend.configuration( ) self._gate_set: Set[OpType] # simulator i.e. "ibmq_qasm_simulator" does not have `supported_instructions` # attribute self._gate_set = _tk_gate_set(self._backend) self._mid_measure = self._config.simulator or self._config.multi_meas_enabled self._legacy_gateset = OpType.V not in self._gate_set if self._legacy_gateset: if not self._gate_set >= { OpType.U1, OpType.U2, OpType.U3, OpType.CX }: raise NotImplementedError( f"Gate set {self._gate_set} unsupported") self._rebase_pass = RebaseIBM() else: if not self._gate_set >= { OpType.X, OpType.V, OpType.Rz, OpType.CX }: raise NotImplementedError( f"Gate set {self._gate_set} unsupported") self._rebase_pass = RebaseCustom( {OpType.CX}, Circuit(2).CX(0, 1), {OpType.X, OpType.V, OpType.Rz}, _tk1_to_x_v_rz, ) if hasattr(self._config, "max_experiments"): self._max_per_job = self._config.max_experiments else: self._max_per_job = 1 self._characterisation: Dict[str, Any] = process_characterisation( self._backend) self._device = Device( self._characterisation.get("NodeErrors", {}), self._characterisation.get("EdgeErrors", {}), self._characterisation.get("Architecture", Architecture([])), ) self._monitor = monitor self._MACHINE_DEBUG = False
[18, 15], [19, 20], [19, 16], [20, 21], [20, 19], [21, 28], [21, 22], [21, 20], [22, 23], [22, 21], [23, 24], [23, 22], [23, 17], [24, 25], [24, 23], [25, 29], [25, 26], [25, 24], [26, 27], [26, 25], [27, 26], [27, 18], [28, 32], [28, 21], [29, 36], [29, 25], [30, 39], [30, 31], [31, 32], [31, 30], [32, 33], [32, 31], [32, 28], [33, 34], [33, 32], [34, 40], [34, 35], [34, 33], [35, 36], [35, 34], [36, 37], [36, 35], [36, 29], [37, 38], [37, 36], [38, 41], [38, 37], [39, 42], [39, 30], [40, 46], [40, 34], [41, 50], [41, 38], [42, 43], [42, 39], [43, 44], [43, 42], [44, 51], [44, 45], [44, 43], [45, 46], [45, 44], [46, 47], [46, 45], [46, 40], [47, 48], [47, 46], [48, 52], [48, 49], [48, 47], [49, 50], [49, 48], [50, 49], [50, 41], [51, 44], [52, 48]] ### devices: rigetti_device = Device(Architecture(rigetti_coupling)) google_sycamore_device = Device(Architecture(google_coupling)) ibm_rochester_device = Device(Architecture(ibm_coupling)) all_device = Device(Architecture(all_to_all_coupling)) def gen_tket_pass(optimisepass, backend: str): if backend == _BACKEND_FULL: return optimisepass elif backend == _BACKEND_RIGETTI: final_pass = RebaseQuil() device = rigetti_device elif backend == _BACKEND_GOOGLE: final_pass = RebaseCirq() device = google_sycamore_device elif backend == _BACKEND_IBM:
# The Architecture class is used in ```pytket``` to hold information about a quantum architectures connectivity constraints. An Architecture object requires a coupling map to be created i.e. a list of edges between qubits which defines where two-qubit primitives may be executed. A coupling map can be produced naively by the integer indexing of nodes and edges in your architecture. We also use networkx and matplotlib to draw a graph representation of our Architecture. import networkx as nx import matplotlib.pyplot as plt def draw_graph(coupling_map): coupling_graph = nx.Graph(coupling_map) nx.draw(coupling_graph, labels={node: node for node in coupling_graph.nodes()}) simple_coupling_map = [(0, 1), (1, 2), (2, 3)] simple_architecture = Architecture(simple_coupling_map) draw_graph(simple_coupling_map) # Alternatively we could use the `Node` class to assign our nodes - you will see why this can be helpful later. Lets create an Architecture with an identical graph in this manner. from pytket.circuit import Node node_0 = Node("example_register", 0) node_1 = Node("example_register", 1) node_2 = Node("example_register", 2) node_3 = Node("example_register", 3) id_coupling_map = [(node_0, node_1), (node_1, node_2), (node_2, node_3)] id_architecture = Architecture(id_coupling_map) draw_graph(id_coupling_map)
def process_characterisation(backend: BaseBackend) -> Dict[str, Any]: """Convert a :py:class:`qiskit.BaseBackend` to a dictionary containing device Characteristics :param backend: A backend to be converted :type backend: BaseBackend :return: A dictionary containing device characteristics :rtype: dict """ gate_set = _tk_gate_set(backend) assert OpType.CX in gate_set # TODO explicitly check for and separate 1 and 2 qubit gates properties = cast("BackendProperties", backend.properties()) def return_value_if_found(iterator: Iterable["Nduv"], name: str) -> Optional[Any]: try: first_found = next(filter(lambda item: item.name == name, iterator)) except StopIteration: return None if hasattr(first_found, "value"): return first_found.value return None config = backend.configuration() coupling_map = config.coupling_map n_qubits = config.n_qubits if coupling_map is None: # Assume full connectivity arc = FullyConnected(n_qubits) link_ers_dict = {} else: arc = Architecture(coupling_map) link_ers_dict = { tuple(pair): QubitErrorContainer({OpType.CX}) for pair in coupling_map } node_ers_dict = {} supported_single_optypes = gate_set.difference({OpType.CX}) t1_times_dict = {} t2_times_dict = {} frequencies_dict = {} gate_times_dict = {} if properties is not None: for index, qubit_info in enumerate(properties.qubits): error_cont = QubitErrorContainer(supported_single_optypes) error_cont.add_readout( return_value_if_found(qubit_info, "readout_error")) t1_times_dict[index] = return_value_if_found(qubit_info, "T1") t2_times_dict[index] = return_value_if_found(qubit_info, "T2") frequencies_dict[index] = return_value_if_found( qubit_info, "frequency") node_ers_dict[index] = error_cont for gate in properties.gates: name = gate.gate if name in _gate_str_2_optype: optype = _gate_str_2_optype[name] qubits = gate.qubits gate_error = return_value_if_found(gate.parameters, "gate_error") gate_error = gate_error if gate_error else 0.0 gate_length = return_value_if_found(gate.parameters, "gate_length") gate_length = gate_length if gate_length else 0.0 gate_times_dict[(optype, tuple(qubits))] = gate_length # add gate fidelities to their relevant lists if len(qubits) == 1: node_ers_dict[qubits[0]].add_error((optype, gate_error)) elif len(qubits) == 2: link_ers_dict[tuple(qubits)].add_error( (optype, gate_error)) opposite_link = tuple(qubits[::-1]) if opposite_link not in coupling_map: # to simulate a worse reverse direction square the fidelity link_ers_dict[opposite_link] = QubitErrorContainer( {OpType.CX}) link_ers_dict[opposite_link].add_error( (optype, 2 * gate_error)) # convert qubits to architecture Nodes node_ers_dict = { Node(q_index): ers for q_index, ers in node_ers_dict.items() } link_ers_dict = {(Node(q_indices[0]), Node(q_indices[1])): ers for q_indices, ers in link_ers_dict.items()} characterisation: Dict[str, Any] = dict() characterisation["NodeErrors"] = node_ers_dict characterisation["EdgeErrors"] = link_ers_dict characterisation["Architecture"] = arc characterisation["t1times"] = t1_times_dict characterisation["t2times"] = t2_times_dict characterisation["Frequencies"] = frequencies_dict characterisation["GateTimes"] = gate_times_dict return characterisation