Exemple #1
0
def test_pop_measurements_and_add_measurements():
    """Tests popping measurements from a circuit.."""
    # Test circuit:
    # 0: ───H───T───@───M───
    #               │   │
    # 1: ───H───M───┼───┼───
    #               │   │
    # 2: ───H───────X───M───
    qreg = LineQubit.range(3)
    circ = Circuit(
        [ops.H.on_each(qreg)],
        [ops.T.on(qreg[0])],
        [ops.measure(qreg[1])],
        [ops.CNOT.on(qreg[0], qreg[2])],
        [ops.measure(qreg[0], qreg[2])],
    )
    copy = deepcopy(circ)
    measurements = _pop_measurements(copy)
    correct = Circuit(
        [ops.H.on_each(qreg)],
        [ops.T.on(qreg[0])],
        [ops.CNOT.on(qreg[0], qreg[2])],
    )
    assert _equal(copy, correct)
    _append_measurements(copy, measurements)
    assert _equal(copy, circ)
Exemple #2
0
def test_teleportation_diagram():
    ali = ops.NamedQubit('alice')
    car = ops.NamedQubit('carrier')
    bob = ops.NamedQubit('bob')

    circuit = Circuit.from_ops(
        ops.H(car),
        ops.CNOT(car, bob),
        ops.X(ali)**0.5,
        ops.CNOT(ali, car),
        ops.H(ali),
        [ops.measure(ali), ops.measure(car)],
        ops.CNOT(car, bob),
        ops.CZ(ali, bob))

    diagram = circuit_to_latex_using_qcircuit(
        circuit,
        qubit_order=ops.QubitOrder.explicit([ali, car, bob]))
    assert diagram.strip() == """
\\Qcircuit @R=1em @C=0.75em { \\\\ 
 \\lstick{\\text{alice}}& \\qw &\\qw & \\gate{\\text{X}^{0.5}} \\qw & \\control \\qw & \\gate{\\text{H}} \\qw & \\meter \\qw &\\qw & \\control \\qw &\\qw\\\\
 \\lstick{\\text{carrier}}& \\qw & \\gate{\\text{H}} \\qw & \\control \\qw & \\targ \\qw \\qwx &\\qw & \\meter \\qw & \\control \\qw &\\qw \\qwx &\\qw\\\\
 \\lstick{\\text{bob}}& \\qw &\\qw & \\targ \\qw \\qwx &\\qw &\\qw &\\qw & \\targ \\qw \\qwx & \\control \\qw \\qwx &\\qw \\\\ 
 \\\\ }
        """.strip()
Exemple #3
0
def test_init():
    d = square_device(2, 2, holes=[XmonQubit(1, 1)])
    ns = Duration(nanos=1)
    q00 = XmonQubit(0, 0)
    q01 = XmonQubit(0, 1)
    q10 = XmonQubit(1, 0)

    assert d.qubits == {q00, q01, q10}
    assert d.duration_of(ExpZGate().on(q00)) == 0 * ns
    assert d.duration_of(ops.measure(q00)) == ns
    assert d.duration_of(ops.measure(q00, q01)) == ns
    assert d.duration_of(ExpWGate().on(q00)) == 2 * ns
    assert d.duration_of(Exp11Gate().on(q00, q01)) == 3 * ns
def single_qubit_state_tomography(
    sampler: 'cirq.Sampler',
    qubit: 'cirq.Qid',
    circuit: 'cirq.AbstractCircuit',
    repetitions: int = 1000,
) -> TomographyResult:
    """Single-qubit state tomography.

    The density matrix of the output state of a circuit is measured by first
    doing projective measurements in the z-basis, which determine the
    diagonal elements of the matrix. A X/2 or Y/2 rotation is then added before
    the z-basis measurement, which determines the imaginary and real parts of
    the off-diagonal matrix elements, respectively.

    See Vandersypen and Chuang, Rev. Mod. Phys. 76, 1037 for details.

    Args:
        sampler: The quantum engine or simulator to run the circuits.
        qubit: The qubit under test.
        circuit: The circuit to execute on the qubit before tomography.
        repetitions: The number of measurements for each basis rotation.

    Returns:
        A TomographyResult object that stores and plots the density matrix.
    """
    circuit_z = circuit + circuits.Circuit(ops.measure(qubit, key='z'))
    results = sampler.run(circuit_z, repetitions=repetitions)
    rho_11 = np.mean(results.measurements['z'])
    rho_00 = 1.0 - rho_11

    circuit_x = circuits.Circuit(circuit,
                                 ops.X(qubit)**0.5, ops.measure(qubit,
                                                                key='z'))
    results = sampler.run(circuit_x, repetitions=repetitions)
    rho_01_im = np.mean(results.measurements['z']) - 0.5

    circuit_y = circuits.Circuit(circuit,
                                 ops.Y(qubit)**-0.5, ops.measure(qubit,
                                                                 key='z'))
    results = sampler.run(circuit_y, repetitions=repetitions)
    rho_01_re = 0.5 - np.mean(results.measurements['z'])

    rho_01 = rho_01_re + 1j * rho_01_im
    rho_10 = np.conj(rho_01)

    rho = np.array([[rho_00, rho_01], [rho_10, rho_11]])

    return TomographyResult(rho)
