def flip_inversion(op: 'cirq.Operation', _) -> 'cirq.OP_TREE':
     if isinstance(op.gate, ops.MeasurementGate):
         return [
             ops.X(q) if b else ops.I(q)
             for q, b in zip(op.qubits, op.gate.full_invert_mask())
         ]
     return op
Example #2
0
    def expand_to(self, qubits: Iterable['cirq.Qid']) -> 'cirq.Moment':
        """Returns self expanded to given superset of qubits by making identities explicit."""
        if not self.qubits.issubset(qubits):
            raise ValueError(f'{qubits} is not a superset of {self.qubits}')

        operations = list(self.operations)
        for q in set(qubits) - self.qubits:
            operations.append(ops.I(q))
        return Moment(*operations)
Example #3
0
    def expand_to(self, qubits: Iterable['cirq.Qid']) -> 'cirq.Moment':
        """Returns self expanded to given superset of qubits by making identities explicit.

        Args:
            qubits: Iterable of `cirq.Qid`s to expand this moment to.

        Returns:
            A new `cirq.Moment` with identity operations on the new qubits
            not currently found in the moment.

        Raises:
            ValueError: if this moments' qubits are not a subset of `qubits`.
        """
        if not self.qubits.issubset(qubits):
            raise ValueError(f'{qubits} is not a superset of {self.qubits}')

        operations = list(self.operations)
        for q in set(qubits) - self.qubits:
            operations.append(ops.I(q))
        return Moment(*operations)
def test_from_braket_non_parameterized_single_qubit_gates():
    braket_circuit = BKCircuit()
    instructions = [
        Instruction(braket_gates.I(), target=0),
        Instruction(braket_gates.X(), target=1),
        Instruction(braket_gates.Y(), target=2),
        Instruction(braket_gates.Z(), target=3),
        Instruction(braket_gates.H(), target=0),
        Instruction(braket_gates.S(), target=1),
        Instruction(braket_gates.Si(), target=2),
        Instruction(braket_gates.T(), target=3),
        Instruction(braket_gates.Ti(), target=0),
        Instruction(braket_gates.V(), target=1),
        Instruction(braket_gates.Vi(), target=2),
    ]
    for instr in instructions:
        braket_circuit.add_instruction(instr)
    cirq_circuit = from_braket(braket_circuit)

    for i, op in enumerate(cirq_circuit.all_operations()):
        assert np.allclose(
            instructions[i].operator.to_matrix(), protocols.unitary(op)
        )

    qreg = LineQubit.range(4)
    expected_cirq_circuit = Circuit(
        ops.I(qreg[0]),
        ops.X(qreg[1]),
        ops.Y(qreg[2]),
        ops.Z(qreg[3]),
        ops.H(qreg[0]),
        ops.S(qreg[1]),
        ops.S(qreg[2]) ** -1,
        ops.T(qreg[3]),
        ops.T(qreg[0]) ** -1,
        ops.X(qreg[1]) ** 0.5,
        ops.X(qreg[2]) ** -0.5,
    )
    assert _equal(cirq_circuit, expected_cirq_circuit)
Example #5
0
    def sample_from_amplitudes(
        self,
        circuit: 'cirq.AbstractCircuit',
        param_resolver: 'cirq.ParamResolver',
        seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE',
        repetitions: int = 1,
        qubit_order: 'cirq.QubitOrderOrList' = ops.QubitOrder.DEFAULT,
    ) -> Dict[int, int]:
        """Uses amplitude simulation to sample from the given circuit.

        This implements the algorithm outlined by Bravyi, Gosset, and Liu in
        https://arxiv.org/abs/2112.08499 to more efficiently calculate samples
        given an amplitude-based simulator.

        Simulators which also implement SimulatesSamples or SimulatesFullState
        should prefer `run()` or `simulate()`, respectively, as this method
        only accelerates sampling for amplitude-based simulators.

        Args:
            circuit: The circuit to simulate.
            param_resolver: Parameters to run with the program.
            seed: Random state to use as a seed. This must be provided
                manually - if the simulator has its own seed, it will not be
                used unless it is passed as this argument.
            repetitions: The number of repetitions to simulate.
            qubit_order: Determines the canonical ordering of the qubits. This
                is often used in specifying the initial state, i.e. the
                ordering of the computational basis states.

        Returns:
            A dict of bitstrings sampled from the final state of `circuit` to
            the number of occurrences of that bitstring.

        Raises:
            ValueError: if 'circuit' has non-unitary elements, as differences
                in behavior between sampling steps break this algorithm.
        """
        prng = value.parse_random_state(seed)
        qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for(
            circuit.all_qubits())
        base_circuit = circuits.Circuit(ops.I(q)
                                        for q in qubits) + circuit.unfreeze()
        qmap = {q: i for i, q in enumerate(qubits)}
        current_samples = {(0, ) * len(qubits): repetitions}
        solved_circuit = protocols.resolve_parameters(base_circuit,
                                                      param_resolver)
        if not protocols.has_unitary(solved_circuit):
            raise ValueError(
                "sample_from_amplitudes does not support non-unitary behavior."
            )
        if protocols.is_measurement(solved_circuit):
            raise ValueError(
                "sample_from_amplitudes does not support intermediate measurement."
            )
        for m_id, moment in enumerate(solved_circuit[1:]):
            circuit_prefix = solved_circuit[:m_id + 1]
            for t, op in enumerate(moment.operations):
                new_samples: Dict[Tuple[int, ...],
                                  int] = collections.defaultdict(int)
                qubit_indices = {qmap[q] for q in op.qubits}
                subcircuit = circuit_prefix + circuits.Moment(
                    moment.operations[:t + 1])
                for current_sample, count in current_samples.items():
                    sample_set = [current_sample]
                    for idx in qubit_indices:
                        sample_set = [
                            target[:idx] + (result, ) + target[idx + 1:]
                            for target in sample_set for result in [0, 1]
                        ]
                    bitstrings = [
                        int(''.join(map(str, sample)), base=2)
                        for sample in sample_set
                    ]
                    amps = self.compute_amplitudes(subcircuit,
                                                   bitstrings,
                                                   qubit_order=qubit_order)
                    weights = np.abs(np.square(np.array(amps))).astype(
                        np.float64)
                    weights /= np.linalg.norm(weights, 1)
                    subsample = prng.choice(len(sample_set),
                                            p=weights,
                                            size=count)
                    for sample_index in subsample:
                        new_samples[sample_set[sample_index]] += 1
                current_samples = new_samples

        return {
            int(''.join(map(str, k)), base=2): v
            for k, v in current_samples.items()
        }