Exemplo n.º 1
0
    def aggregregate_measurements(
        self,
        jobs: List[IBMQJob],
        batches: List[List[QuantumCircuit]],
        multiplicities: List[int],
        **kwargs,
    ) -> List[Measurements]:
        """Combine samples from a circuit set that has been expanded and batched
        to obtain a set of measurements for each of the original circuits. Also
        applies readout correction after combining.

        Args:
            jobs: The submitted IBMQ jobs.
            batches: The batches of experiments submitted.
            multiplicities: The number of copies of each of the original
                circuits.
            kwargs: Passed to self.apply_readout_correction.

        Returns:
            A list of list of measurements, where each list of measurements
            corresponds to one of the circuits of the original (unexpanded)
            circuit set.
        """
        ibmq_circuit_counts_set = []
        for job, batch in zip(jobs, batches):
            for experiment in batch:
                ibmq_circuit_counts_set.append(job.result().get_counts(experiment))

        measurements_set = []
        ibmq_circuit_index = 0
        for multiplicity in multiplicities:
            combined_counts = Counts({})
            for i in range(multiplicity):
                for bitstring, counts in ibmq_circuit_counts_set[
                    ibmq_circuit_index
                ].items():
                    combined_counts[bitstring] = (
                        combined_counts.get(bitstring, 0) + counts
                    )
                ibmq_circuit_index += 1

            if self.readout_correction:
                combined_counts = self.apply_readout_correction(combined_counts, kwargs)

            # qiskit counts object maps bitstrings in reversed order to ints, so we must
            # flip the bitstrings
            reversed_counts = {}
            for bitstring in combined_counts.keys():
                reversed_counts[bitstring[::-1]] = int(combined_counts[bitstring])

            measurements = Measurements.from_counts(reversed_counts)
            measurements_set.append(measurements)

        return measurements_set
Exemplo n.º 2
0
def expectation_value(
    counts: Counts,
    diagonal: Optional[np.ndarray] = None,
    qubits: Optional[List[int]] = None,
    clbits: Optional[List[int]] = None,
    meas_mitigator: Optional = None,
) -> Tuple[float, float]:
    r"""Compute the expectation value of a diagonal operator from counts.

    This computes the estimator of
    :math:`\langle O \rangle = \mbox{Tr}[\rho. O]`, optionally with measurement
    error mitigation, of a diagonal observable
    :math:`O = \sum_{x\in\{0, 1\}^n} O(x)|x\rangle\!\langle x|`.

    Args:
        counts: counts object
        diagonal: Optional, the vector of diagonal values for summing the
                    expectation value. If ``None`` the the default value is
                    :math:`[1, -1]^\otimes n`.
        qubits: Optional, the measured physical qubits the count
                bitstrings correspond to. If None qubits are assumed to be
                :math:`[0, ..., n-1]`.
        clbits: Optional, if not None marginalize counts to the specified bits.
        meas_mitigator: Optional, a measurement mitigator to apply mitigation.

    Returns:
        (float, float): the expectation value and standard deviation.

    Additional Information:
        The diagonal observable :math:`O` is input using the ``diagonal``
        kwarg as a list or Numpy array :math:`[O(0), ..., O(2^n -1)]`. If
        no diagonal is specified the diagonal of the Pauli operator
        :math:`O = \mbox{diag}(Z^{\otimes n}) = [1, -1]^{\otimes n}` is used.

        The ``clbits`` kwarg is used to marginalize the input counts dictionary
        over the specified bit-values, and the ``qubits`` kwarg is used to specify
        which physical qubits these bit-values correspond to as
        ``circuit.measure(qubits, clbits)``.

        For calibrating a expval measurement error mitigator for the
        ``meas_mitigator`` kwarg see
        :func:`qiskit.ignis.mitigation.expval_meas_mitigator_circuits` and
        :class:`qiskit.ignis.mitigation.ExpvalMeasMitigatorFitter`.
    """
    if meas_mitigator is not None:
        # Use mitigator expectation value method
        return meas_mitigator.expectation_value(counts,
                                                diagonal=diagonal,
                                                clbits=clbits,
                                                qubits=qubits)

    # Marginalize counts
    if clbits is not None:
        counts = marginal_counts(counts, meas_qubits=clbits)

    # Get counts shots and probabilities
    probs = np.array(list(counts.values()))
    shots = probs.sum()
    probs = probs / shots

    # Get diagonal operator coefficients
    if diagonal is None:
        coeffs = np.array([(-1)**(key.count('1') % 2)
                           for key in counts.keys()],
                          dtype=probs.dtype)
    else:
        diagonal = np.asarray(diagonal)
        keys = [int(key, 2) for key in counts.keys()]
        coeffs = np.asarray(diagonal[keys], dtype=probs.dtype)

    return _expval_with_stddev(coeffs, probs, shots)