def rabi_oscillations(sampler: sim.SimulatesSamples, qubit: devices.GridQubit,
                      max_angle: float = 2 * np.pi, *,
                      repetitions: int = 1000,
                      num_points: int = 200) -> RabiResult:
    """Runs a Rabi oscillation experiment.

    Rotates a qubit around the x-axis of the Bloch sphere by a sequence of Rabi
    angles evenly spaced between 0 and max_angle. For each rotation, repeat
    the circuit a number of times and measure the average probability of the
    qubit being in the |1> state.

    Args:
        sampler: The quantum engine or simulator to run the circuits.
        qubit: The qubit under test.
        max_angle: The final Rabi angle in radians.
        repetitions: The number of repetitions of the circuit for each Rabi
            angle.
        num_points: The number of Rabi angles.

    Returns:
        A RabiResult object that stores and plots the result.
    """
    theta = sympy.Symbol('theta')
    circuit = circuits.Circuit.from_ops(ops.X(qubit) ** theta)
    circuit.append(ops.measure(qubit, key='z'))
    sweep = study.Linspace(key='theta', start=0.0, stop=max_angle / np.pi,
                           length=num_points)
    results = sampler.run_sweep(circuit, params=sweep, repetitions=repetitions)
    angles = np.linspace(0.0, max_angle, num_points)
    excited_state_probs = np.zeros(num_points)
    for i in range(num_points):
        excited_state_probs[i] = np.mean(results[i].measurements['z'])

    return RabiResult(angles, excited_state_probs)
 def _measurement(two_qubit_circuit: circuits.Circuit) -> np.ndarray:
     two_qubit_circuit.append(ops.measure(first_qubit, second_qubit,
                                          key='z'))
     results = sampler.run(two_qubit_circuit, repetitions=repetitions)
     results_hist = results.histogram(key='z')
     prob_list = [results_hist[0], results_hist[1], results_hist[2]]
     return np.asarray(prob_list) / repetitions
def _with_parameterized_layers(
    circuit: 'cirq.Circuit',
    qubits: Sequence['cirq.Qid'],
    needs_init_layer: bool,
) -> 'cirq.Circuit':
    """Return a copy of the input circuit with parameterized single-qubit rotations.

    These rotations flank the circuit: the initial two layers of X and Y gates
    are given parameter names "{qubit}-Xi" and "{qubit}-Yi" and are used
    to set up the initial state. If `needs_init_layer` is False,
    these two layers of gates are omitted.

    The final two layers of X and Y gates are given parameter names
    "{qubit}-Xf" and "{qubit}-Yf" and are use to change the frame of the
    qubit before measurement, effectively measuring in bases other than Z.
    """
    x_beg_mom = ops.Moment([ops.X(q)**sympy.Symbol(f'{q}-Xi') for q in qubits])
    y_beg_mom = ops.Moment([ops.Y(q)**sympy.Symbol(f'{q}-Yi') for q in qubits])
    x_end_mom = ops.Moment([ops.X(q)**sympy.Symbol(f'{q}-Xf') for q in qubits])
    y_end_mom = ops.Moment([ops.Y(q)**sympy.Symbol(f'{q}-Yf') for q in qubits])
    meas_mom = ops.Moment([ops.measure(*qubits, key='z')])
    if needs_init_layer:
        total_circuit = circuits.Circuit([x_beg_mom, y_beg_mom])
        total_circuit += circuit.copy()
    else:
        total_circuit = circuit.copy()
    total_circuit.append([x_end_mom, y_end_mom, meas_mom])
    return total_circuit
Exemple #8
0
    def noisy_moments(
            self, moments: Iterable['cirq.Moment'],
            system_qubits: Sequence['cirq.Qid']) -> Sequence['cirq.OP_TREE']:
        # Split multi-qubit measurements into single-qubit measurements.
        # These will be recombined after noise is applied.
        split_measure_moments = []
        multi_measurements = {}
        for moment in moments:
            split_measure_ops = []
            for op in moment:
                if not protocols.is_measurement(op):
                    split_measure_ops.append(op)
                    continue
                m_key = protocols.measurement_key_obj(op)
                multi_measurements[m_key] = op
                for q in op.qubits:
                    split_measure_ops.append(ops.measure(q, key=m_key))
            split_measure_moments.append(circuits.Moment(split_measure_ops))

        # Append PHYSICAL_GATE_TAG to non-virtual ops in the input circuit,
        # using `self.virtual_predicate` to determine virtuality.
        new_moments = []
        for moment in split_measure_moments:
            virtual_ops = {op for op in moment if self.virtual_predicate(op)}
            physical_ops = [
                op.with_tags(PHYSICAL_GATE_TAG) for op in moment
                if op not in virtual_ops
            ]
            # Both physical and virtual operations remain in the circuit, but
            # only ops with PHYSICAL_GATE_TAG will receive noise.
            if virtual_ops:
                # Only subclasses will trigger this case.
                new_moments.append(
                    circuits.Moment(virtual_ops))  # coverage: ignore
            if physical_ops:
                new_moments.append(circuits.Moment(physical_ops))

        split_measure_circuit = circuits.Circuit(new_moments)

        # Add noise from each noise model. The PHYSICAL_GATE_TAGs added
        # previously allow noise models to distinguish physical gates from
        # those added by other noise models.
        noisy_circuit = split_measure_circuit.copy()
        for model in self.noise_models:
            noisy_circuit = noisy_circuit.with_noise(model)

        # Recombine measurements.
        final_moments = []
        for moment in noisy_circuit:
            combined_measure_ops = []
            restore_keys = set()
            for op in moment:
                if not protocols.is_measurement(op):
                    combined_measure_ops.append(op)
                    continue
                restore_keys.add(protocols.measurement_key_obj(op))
            for key in restore_keys:
                combined_measure_ops.append(multi_measurements[key])
            final_moments.append(circuits.Moment(combined_measure_ops))
        return final_moments
