Пример #1
0
    def _base_iterator(self,
                       circuit: circuits.Circuit,
                       qubit_order: ops.QubitOrderOrList,
                       initial_state: Union[int, np.ndarray],
                       perform_measurements: bool = True) -> Iterator:

        qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for(
            circuit.all_qubits())
        num_qubits = len(qubits)
        qubit_map = {q: i for i, q in enumerate(qubits)}
        matrix = to_valid_density_matrix(initial_state,
                                         num_qubits,
                                         dtype=self._dtype)
        if len(circuit) == 0:
            yield DensityMatrixStepResult(matrix, {},
                                          qubit_map,
                                          dtype=self._dtype)

        matrix = np.reshape(matrix, (2**num_qubits, 2**num_qubits))
        noisy_moments = self.noise.noisy_moments(circuit,
                                                 sorted(circuit.all_qubits()))

        state = qulacs.DensityMatrix(num_qubits)
        state.load(matrix)

        for moment in noisy_moments:
            measurements = collections.defaultdict(
                list)  # type: Dict[str, List[bool]]
            operations = moment.operations
            for op in operations:
                indices = [
                    num_qubits - 1 - qubit_map[qubit] for qubit in op.qubits
                ]
                indices.reverse()

                if isinstance(op, ops.MeasurementGate):
                    # Not implemented
                    raise NotImplementedError(
                        "Measurement is not supported in qulacs simulator")

                else:
                    gate = cast(ops.GateOperation, op).gate
                    channel = protocols.channel(gate)

                    qulacs_gates = []
                    for krauss in channel:
                        krauss = krauss.astype(np.complex128)
                        qulacs_gate = qulacs.gate.DenseMatrix(indices, krauss)
                        qulacs_gates.append(qulacs_gate)
                    qulacs_cptp_map = qulacs.gate.CPTP(qulacs_gates)
                    qulacs_cptp_map.update_quantum_state(state)

            matrix = state.get_matrix()
            matrix = np.reshape(matrix, (2, ) * num_qubits * 2)

            yield DensityMatrixStepResult(density_matrix=matrix,
                                          measurements=measurements,
                                          qubit_map=qubit_map,
                                          dtype=self._dtype)
Пример #2
0
    def _channel_(self):
        if self._is_parameterized_():
            return NotImplemented

        channel = protocols.channel(self.sub_gate, None)
        if channel is None:
            return NotImplemented

        do_nothing = np.eye(np.product(protocols.qid_shape(self.sub_gate)),
                            dtype=np.float64)
        result = [e * np.sqrt(self.probability) for e in channel]
        result.append(np.sqrt(1 - float(self.probability)) * do_nothing)
        return result
Пример #3
0
def operation_to_channel_matrix(
        operation: 'protocols.SupportsChannel') -> np.ndarray:
    """Returns the matrix representation of a superoperator in standard basis.

    Let E: L(H1) -> L(H2) denote a linear map which takes linear operators on Hilbert space H1
    to linear operators on Hilbert space H2 and let d1 = dim H1 and d2 = dim H2. Also, let Fij
    denote an operator whose matrix has one in ith row and jth column and zeros everywhere else.
    Note that d1-by-d1 operators Fij form a basis of L(H1). Similarly, d2-by-d2 operators Fij
    form a basis of L(H2). This function returns the matrix of E in these bases.

    Args:
        operation: Quantum channel.
    Returns:
        Matrix representation of operation.
    """
    return kraus_to_channel_matrix(protocols.channel(operation))
def _strat_act_on_state_vector_from_channel(action: Any,
                                            args: 'cirq.ActOnStateVectorArgs'
                                           ) -> bool:
    kraus_operators = protocols.channel(action, default=None)
    if kraus_operators is None:
        return NotImplemented

    def prepare_into_buffer(k: int):
        linalg.targeted_left_multiply(
            left_matrix=kraus_tensors[k],
            right_target=args.target_tensor,
            target_axes=args.axes,
            out=args.available_buffer,
        )

    shape = protocols.qid_shape(action)
    kraus_tensors = [
        e.reshape(shape * 2).astype(args.target_tensor.dtype)
        for e in kraus_operators
    ]
    p = args.prng.random()
    weight = None
    fallback_weight = 0
    fallback_weight_i = 0
    for i in range(len(kraus_tensors)):
        prepare_into_buffer(i)
        weight = np.linalg.norm(args.available_buffer)**2

        if weight > fallback_weight:
            fallback_weight_i = i
            fallback_weight = weight

        p -= weight
        if p < 0:
            break

    assert weight is not None, "No Kraus operators"
    if p >= 0 or weight == 0:
        # Floating point error resulted in a malformed sample.
        # Fall back to the most likely case.
        prepare_into_buffer(fallback_weight_i)
        weight = fallback_weight

    args.available_buffer /= np.sqrt(weight)
    args.swap_target_tensor_for(args.available_buffer)
    return True
