Exemple #1
0
    def run_sweep(
        self,
        program: 'cirq.Circuit',
        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(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)
        ]
Exemple #2
0
    def _run(self, circuit: circuits.Circuit,
             param_resolver: study.ParamResolver,
             repetitions: int) -> Dict[str, List[np.ndarray]]:

        param_resolver = param_resolver or study.ParamResolver({})
        resolved_circuit = protocols.resolve_parameters(
            circuit, param_resolver)
        self._check_all_resolved(resolved_circuit)

        measurements = {}  # type: Dict[str, List[np.ndarray]]
        if repetitions == 0:
            for _, op, _ in resolved_circuit.findall_operations_with_gate_type(
                    ops.MeasurementGate):
                measurements[protocols.measurement_key(op)] = np.empty([0, 1])

        for _ in range(repetitions):
            all_step_results = self._base_iterator(
                resolved_circuit,
                qubit_order=ops.QubitOrder.DEFAULT,
                initial_state=0)

            for step_result in all_step_results:
                for k, v in step_result.measurements.items():
                    if not k in measurements:
                        measurements[k] = []
                    measurements[k].append(np.array(v, dtype=bool))

        return {k: np.array(v) for k, v in measurements.items()}
Exemple #3
0
    def run_sweep(
            self,
            program: 'cirq.Circuit',
            params: study.Sweepable,
            repetitions: int = 1,
    ) -> List[study.TrialResult]:
        """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:
            TrialResult list for this run; one for each possible parameter
            resolver.
        """
        if self.gate_set is not None:
            for op in program.all_operations():
                assert self.gate_set.is_supported_operation(op), (
                    "Unsupported operation: %s" % op)

        measurements = {}  # type: Dict[str, np.ndarray]
        for op in program.all_operations():
            key = protocols.measurement_key(op, default=None)
            if key is not None:
                measurements[key] = np.zeros((repetitions, len(op.qubits)),
                                             dtype=np.int8)
        return [
            study.TrialResult.from_single_parameter_set(
                params=param_resolver, measurements=measurements)
            for param_resolver in study.to_resolvers(params)
        ]
Exemple #4
0
    def _base_iterator(
        self, circuit: circuits.Circuit, qubit_order: ops.QubitOrderOrList,
        initial_state: int
    ) -> Iterator['cirq.contrib.quimb.mps_simulator.MPSSimulatorStepResult']:
        """Iterator over MPSSimulatorStepResult from Moments of a Circuit

        Args:
            circuit: The circuit 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.
            initial_state: The initial state for the simulation in the
                computational basis. Represented as a big endian int.

        Yields:
            MPSStepResult from simulating a Moment of the Circuit.
        """
        qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for(
            circuit.all_qubits())

        qubit_map = {q: i for i, q in enumerate(qubits)}

        if len(circuit) == 0:
            yield MPSSimulatorStepResult(
                measurements={},
                state=MPSState(
                    qubit_map,
                    self.simulation_options,
                    self.grouping,
                    initial_state=initial_state,
                ),
            )
            return

        state = MPSState(
            qubit_map,
            self.simulation_options,
            self.grouping,
            initial_state=initial_state,
        )

        noisy_moments = self.noise.noisy_moments(circuit,
                                                 sorted(circuit.all_qubits()))
        for op_tree in noisy_moments:
            measurements: Dict[str, List[int]] = collections.defaultdict(list)

            for op in flatten_to_ops(op_tree):
                if isinstance(op.gate, ops.MeasurementGate):
                    key = str(protocols.measurement_key(op))
                    measurements[key].extend(
                        state.perform_measurement(op.qubits, self.prng))
                elif protocols.has_mixture(op):
                    state.apply_op(op, self.prng)
                else:
                    raise NotImplementedError(
                        f"Unrecognized operation: {op!r}")

            yield MPSSimulatorStepResult(measurements=measurements,
                                         state=state)
Exemple #5
0
def _verify_unique_measurement_keys(operations: Iterable['cirq.Operation']):
    seen: Set[str] = set()
    for op in operations:
        if protocols.is_measurement(op):
            key = protocols.measurement_key(op)
            if key in seen:
                raise ValueError('Measurement key {} repeated'.format(key))
            seen.add(key)
Exemple #6
0
def _verify_unique_measurement_keys(operations: Iterable[ops.Operation]):
    seen = set()  # type: Set[str]
    for op in operations:
        if ops.MeasurementGate.is_measurement(op):
            key = protocols.measurement_key(op)
            if key in seen:
                raise ValueError('Measurement key {} repeated'.format(key))
            seen.add(key)
Exemple #7
0
def find_measurement_keys(circuit: circuits.Circuit) -> Set[str]:
    keys: Set[str] = set()
    for _, _, gate in circuit.findall_operations_with_gate_type(
            ops.MeasurementGate):
        key = protocols.measurement_key(gate)
        if key in keys:
            raise ValueError('Repeated Measurement key {}'.format(key))
        keys.add(key)
    return keys
