示例#1
0
    def create_with_ideal_sqrt_iswap(
        cls,
        *,
        simulator: Optional[Simulator] = None,
    ) -> 'PhasedFSimEngineSimulator':
        """Creates a PhasedFSimEngineSimulator that simulates ideal FSimGate(theta=π/4, phi=0).

        Attributes:
            simulator: Simulator object to use. When None, a new instance of cirq.Simulator() will
                be created.

        Returns:
            New PhasedFSimEngineSimulator instance.
        """
        def sample_gate(_1: Qid, _2: Qid,
                        gate: FSimGate) -> PhasedFSimCharacterization:
            assert isinstance(gate, FSimGate), f'Expected FSimGate, got {gate}'
            assert np.isclose(gate.theta, np.pi / 4) and np.isclose(
                gate.phi, 0.0), f'Expected ISWAP ** -0.5 like gate, got {gate}'
            return PhasedFSimCharacterization(theta=np.pi / 4,
                                              zeta=0.0,
                                              chi=0.0,
                                              gamma=0.0,
                                              phi=0.0)

        if simulator is None:
            simulator = Simulator()

        return cls(simulator,
                   drift_generator=sample_gate,
                   gates_translator=try_convert_sqrt_iswap_to_fsim)
示例#2
0
    def create_from_characterizations_sqrt_iswap(
        cls,
        characterizations: Iterable[PhasedFSimCalibrationResult],
        *,
        simulator: Optional[Simulator] = None,
        ideal_when_missing_gate: bool = False,
        ideal_when_missing_parameter: bool = False,
    ) -> 'PhasedFSimEngineSimulator':
        """Creates PhasedFSimEngineSimulator with fixed drifts from the characterizations results.

        Args:
            characterizations: Characterization results which are source of the parameters for
                each gate.
            simulator: Simulator object to use. When None, a new instance of cirq.Simulator() will
                be created.
            ideal_when_missing_gate: When set and parameters for some gate for a given pair of
                qubits are not specified in the parameters dictionary then the
                FSimGate(theta=π/4, phi=0) gate parameters will be used. When not set and this
                situation occurs, ValueError is thrown during simulation.
            ideal_when_missing_parameter: When set and some parameter for some gate for a given pair
                of qubits is specified then the matching parameter of FSimGate(theta=π/4, phi=0)
                gate will be used. When not set and this situation occurs, ValueError is thrown
                during simulation.

        Returns:
            New PhasedFSimEngineSimulator instance.
        """

        parameters: PhasedFsimDictParameters = {}
        for characterization in characterizations:
            gate = characterization.gate
            if (not isinstance(gate, FSimGate)
                    or not np.isclose(gate.theta, np.pi / 4)
                    or not np.isclose(gate.phi, 0.0)):
                raise ValueError(
                    f'Expected ISWAP ** -0.5 like gate, got {gate}')

            for (a, b), pair_parameters in characterization.parameters.items():
                if a > b:
                    a, b = b, a
                    pair_parameters = pair_parameters.parameters_for_qubits_swapped(
                    )
                if (a, b) in parameters:
                    raise ValueError(
                        f'Pair ({(a, b)}) appears in multiple moments, multi-moment '
                        f'simulation is not supported.')
                parameters[(a, b)] = pair_parameters

        if simulator is None:
            simulator = Simulator()

        return cls.create_from_dictionary_sqrt_iswap(
            parameters,
            simulator=simulator,
            ideal_when_missing_gate=ideal_when_missing_gate,
            ideal_when_missing_parameter=ideal_when_missing_parameter,
        )
