Beispiel #1
0
    def run_sweep(
        self,
        program: 'cirq.AbstractCircuit',
        params: study.Sweepable,
        repetitions: int = 1,
    ) -> List[study.Result]:
        """Samples circuit as if every measurement resulted in zero.

        Args:
            program: The circuit to sample from.
            params: Parameters to run with the program.
            repetitions: The number of times to sample.

        Returns:
            Result list for this run; one for each possible parameter
            resolver.

        Raises:
            ValueError if this sampler has a device and the circuit is not
            valid for the device.
        """
        if self.device:
            self.device.validate_circuit(program)
        measurements = {}  # type: Dict[str, np.ndarray]
        for op in program.all_operations():
            key = protocols.measurement_key_name(op, default=None)
            if key is not None:
                measurements[key] = np.zeros((repetitions, len(op.qubits)),
                                             dtype=int)
        return [
            study.Result(params=param_resolver, measurements=measurements)
            for param_resolver in study.to_resolvers(params)
        ]
Beispiel #2
0
    def _get_measurement_shapes(
        circuit: 'cirq.AbstractCircuit',
    ) -> Dict[str, Tuple[int, Tuple[int, ...]]]:
        """Gets the shapes of measurements in the given circuit.

        Returns:
            A mapping from measurement key name to a tuple of (num_instances, qid_shape),
            where num_instances is the number of times that key appears in the circuit and
            qid_shape is the shape of measured qubits for the key, as determined by the
            `cirq.qid_shape` protocol.

        Raises:
            ValueError: if the qid_shape of different instances of the same measurement
            key disagree.
        """
        qid_shapes: Dict[str, Tuple[int, ...]] = {}
        num_instances: Dict[str, int] = collections.Counter()
        for op in circuit.all_operations():
            key = protocols.measurement_key_name(op, default=None)
            if key is not None:
                qid_shape = protocols.qid_shape(op)
                prev_qid_shape = qid_shapes.setdefault(key, qid_shape)
                if qid_shape != prev_qid_shape:
                    raise ValueError(
                        "Different qid shapes for repeated measurement: "
                        f"key={key!r}, prev_qid_shape={prev_qid_shape}, qid_shape={qid_shape}"
                    )
                num_instances[key] += 1
        return {
            k: (num_instances[k], qid_shape)
            for k, qid_shape in qid_shapes.items()
        }
Beispiel #3
0
    def run_sweep_iter(
        self, program: 'cirq.AbstractCircuit', params: 'cirq.Sweepable', repetitions: int = 1
    ) -> Iterator['cirq.Result']:
        """Runs the supplied Circuit, mimicking quantum hardware.

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

        Args:
            program: The circuit to simulate.
            params: Parameters to run with the program.
            repetitions: The number of repetitions to simulate.

        Returns:
            Result list for this run; one for each possible parameter
            resolver.

        Raises:
            ValueError: If the circuit has no measurements.
        """
        if not program.has_measurements():
            raise ValueError("Circuit has no measurements to sample.")

        for param_resolver in study.to_resolvers(params):
            records = {}
            if repetitions == 0:
                for _, op, _ in program.findall_operations_with_gate_type(ops.MeasurementGate):
                    records[protocols.measurement_key_name(op)] = np.empty([0, 1, 1])
            else:
                records = self._run(
                    circuit=program, param_resolver=param_resolver, repetitions=repetitions
                )
            yield study.ResultDict(params=param_resolver, records=records)
Beispiel #4
0
def _verify_unique_measurement_keys(operations: Iterable[ops.Operation]):
    seen: Set[str] = set()
    for op in operations:
        if isinstance(op.gate, ops.MeasurementGate):
            meas = op.gate
            key = protocols.measurement_key_name(meas)
            if key in seen:
                raise ValueError(f'Measurement key {key} repeated')
            seen.add(key)
def _strat_act_on_state_vector_from_channel(
        action: Any, args: 'cirq.StateVectorSimulationState',
        qubits: Sequence['cirq.Qid']) -> bool:
    index = args._state.apply_channel(action, args.get_axes(qubits), args.prng)
    if index is None:
        return NotImplemented
    if protocols.is_measurement(action):
        key = protocols.measurement_key_name(action)
        args._classical_data.record_channel_measurement(key, index)
    return True
