Example #1
0
    def simulate_sweep(
        self,
        program: circuits.Circuit,
        params: study.Sweepable,
        qubit_order: ops.QubitOrderOrList = ops.QubitOrder.DEFAULT,
        initial_state: Any = None,
    ) -> List['SimulationTrialResult']:
        """Simulates the supplied Circuit.

      This method returns a result which allows access to the entire
      wave function. In contrast to simulate, this allows for sweeping
      over different parameter values.

      Args:
          program: The circuit 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.
      """
        if not isinstance(program, qsimc.QSimCircuit):
            raise ValueError('{!r} is not a QSimCircuit'.format(program))

        options = {}
        options.update(self.qsim_options)

        param_resolvers = study.to_resolvers(params)

        trials_results = []
        for prs in param_resolvers:
            solved_circuit = protocols.resolve_parameters(program, prs)

            options['c'] = solved_circuit.translate_cirq_to_qsim(qubit_order)
            ordered_qubits = ops.QubitOrder.as_qubit_order(
                qubit_order).order_for(solved_circuit.all_qubits())
            qubit_map = {
                qubit: index
                for index, qubit in enumerate(ordered_qubits)
            }

            qsim_state = qsim.qsim_simulate_fullstate(options)
            assert qsim_state.dtype == np.float32
            assert qsim_state.ndim == 1
            final_state = QSimSimulatorState(qsim_state, qubit_map)
            # create result for this parameter
            # TODO: We need to support measurements.
            result = QSimSimulatorTrialResult(
                params=prs, measurements={}, final_simulator_state=final_state)
            trials_results.append(result)

        return trials_results
Example #2
0
 def test_qsim_simulate_fullstate(self):
   qsim_fullstate_options = {
       'c': '2\n0 cnot 0 1\n1 cnot 1 0\n2 cz 0 1\n',
       't': 1,
       'v': 0
   }
   self.assertSequenceEqual(
       qsim.qsim_simulate_fullstate(qsim_fullstate_options).tolist(),
       [1., 0., 0., 0., 0., 0., 0., 0.])
Example #3
0
    def _sample_measure_results(
        self,
        program: circuits.Circuit,
        repetitions: int = 1,
    ) -> Dict[str, np.ndarray]:
        """Samples from measurement gates in the circuit.

    Note that this will execute the circuit 'repetitions' times.

    Args:
        program: The circuit to sample from.
        repetitions: The number of samples to take.

    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 there are multiple MeasurementGates with the same key,
            or if repetitions is negative.
    """
        if not isinstance(program, qsimc.QSimCircuit):
            program = qsimc.QSimCircuit(program, device=program.device)

        # Compute indices of measured qubits
        ordered_qubits = ops.QubitOrder.DEFAULT.order_for(program.all_qubits())
        num_qubits = len(ordered_qubits)

        qubit_map = {
            qubit: index
            for index, qubit in enumerate(ordered_qubits)
        }

        # Computes
        # - the list of qubits to be measured
        # - the start (inclusive) and end (exclusive) indices of each measurement
        # - a mapping from measurement key to measurement gate
        measurement_ops = [
            op for _, op, _ in program.findall_operations_with_gate_type(
                ops.MeasurementGate)
        ]
        measured_qubits = []  # type: List[ops.Qid]
        bounds = {}  # type: Dict[str, Tuple]
        meas_ops = {}  # type: Dict[str, cirq.GateOperation]
        current_index = 0
        for op in measurement_ops:
            gate = op.gate
            key = protocols.measurement_key(gate)
            meas_ops[key] = op
            if key in bounds:
                raise ValueError(
                    "Duplicate MeasurementGate with key {}".format(key))
            bounds[key] = (current_index, current_index + len(op.qubits))
            measured_qubits.extend(op.qubits)
            current_index += len(op.qubits)

        # Set qsim options
        options = {}
        options.update(self.qsim_options)

        results = {}
        for key, bound in bounds.items():
            results[key] = np.ndarray(shape=(repetitions, bound[1] - bound[0]),
                                      dtype=int)

        noisy = _needs_trajectories(program)
        if noisy:
            translator_fn_name = 'translate_cirq_to_qtrajectory'
            sampler_fn = qsim.qtrajectory_sample
        else:
            translator_fn_name = 'translate_cirq_to_qsim'
            sampler_fn = qsim.qsim_sample

        if not noisy and program.are_all_measurements_terminal(
        ) and repetitions > 1:
            print('Provided circuit has no intermediate measurements. ' +
                  'Sampling repeatedly from final state vector.')
            # Measurements must be replaced with identity gates to sample properly.
            # Simply removing them may omit qubits from the circuit.
            for i in range(len(program.moments)):
                program.moments[i] = ops.Moment(
                    op if not isinstance(op.gate, ops.MeasurementGate) else
                    [ops.IdentityGate(1).on(q) for q in op.qubits]
                    for op in program.moments[i])
            options['c'] = program.translate_cirq_to_qsim(
                ops.QubitOrder.DEFAULT)
            options['s'] = self.get_seed()
            final_state = qsim.qsim_simulate_fullstate(options, 0)
            full_results = sim.sample_state_vector(final_state.view(
                np.complex64),
                                                   range(num_qubits),
                                                   repetitions=repetitions,
                                                   seed=self._prng)

            for i in range(repetitions):
                for key, op in meas_ops.items():
                    meas_indices = [qubit_map[qubit] for qubit in op.qubits]
                    for j, q in enumerate(meas_indices):
                        results[key][i][j] = full_results[i][q]
        else:
            translator_fn = getattr(program, translator_fn_name)
            options['c'] = translator_fn(ops.QubitOrder.DEFAULT)
            for i in range(repetitions):
                options['s'] = self.get_seed()
                measurements = sampler_fn(options)
                for key, bound in bounds.items():
                    for j in range(bound[1] - bound[0]):
                        results[key][i][j] = int(measurements[bound[0] + j])

        return results