Exemple #9
0
    def generate_circuit_from_list(self, json_string: str):
        """Generates a list of cirq operations from a json string.

        The default behavior is to add a measurement to any qubit at the end
        of the circuit as there are no measurements defined in the AQT API.

        Args:
            json_string: json that specifies the sequence
        """
        self.circuit = Circuit()
        json_obj = json.loads(json_string)
        gate: Union[ops.PhasedXPowGate, ops.EigenGate]
        for circuit_list in json_obj:
            op_str = circuit_list[0]
            if op_str == 'R':
                gate = cast(ops.PhasedXPowGate, gate_dict[op_str])
                theta = circuit_list[1]
                phi = circuit_list[2]
                qubits = [self.qubit_list[i] for i in circuit_list[3]]
                self.circuit.append(gate(phase_exponent=phi, exponent=theta).on(*qubits))
            else:
                gate = cast(ops.EigenGate, gate_dict[op_str])
                angle = circuit_list[1]
                qubits = [self.qubit_list[i] for i in circuit_list[2]]
                self.circuit.append(gate.on(*qubits) ** angle)
        # TODO: Better solution for measurement at the end.
        # Github issue: https://github.com/quantumlib/Cirq/issues/2199
        self.circuit.append(ops.measure(*[qubit for qubit in self.qubit_list], key='m'))
def qft(qubits, tol=None, mea=False, initial=None, control=()):
    size = len(qubits)
    if tol == None:  # Sets maximum distance of controlled gates to cover entire circuit if not given.
        tol = size
    if initial == None:  # Sets array for qubit starting state to all 0's if not given.
        initial = zeros(size)

    for i in range(
            size):  # Applies an X gate to all qubits starting in the state 1.
        if initial[i] == 1:
            yield cirq.ControlledGate(X, num_controls=len(control))(*control,
                                                                    qubits[i])

    for i in range(
            size
    ):  # Applies Hadamard and CPhase gates to each block of qubits.
        yield cirq.ControlledGate(H, num_controls=len(control))(*control,
                                                                qubits[i])
        for j in range(1, min(size - i, tol)):
            yield cirq.ControlledGate(CZP(exponent=1 / (2**(j))),
                                      num_controls=len(control))(*control,
                                                                 qubits[i],
                                                                 qubits[i + j])

    for i in range(
            size // 2
    ):  # Applies swap gates to switch order of qubits at the end of the circuit.
        yield cirq.ControlledGate(SWAP, num_controls=len(control))(
            *control, qubits[i], qubits[size - i - 1])

    for i in range(
            size
    ):  # Adds measurement operators at the end of the circuit if mea is set to true.
        if mea:
            yield measure(qubits[i], key='q{}'.format(str(i)))
Exemple #11
0
def _generate_sample_2q_xeb_tasks(
    zipped_circuits: List[_ZippedCircuit], cycle_depths: Sequence[int]
) -> List[_Sample2qXEBTask]:
    """Helper function used in `sample_2q_xeb_circuits` to prepare circuits in sampling tasks."""
    tasks: List[_Sample2qXEBTask] = []
    for cycle_depth in cycle_depths:
        for zipped_circuit in zipped_circuits:
            circuit_depth = cycle_depth * 2 + 1
            assert circuit_depth <= len(zipped_circuit.wide_circuit)
            # Slicing creates a copy, although this isn't documented
            prepared_circuit = zipped_circuit.wide_circuit[:circuit_depth]
            prepared_circuit += Moment(
                ops.measure(*pair, key=str(pair_i))
                for pair_i, pair in enumerate(zipped_circuit.pairs)
            )
            tasks.append(
                _Sample2qXEBTask(
                    cycle_depth=cycle_depth,
                    layer_i=zipped_circuit.layer_i,
                    combination_i=zipped_circuit.combination_i,
                    prepared_circuit=prepared_circuit,
                    combination=zipped_circuit.combination,
                )
            )
    return tasks
Exemple #12
0
def t1_decay(
    sampler: 'cirq.Sampler',
    *,
    qubit: 'cirq.Qid',
    num_points: int,
    max_delay: 'cirq.DURATION_LIKE',
    min_delay: 'cirq.DURATION_LIKE' = None,
    repetitions: int = 1000,
) -> 'cirq.experiments.T1DecayResult':
    """Runs a t1 decay experiment.

    Initializes a qubit into the |1⟩ state, waits for a variable amount of time,
    and measures the qubit. Plots how often the |1⟩ state is observed for each
    amount of waiting.

    Args:
        sampler: The quantum engine or simulator to run the circuits.
        qubit: The qubit under test.
        num_points: The number of evenly spaced delays to test.
        max_delay: The largest delay to test.
        min_delay: The smallest delay to test. Defaults to no delay.
        repetitions: The number of repetitions of the circuit for each delay.

    Returns:
        A T1DecayResult object that stores and can plot the data.
    """
    min_delay_dur = value.Duration(min_delay)
    max_delay_dur = value.Duration(max_delay)

    if repetitions <= 0:
        raise ValueError('repetitions <= 0')
    if max_delay_dur < min_delay_dur:
        raise ValueError('max_delay < min_delay')
    if min_delay_dur < 0:
        raise ValueError('min_delay < 0')
    var = sympy.Symbol('delay_ns')

    sweep = study.Linspace(var,
                           start=min_delay_dur.total_nanos(),
                           stop=max_delay_dur.total_nanos(),
                           length=num_points)

    circuit = circuits.Circuit(
        ops.X(qubit),
        ops.wait(qubit, nanos=var),
        ops.measure(qubit, key='output'),
    )

    results = sampler.sample(circuit, params=sweep, repetitions=repetitions)

    # Cross tabulate into a delay_ns, false_count, true_count table.
    tab = pd.crosstab(results.delay_ns, results.output)
    tab.rename_axis(None, axis="columns", inplace=True)
    tab = tab.rename(columns={0: 'false_count', 1: 'true_count'}).reset_index()
    for col_index, name in [(1, 'false_count'), (2, 'true_count')]:
        if name not in tab:
            tab.insert(col_index, name, [0] * tab.shape[0])

    return T1DecayResult(tab)