Beispiel #6
0
    def _write_qasm(self, output_func: Callable[[str], None]) -> None:
        self.args.validate_version('2.0')

        # Generate nice line spacing
        line_gap = [0]

        def output_line_gap(n):
            line_gap[0] = max(line_gap[0], n)

        def output(text):
            if line_gap[0] > 0:
                output_func('\n' * line_gap[0])
                line_gap[0] = 0
            output_func(text)

        # Comment header
        if self.header:
            for line in self.header.split('\n'):
                output(('// ' + line).rstrip() + '\n')
            output('\n')

        # Version
        output('OPENQASM 2.0;\n')
        output('include "qelib1.inc";\n')
        output_line_gap(2)

        # Function definitions
        # None yet

        # Register definitions
        # Qubit registers
        output(f"// Qubits: [{', '.join(map(str, self.qubits))}]\n")
        if len(self.qubits) > 0:
            output(f'qreg q[{len(self.qubits)}];\n')
        # Classical registers
        # Pick an id for the creg that will store each measurement
        already_output_keys: Set[str] = set()
        for meas in self.measurements:
            key = protocols.measurement_key_name(meas)
            if key in already_output_keys:
                continue
            already_output_keys.add(key)
            meas_id = self.args.meas_key_id_map[key]
            comment = self.meas_comments[key]
            if comment is None:
                output(f'creg {meas_id}[{len(meas.qubits)}];\n')
            else:
                output(
                    f'creg {meas_id}[{len(meas.qubits)}];  // Measurement: {comment}\n'
                )
        output_line_gap(2)

        # Operations
        self._write_operations(self.operations, output, output_line_gap)
Beispiel #7
0
 def _generate_measurement_ids(self) -> Dict[str, str]:
     index = 0
     measurement_id_map: Dict[str, str] = {}
     for op in self.operations:
         if isinstance(op.gate, ops.MeasurementGate):
             key = protocols.measurement_key_name(op)
             if key in measurement_id_map:
                 continue
             measurement_id_map[key] = f'm{index}'
             index += 1
     return measurement_id_map
Beispiel #8
0
def _strat_act_on_state_vector_from_channel(
        action: Any, args: 'cirq.ActOnStateVectorArgs',
        qubits: Sequence['cirq.Qid']) -> bool:
    kraus_operators = protocols.kraus(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.get_axes(qubits),
            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_index = 0
    for index in range(len(kraus_tensors)):
        prepare_into_buffer(index)
        weight = np.linalg.norm(args.available_buffer)**2

        if weight > fallback_weight:
            fallback_weight_index = index
            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_index)
        weight = fallback_weight
        index = fallback_weight_index

    args.available_buffer /= np.sqrt(weight)
    args.swap_target_tensor_for(args.available_buffer)
    if protocols.is_measurement(action):
        key = protocols.measurement_key_name(action)
        args._classical_data.record_channel_measurement(key, index)
    return True
Beispiel #9
0
    def run_sweep_iter(
        self,
        program: 'cirq.AbstractCircuit',
        params: 'cirq.Sweepable',
        repetitions: int = 1,
    ) -> Iterator['cirq.Result']:
        """Runs the supplied Circuit, mimicking quantum hardware.

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

        Args:
            program: The circuit to simulate.
            params: Parameters to run with the program.
            repetitions: The number of repetitions to simulate.

        Returns:
            Result list for this run; one for each possible parameter
            resolver.

        Raises:
            ValueError: If the circuit has no measurements.
        """
        if not program.has_measurements():
            raise ValueError("Circuit has no measurements to sample.")

        for param_resolver in study.to_resolvers(params):
            records = {}
            if repetitions == 0:
                for _, op, _ in program.findall_operations_with_gate_type(
                        ops.MeasurementGate):
                    records[protocols.measurement_key_name(op)] = np.empty(
                        [0, 1, 1])
            else:
                records = self._run(circuit=program,
                                    param_resolver=param_resolver,
                                    repetitions=repetitions)
                flat_records = False
                for k, v in records.items():
                    if v.ndim == 2:
                        flat_records = True
                        records[k] = v.reshape((v.shape[0], 1, v.shape[1]))
                if flat_records:
                    warnings.warn(
                        ('Starting in Cirq v0.15, values in the output of simulator._run must '
                         'be 3D instead of 2D, with a new dimension between the existing two '
                         'to capture "instances" of a key.'),
                        DeprecationWarning,
                    )
            yield study.ResultDict(params=param_resolver, records=records)
Beispiel #10
0
    def _write_quil(self, output_func: Callable[[str], None]) -> None:
        output_func('# Created using Cirq.\n\n')
        if len(self.measurements) > 0:
            measurements_declared: Set[str] = set()
            for m in self.measurements:
                key = protocols.measurement_key_name(m)
                if key in measurements_declared:
                    continue
                measurements_declared.add(key)
                output_func(
                    f'DECLARE {self.measurement_id_map[key]} BIT[{len(m.qubits)}]\n'
                )
            output_func('\n')

        def keep(op: 'cirq.Operation') -> bool:
            return protocols.quil(op, formatter=self.formatter) is not None

        def fallback(op):
            if len(op.qubits) not in [1, 2]:
                return NotImplemented

            mat = protocols.unitary(op, None)
            if mat is None:
                return NotImplemented

            # Following code is a safety measure
            # Could not find a gate that doesn't decompose into a gate
            # with a _quil_ implementation
            # coverage: ignore
            if len(op.qubits) == 1:
                return QuilOneQubitGate(mat).on(*op.qubits)
            return QuilTwoQubitGate(mat).on(*op.qubits)

        def on_stuck(bad_op):
            return ValueError(f'Cannot output operation as QUIL: {bad_op!r}')

        for main_op in self.operations:
            decomposed = protocols.decompose(main_op,
                                             keep=keep,
                                             fallback_decomposer=fallback,
                                             on_stuck_raise=on_stuck)

            for decomposed_op in decomposed:
                output_func(
                    protocols.quil(decomposed_op, formatter=self.formatter))