Пример #5
0
def operation_to_choi(operation: 'protocols.SupportsChannel') -> np.ndarray:
    r"""Returns the unique Choi matrix associated with a superoperator.

    Choi matrix J(E) of a linear map E: L(H1) -> L(H2) which takes linear operators
    on Hilbert space H1 to linear operators on Hilbert space H2 is defined as

        $$
        J(E) = (E \otimes I)(|\phi\rangle\langle\phi|)
        $$

    where $|\phi\rangle = \sum_i|i\rangle|i\rangle$ is the unnormalized maximally
    entangled state and I: L(H1) -> L(H1) is the identity map. Note that J(E) is
    a square matrix with d1*d2 rows and columns where d1 = dim H1 and d2 = dim H2.

    Args:
        operation: Quantum channel.
    Returns:
        Choi matrix corresponding to operation.
    """
    return kraus_to_choi(protocols.channel(operation))
Пример #6
0
def entanglement_fidelity(operation: 'cirq.SupportsChannel') -> float:
    r"""Returns entanglement fidelity of a given quantum channel.

    Entanglement fidelity $F_e$ of a quantum channel $E: L(H) \to L(H)$ is the overlap between
    the maximally entangled state $|\phi\rangle = \frac{1}{\sqrt{dim H}} \sum_i|i\rangle|i\rangle$
    and the state obtained by sending one half of $|\phi\rangle$ through the channel $E$, i.e.

        $$
        F_e = \langle\phi|(E \otimes I)(|\phi\rangle\langle\phi|)|\phi\rangle
        $$

    where $I: L(H) \to L(H)$ is the identity map.

    Args:
        operation: Quantum channel whose entanglement fidelity is to be computed.
    Returns:
        Entanglement fidelity of the channel represented by operation.
    """
    f = 0.0
    for k in protocols.channel(operation):
        f += np.abs(np.trace(k))**2
    n_qubits = protocols.num_qubits(operation)
    return float(f / 4**n_qubits)
Пример #7
0
    def _base_iterator(
            self,
            circuit: circuits.Circuit,
            qubit_order: ops.QubitOrderOrList,
            initial_state: Union[int, np.ndarray],
            perform_measurements: bool = True) -> Iterator:
        qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for(
            circuit.all_qubits())
        num_qubits = len(qubits)
        qubit_map = {q: i for i, q in enumerate(qubits)}
        matrix = density_matrix_utils.to_valid_density_matrix(
            initial_state, num_qubits, self._dtype)
        if len(circuit) == 0:
            yield DensityMatrixStepResult(matrix, {}, qubit_map, self._dtype)
        matrix = np.reshape(matrix, (2,) * num_qubits * 2)

        def on_stuck(bad_op: ops.Operation):
            return TypeError(
                "Can't simulate operations that don't implement "
                "SupportsUnitary, SupportsApplyUnitary, SupportsMixture, "
                "SupportsChannel or is a measurement: {!r}".format(bad_op))

        def keep(potential_op: ops.Operation) -> bool:
            return (protocols.has_channel(potential_op)
                    or (ops.op_gate_of_type(potential_op,
                                            ops.MeasurementGate) is not None)
                    or isinstance(potential_op,
                                  (ops.SamplesDisplay,
                                   ops.WaveFunctionDisplay,
                                   ops.DensityMatrixDisplay))
                    )

        matrix = np.reshape(matrix, (2,) * num_qubits * 2)
        noisy_moments = self.noise.noisy_moments(circuit,
                                                 sorted(circuit.all_qubits()))

        for moment in noisy_moments:
            measurements = collections.defaultdict(
                list)  # type: Dict[str, List[bool]]

            channel_ops_and_measurements = protocols.decompose(
                moment, keep=keep, on_stuck_raise=on_stuck)

            for op in channel_ops_and_measurements:
                indices = [qubit_map[qubit] for qubit in op.qubits]
                if isinstance(op,
                              (ops.SamplesDisplay,
                                  ops.WaveFunctionDisplay,
                                  ops.DensityMatrixDisplay)):
                    continue
                # TODO: support more general measurements.
                meas = ops.op_gate_of_type(op, ops.MeasurementGate)
                if meas:
                    if perform_measurements:
                        invert_mask = meas.invert_mask or num_qubits * (False,)
                        # Measure updates inline.
                        bits, _ = density_matrix_utils.measure_density_matrix(
                            matrix, indices, matrix)
                        corrected = [bit ^ mask for bit, mask in
                                     zip(bits, invert_mask)]
                        key = protocols.measurement_key(meas)
                        measurements[key].extend(corrected)
                else:
                    # TODO: Use apply_channel similar to apply_unitary.
                    gate = cast(ops.GateOperation, op).gate
                    channel = protocols.channel(gate)
                    sum_buffer = np.zeros((2,) * 2 * num_qubits,
                                          dtype=self._dtype)
                    buffer = np.empty((2,) * 2 * num_qubits, dtype=self._dtype)
                    out = np.empty((2,) * 2 * num_qubits, dtype=self._dtype)
                    for krauss in channel:
                        krauss_tensor = np.reshape(krauss.astype(self._dtype),
                                                   (2,) * gate.num_qubits() * 2)
                        result = linalg.targeted_conjugate_about(krauss_tensor,
                                                                 matrix,
                                                                 indices,
                                                                 buffer=buffer,
                                                                 out=out)
                        sum_buffer += result
                    np.copyto(dst=matrix, src=sum_buffer)
            yield DensityMatrixStepResult(
                    density_matrix=matrix,
                    measurements=measurements,
                    qubit_map=qubit_map,
                    dtype=self._dtype)