def single_qubit_randomized_benchmarking(
    sampler: 'cirq.Sampler',
    qubit: 'cirq.Qid',
    use_xy_basis: bool = True,
    *,
    num_clifford_range: Sequence[int] = range(10, 100, 10),
    num_circuits: int = 20,
    repetitions: int = 1000,
) -> RandomizedBenchMarkResult:
    """Clifford-based randomized benchmarking (RB) of a single qubit.

    A total of num_circuits random circuits are generated, each of which
    contains a fixed number of single-qubit Clifford gates plus one
    additional Clifford that inverts the whole sequence and a measurement in
    the z-basis. Each circuit is repeated a number of times and the average
    |0> state population is determined from the measurement outcomes of all
    of the circuits.

    The above process is done for different circuit lengths specified by the
    integers in num_clifford_range. For example, an integer 10 means the
    random circuits will contain 10 Clifford gates each plus one inverting
    Clifford. The user may use the result to extract an average gate fidelity,
    by analyzing the change in the average |0> state population at different
    circuit lengths. For actual experiments, one should choose
    num_clifford_range such that a clear exponential decay is observed in the
    results.

    See Barends et al., Nature 508, 500 for details.

    Args:
        sampler: The quantum engine or simulator to run the circuits.
        qubit: The qubit under test.
        use_xy_basis: Determines if the Clifford gates are built with x and y
            rotations (True) or x and z rotations (False).
        num_clifford_range: The different numbers of Cliffords in the RB study.
        num_circuits: The number of random circuits generated for each
            number of Cliffords.
        repetitions: The number of repetitions of each circuit.

    Returns:
        A RandomizedBenchMarkResult object that stores and plots the result.
    """

    cliffords = _single_qubit_cliffords()
    c1 = cliffords.c1_in_xy if use_xy_basis else cliffords.c1_in_xz
    cfd_mats = np.array([_gate_seq_to_mats(gates) for gates in c1])

    gnd_probs = []
    for num_cfds in num_clifford_range:
        excited_probs_l = []
        for _ in range(num_circuits):
            circuit = _random_single_q_clifford(qubit, num_cfds, c1, cfd_mats)
            circuit.append(ops.measure(qubit, key='z'))
            results = sampler.run(circuit, repetitions=repetitions)
            excited_probs_l.append(np.mean(results.measurements['z']))
        gnd_probs.append(1.0 - np.mean(excited_probs_l))

    return RandomizedBenchMarkResult(num_clifford_range, gnd_probs)
def two_qubit_randomized_benchmarking(
    sampler: 'cirq.Sampler',
    first_qubit: 'cirq.Qid',
    second_qubit: 'cirq.Qid',
    *,
    num_clifford_range: Sequence[int] = range(5, 50, 5),
    num_circuits: int = 20,
    repetitions: int = 1000,
) -> RandomizedBenchMarkResult:
    """Clifford-based randomized benchmarking (RB) of two qubits.

    A total of num_circuits random circuits are generated, each of which
    contains a fixed number of two-qubit Clifford gates plus one additional
    Clifford that inverts the whole sequence and a measurement in the
    z-basis. Each circuit is repeated a number of times and the average
    |00> state population is determined from the measurement outcomes of all
    of the circuits.

    The above process is done for different circuit lengths specified by the
    integers in num_clifford_range. For example, an integer 10 means the
    random circuits will contain 10 Clifford gates each plus one inverting
    Clifford. The user may use the result to extract an average gate fidelity,
    by analyzing the change in the average |00> state population at different
    circuit lengths. For actual experiments, one should choose
    num_clifford_range such that a clear exponential decay is observed in the
    results.

    The two-qubit Cliffords here are decomposed into CZ gates plus single-qubit
    x and y rotations. See Barends et al., Nature 508, 500 for details.

    Args:
        sampler: The quantum engine or simulator to run the circuits.
        first_qubit: The first qubit under test.
        second_qubit: The second qubit under test.
        num_clifford_range: The different numbers of Cliffords in the RB study.
        num_circuits: The number of random circuits generated for each
            number of Cliffords.
        repetitions: The number of repetitions of each circuit.

    Returns:
        A RandomizedBenchMarkResult object that stores and plots the result.
    """
    cliffords = _single_qubit_cliffords()
    cfd_matrices = _two_qubit_clifford_matrices(first_qubit, second_qubit,
                                                cliffords)
    gnd_probs = []
    for num_cfds in num_clifford_range:
        gnd_probs_l = []
        for _ in range(num_circuits):
            circuit = _random_two_q_clifford(first_qubit, second_qubit,
                                             num_cfds, cfd_matrices, cliffords)
            circuit.append(ops.measure(first_qubit, second_qubit, key='z'))
            results = sampler.run(circuit, repetitions=repetitions)
            gnds = [(not r[0] and not r[1]) for r in results.measurements['z']]
            gnd_probs_l.append(np.mean(gnds))
        gnd_probs.append(float(np.mean(gnd_probs_l)))

    return RandomizedBenchMarkResult(num_clifford_range, gnd_probs)