Beispiel #11
0
 def _generate_measurement_ids(self) -> Tuple[Dict[str, str], Dict[str, Optional[str]]]:
     # Pick an id for the creg that will store each measurement
     meas_key_id_map = {}  # type: Dict[str, str]
     meas_comments = {}  # type: Dict[str, Optional[str]]
     meas_i = 0
     for meas in self.measurements:
         key = protocols.measurement_key_name(meas)
         if key in meas_key_id_map:
             continue
         meas_id = f'm_{key}'
         if self.is_valid_qasm_id(meas_id):
             meas_comments[key] = None
         else:
             meas_id = f'm{meas_i}'
             meas_i += 1
             meas_comments[key] = ' '.join(key.split('\n'))
         meas_key_id_map[key] = meas_id
     return meas_key_id_map, meas_comments
Beispiel #12
0
def _strat_act_on_state_vector_from_mixture(
        action: Any, args: 'cirq.ActOnStateVectorArgs',
        qubits: Sequence['cirq.Qid']) -> bool:
    mixture = protocols.mixture(action, default=None)
    if mixture is None:
        return NotImplemented
    probabilities, unitaries = zip(*mixture)

    index = args.prng.choice(range(len(unitaries)), p=probabilities)
    shape = protocols.qid_shape(action) * 2
    unitary = unitaries[index].astype(args.target_tensor.dtype).reshape(shape)
    linalg.targeted_left_multiply(unitary,
                                  args.target_tensor,
                                  args.get_axes(qubits),
                                  out=args.available_buffer)
    args.swap_target_tensor_for(args.available_buffer)
    if protocols.is_measurement(action):
        key = protocols.measurement_key_name(action)
        args._classical_data.record_channel_measurement(key, index)
    return True
Beispiel #13
0
    def sample_measurement_ops(
        self,
        measurement_ops: List['cirq.GateOperation'],
        repetitions: int = 1,
        seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None,
    ) -> Dict[str, np.ndarray]:
        """Samples from the system at this point in the computation.

        Note that this does not collapse the state vector.

        In contrast to `sample` which samples qubits, this takes a list of
        `cirq.GateOperation` instances whose gates are `cirq.MeasurementGate`
        instances and then returns a mapping from the key in the measurement
        gate to the resulting bit strings. Different measurement operations must
        not act on the same qubits.

        Args:
            measurement_ops: `GateOperation` instances whose gates are
                `MeasurementGate` instances to be sampled form.
            repetitions: The number of samples to take.
            seed: A seed for the pseudorandom number generator.

        Returns: A dictionary from measurement gate key to measurement
            results. Measurement results are stored in a 2-dimensional
            numpy array, the first dimension corresponding to the repetition
            and the second to the actual boolean measurement results (ordered
            by the qubits being measured.)

        Raises:
            ValueError: If the operation's gates are not `MeasurementGate`
                instances or a qubit is acted upon multiple times by different
                operations from `measurement_ops`.
        """

        # Sanity checks.
        seen_measurement_keys: Set[str] = set()
        for op in measurement_ops:
            gate = op.gate
            if not isinstance(gate, ops.MeasurementGate):
                raise ValueError(f'{op.gate} was not a MeasurementGate')
            key = protocols.measurement_key_name(gate)
            if key in seen_measurement_keys:
                raise ValueError(f'Duplicate MeasurementGate with key {key}')
            seen_measurement_keys.add(key)

        # Find measured qubits, ensuring a consistent ordering.
        measured_qubits = []
        seen_qubits: Set[cirq.Qid] = set()
        for op in measurement_ops:
            for q in op.qubits:
                if q not in seen_qubits:
                    seen_qubits.add(q)
                    measured_qubits.append(q)

        # Perform whole-system sampling of the measured qubits.
        indexed_sample = self.sample(measured_qubits, repetitions, seed=seed)

        # Extract results for each measurement.
        results: Dict[str, np.ndarray] = {}
        qubits_to_index = {q: i for i, q in enumerate(measured_qubits)}
        for op in measurement_ops:
            gate = cast(ops.MeasurementGate, op.gate)
            out = np.zeros(shape=(repetitions, len(op.qubits)), dtype=np.int8)
            inv_mask = gate.full_invert_mask()
            for i, q in enumerate(op.qubits):
                out[:, i] = indexed_sample[:, qubits_to_index[q]]
                if inv_mask[i]:
                    out[:, i] ^= out[:, i] < 2
            results[gate.key] = out

        return results
Beispiel #14
0
 def _measurement_key_name_(self) -> str:
     return protocols.measurement_key_name(self.sub_operation,
                                           NotImplemented)