def cross_entropy_benchmarking(
        sampler: work.Sampler,
        qubits: Sequence[ops.Qid],
        *,
        benchmark_ops: Sequence[ops.Moment] = None,
        num_circuits: int = 20,
        repetitions: int = 1000,
        cycles: Union[int, Iterable[int]] = range(2, 103, 10),
        scrambling_gates_per_cycle: List[List[ops.SingleQubitGate]] = None,
        simulator: sim.Simulator = None,
) -> CrossEntropyResult:
    r"""Cross-entropy benchmarking (XEB) of multiple qubits.

    A total of M random circuits are generated, each of which comprises N
    layers where N = max('cycles') or 'cycles' if a single value is specified
    for the 'cycles' parameter. Every layer contains randomly generated
    single-qubit gates applied to each qubit, followed by a set of
    user-defined benchmarking operations (e.g. a set of two-qubit gates).

    Each circuit (circuit_m) from the M random circuits is further used to
    generate a set of circuits {circuit_mn}, where circuit_mn is built from the
    first n cycles of circuit_m. n spans all the values in 'cycles'.

    For each fixed value n, the experiment performs the following:

    1) Experimentally collect a number of bit-strings for each circuit_mn via
    projective measurements in the z-basis.

    2) Theoretically compute the expected bit-string probabilities
    $P^{th, mn}_|...00>$,  $P^{th, mn}_|...01>$, $P^{th, mn}_|...10>$,
    $P^{th, mn}_|...11>$ ... at the end of circuit_mn for all m and for all
    possible bit-strings in the Hilbert space.

    3) Compute an experimental XEB function for each circuit_mn:

    $f_{mn}^{meas} = \langle D * P^{th, mn}_q - 1 \rangle$

    where D is the number of states in the Hilbert space, $P^{th, mn}_q$ is the
    theoretical probability of a bit-string q at the end of circuit_mn, and
    $\langle \rangle$ corresponds to the ensemble average over all measured
    bit-strings.

    Then, take the average of $f_{mn}^{meas}$ over all circuit_mn with fixed
    n to obtain:

    $f_{n} ^ {meas} = (\sum_m f_{mn}^{meas}) / M$

    4) Compute a theoretical XEB function for each circuit_mn:

    $f_{mn}^{th} = D \sum_q (P^{th, mn}_q) ** 2 - 1$

    where the summation goes over all possible bit-strings q in the Hilbert
    space.

    Similarly, we then average $f_m^{th}$ over all circuit_mn with fixed n to
    obtain:

    $f_{n} ^ {th} = (\sum_m f_{mn}^{th}) / M$

    5) Calculate the XEB fidelity $\alpha_n$ at fixed n:

    $\alpha_n = f_{n} ^ {meas} / f_{n} ^ {th}$

    Args:
        sampler: The quantum engine or simulator to run the circuits.
        qubits: The qubits included in the XEB experiment.
        benchmark_ops: A sequence of ops.Moment containing gate operations
            between specific qubits which are to be benchmarked for fidelity.
            If more than one ops.Moment is specified, the random circuits
            will rotate between the ops.Moment's. As an example,
            if benchmark_ops = [Moment([ops.CZ(q0, q1), ops.CZ(q2, q3)]),
            Moment([ops.CZ(q1, q2)]) where q0, q1, q2 and q3 are instances of
            Qid (such as GridQubits), each random circuit will apply CZ gate
            between q0 and q1 plus CZ between q2 and q3 for the first cycle,
            CZ gate between q1 and q2 for the second cycle, CZ between q0 and
            q1 and CZ between q2 and q3 for the third cycle and so on. If
            None, the circuits will consist only of single-qubit gates.
        num_circuits: The total number of random circuits to be used.
        repetitions: The number of measurements for each circuit to estimate
            the bit-string probabilities.
        cycles: The different numbers of circuit layers in the XEB study.
            Could be a single or a collection of values.
        scrambling_gates_per_cycle: If None (by default), the single-qubit
            gates are chosen from X/2 ($\pi/2$ rotation around the X axis),
            Y/2 ($\pi/2$ rotation around the Y axis) and (X + Y)/2 ($\pi/2$
            rotation around an axis $\pi/4$ away from the X on the equator of
            the Bloch sphere). Otherwise the single-qubit gates for each layer
            are chosen from a list of possible choices (each choice is a list
            of one or more single-qubit gates).
        simulator: A simulator that calculates the bit-string probabilities
            of the ideal circuit. By default, this is set to sim.Simulator().

    Returns:
        A CrossEntropyResult object that stores and plots the result.
    """
    simulator = sim.Simulator() if simulator is None else simulator
    num_qubits = len(qubits)

    if isinstance(cycles, int):
        cycle_range = [cycles]
    else:
        cycle_range = list(cycles)

    # These store the measured and simulated bit-string probabilities from
    # all trials in two dictionaries. The keys of the dictionaries are the
    # numbers of cycles. The values are 2D arrays with each row being the
    # probabilities obtained from a single trial.
    probs_meas = {
        n: np.zeros((num_circuits, 2**num_qubits)) for n in cycle_range
    }
    probs_exp = {
        n: np.zeros((num_circuits, 2**num_qubits)) for n in cycle_range
    }

    for k in range(num_circuits):

        # Generates one random XEB circuit with max(num_cycle_range) cycles.
        # Then the first n cycles of the circuit are taken to generate
        # shorter circuits with n cycles (n taken from cycles). All of these
        # circuits are stored in circuits_k.
        circuits_k = _build_xeb_circuits(qubits, cycle_range,
                                         scrambling_gates_per_cycle,
                                         benchmark_ops)

        # Run each circuit with the sampler to obtain a collection of
        # bit-strings, from which the bit-string probabilities are estimated.
        probs_meas_k = _measure_prob_distribution(sampler, repetitions, qubits,
                                                  circuits_k)

        # Simulate each circuit with the Cirq simulator to obtain the
        # wavefunction at the end of each circuit, from which the
        # theoretically expected bit-string probabilities are obtained.
        probs_exp_k = []  # type: List[np.ndarray]
        for circ_k in circuits_k:
            res = simulator.simulate(circ_k, qubit_order=qubits)
            state_probs = np.abs(np.asarray(res.final_state)  # type: ignore
                                )**2
            probs_exp_k.append(state_probs)

        for i, num_cycle in enumerate(cycle_range):
            probs_exp[num_cycle][k, :] = probs_exp_k[i]
            probs_meas[num_cycle][k, :] = probs_meas_k[i]

    fidelity_vals = _xeb_fidelities(probs_exp, probs_meas)
    xeb_data = [
        CrossEntropyPair(c, k) for (c, k) in zip(cycle_range, fidelity_vals)
    ]
    return CrossEntropyResult(xeb_data)