Exemple #15
0
def _circuit_plus_pauli_string_measurements(
        circuit: 'cirq.Circuit',
        pauli_string: 'cirq.PauliString') -> 'cirq.Circuit':
    """A circuit measuring the given observable at the end of the given circuit."""
    assert pauli_string
    circuit = circuit.copy()
    circuit.append(ops.Moment(pauli_string.to_z_basis_ops()))
    circuit.append(
        ops.Moment([ops.measure(*sorted(pauli_string.keys()), key='out')]))
    return circuit
def _measurement(identifier: str,
                 basis_change: Optional['cirq.Gate'] = None) -> CellMaker:
    return CellMaker(
        identifier=identifier,
        size=1,
        maker=lambda args: ExplicitOperationsCell(
            [ops.measure(*args.qubits, key=f'row={args.row},col={args.col}')],
            basis_change=cast(Iterable['cirq.Operation'],
                              [basis_change.on(*args.qubits)]
                              if basis_change else ())))
Exemple #17
0
def test_scale_with_measurement():
    """Tests that we ignore measurement gates.

    Test circuit:
    0: ───H───T───@───M───
                  │   │
    1: ───H───M───┼───┼───
                  │   │
    2: ───H───────X───M───

    """
    qreg = LineQubit.range(3)
    circ = Circuit(
        [ops.H.on_each(qreg)],
        [ops.T.on(qreg[0])],
        [ops.measure(qreg[1])],
        [ops.CNOT.on(qreg[0], qreg[2])],
        [ops.measure(qreg[0], qreg[2])],
    )
    scaled = scale_parameters(circ, scale_factor=1, sigma=0.001)
    assert _equal(circ, scaled)
 def run_truncated_circuit(truncated_circuit: 'cirq.Circuit',
                           layer: GridInteractionLayer, depth: int,
                           circuit_index: int) -> None:
     print(f'\tSampling from circuit {circuit_index} of layer {layer}.')
     truncated_circuit.append(ops.measure(*qubits, key='m'))
     trial_result = sampler.run(truncated_circuit, repetitions=repetitions)
     trial_result_params = GridParallelXEBTrialResultParameters(
         data_collection_id=cast(str, data_collection_id),
         layer=layer,
         depth=depth,
         circuit_index=circuit_index)
     save(trial_result_params, trial_result, base_dir=base_dir)
Exemple #19
0
def test_is_measurement():
    """Tests for checking if operations are measurements."""
    # Test circuit:
    # 0: ───H───X───Z───
    qbit = LineQubit(0)
    circ = Circuit(
        [ops.H.on(qbit), ops.X.on(qbit), ops.Z.on(qbit), ops.measure(qbit)]
    )
    for (i, op) in enumerate(circ.all_operations()):
        if i == 3:
            assert _is_measurement(op)
        else:
            assert not _is_measurement(op)
 def sample(
     self,
     qubits: Sequence['cirq.Qid'],
     repetitions: int = 1,
     seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None,
 ) -> np.ndarray:
     measurements: Dict[str, List[np.ndarray]] = {}
     prng = value.parse_random_state(seed)
     for i in range(repetitions):
         op = ops.measure(*qubits, key=str(i))
         state = self.state.copy()
         ch_form_args = ActOnStabilizerCHFormArgs(state, prng, measurements, self.qubits)
         protocols.act_on(op, ch_form_args)
     return np.array(list(measurements.values()), dtype=bool)
Exemple #21
0
    def compute_samples_displays_sweep(
            self,
            program: Union[circuits.Circuit, schedules.Schedule],
            params: Optional[study.Sweepable] = None
    ) -> List[study.ComputeDisplaysResult]:
        """Computes SamplesDisplays in the supplied Circuit or Schedule.

        In contrast to `compute_displays`, this allows for sweeping
        over different parameter values.

        Args:
            program: The circuit or schedule to simulate.
            params: Parameters to run with the program.

        Returns:
            List of ComputeDisplaysResults for this run, one for each
            possible parameter resolver.
        """
        circuit = (program if isinstance(program, circuits.Circuit)
                   else program.to_circuit())
        param_resolvers = study.to_resolvers(params or study.ParamResolver({}))

        compute_displays_results = []  # type: List[study.ComputeDisplaysResult]
        for param_resolver in param_resolvers:
            display_values = {}  # type: Dict[Hashable, Any]
            preceding_circuit = circuits.Circuit()
            for i, moment in enumerate(circuit):
                displays = (op for op in moment
                            if isinstance(op, ops.SamplesDisplay))
                for display in displays:
                    measurement_key = str(display.key)
                    measurement_circuit = circuits.Circuit.from_ops(
                        display.measurement_basis_change(),
                        ops.measure(*display.qubits,
                                    key=measurement_key)
                    )
                    measurements = self._run(
                        preceding_circuit + measurement_circuit,
                        param_resolver,
                        display.num_samples)
                    display_values[display.key] = (
                        display.value_derived_from_samples(
                            measurements[measurement_key]))
                preceding_circuit.append(circuit[i])
            compute_displays_results.append(study.ComputeDisplaysResult(
                params=param_resolver,
                display_values=display_values))

        return compute_displays_results
