def test_readout_error_correlated_2qubit(self): """Test a correlated two-qubit readout error""" # Test circuit: prepare all plus state qr = QuantumRegister(2, 'qr') cr = ClassicalRegister(2, 'cr') circuit = QuantumCircuit(qr, cr) circuit.h(qr) circuit.barrier(qr) # We will manually add a correlated measure operation to # the compiled qobj backend = QasmSimulator() # Correlated 2-qubit readout error probs_given00 = [0.3, 0, 0, 0.7] probs_given01 = [0, 0.6, 0.4, 0] probs_given10 = [0, 0, 1, 0] probs_given11 = [0.1, 0, 0, 0.9] probs_noise = [ probs_given00, probs_given01, probs_given10, probs_given11 ] noise_model = NoiseModel() noise_model.add_readout_error(probs_noise, [0, 1]) # Expected counts shots = 2000 probs_ideal = [0.25, 0.25, 0.25, 0.25] p00 = sum([ ideal * noise[0] for ideal, noise in zip(probs_ideal, probs_noise) ]) p01 = sum([ ideal * noise[1] for ideal, noise in zip(probs_ideal, probs_noise) ]) p10 = sum([ ideal * noise[2] for ideal, noise in zip(probs_ideal, probs_noise) ]) p11 = sum([ ideal * noise[3] for ideal, noise in zip(probs_ideal, probs_noise) ]) target = { '0x0': p00 * shots, '0x1': p01 * shots, '0x2': p10 * shots, '0x3': p11 * shots } qobj = compile([circuit], backend, shots=shots, basis_gates=noise_model.basis_gates) # Add measure to qobj item = measure_instr([0, 1], [0, 1]) append_instr(qobj, 0, item) # Execute result = backend.run(qobj, noise_model=noise_model).result() self.is_completed(result) self.compare_counts(result, [circuit], [target], delta=0.05 * shots)
def _maybe_add_aer_expectation_instruction(qobj, options): if 'expectation' in options: from qiskit.providers.aer.utils.qobj_utils import snapshot_instr, append_instr, get_instr_pos # add others, how to derive the correct used number of qubits? # the compiled qobj could be wrong if coupling map is used. params = options['expectation']['params'] num_qubits = options['expectation']['num_qubits'] for idx in range(len(qobj.experiments)): # if mulitple params are provided, we assume that each circuit is corresponding one param # otherwise, params are used for all circuits. param_idx = idx if len(params) > 1 else 0 snapshot_pos = get_instr_pos(qobj, idx, 'snapshot') if len(snapshot_pos) == 0: # does not append the instruction yet. new_ins = snapshot_instr('expectation_value_pauli', 'test', range(num_qubits), params=params[param_idx]) qobj = append_instr(qobj, idx, new_ins) else: for i in snapshot_pos: # update all expectation_value_snapshot if qobj.experiments[idx].instructions[ i].type == 'expectation_value_pauli': qobj.experiments[idx].instructions[i].params = params[ param_idx] return qobj
def maybe_add_aer_expectation_instruction(qobj, options): """ Add aer expectation instruction if `expectation` in the options. Args: qobj (QasmQobj): qobj options (dict): the setting for aer expectation instruction Returns: QasmQobj: a mutated qobj with aer expectation instruction inserted """ if 'expectation' in options: from qiskit.providers.aer.utils.qobj_utils \ import snapshot_instr, append_instr, get_instr_pos # add others, how to derive the correct used number of qubits? # the compiled qobj could be wrong if coupling map is used. params = options['expectation']['params'] num_qubits = options['expectation']['num_qubits'] for idx in range(len(qobj.experiments)): # if multiple params are provided, we assume # that each circuit is corresponding one param # otherwise, params are used for all circuits. param_idx = idx if len(params) > 1 else 0 snapshot_pos = get_instr_pos(qobj, idx, 'snapshot') if not snapshot_pos: # does not append the instruction yet. new_ins = snapshot_instr('expectation_value_pauli', 'test', list(range(num_qubits)), params=params[param_idx]) qobj = append_instr(qobj, idx, new_ins) else: for i in snapshot_pos: # update all expectation_value_snapshot if qobj.experiments[idx].instructions[i].type == 'expectation_value_pauli': qobj.experiments[idx].instructions[i].params = params[param_idx] return qobj
def unitary_gate_circuits_real_deterministic(final_measure=True): """Unitary gate test circuits with deterministic count output.""" final_qobj = _dummy_qobj() qr = QuantumRegister(2) if final_measure: cr = ClassicalRegister(2) regs = (qr, cr) else: regs = (qr, ) x_mat = np.array([[0, 1], [1, 0]]) cx_mat = np.array([[1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0]]) # CX01, |00> state circuit = QuantumCircuit(*regs) circuit.barrier(qr) qobj = assemble(circuit, QasmSimulator(), shots=1) append_instr(qobj, 0, unitary_instr(cx_mat, [0, 1])) if final_measure: append_instr(qobj, 0, measure_instr([0], [0])) append_instr(qobj, 0, measure_instr([1], [1])) final_qobj.experiments.append(qobj.experiments[0]) # CX10, |00> state circuit = QuantumCircuit(*regs) circuit.barrier(qr) qobj = assemble(circuit, QasmSimulator(), shots=1) append_instr(qobj, 0, unitary_instr(cx_mat, [1, 0])) if final_measure: append_instr(qobj, 0, measure_instr([0], [0])) append_instr(qobj, 0, measure_instr([1], [1])) final_qobj.experiments.append(qobj.experiments[0]) # CX01.(X^I), |10> state circuit = QuantumCircuit(*regs) circuit.barrier(qr) qobj = assemble(circuit, QasmSimulator(), shots=1) append_instr(qobj, 0, unitary_instr(x_mat, [1])) append_instr(qobj, 0, unitary_instr(cx_mat, [0, 1])) if final_measure: append_instr(qobj, 0, measure_instr([0], [0])) append_instr(qobj, 0, measure_instr([1], [1])) final_qobj.experiments.append(qobj.experiments[0]) # CX10.(I^X), |01> state circuit = QuantumCircuit(*regs) circuit.barrier(qr) qobj = assemble(circuit, QasmSimulator(), shots=1) append_instr(qobj, 0, unitary_instr(x_mat, [0])) append_instr(qobj, 0, unitary_instr(cx_mat, [1, 0])) if final_measure: append_instr(qobj, 0, measure_instr([0], [0])) append_instr(qobj, 0, measure_instr([1], [1])) final_qobj.experiments.append(qobj.experiments[0]) # CX01.(I^X), |11> state circuit = QuantumCircuit(*regs) circuit.barrier(qr) qobj = assemble(circuit, QasmSimulator(), shots=1) append_instr(qobj, 0, unitary_instr(x_mat, [0])) append_instr(qobj, 0, unitary_instr(cx_mat, [0, 1])) if final_measure: append_instr(qobj, 0, measure_instr([0], [0])) append_instr(qobj, 0, measure_instr([1], [1])) final_qobj.experiments.append(qobj.experiments[0]) # CX10.(X^I), |11> state circuit = QuantumCircuit(*regs) circuit.barrier(qr) qobj = assemble(circuit, QasmSimulator(), shots=1) append_instr(qobj, 0, unitary_instr(x_mat, [1])) append_instr(qobj, 0, unitary_instr(cx_mat, [1, 0])) if final_measure: append_instr(qobj, 0, measure_instr([0], [0])) append_instr(qobj, 0, measure_instr([1], [1])) final_qobj.experiments.append(qobj.experiments[0]) return final_qobj
def compile_and_run_circuits(circuits, backend, backend_config, compile_config, run_config, qjob_config=None, backend_options=None, noise_config=None, show_circuit_summary=False, has_shared_circuits=False, circuit_cache=None, skip_qobj_validation=False, **kwargs): """ An execution wrapper with Qiskit-Terra, with job auto recover capability. The autorecovery feature is only applied for non-simulator backend. This wraper will try to get the result no matter how long it costs. Args: circuits (QuantumCircuit or list[QuantumCircuit]): circuits to execute backend (BaseBackend): backend instance backend_config (dict): configuration for backend compile_config (dict): configuration for compilation run_config (RunConfig): configuration for running a circuit qjob_config (dict): configuration for quantum job object backend_options (dict): configuration for simulator noise_config (dict): configuration for noise model show_circuit_summary (bool): showing the summary of submitted circuits. has_shared_circuits (bool): use the 0-th circuits as initial state for other circuits. Returns: Result: Result object Raises: AquaError: Any error except for JobError raised by Qiskit Terra """ qjob_config = qjob_config or {} backend_options = backend_options or {} noise_config = noise_config or {} if backend is None or not isinstance(backend, BaseBackend): raise ValueError( 'Backend is missing or not an instance of BaseBackend') if not isinstance(circuits, list): circuits = [circuits] if 'statevector' in backend.name(): circuits = _avoid_empty_circuits(circuits) if has_shared_circuits: return _reuse_shared_circuits(circuits, backend, backend_config, compile_config, run_config, qjob_config, backend_options) with_autorecover = False if backend.configuration().simulator else True if MAX_CIRCUITS_PER_JOB is not None: max_circuits_per_job = int(MAX_CIRCUITS_PER_JOB) else: if backend.configuration().local: max_circuits_per_job = sys.maxsize else: max_circuits_per_job = backend.configuration().max_experiments if circuit_cache is not None and circuit_cache.try_reusing_qobjs: # Check if all circuits are the same length. If not, don't try to use the same qobj.experiment for all of them. if len(set([len(circ.data) for circ in circuits])) > 1: circuit_cache.try_reusing_qobjs = False else: # Try setting up the reusable qobj # Compile and cache first circuit if cache is empty. The load method will try to reuse it if circuit_cache.try_reusing_qobjs and circuit_cache.qobjs is None: qobj = q_compile([circuits[0]], backend, **execute_config) circuit_cache.cache_circuit(qobj, [circuits[0]], 0) qobjs = [] jobs = [] job_ids = [] chunks = int(np.ceil(len(circuits) / max_circuits_per_job)) for i in range(chunks): sub_circuits = circuits[i * max_circuits_per_job:(i + 1) * max_circuits_per_job] if circuit_cache is not None and circuit_cache.misses < circuit_cache.allowed_misses: try: qobj = circuit_cache.load_qobj_from_cache( sub_circuits, i, run_config=run_config) # cache miss, fail gracefully except (TypeError, IndexError, FileNotFoundError, EOFError, AquaError, AttributeError) as e: circuit_cache.try_reusing_qobjs = False # Reusing Qobj didn't work circuit_cache.clear_cache() logger.debug( 'Circuit cache miss, recompiling. Cache miss reason: ' + repr(e)) qobj = q_compile(sub_circuits, backend, **backend_config, **compile_config, **run_config.to_dict()) circuit_cache.cache_circuit(qobj, sub_circuits, i) circuit_cache.misses += 1 else: qobj = q_compile(sub_circuits, backend, **backend_config, **compile_config, **run_config.to_dict()) if 'expectation' in kwargs: from qiskit.providers.aer.utils.qobj_utils import snapshot_instr, append_instr # add others, how to derive the correct used number of qubits? # the compiled qobj could be wrong if coupling map is used. # if mulitple params are provided, we assume that each circuit is corresponding one param # otherwise, params are used for all circuits. params = kwargs['expectation']['params'] num_qubits = kwargs['expectation']['num_qubits'] if len(params) == 1: new_ins = snapshot_instr('expectation_value_pauli', 'test', range(num_qubits), params=params[0]) for ii in range(len(sub_circuits)): qobj = append_instr(qobj, ii, new_ins) else: for ii in range(len(sub_circuits)): new_ins = snapshot_instr('expectation_value_pauli', 'test', range(num_qubits), params=params[ii]) qobj = append_instr(qobj, ii, new_ins) # assure get job ids while True: job = run_on_backend(backend, qobj, backend_options=backend_options, noise_config=noise_config, skip_qobj_validation=skip_qobj_validation) try: job_id = job.job_id() break except JobError as e: logger.warning( "FAILURE: the {}-th chunk of circuits, can not get job id, " "Resubmit the qobj to get job id. " "Terra job error: {} ".format(i, e)) except Exception as e: logger.warning( "FAILURE: the {}-th chunk of circuits, can not get job id, " "Resubmit the qobj to get job id. " "Error: {} ".format(i, e)) job_ids.append(job_id) jobs.append(job) qobjs.append(qobj) if logger.isEnabledFor(logging.DEBUG) and show_circuit_summary: logger.debug(summarize_circuits(circuits)) results = [] if with_autorecover: logger.info("Backend status: {}".format(backend.status())) logger.info( "There are {} circuits and they are chunked into {} chunks, " "each with {} circutis (max.).".format(len(circuits), chunks, max_circuits_per_job)) logger.info("All job ids:\n{}".format(job_ids)) for idx in range(len(jobs)): while True: job = jobs[idx] job_id = job_ids[idx] logger.info("Running {}-th chunk circuits, job id: {}".format( idx, job_id)) # try to get result if possible try: result = job.result(**qjob_config) if result.success: results.append(result) logger.info("COMPLETED the {}-th chunk of circuits, " "job id: {}".format(idx, job_id)) break else: logger.warning("FAILURE: the {}-th chunk of circuits, " "job id: {}".format(idx, job_id)) except JobError as e: # if terra raise any error, which means something wrong, re-run it logger.warning( "FAILURE: the {}-th chunk of circuits, job id: {} " "Terra job error: {} ".format(idx, job_id, e)) except Exception as e: raise AquaError( "FAILURE: the {}-th chunk of circuits, job id: {} " "Unknown error: {} ".format(idx, job_id, e)) from e # something wrong here, querying the status to check how to handle it. # keep qeurying it until getting the status. while True: try: job_status = job.status() break except JobError as e: logger.warning("FAILURE: job id: {}, " "status: 'FAIL_TO_GET_STATUS' " "Terra job error: {}".format(job_id, e)) time.sleep(5) except Exception as e: raise AquaError("FAILURE: job id: {}, " "status: 'FAIL_TO_GET_STATUS' " "Unknown error: ({})".format( job_id, e)) from e logger.info("Job status: {}".format(job_status)) # handle the failure job based on job status if job_status == JobStatus.DONE: logger.info( "Job ({}) is completed anyway, retrieve result " "from backend.".format(job_id)) job = backend.retrieve_job(job_id) elif job_status == JobStatus.RUNNING or job_status == JobStatus.QUEUED: logger.info("Job ({}) is {}, but encounter an exception, " "recover it from backend.".format( job_id, job_status)) job = backend.retrieve_job(job_id) else: logger.info( "Fail to run Job ({}), resubmit it.".format(job_id)) qobj = qobjs[idx] # assure job get its id while True: job = run_on_backend( backend, qobj, backend_options=backend_options, noise_config=noise_config, skip_qobj_validation=skip_qobj_validation) try: job_id = job.job_id() break except JobError as e: logger.warning( "FAILURE: the {}-th chunk of circuits, " "can not get job id. Resubmit the qobj to get job id. " "Terra job error: {} ".format(idx, e)) except Exception as e: logger.warning( "FAILURE: the {}-th chunk of circuits, " "can not get job id, Resubmit the qobj to get job id. " "Unknown error: {} ".format(idx, e)) jobs[idx] = job job_ids[idx] = job_id else: results = [] for job in jobs: results.append(job.result(**qjob_config)) result = _combine_result_objects(results) if len(results) != 0 else None return result