示例#4
0
    def create_from_dictionary_sqrt_iswap(
        cls,
        parameters: PhasedFsimDictParameters,
        *,
        simulator: Optional[Simulator] = None,
        ideal_when_missing_gate: bool = False,
        ideal_when_missing_parameter: bool = False,
    ) -> 'PhasedFSimEngineSimulator':
        """Creates PhasedFSimEngineSimulator with fixed drifts.

        Args:
            parameters: Parameters to use for each gate. All keys must be stored in canonical order,
                when the first qubit is not greater than the second one.
            simulator: Simulator object to use. When None, a new instance of cirq.Simulator() will
                be created.
            ideal_when_missing_gate: When set and parameters for some gate for a given pair of
                qubits are not specified in the parameters dictionary then the
                FSimGate(theta=π/4, phi=0) gate parameters will be used. When not set and this
                situation occurs, ValueError is thrown during simulation.
            ideal_when_missing_parameter: When set and some parameter for some gate for a given pair
                of qubits is specified then the matching parameter of FSimGate(theta=π/4, phi=0)
                gate will be used. When not set and this situation occurs, ValueError is thrown
                during simulation.

        Returns:
            New PhasedFSimEngineSimulator instance.
        """
        def sample_gate(a: Qid, b: Qid,
                        gate: FSimGate) -> PhasedFSimCharacterization:
            assert isinstance(gate, FSimGate), f'Expected FSimGate, got {gate}'
            assert np.isclose(gate.theta, np.pi / 4) and np.isclose(
                gate.phi, 0.0), f'Expected ISWAP ** -0.5 like gate, got {gate}'

            if (a, b) in parameters:
                pair_parameters = parameters[(a, b)]
                if not isinstance(pair_parameters, PhasedFSimCharacterization):
                    pair_parameters = PhasedFSimCharacterization(
                        **pair_parameters)
            elif (b, a) in parameters:
                pair_parameters = parameters[(b, a)]
                if not isinstance(pair_parameters, PhasedFSimCharacterization):
                    pair_parameters = PhasedFSimCharacterization(
                        **pair_parameters)
                pair_parameters = pair_parameters.parameters_for_qubits_swapped(
                )
            elif ideal_when_missing_gate:
                pair_parameters = SQRT_ISWAP_INV_PARAMETERS
            else:
                raise ValueError(f'Missing parameters for pair {(a, b)}')

            if pair_parameters.any_none():
                if not ideal_when_missing_parameter:
                    raise ValueError(
                        f'Missing parameter value for pair {(a, b)}, '
                        f'parameters={pair_parameters}')
                pair_parameters = pair_parameters.merge_with(
                    SQRT_ISWAP_INV_PARAMETERS)

            return pair_parameters

        for a, b in parameters:
            if a > b:
                raise ValueError(
                    f'All qubit pairs must be given in canonical order where the first qubit is '
                    f'less than the second, got {a} > {b}')

        if simulator is None:
            simulator = Simulator()

        return cls(simulator,
                   drift_generator=sample_gate,
                   gates_translator=try_convert_sqrt_iswap_to_fsim)