Exemple #22
0
def _measure_prob_distribution(
        sampler: work.Sampler, repetitions: int, qubits: Sequence[ops.Qid],
        circuit_list: List[circuits.Circuit]) -> List[np.ndarray]:
    all_probs = []  # type: List[np.ndarray]
    num_states = 2**len(qubits)
    for circuit in circuit_list:
        trial_circuit = circuit.copy()
        trial_circuit.append(ops.measure(*qubits, key='z'))
        res = sampler.run(trial_circuit, repetitions=repetitions)
        res_hist = dict(res.histogram(key='z'))
        probs = np.zeros(num_states, dtype=float)
        for k, v in res_hist.items():
            probs[k] = float(v) / float(repetitions)
        all_probs.append(probs)
    return all_probs
Exemple #23
0
 def generate_circuit_from_list(self, json_string: str):
     """Generates a list of cirq operations from a json string
     Args:
         json_string: json that specifies the sequence
     """
     self.circuit = Circuit()
     # TODO add ion device here, is this still required?
     json_obj = json.loads(json_string)
     for gate_list in json_obj:
         gate = gate_list[0]
         angle = gate_list[1]
         qubits = [self.qubit_list[i] for i in gate_list[2]]
         self.circuit.append(gate_dict[gate].on(*qubits)**angle)
     # TODO: Better solution for measurement at the end
     self.circuit.append(
         ops.measure(*[qubit for qubit in self.qubit_list], key='m'))
Exemple #24
0
    def generate_circuit_from_list(self, json_string: str):
        """Generates a list of cirq operations from a json string.

        The default behavior is to add a measurement to any qubit at the end
        of the circuit as there are no measurements defined in the AQT API.

        Args:
            json_string: json that specifies the sequence
        """
        self.circuit = Circuit()
        json_obj = json.loads(json_string)
        for gate_list in json_obj:
            gate = gate_list[0]
            angle = gate_list[1]
            qubits = [self.qubit_list[i] for i in gate_list[2]]
            self.circuit.append(gate_dict[gate].on(*qubits)**angle)
        # TODO: Better solution for measurement at the end. Issue #2199
        self.circuit.append(
            ops.measure(*[qubit for qubit in self.qubit_list], key='m'))
def measure_confusion_matrix(
    sampler: 'cirq.Sampler',
    qubits: Union[Sequence['cirq.Qid'], Sequence[Sequence['cirq.Qid']]],
    repetitions: int = 1000,
) -> TensoredConfusionMatrices:
    """Prepares `TensoredConfusionMatrices` for the n qubits in the input.

    The confusion matrix (CM) for two qubits is the following matrix:

        ⎡ Pr(00|00) Pr(01|00) Pr(10|00) Pr(11|00) ⎤
        ⎢ Pr(00|01) Pr(01|01) Pr(10|01) Pr(11|01) ⎥
        ⎢ Pr(00|10) Pr(01|10) Pr(10|10) Pr(11|10) ⎥
        ⎣ Pr(00|11) Pr(01|11) Pr(10|11) Pr(11|11) ⎦

    where Pr(ij | pq) = Probability of observing “ij” given state “pq” was prepared.

    Args:
        sampler: Sampler to collect the data from.
        qubits: Qubits for which the confusion matrix should be measured.
        repetitions: Number of times to sample each circuit for a confusion matrix row.
    """
    qubits = cast(Sequence[Sequence['cirq.Qid']],
                  [qubits] if isinstance(qubits[0], ops.Qid) else qubits)
    confusion_matrices = []
    for qs in qubits:
        flip_symbols = sympy.symbols(f'flip_0:{len(qs)}')
        flip_circuit = circuits.Circuit(
            [ops.X(q)**s for q, s in zip(qs, flip_symbols)],
            ops.measure(*qs),
        )
        sweeps = study.Product(
            *[study.Points(f'flip_{i}', [0, 1]) for i in range(len(qs))])
        results = sampler.run_sweep(flip_circuit,
                                    sweeps,
                                    repetitions=repetitions)
        confusion_matrices.append(
            np.asarray([vis.get_state_histogram(r) for r in results],
                       dtype=float) / repetitions)
    return TensoredConfusionMatrices(confusion_matrices,
                                     qubits,
                                     repetitions=repetitions,
                                     timestamp=time.time())
def get_state_tomography_data(
    sampler: 'cirq.Sampler',
    qubits: Sequence['cirq.Qid'],
    circuit: 'cirq.Circuit',
    rot_circuit: 'cirq.Circuit',
    rot_sweep: 'cirq.Sweep',
    repetitions: int = 1000,
) -> np.ndarray:
    """Gets the data for each rotation string added to the circuit.

    For each sequence in prerotation_sequences gets the probability of all
    2**n bit strings.  Resulting matrix will have dimensions
    (len(rot_sweep)**n, 2**n).
    This is a default way to get data that can be replaced by the user if they
    have a more advanced protocol in mind.

    Args:
        sampler: Sampler to collect the data from.
        qubits: Qubits to do the tomography on.
        circuit: Circuit to do the tomography on.
        rot_circuit: Circuit with parameterized rotation gates to do before the
            final measurements.
        rot_sweep: The list of rotations on the qubits to perform before
            measurement.
        repetitions: Number of times to sample each rotation sequence.

    Returns:
        2D array of probabilities, where first index is which pre-rotation was
        applied and second index is the qubit state.
    """
    results = sampler.run_sweep(
        circuit + rot_circuit + [ops.measure(*qubits, key='z')],
        params=rot_sweep,
        repetitions=repetitions,
    )

    all_probs = []
    for result in results:
        hist = result.histogram(key='z')
        probs = [hist[i] for i in range(2**len(qubits))]
        all_probs.append(np.array(probs) / repetitions)
    return np.array(all_probs)