Exemple #8
0
    def sample_measurement_ops(
        self,
        measurement_ops: List[ops.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 wave function.

        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`.
        """
        bounds = {}  # type: Dict[str, Tuple]
        all_qubits = []  # type: List[ops.Qid]
        meas_ops = {}
        current_index = 0
        for op in measurement_ops:
            gate = op.gate
            if not isinstance(gate, ops.MeasurementGate):
                raise ValueError('{} was not a MeasurementGate'.format(gate))
            key = protocols.measurement_key(gate)
            meas_ops[key] = gate
            if key in bounds:
                raise ValueError(
                    'Duplicate MeasurementGate with key {}'.format(key))
            bounds[key] = (current_index, current_index + len(op.qubits))
            all_qubits.extend(op.qubits)
            current_index += len(op.qubits)
        indexed_sample = self.sample(all_qubits, repetitions, seed=seed)

        results = {}
        for k, (s, e) in bounds.items():
            before_invert_mask = indexed_sample[:, s:e]
            results[k] = before_invert_mask ^ (np.logical_and(
                before_invert_mask < 2, meas_ops[k].full_invert_mask()))
        return results
Exemple #9
0
def _verify_unique_measurement_keys(circuit: circuits.Circuit):
    result = collections.Counter(
        protocols.measurement_key(op, default=None)
        for op in ops.flatten_op_tree(iter(circuit)))
    result[None] = 0
    duplicates = [k for k, v in result.most_common() if v > 1]
    if duplicates:
        raise ValueError('Measurement key {} repeated'.format(
            ",".join(duplicates)))
Exemple #10
0
def _verify_unique_measurement_keys(operations: Iterable['cirq.Operation']):
    """Raises an error if a measurement key is repeated in the given set of Operations."""
    seen_keys: Set[str] = set()
    for op in operations:
        if protocols.is_measurement(op):
            key = protocols.measurement_key(op)
            if key in seen_keys:
                raise ValueError('Measurement key {} repeated'.format(key))
            seen_keys.add(key)
Exemple #11
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(meas)
            if key in seen:
                raise ValueError(f'Measurement key {key} repeated')
            seen.add(key)
Exemple #12
0
def _verify_unique_measurement_keys(operations: Iterable[ops.Operation]):
    seen: Set[str] = set()
    for op in operations:
        meas = ops.op_gate_of_type(op, ops.MeasurementGate)
        if meas:
            key = protocols.measurement_key(meas)
            if key in seen:
                raise ValueError('Measurement key {} repeated'.format(key))
            seen.add(key)
Exemple #13
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(op)
             if key in measurement_id_map:
                 continue
             measurement_id_map[key] = f'm{index}'
             index += 1
     return measurement_id_map
Exemple #14
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(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)
Exemple #15
0
 def _serialize_measurement_gate(self, gate: 'cirq.MeasurementGate',
                                 targets: Sequence[int]) -> dict:
     key = protocols.measurement_key(gate)
     if chr(31) in key or chr(30) in key:
         raise ValueError(
             'Measurement gates for IonQ API cannot have a key with a ascii unit'
             f'or record separator in it. Key was {key}')
     return {
         'gate': 'meas',
         'key': key,
         'targets': ','.join(str(t) for t in targets)
     }
Exemple #16
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(action)
        args.log_of_measurement_results[key] = [index]
    return True
Exemple #17
0
    def _base_iterator(
            self, circuit: circuits.Circuit, qubit_order: ops.QubitOrderOrList,
            initial_state: int
    ) -> Iterator['cirq.CliffordSimulatorStepResult']:
        """Iterator over CliffordSimulatorStepResult from Moments of a Circuit

        Args:
            circuit: The circuit 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.
            initial_state: The initial state for the simulation in the
                computational basis. Represented as a big endian int.


        Yields:
            CliffordStepResult from simulating a Moment of the Circuit.
        """
        qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for(
            circuit.all_qubits())

        qubit_map = {q: i for i, q in enumerate(qubits)}

        if len(circuit) == 0:
            yield CliffordSimulatorStepResult(measurements={},
                                              state=CliffordState(
                                                  qubit_map,
                                                  initial_state=initial_state))
            return

        state = CliffordState(qubit_map, initial_state=initial_state)

        for moment in circuit:
            measurements: Dict[
                str, List[np.ndarray]] = collections.defaultdict(list)

            for op in moment:
                if isinstance(op.gate, ops.MeasurementGate):
                    key = protocols.measurement_key(op)
                    measurements[key].extend(
                        state.perform_measurement(op.qubits, self._prng))
                elif protocols.has_unitary(op):
                    state.apply_unitary(op)
                else:
                    raise NotImplementedError(
                        f"Unrecognized operation: {op!r}")

            yield CliffordSimulatorStepResult(measurements=measurements,
                                              state=state)
Exemple #18
0
 def _simulate_measurement(self, op: ops.Operation, data: _StateAndBuffer,
                           indices: List[int],
                           measurements: Dict[str, List[bool]],
                           num_qubits: int) -> None:
     """Simulate an op that is a measurement in the computataional basis."""
     meas = ops.op_gate_of_type(op, ops.MeasurementGate)
     # TODO: support measurement outside computational basis.
     if meas:
         invert_mask = meas.invert_mask or num_qubits * (False, )
         # Measure updates inline.
         bits, _ = wave_function.measure_state_vector(
             data.state, indices, data.state)
         corrected = [bit ^ mask for bit, mask in zip(bits, invert_mask)]
         key = protocols.measurement_key(meas)
         measurements[key].extend(corrected)
Exemple #19
0
def _measure_to_proto(gate: 'cirq.MeasurementGate',
                      qubits: Sequence['cirq.Qid']):
    if len(qubits) == 0:
        raise ValueError('Measurement gate on no qubits.')

    invert_mask = None
    if gate.invert_mask:
        invert_mask = gate.invert_mask + (False, ) * (gate.num_qubits() -
                                                      len(gate.invert_mask))

    if invert_mask and len(invert_mask) != len(qubits):
        raise ValueError('Measurement gate had invert mask of length '
                         'different than number of qubits it acts on.')
    return operations_pb2.Measurement(
        targets=[_qubit_to_proto(q) for q in qubits],
        key=protocols.measurement_key(gate),
        invert_mask=invert_mask)
    def _run_sweep_repeat(self, circuit: circuits.Circuit,
                          repetitions: int) -> Dict[str, np.ndarray]:
        measurements = {}  # type: Dict[str, List[np.ndarray]]
        if repetitions == 0:
            for _, op, _ in circuit.findall_operations_with_gate_type(
                    ops.MeasurementGate):
                measurements[protocols.measurement_key(op)] = np.empty([0, 1])

        for _ in range(repetitions):
            all_step_results = self._base_iterator(
                circuit, qubit_order=ops.QubitOrder.DEFAULT, initial_state=0)
            for step_result in all_step_results:
                for k, v in step_result.measurements.items():
                    if not k in measurements:
                        measurements[k] = []
                    measurements[k].append(np.array(v, dtype=np.uint8))
        return {k: np.array(v) for k, v in measurements.items()}
Exemple #21
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(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))
    def _base_iterator(
            self, circuit: circuits.Circuit, qubit_order: ops.QubitOrderOrList,
            initial_state: int
    ) -> Iterator['cirq.CliffordSimulatorStepResult']:
        """Iterator over CliffordSimulatorStepResult from Moments of a Circuit

        Args:
            circuit: The circuit 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.
            initial_state: The initial state for the simulation.


        Yields:
            CliffordStepResult from simulating a Moment of the Circuit.
        """
        qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for(
            circuit.all_qubits())

        qubit_map = {q: i for i, q in enumerate(qubits)}

        if len(circuit) == 0:
            yield CliffordSimulatorStepResult(measurements={},
                                              state=CliffordState(
                                                  qubit_map,
                                                  initial_state=initial_state))
        else:
            state = CliffordState(qubit_map, initial_state=initial_state)

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

                for op in moment:
                    print(type(op))
                    if protocols.has_unitary(op):
                        state.apply_unitary(op)
                    elif protocols.is_measurement(op):
                        key = protocols.measurement_key(op)
                        measurements[key].extend(
                            state.perform_measurement(op.qubits))

                yield CliffordSimulatorStepResult(measurements=measurements,
                                                  state=state)
Exemple #23
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(meas)
         if key in meas_key_id_map:
             continue
         meas_id = 'm_{}'.format(key)
         if self.is_valid_qasm_id(meas_id):
             meas_comments[key] = None
         else:
             meas_id = 'm{}'.format(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
Exemple #24
0
def _measure_to_proto_dict(gate: 'cirq.MeasurementGate',
                           qubits: Sequence['cirq.Qid']):
    if len(qubits) == 0:
        raise ValueError('Measurement gate on no qubits.')

    invert_mask = None
    if gate.invert_mask:
        invert_mask = gate.invert_mask + (False, ) * (gate.num_qubits() -
                                                      len(gate.invert_mask))

    if invert_mask and len(invert_mask) != len(qubits):
        raise ValueError('Measurement gate had invert mask of length '
                         'different than number of qubits it acts on.')
    measurement = {
        'targets': [_qubit_to_proto_dict(q) for q in qubits],
        'key': protocols.measurement_key(gate),
    }
    if invert_mask:
        measurement['invert_mask'] = [json.dumps(x) for x in invert_mask]
    return {'measurement': measurement}
Exemple #25
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(action)
        args.log_of_measurement_results[key] = [index]
    return True
Exemple #26
0
    def run_sweep(
        self,
        program: 'cirq.Circuit',
        params: study.Sweepable,
        repetitions: int = 1,
    ) -> List[study.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.
        """
        if not program.has_measurements():
            raise ValueError("Circuit has no measurements to sample.")

        _verify_unique_measurement_keys(program)

        trial_results = []  # type: List[study.Result]
        for param_resolver in study.to_resolvers(params):
            measurements = {}
            if repetitions == 0:
                for _, op, _ in program.findall_operations_with_gate_type(
                        ops.MeasurementGate):
                    measurements[protocols.measurement_key(op)] = np.empty(
                        [0, 1])
            else:
                measurements = self._run(circuit=program,
                                         param_resolver=param_resolver,
                                         repetitions=repetitions)
            trial_results.append(
                study.Result.from_single_parameter_set(
                    params=param_resolver, measurements=measurements))
        return trial_results
Exemple #27
0
    def _run(self, circuit: circuits.Circuit,
             param_resolver: study.ParamResolver,
             repetitions: int) -> Dict[str, List[np.ndarray]]:
        """Repeats measurements multiple times.

        Args:
            circuit: The circuit to simulate.
            param_resolver: A ParamResolver for determining values of
                Symbols.
            repetitions: How many measurements to perform
            final_simulator_state: The final state of the simulator.

        Returns:
            A dictionay of measurement key (e.g. qubit) to a list of arrays that
            are the measurements.
        """
        param_resolver = param_resolver or study.ParamResolver({})
        resolved_circuit = protocols.resolve_parameters(
            circuit, param_resolver)
        self._check_all_resolved(resolved_circuit)

        measurements = {}  # type: Dict[str, List[np.ndarray]]
        if repetitions == 0:
            for _, op, _ in resolved_circuit.findall_operations_with_gate_type(
                    ops.MeasurementGate):
                measurements[protocols.measurement_key(op)] = np.empty([0, 1])

        for _ in range(repetitions):
            all_step_results = self._base_iterator(
                resolved_circuit,
                qubit_order=ops.QubitOrder.DEFAULT,
                initial_state=0)

            for step_result in all_step_results:
                for k, v in step_result.measurements.items():
                    if not k in measurements:
                        measurements[k] = []
                    measurements[k].append(np.array(v, dtype=int))

        return {k: np.array(v) for k, v in measurements.items()}
Exemple #28
0
 def _simulate_measurement(self, op: ops.Operation, data: _StateAndBuffer,
                           indices: List[int],
                           measurements: Dict[str, List[int]],
                           num_qubits: int) -> None:
     """Simulate an op that is a measurement in the computational basis."""
     # TODO: support measurement outside computational basis.
     if isinstance(op.gate, ops.MeasurementGate):
         meas = op.gate
         invert_mask = meas.full_invert_mask()
         # Measure updates inline.
         bits, _ = wave_function.measure_state_vector(
             data.state,
             indices,
             out=data.state,
             qid_shape=data.state.shape,
             seed=self.prng)
         corrected = [
             bit ^ (bit < 2 and mask)
             for bit, mask in zip(bits, invert_mask)
         ]
         key = protocols.measurement_key(meas)
         measurements[key].extend(corrected)
Exemple #29
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())
        qid_shape = protocols.qid_shape(qubits)
        qubit_map = {q: i for i, q in enumerate(qubits)}
        initial_matrix = density_matrix_utils.to_valid_density_matrix(
            initial_state,
            len(qid_shape),
            qid_shape=qid_shape,
            dtype=self._dtype)
        if len(circuit) == 0:
            yield DensityMatrixStepResult(initial_matrix, {}, qubit_map,
                                          self._dtype)
            return

        state = _StateAndBuffers(len(qid_shape),
                                 initial_matrix.reshape(qid_shape * 2))

        def on_stuck(bad_op: ops.Operation):
            return TypeError(
                "Can't simulate operations that don't implement "
                "SupportsUnitary, SupportsConsistentApplyUnitary, "
                "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)))

        noisy_moments = self.noise.noisy_moments(circuit,
                                                 sorted(circuit.all_qubits()))

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

            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.full_invert_mask()
                        # Measure updates inline.
                        bits, _ = density_matrix_utils.measure_density_matrix(
                            state.tensor,
                            indices,
                            qid_shape=qid_shape,
                            out=state.tensor)
                        corrected = [
                            bit ^ (bit < 2 and 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.
                    self._apply_op_channel(op, state, indices)
            yield DensityMatrixStepResult(density_matrix=state.tensor,
                                          measurements=measurements,
                                          qubit_map=qubit_map,
                                          dtype=self._dtype)
Exemple #30
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)