Example #4
0
    def simulate_sweep(
        self,
        program: circuits.Circuit,
        params: study.Sweepable,
        qubit_order: ops.QubitOrderOrList = ops.QubitOrder.DEFAULT,
        initial_state: Any = None,
    ) -> List['SimulationTrialResult']:
        """Simulates the supplied Circuit.

      This method returns a result which allows access to the entire
      wave function. In contrast to simulate, this allows for sweeping
      over different parameter values.

      Args:
          program: The circuit 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. This is currently
            unsupported in qsim; the recommended workaround is to prepend the
            circuit with X gates as necessary.

      Returns:
          List of SimulationTrialResults for this run, one for each
          possible parameter resolver.

      Raises:
          ValueError: if an initial_state is provided.
      """
        if initial_state is not None:
            raise ValueError(
                f'initial_state is not supported; received {initial_state}')

        if not isinstance(program, qsimc.QSimCircuit):
            program = qsimc.QSimCircuit(program, device=program.device)

        options = {}
        options.update(self.qsim_options)

        param_resolvers = study.to_resolvers(params)

        trials_results = []
        for prs in param_resolvers:
            solved_circuit = protocols.resolve_parameters(program, prs)

            options['c'] = solved_circuit.translate_cirq_to_qsim(qubit_order)
            options['s'] = self.get_seed()
            ordered_qubits = ops.QubitOrder.as_qubit_order(
                qubit_order).order_for(solved_circuit.all_qubits())
            # qsim numbers qubits in reverse order from cirq
            ordered_qubits = list(reversed(ordered_qubits))

            qubit_map = {
                qubit: index
                for index, qubit in enumerate(ordered_qubits)
            }

            qsim_state = qsim.qsim_simulate_fullstate(options)
            assert qsim_state.dtype == np.float32
            assert qsim_state.ndim == 1
            final_state = QSimSimulatorState(qsim_state, qubit_map)
            # create result for this parameter
            # TODO: We need to support measurements.
            result = QSimSimulatorTrialResult(
                params=prs, measurements={}, final_simulator_state=final_state)
            trials_results.append(result)

        return trials_results