Пример #8
0
 def _channel_(self) -> Union[Tuple[np.ndarray], NotImplementedType]:
     return protocols.channel(self.sub_operation, NotImplemented)
Пример #9
0
    def simulate_sweep(
        self,
        program: Union[circuits.Circuit, schedules.Schedule],
        params: study.Sweepable,
        qubit_order: ops.QubitOrderOrList = ops.QubitOrder.DEFAULT,
        initial_state: Any = None,
    ) -> List['SimulationTrialResult']:
        """Simulates the supplied Circuit or Schedule with Qulacs
        Args:
            program: The circuit or schedule to simulate.
            params: Parameters to run with the program.
            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.
            initial_state: The initial state for the simulation. The form of
                this state depends on the simulation implementation.  See
                documentation of the implementing class for details.
        Returns:
            List of SimulationTrialResults for this run, one for each
            possible parameter resolver.
        """
        trial_results = []
        # sweep for each parameters
        resolvers = study.to_resolvers(params)
        for resolver in resolvers:

            # result circuit
            cirq_circuit = protocols.resolve_parameters(program, resolver)
            qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for(
                cirq_circuit.all_qubits())
            qubit_map = {q: i for i, q in enumerate(qubits)}
            num_qubits = len(qubits)

            # create state
            qulacs_state = self._get_qulacs_state(num_qubits)
            if initial_state is not None:
                cirq_state = wave_function.to_valid_state_vector(
                    initial_state, num_qubits)
                qulacs_state.load(cirq_state)
                del cirq_state

            # create circuit
            qulacs_circuit = qulacs.QuantumCircuit(num_qubits)
            address_to_key = {}
            register_address = 0
            for moment in cirq_circuit:
                operations = moment.operations
                for op in operations:
                    indices = [
                        num_qubits - 1 - qubit_map[qubit]
                        for qubit in op.qubits
                    ]
                    result = self._try_append_gate(op, qulacs_circuit, indices)
                    if result:
                        continue

                    if isinstance(op.gate, ops.ResetChannel):
                        qulacs_circuit.update_quantum_state(qulacs_state)
                        qulacs_state.set_zero_state()
                        qulacs_circuit = qulacs.QuantumCircuit(num_qubits)

                    elif protocols.is_measurement(op):
                        for index in indices:
                            qulacs_circuit.add_gate(
                                qulacs.gate.Measurement(
                                    index, register_address))
                            address_to_key[
                                register_address] = protocols.measurement_key(
                                    op.gate)
                            register_address += 1

                    elif protocols.has_mixture(op):
                        indices.reverse()
                        qulacs_gates = []
                        gate = cast(ops.GateOperation, op).gate
                        channel = protocols.channel(gate)
                        for krauss in channel:
                            krauss = krauss.astype(np.complex128)
                            qulacs_gate = qulacs.gate.DenseMatrix(
                                indices, krauss)
                            qulacs_gates.append(qulacs_gate)
                        qulacs_cptp_map = qulacs.gate.CPTP(qulacs_gates)
                        qulacs.circuit.add_gate(qulacs_cptp_map)

            # perform simulation
            qulacs_circuit.update_quantum_state(qulacs_state)

            # fetch final state and measurement results
            final_state = qulacs_state.get_vector()
            measurements = collections.defaultdict(list)
            for register_index in range(register_address):
                key = address_to_key[register_index]
                value = qulacs_state.get_classical_value(register_index)
                measurements[key].append(value)

            # create result for this parameter
            result = SimulationTrialResult(params=resolver,
                                           measurements=measurements,
                                           final_simulator_state=final_state)
            trial_results.append(result)

            # release memory
            del qulacs_state
            del qulacs_circuit

        return trial_results