def order_find(a, N, zeros_qubits, x_qubits, anc0, m_qubits):

    m_qubits.reverse(
    )  # Reverces the order of the measurment qubits so the order is cosistant with the other programs.

    for qubit in m_qubits:  # Applies hadamards to the measurment qubits.
        yield H(qubit)

    for qubit in x_qubits:  # Sets the x qubits to 1.
        yield X(qubit)

    for i, c in enumerate(
            m_qubits
    ):  # applies sucessive multiplying gates to x_qubits controlled by the measurment qubits.
        yield c_ua(a**(2**i) % N, N, zeros_qubits, x_qubits, [anc0, c])

    for gate in reversecir(qft(
            m_qubits)):  # Applies the reverse qft on the measurment qubits.
        yield gate

    yield measure(*m_qubits, key='q')
Exemple #28
0
    circuit.append(H(q2))

    if humanMove == "s":
        circuit.append(S(q2))
    else:
        circuit.append(cirq.inverse(S(q2)))

    circuit.append([
        H(qubits[opponent]),
        S(q2),
        H(q2),
        CNOT(qubits[opponent], q2),
        H(q2),
        H(q2),
        measure(q2, key="m")
    ])

    print(circuit)

    simulator = cirq.Simulator()
    results = simulator.run(circuit, repetitions=1)
    # print(results.histogram(key="m"))
    keys = results.histogram(key="m").keys()

    for key in keys:
        if key == 1:
            print("You win!")
        elif key == 0:
            print("You lose")
        else:
import cirq
from cirq.ops import H, T, CNOT, measure
from cirq.circuits import InsertStrategy

q0, q1, q2 = [cirq.GridQubit(i, 0) for i in range(3)]
circuit = cirq.Circuit()

circuit.append([H(q0)], strategy=InsertStrategy.NEW)
circuit.append([H(q1)], strategy=InsertStrategy.NEW)
circuit.append([H(q2)], strategy=InsertStrategy.NEW)

circuit.append([T(q0)], strategy=InsertStrategy.NEW)
circuit.append([T(q1)], strategy=InsertStrategy.NEW)
circuit.append([T(q2)], strategy=InsertStrategy.NEW)

circuit.append([CNOT(q0, q1)], strategy=InsertStrategy.NEW)

circuit.append([measure(q0)], strategy=InsertStrategy.NEW)
circuit.append([measure(q1)], strategy=InsertStrategy.NEW)
circuit.append([measure(q2)], strategy=InsertStrategy.NEW)

