Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
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
Ejemplo n.º 5
0
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