Пример #10
0
 def _channel_(self) -> Union[Tuple[np.ndarray], NotImplementedType]:
     return protocols.channel(self._gate, NotImplemented)
    def _base_iterator(self,
                       circuit: circuits.Circuit,
                       qubit_order: ops.QubitOrderOrList,
                       initial_state: Union[int, np.ndarray],
                       perform_measurements: bool = True) -> Iterator:

        qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for(
            circuit.all_qubits())
        num_qubits = len(qubits)
        qubit_map = {q: i for i, q in enumerate(qubits)}
        matrix = density_matrix_utils.to_valid_density_matrix(
            initial_state, num_qubits, self._dtype)
        if len(circuit) == 0:
            yield DensityMatrixStepResult(matrix, {}, qubit_map, self._dtype)

        def on_stuck(bad_op: ops.Operation):
            return TypeError(
                "Can't simulate operations that don't implement "
                "SupportsUnitary, SupportsApplyUnitary, SupportsMixture, "
                "SupportsChannel or is a measurement: {!r}".format(bad_op))

        def keep(potential_op: ops.Operation) -> bool:
            return (protocols.has_channel(potential_op)
                    or (ops.op_gate_of_type(potential_op, ops.MeasurementGate)
                        is not None)
                    or isinstance(potential_op,
                                  (ops.SamplesDisplay, ops.WaveFunctionDisplay,
                                   ops.DensityMatrixDisplay)))

        matrix = np.reshape(matrix, (2**num_qubits, 2**num_qubits))
        noisy_moments = self.noise.noisy_moments(circuit,
                                                 sorted(circuit.all_qubits()))

        state = qulacs.DensityMatrix(num_qubits)
        state.load(matrix)

        for moment in noisy_moments:
            measurements = collections.defaultdict(
                list)  # type: Dict[str, List[bool]]

            channel_ops_and_measurements = protocols.decompose(
                moment, keep=keep, on_stuck_raise=on_stuck)

            for op in channel_ops_and_measurements:
                #indices = [qubit_map[qubit] for qubit in op.qubits]
                indices = [
                    num_qubits - 1 - qubit_map[qubit] for qubit in op.qubits
                ]
                indices.reverse()
                if isinstance(op, (ops.SamplesDisplay, ops.WaveFunctionDisplay,
                                   ops.DensityMatrixDisplay)):
                    continue
                # TODO: support more general measurements.

                meas = ops.op_gate_of_type(op, ops.MeasurementGate)
                if meas:
                    # Not implemented
                    raise NotImplementedError(
                        "Measurement is not supported in qulacs simulator")

                else:
                    # TODO: Use apply_channel similar to apply_unitary.
                    gate = cast(ops.GateOperation, op).gate
                    channel = protocols.channel(gate)

                    qulacs_gates = []
                    for krauss in channel:
                        krauss = krauss.astype(np.complex128)
                        qulacs_gate = qulacs.gate.DenseMatrix(indices, krauss)
                        qulacs_gates.append(qulacs_gate)
                    qulacs_cptp_map = qulacs.gate.CPTP(qulacs_gates)
                    qulacs_cptp_map.update_quantum_state(state)

            matrix = state.get_matrix()
            matrix = np.reshape(matrix, (2, ) * num_qubits * 2)

            yield DensityMatrixStepResult(density_matrix=matrix,
                                          measurements=measurements,
                                          qubit_map=qubit_map,
                                          dtype=self._dtype)