print(circuit)
Exemple #30
0
def t2_decay(
    sampler: 'cirq.Sampler',
    *,
    qubit: 'cirq.Qid',
    experiment_type: 'ExperimentType' = ExperimentType.RAMSEY,
    num_points: int,
    max_delay: 'cirq.DURATION_LIKE',
    min_delay: 'cirq.DURATION_LIKE' = None,
    repetitions: int = 1000,
    delay_sweep: Optional[study.Sweep] = None,
    num_pulses: List[int] = None
) -> Union['cirq.experiments.T2DecayResult',
           List['cirq.experiments.T2DecayResult']]:
    """Runs a t2 transverse relaxation experiment.

    Initializes a qubit into a superposition state, evolves the system using
    rules determined by the experiment type and by the delay parameters,
    then rotates back for measurement.  This will measure the phase decoherence
    decay.  This experiment has three types of T2 metrics, each which measure
    a different slice of the noise spectrum.

    For the Ramsey experiment type (often denoted T2*), the state will be
    prepared with a square root Y gate (`cirq.Y ** 0.5`) and then waits for
    a variable amount of time.  After this time, it will do basic state
    tomography to measure the expectation of the Pauli-X and Pauli-Y operators
    by performing either a `cirq.Y ** -0.5` or `cirq.X ** 0.5`.  The square of
    these two measurements is summed to determine the length of the Bloch
    vector. This experiment measures the phase decoherence of the system under
    free evolution.

    For the Hahn echo experiment (often denoted T2 or spin echo), the state
    will also be prepared with a square root Y gate (`cirq.Y ** 0.5`).
    However, during the mid-point of the delay time being measured, a pi-pulse
    (`cirq.X`) gate will be applied to cancel out inhomogeneous dephasing.
    The same method of measuring the final state as Ramsey experiment is applied
    after the second half of the delay period.  See the animation on the wiki
    page https://en.wikipedia.org/wiki/Spin_echo for a visual illustration
    of this experiment.

    CPMG, or the Carr-Purcell-Meiboom-Gill sequence, involves using a sqrt(Y)
    followed by a sequence of pi pulses (X gates) in a specific timing pattern:

        π/2, t, π, 2t, π, ... 2t, π, t

    The first pulse, a sqrt(Y) gate, will put the qubit's state on the Bloch
    equator.  After a delay, successive X gates will refocus dehomogenous
    phase effects by causing them to precess in opposite directions and
    averaging their effects across the entire pulse train.

    This pulse pattern has two variables that can be adjusted.  The first,
    denoted as 't' in the above sequence, is delay, which can be specified
    with `delay_min` and `delay_max` or by using a `delay_sweep`, similar to
    the other experiments.  The second variable is the number of pi pulses
    (X gates).  This can be specified as a list of integers using the
    `num_pulses` parameter.  If multiple different pulses are specified,
    the data will be presented in a data frame with two
    indices (delay_ns and num_pulses).

    See the following reference for more information about CPMG pulse trains:
    Meiboom, S., and D. Gill, “Modified spin-echo method for measuring nuclear
    relaxation times”, Rev. Sci. Inst., 29, 688–691 (1958).
    https://doi.org/10.1063/1.1716296

    Note that interpreting T2 data is fairly tricky and subtle, as it can
    include other effects that need to be accounted for.  For instance,
    amplitude damping (T1) will present as T2 noise and needs to be
    appropriately compensated for to find a true measure of T2.  Due to this
    subtlety and lack of standard way to interpret the data, the fitting
    of the data to an exponential curve and the extrapolation of an actual
    T2 time value is left as an exercise to the reader.

    Args:
        sampler: The quantum engine or simulator to run the circuits.
        qubit: The qubit under test.
        experiment_type: The type of T2 test to run.
        num_points: The number of evenly spaced delays to test.
        max_delay: The largest delay to test.
        min_delay: The smallest delay to test. Defaults to no delay.
        repetitions: The number of repetitions of the circuit
             for each delay and for each tomography result.
        delay_sweep: Optional range of time delays to sweep across.  This should
             be a SingleSweep using the 'delay_ns' with values in integer number
             of nanoseconds.  If specified, this will override the max_delay and
             min_delay parameters.  If not specified, the experiment will sweep
             from min_delay to max_delay with linear steps.
        num_pulses: For CPMG, a list of the number of pulses to use.
             If multiple pulses are specified, each will be swept on.
    Returns:
        A T2DecayResult object that stores and can plot the data.
    """
    min_delay_dur = value.Duration(min_delay)
    max_delay_dur = value.Duration(max_delay)

    # Input validation
    if repetitions <= 0:
        raise ValueError('repetitions <= 0')
    if max_delay_dur < min_delay_dur:
        raise ValueError('max_delay < min_delay')
    if min_delay_dur < 0:
        raise ValueError('min_delay < 0')
    if num_pulses and experiment_type != ExperimentType.CPMG:
        raise ValueError('num_pulses is only valid for CPMG experiments.')

    # Initialize values used in sweeps
    delay_var = sympy.Symbol('delay_ns')
    inv_x_var = sympy.Symbol('inv_x')
    inv_y_var = sympy.Symbol('inv_y')
    max_pulses = max(num_pulses) if num_pulses else 0

    if not delay_sweep:
        delay_sweep = study.Linspace(delay_var,
                                     start=min_delay_dur.total_nanos(),
                                     stop=max_delay_dur.total_nanos(),
                                     length=num_points)
    if delay_sweep.keys != ['delay_ns']:
        raise ValueError('delay_sweep must be a SingleSweep '
                         'with delay_ns parameter')

    if experiment_type == ExperimentType.RAMSEY:
        # Ramsey T2* experiment
        # Use sqrt(Y) to flip to the equator.
        # Evolve the state for a given amount of delay time
        # Then measure the state in both X and Y bases.

        circuit = circuits.Circuit(
            ops.Y(qubit)**0.5,
            ops.wait(qubit, nanos=delay_var),
        )
    else:
        if experiment_type == ExperimentType.HAHN_ECHO:
            # Hahn / Spin Echo T2 experiment
            # Use sqrt(Y) to flip to the equator.
            # Evolve the state for the given amount of delay time
            # Flip the state using an X gate
            # Evolve the state for the given amount of delay time
            # Then measure the state in both X and Y bases.
            num_pulses = [0]
            # This is equivalent to a CPMG experiment with zero pulses
            # and will follow the same code path.

        # Carr-Purcell-Meiboom-Gill sequence.
        # Performs the following sequence
        # π/2 - wait(t) - π - wait(2t) - ... - π - wait(t)
        # There will be N π pulses (X gates)
        # where N sweeps over the values of num_pulses
        #
        if not num_pulses:
            raise ValueError('At least one value must be given '
                             'for num_pulses in a CPMG experiment')
        circuit = _cpmg_circuit(qubit, delay_var, max_pulses)

    # Add simple state tomography
    circuit.append(ops.X(qubit)**inv_x_var)
    circuit.append(ops.Y(qubit)**inv_y_var)
    circuit.append(ops.measure(qubit, key='output'))
    tomography_sweep = study.Zip(
        study.Points('inv_x', [0.0, 0.5]),
        study.Points('inv_y', [-0.5, 0.0]),
    )

    if num_pulses and max_pulses > 0:
        pulse_sweep = _cpmg_sweep(num_pulses)
        sweep = study.Product(delay_sweep, pulse_sweep, tomography_sweep)
    else:
        sweep = study.Product(delay_sweep, tomography_sweep)

    # Tabulate measurements into a histogram
    results = sampler.sample(circuit, params=sweep, repetitions=repetitions)

    y_basis_measurements = results[abs(results.inv_y) > 0].copy()
    x_basis_measurements = results[abs(results.inv_x) > 0].copy()

    if num_pulses and len(num_pulses) > 1:
        cols = tuple(f'pulse_{t}' for t in range(max_pulses))
        x_basis_measurements[
            'num_pulses'] = x_basis_measurements.loc[:, cols].sum(axis=1)
        y_basis_measurements[
            'num_pulses'] = y_basis_measurements.loc[:, cols].sum(axis=1)

    x_basis_tabulation = _create_tabulation(x_basis_measurements)
    y_basis_tabulation = _create_tabulation(y_basis_measurements)

    # Return the results in a container object
    return T2DecayResult(x_basis_tabulation, y_basis_tabulation)