示例#5
0
    def create_with_random_gaussian_sqrt_iswap(
        cls,
        mean: PhasedFSimCharacterization = SQRT_ISWAP_INV_PARAMETERS,
        *,
        simulator: Optional[Simulator] = None,
        sigma: PhasedFSimCharacterization = PhasedFSimCharacterization(
            theta=0.02, zeta=0.05, chi=0.05, gamma=0.05, phi=0.02),
        random_or_seed: RANDOM_STATE_OR_SEED_LIKE = None,
    ) -> 'PhasedFSimEngineSimulator':
        """Creates a PhasedFSimEngineSimulator that introduces a random deviation from the mean.

        The random deviations are described by a Gaussian distribution of a given mean and sigma,
        for each angle respectively.

        Each gate for each pair of qubits retains the sampled values for the entire simulation, even
        when used multiple times within a circuit.

        Attributes:
            mean: The mean value for each unitary angle. All parameters must be provided.
            simulator: Simulator object to use. When None, a new instance of cirq.Simulator() will
                be created.
            sigma: The standard deviation for each unitary angle. For sigma parameters that are
                None, the mean value will be used without any sampling.

        Returns:
            New PhasedFSimEngineSimulator instance.
        """

        if mean.any_none():
            raise ValueError(
                f'All mean values must be provided, got mean of {mean}')

        rand = parse_random_state(random_or_seed)

        def sample_value(gaussian_mean: Optional[float],
                         gaussian_sigma: Optional[float]) -> float:
            assert gaussian_mean is not None
            if gaussian_sigma is None:
                return gaussian_mean
            return rand.normal(gaussian_mean, gaussian_sigma)

        def sample_gate(_1: Qid, _2: Qid,
                        gate: FSimGate) -> PhasedFSimCharacterization:
            assert isinstance(gate, FSimGate), f'Expected FSimGate, got {gate}'
            assert np.isclose(gate.theta, np.pi / 4) and np.isclose(
                gate.phi, 0.0), f'Expected ISWAP ** -0.5 like gate, got {gate}'

            return PhasedFSimCharacterization(
                theta=sample_value(mean.theta, sigma.theta),
                zeta=sample_value(mean.zeta, sigma.zeta),
                chi=sample_value(mean.chi, sigma.chi),
                gamma=sample_value(mean.gamma, sigma.gamma),
                phi=sample_value(mean.phi, sigma.phi),
            )

        if simulator is None:
            simulator = Simulator()

        return cls(simulator,
                   drift_generator=sample_gate,
                   gates_translator=try_convert_sqrt_iswap_to_fsim)
示例#6
0
 def set_simulator(self, **kwargs: KwargTypes) -> Simulator:
     return Simulator(seed=kwargs.get("seed"))