def from_backend(cls, backend: BaseBackend): """Construct an :class:`InstructionDurations` object from the backend. Args: backend: backend from which durations (gate lengths) and dt are extracted. Returns: InstructionDurations: The InstructionDurations constructed from backend. Raises: TranspilerError: If dt and dtm is different in the backend. """ # All durations in seconds in gate_length instruction_durations = [] for gate, insts in backend.properties()._gates.items(): for qubits, props in insts.items(): if 'gate_length' in props: gate_length = props['gate_length'][ 0] # Throw away datetime at index 1 instruction_durations.append( (gate, qubits, gate_length, 's')) for q, props in backend.properties()._qubits.items(): if 'readout_length' in props: readout_length = props['readout_length'][ 0] # Throw away datetime at index 1 instruction_durations.append( ('measure', [q], readout_length, 's')) try: dt = backend.configuration().dt # pylint: disable=invalid-name except AttributeError: dt = None return InstructionDurations(instruction_durations, dt=dt)
def from_backend(cls, backend: BaseBackend, **kwargs): """Automatically loads a QuaC noise model given a backend of type BaseBackend. Primarily for speeding up definition of IBMQ hardware noise models in QuaC :param backend: an object of type BaseBackend :param kwargs: an optional dictionary mapping strings to booleans stating which types of noise to include (keys are t1, t2, meas, and zz) :return: a QuacNoiseModel object """ n_qubits = len(backend.properties().qubits) qubits = list(range(n_qubits)) # Set up defaults t1_times = [float('inf') for _ in range(n_qubits)] t2_times = [float('inf') for _ in range(n_qubits)] meas_matrices = None zz = None # Adjust defaults as appropriate if kwargs.get("t1"): t1_times = [ backend.properties().t1(qubit) * 1e9 for qubit in qubits ] if kwargs.get("t2"): t2_times = [ backend.properties().t2(qubit) * 1e9 for qubit in qubits ] if kwargs.get("meas"): meas_matrices = [] # Construct probability matrix for measurement error adjustments for qubit in range(n_qubits): # Not all backends have measurement errors added try: prob_meas0_prep1 = backend.properties().qubit_property( qubit, "prob_meas0_prep1")[0] prob_meas1_prep0 = backend.properties().qubit_property( qubit, "prob_meas1_prep0")[0] except BackendPropertyError: warnings.warn( "Measurement error simulation not supported on this backend" ) break qubit_measurement_error_matrix = np.array( [[1 - prob_meas1_prep0, prob_meas0_prep1], [prob_meas1_prep0, 1 - prob_meas0_prep1]]) meas_matrices.append(qubit_measurement_error_matrix) if kwargs.get("zz"): warnings.warn("ZZ coupling not supported in automatic loading") return QuacNoiseModel(t1_times, t2_times, meas_matrices, zz)
def quac_time_qasm_transpiler(circuit: QuantumCircuit, backend: BaseBackend) -> str: """Converts a circuit of type QuantumCircuit to a string of TIMEQASM specification :param circuit: a QuantumCircuit (need not be transpiled) :param backend: a specific backend to generate the QASM for (for tranpsilation) :return: a string containing necessary QASM with times for each gate """ # Get original QASM transpiled_circuit = transpile(circuit, backend) original_qasm = transpiled_circuit.qasm() # Get body of original QASM start = 2 + len(circuit.qregs) + len(circuit.cregs) original_qasm_body = original_qasm.splitlines()[start:] # Formulate header qasm_modified = "TIMEQASM 1.0;\n" qasm_modified += "\n".join(original_qasm.splitlines()[1:start]) qasm_modified += "\n" # Schedule circuit qobj = assemble(transpiled_circuit, backend) qexp = qobj.experiments[0] qschedule = list_schedule_experiment(qexp, backend.properties()) # Formulate body for instruction, time in qschedule: # Note: ID was custom injected by the scheduler in this plugin qasm_modified += f"{original_qasm_body[instruction.id][:-1]} @{time};\n" return qasm_modified
def from_backend(cls, backend: BaseBackend): """Construct an :class:`InstructionDurations` object from the backend. Args: backend: backend from which durations (gate lengths) and dt are extracted. Returns: InstructionDurations: The InstructionDurations constructed from backend. Raises: TranspilerError: If dt and dtm is different in the backend. """ # All durations in seconds in gate_length instruction_durations = [] for gate, insts in backend.properties()._gates.items(): for qubits, props in insts.items(): if 'gate_length' in props: gate_length = props['gate_length'][ 0] # Throw away datetime at index 1 instruction_durations.append( (gate, qubits, gate_length, 's')) try: dt = backend.configuration().dt # pylint: disable=invalid-name except AttributeError: dt = None # TODO: backend.properties() should tell us durations of measurements # TODO: Remove the following lines after that try: dtm = backend.configuration().dtm if dtm != dt: raise TranspilerError("dtm != dt case is not supported.") inst_map = backend.defaults().instruction_schedule_map all_qubits = tuple(range(backend.configuration().num_qubits)) meas_duration = inst_map.get('measure', all_qubits).duration for q in all_qubits: instruction_durations.append( ('measure', [q], meas_duration, 'dt')) except AttributeError: pass return InstructionDurations(instruction_durations, dt=dt)
def from_calibration_results(cls, backend: BaseBackend, t1_result: Tuple[np.array, Result], t2_result: Tuple[np.array, Result], meas_result: Result, zz_results: Dict[Tuple[int, int], Tuple[np.array, float, Result]]): """Takes results from running calibration circuits on hardware and constructs a QuacNoiseModel object :param backend: the backend on which the circuits were run (a BaseBackend object) :param t1_result: a tuple with a list of delay times (in ns) as the 0th element and the T1 calibration Result object as the 1st element :param t2_result: a tuple with a list of delay times (in ns) as the 0th element and the T2 calibration Result object as the 1st element :param meas_result: a Result object from running measurement calibration circuits :param zz_results: a dictionary mapping tuples of qubit indices to a ZZ coupling calibration circuit Result object :return: a QuacNoiseModel object """ n_qubits = len(backend.properties().qubits) qubits = list(range(n_qubits)) # Set up defaults t1_times = [float('inf') for _ in range(n_qubits)] t2_times = [float('inf') for _ in range(n_qubits)] meas_matrices = None zz = None # Adjust defaults as appropriate if t1_result: t1_fit = T1Fitter(t1_result[1], t1_result[0], qubits, fit_p0=[1, 1e5, 0], fit_bounds=([0, 0, -1], [2, 1e10, 1]), time_unit="nano-seconds") t1_times = t1_fit.time() if t2_result: t2_fit = T2Fitter(t2_result[1], t2_result[0], qubits, fit_p0=[1, 1e4, 0], fit_bounds=([0, 0, -1], [2, 1e10, 1]), time_unit="nano-seconds") t2_times = t2_fit.time() if meas_result: meas_fit = TensoredMeasFitter(meas_result, [[qubit] for qubit in qubits]) meas_matrices = meas_fit.cal_matrices if zz_results: zz = {} for qubit1 in qubits: for qubit2 in qubits: if qubit1 < qubit2: zz_information = zz_results[(qubit1, qubit2)] xdata, osc_freq, zz_result = zz_information zz_fit = ZZFitter( zz_result, xdata, [qubit1], [qubit2], fit_p0=[1, osc_freq, -np.pi / 20, 0], fit_bounds=([-0.5, 0, -np.pi, -0.5], [1.5, 1e10, np.pi, 1.5]), ) zz[(qubit1, qubit2)] = zz_fit.ZZ_rate()[0] return QuacNoiseModel(t1_times, t2_times, meas_matrices, zz)
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