Esempio n. 1
0
 def run_sweep(
         self,
         program: 'cirq.Circuit',
         params: 'cirq.Sweepable',
         repetitions: int = 1,
 ) -> List['cirq.Result']:
     assert isinstance(program, circuits.Circuit)
     meas = list(program.findall_operations_with_gate_type(
         ops.MeasurementGate))
     if len(meas) == 0:
         raise ValueError()
     elif len(meas) > 1:
         for _, m, _ in meas:
             assert len(m.qubits) == 1
         results = [
             study.Result(
                 params=p,
                 measurements={gate.key: np.zeros(
                     (repetitions, 1), dtype=int)
                     for _, _, gate in meas})
             for p in study.to_resolvers(params)
         ]
     else:
         assert len(meas) == 1
         i, op, gate = meas[0]
         n_qubits = len(op.qubits)
         k = gate.key
         results = [
             study.Result(
                 params=p,
                 measurements={k: np.zeros(
                     (repetitions, n_qubits), dtype=int)})
             for p in study.to_resolvers(params)
         ]
     return results
Esempio n. 2
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)
        ]
Esempio n. 3
0
    def compute_amplitudes_sweep(
        self,
        program: circuits.Circuit,
        bitstrings: Sequence[int],
        params: study.Sweepable,
        qubit_order: ops.QubitOrderOrList = ops.QubitOrder.DEFAULT,
    ) -> Sequence[Sequence[complex]]:

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

        n_qubits = len(program.all_qubits())
        # qsim numbers qubits in reverse order from cirq
        bitstrings = [
            format(bitstring, "b").zfill(n_qubits)[::-1]
            for bitstring in bitstrings
        ]

        options = {"i": "\n".join(bitstrings)}
        options.update(self.qsimh_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.update(self.qsimh_options)
            amplitudes = qsim.qsimh_simulate(options)
            trials_results.append(amplitudes)

        return trials_results
Esempio n. 4
0
    def compute_displays_sweep(
        self,
        program: Union[circuits.Circuit, schedules.Schedule],
        params: Optional[study.Sweepable] = None,
        qubit_order: ops.QubitOrderOrList = ops.QubitOrder.DEFAULT,
        initial_state: Union[int, np.ndarray] = 0,
    ) -> List[study.ComputeDisplaysResult]:
        """Computes displays in the supplied Circuit or Schedule.

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

        Args:
            program: The circuit or schedule to simulate.
            params: Parameters to run with the program.
            qubit_order: Determines the canonical ordering of the qubits used to
                define the order of amplitudes in the wave function.
            initial_state: If an int, the state is set to the computational
                basis state corresponding to this state. Otherwise if it is a
                np.ndarray it is the full initial state, either a pure state
                or the full density matrix. If it is the pure state it must be
                the correct size, be normalized (an L2 norm of 1), and be
                safely castable to an appropriate dtype for the simulator.
                If it is a mixed state it must be correctly sized and
                positive semidefinite with trace one.

        Returns:
            List of ComputeDisplaysResults for this run, one for each
            possible parameter resolver.
        """
        circuit = (program.to_circuit()
                   if isinstance(program, schedules.Schedule) else program)
        qubit_order = ops.QubitOrder.as_qubit_order(qubit_order)
        qubits = qubit_order.order_for(circuit.all_qubits())

        compute_displays_results: List[study.ComputeDisplaysResult] = []
        for param_resolver in study.to_resolvers(params):
            display_values: Dict[Hashable, Any] = {}

            # Compute the displays in the first Moment
            moment = circuit[0]
            matrix = density_matrix_utils.to_valid_density_matrix(
                initial_state, num_qubits=len(qubits), dtype=self._dtype)
            qubit_map = {q: i for i, q in enumerate(qubits)}
            _enter_moment_display_values_into_dictionary(
                display_values, moment, matrix, qubits, qubit_map)

            # Compute the displays in the rest of the Moments
            all_step_results = self.simulate_moment_steps(
                circuit, param_resolver, qubits, initial_state)
            for step_result, moment in zip(all_step_results, circuit[1:]):
                _enter_moment_display_values_into_dictionary(
                    display_values, moment, step_result.density_matrix(),
                    qubits, step_result._qubit_map)

            compute_displays_results.append(
                study.ComputeDisplaysResult(params=param_resolver,
                                            display_values=display_values))

        return compute_displays_results
Esempio n. 5
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)
        ]
Esempio n. 6
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: circuit is not valid for the sampler, due to invalid
            repeated keys or incompatibility with the sampler's device.
        """
        if self.device:
            self.device.validate_circuit(program)
        shapes = self._get_measurement_shapes(program)
        return [
            study.ResultDict(
                params=param_resolver,
                records={
                    k: np.zeros((repetitions, num_instances, len(qid_shape)),
                                dtype=int)
                    for k, (num_instances, qid_shape) in shapes.items()
                },
            ) for param_resolver in study.to_resolvers(params)
        ]
Esempio n. 7
0
    def run_sweep(
        self,
        program: Union[circuits.Circuit, schedules.Schedule],
        params: study.Sweepable,
        repetitions: int = 1,
    ) -> List[study.TrialResult]:
        """Runs the entire supplied Circuit, mimicking the quantum hardware.

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

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

        Returns:
            TrialResult list for this run; one for each possible parameter
            resolver.
        """
        circuit = (program if isinstance(program, circuits.Circuit) else
                   program.to_circuit())
        param_resolvers = study.to_resolvers(params)

        trial_results = []  # type: List[study.TrialResult]
        for param_resolver in param_resolvers:
            measurements = self._run(circuit=circuit,
                                     param_resolver=param_resolver,
                                     repetitions=repetitions)
            trial_results.append(
                study.TrialResult(params=param_resolver,
                                  repetitions=repetitions,
                                  measurements=measurements))
        return trial_results
Esempio n. 8
0
  def compute_amplitudes_sweep(
      self,
      program: circuits.Circuit,
      bitstrings: Sequence[str],
      params: study.Sweepable,
      qubit_order: ops.QubitOrderOrList = ops.QubitOrder.DEFAULT,
  ) -> Sequence[Sequence[complex]]:

    if not isinstance(program, qsimc.QSimCircuit):
      raise ValueError('{!r} is not a QSimCircuit'.format(program))

    # qsim numbers qubits in reverse order from cirq
    bitstrings = [bs[::-1] for bs in bitstrings]

    options = {'i': '\n'.join(bitstrings)}
    options.update(self.qsimh_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.update(self.qsimh_options)
      amplitudes = qsim.qsimh_simulate(options)
      trials_results.append(amplitudes)

    return trials_results
Esempio n. 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
                )
            yield study.ResultDict(params=param_resolver, records=records)
Esempio n. 10
0
    def run_sweep(
        self,
        program: 'cirq.Circuit',
        params: study.Sweepable,
        repetitions: int = 1,
    ) -> List[study.TrialResult]:
        """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:
            TrialResult 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.TrialResult]
        for param_resolver in study.to_resolvers(params):
            measurements = self._run(circuit=program,
                                     param_resolver=param_resolver,
                                     repetitions=repetitions)
            trial_results.append(
                study.TrialResult.from_single_parameter_set(
                    params=param_resolver, measurements=measurements))
        return trial_results
 def simulate_expectation_values_sweep(
     self,
     program: 'cirq.Circuit',
     observables: Union['cirq.PauliSumLike', List['cirq.PauliSumLike']],
     params: 'study.Sweepable',
     qubit_order: ops.QubitOrderOrList = ops.QubitOrder.DEFAULT,
     initial_state: Any = None,
     permit_terminal_measurements: bool = False,
 ) -> List[List[float]]:
     if not permit_terminal_measurements and program.are_any_measurements_terminal():
         raise ValueError(
             'Provided circuit has terminal measurements, which may '
             'skew expectation values. If this is intentional, set '
             'permit_terminal_measurements=True.'
         )
     swept_evs = []
     qubit_order = ops.QubitOrder.as_qubit_order(qubit_order)
     qmap = {q: i for i, q in enumerate(qubit_order.order_for(program.all_qubits()))}
     if not isinstance(observables, List):
         observables = [observables]
     pslist = [ops.PauliSum.wrap(pslike) for pslike in observables]
     for param_resolver in study.to_resolvers(params):
         result = cast(
             state_vector_simulator.StateVectorTrialResult,
             self.simulate(
                 program, param_resolver, qubit_order=qubit_order, initial_state=initial_state
             ),
         )
         swept_evs.append(
             [
                 obs.expectation_from_state_vector(result.final_state_vector, qmap)
                 for obs in pslist
             ]
         )
     return swept_evs
Esempio n. 12
0
    def compute_amplitudes_sweep(
        self,
        program: circuits.Circuit,
        bitstrings: Sequence[int],
        params: study.Sweepable,
        qubit_order: ops.QubitOrderOrList = ops.QubitOrder.DEFAULT,
    ) -> Sequence[Sequence[complex]]:
        """Computes the desired amplitudes using qsim.

        The initial state is assumed to be the all zeros state.

        Args:
            program: The circuit to simulate.
            bitstrings: The bitstrings whose amplitudes are desired, input as an
              string array where each string is formed from measured qubit values
              according to `qubit_order` from most to least significant qubit,
              i.e. in big-endian ordering.
            param_resolver: 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.

        Returns:
            List of amplitudes.
        """
        if not isinstance(program, qsimc.QSimCircuit):
            program = qsimc.QSimCircuit(program, device=program.device)

        # qsim numbers qubits in reverse order from cirq
        cirq_order = ops.QubitOrder.as_qubit_order(qubit_order).order_for(
            program.all_qubits())
        num_qubits = len(cirq_order)
        bitstrings = [
            format(bitstring, "b").zfill(num_qubits)[::-1]
            for bitstring in bitstrings
        ]

        options = {"i": "\n".join(bitstrings)}
        options.update(self.qsim_options)

        param_resolvers = study.to_resolvers(params)

        trials_results = []
        if _needs_trajectories(program):
            translator_fn_name = "translate_cirq_to_qtrajectory"
            simulator_fn = qsim.qtrajectory_simulate
        else:
            translator_fn_name = "translate_cirq_to_qsim"
            simulator_fn = qsim.qsim_simulate

        for prs in param_resolvers:
            solved_circuit = protocols.resolve_parameters(program, prs)
            translator_fn = getattr(solved_circuit, translator_fn_name)
            options["c"] = translator_fn(cirq_order)
            options["s"] = self.get_seed()
            amplitudes = simulator_fn(options)
            trials_results.append(amplitudes)

        return trials_results
Esempio n. 13
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
Esempio n. 14
0
    def simulate_sweep(
        self,
        program: Union[circuits.Circuit, schedules.Schedule],
        params: study.Sweepable = study.ParamResolver({}),
        qubit_order: ops.QubitOrderOrList = ops.QubitOrder.DEFAULT,
        initial_state: Union[int, np.ndarray] = 0,
    ) -> List['SimulationTrialResult']:
        """Simulates the entire 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 or schedule to simulate.
            params: Parameters to run with the program.
            qubit_order: Determines the canonical ordering of the qubits used to
                define the order of amplitudes in the wave function.
            initial_state: If an int, the state is set to the computational
                basis state corresponding to this state.
                Otherwise if this is a np.ndarray it is the full initial state.
                In this case it must be the correct size, be normalized (an L2
                norm of 1), and  be safely castable to an appropriate
                dtype for the simulator.

        Returns:
            List of SimulatorTrialResults for this run, one for each
            possible parameter resolver.
        """
        circuit = (program if isinstance(program, circuits.Circuit)
                   else program.to_circuit())
        param_resolvers = study.to_resolvers(params or study.ParamResolver({}))

        trial_results = []  # type: List[SimulationTrialResult]
        qubit_order = ops.QubitOrder.as_qubit_order(qubit_order)
        for param_resolver in param_resolvers:
            step_result = None
            all_step_results = self.simulate_moment_steps(circuit,
                                                          param_resolver,
                                                          qubit_order,
                                                          initial_state)
            measurements = {}  # type: Dict[str, np.ndarray]
            for step_result in all_step_results:
                for k, v in step_result.measurements.items():
                    measurements[k] = np.array(v, dtype=bool)
            if step_result:
                final_state = step_result.state()
            else:
                # Empty circuit, so final state should be initial state.
                num_qubits = len(qubit_order.order_for(circuit.all_qubits()))
                final_state = wave_function.to_valid_state_vector(initial_state,
                                                                  num_qubits)
            trial_results.append(SimulationTrialResult(
                params=param_resolver,
                measurements=measurements,
                final_state=final_state))

        return trial_results
Esempio n. 15
0
    def simulate_sweep_iter(
        self,
        program: 'cirq.AbstractCircuit',
        params: 'cirq.Sweepable',
        qubit_order: 'cirq.QubitOrderOrList' = ops.QubitOrder.DEFAULT,
        initial_state: Any = None,
    ) -> Iterator[TSimulationTrialResult]:
        """Simulates the supplied Circuit.

        This method returns a result which allows access to the entire
        state vector. 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 can be
                either a raw state or an `SimulationStateBase`. The form of the
                raw 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.
        """
        qubit_order = ops.QubitOrder.as_qubit_order(qubit_order)
        for param_resolver in study.to_resolvers(params):
            state = (
                initial_state.copy()
                if isinstance(initial_state, SimulationStateBase)
                else initial_state
            )
            all_step_results = self.simulate_moment_steps(
                program, param_resolver, qubit_order, state
            )
            measurements: Dict[str, np.ndarray] = {}
            for step_result in all_step_results:
                for k, v in step_result.measurements.items():
                    measurements[k] = np.array(v, dtype=np.uint8)
            if (
                'final_simulator_state'
                in inspect.signature(self._create_simulator_trial_result).parameters
            ):
                yield self._create_simulator_trial_result(
                    params=param_resolver,
                    measurements=measurements,
                    final_simulator_state=step_result._simulator_state(),
                )
            else:
                yield self._create_simulator_trial_result(  # pylint: disable=no-value-for-parameter, unexpected-keyword-arg, line-too-long
                    params=param_resolver,
                    measurements=measurements,
                    final_step_result=step_result,  # type: ignore
                )
Esempio n. 16
0
    def simulate_sweep(
        self,
        program: Union[Circuit, MPSimCircuit],
        params: study.Sweepable,
        qubit_order: ops.QubitOrderOrList = ops.QubitOrder.DEFAULT,
        initial_state: Any = None,
    ) -> List[Any]:
        """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, (Circuit, MPSimCircuit)):
            raise ValueError(
                f"Program is of type {type(program)} but should be either "
                "a cirq.Circuit or mpsim.mpsim_cirq.MPSimCircuit.")

        param_resolvers = study.to_resolvers(params)

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

            ordered_qubits = ops.QubitOrder.as_qubit_order(
                qubit_order).order_for(solved_circuit.all_qubits())

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

            mps = MPS(nqudits=len(solved_circuit.all_qubits()))
            # TODO: Account for an input ordering of operations to apply here
            operations = [
                mps_operation_from_gate_operation(gate_operation,
                                                  qubit_to_index_map)
                for gate_operation in solved_circuit.all_operations()
            ]
            mps.apply(operations, **self._options)
            trial_results.append(mps)
        return trial_results
Esempio n. 17
0
    def compute_amplitudes_sweep(
        self,
        program: circuits.Circuit,
        bitstrings: Sequence[int],
        params: study.Sweepable,
        qubit_order: ops.QubitOrderOrList = ops.QubitOrder.DEFAULT,
    ) -> Sequence[Sequence[complex]]:

        if not isinstance(program, qcirc.QFlexCircuit):
            raise ValueError('{!r} is not a QFlexCircuit'.format(program))

        if not isinstance(program.device, qdevice.QFlexVirtualDevice):
            # The circuit was not validated against the device
            # TODO: Make it compatible? Validate, but for which grid?
            raise ValueError('{!r} is not a QFlexVirtualDevice'.format(
                program.device))

        param_resolvers = study.to_resolvers(params)

        trials_results = []
        for prs in param_resolvers:

            from cirq import protocols
            # The QFlexVirtualDevice device is "inherited" from the original program
            solved_circuit = protocols.resolve_parameters(program, prs)

            sweep_return = []
            # Not sure what these params could look like...for the moment
            for bitstring in bitstrings:

                options = {
                    'circuit_filename': solved_circuit.circuit_data,
                    'ordering_filename': solved_circuit.ordering_data,
                    'grid_filename': program.device.grid_data,
                    'final_state': bitstring
                }

                amplitudes = qflex.simulate(options)

                for amp in amplitudes:
                    amplitude = complex(amp[1])

                    # For debugging purposes commented the following
                    # state = amp[0]
                    # print(input_initial_state + " --> " + state + ": " + \
                    #       str(amplitude.real) + " " + str(amplitude.imag))

                    # the amplitude for bitstring is stored
                    sweep_return.append(amplitude)

            trials_results.append(sweep_return)

        return trials_results
Esempio n. 18
0
    def compute_amplitudes_sweep(
        self,
        program: circuits.Circuit,
        bitstrings: Sequence[int],
        params: study.Sweepable,
        qubit_order: ops.QubitOrderOrList = ops.QubitOrder.DEFAULT,
    ) -> Sequence[Sequence[complex]]:
        """Computes the desired amplitudes using qsim.

      The initial state is assumed to be the all zeros state.

      Args:
          program: The circuit to simulate.
          bitstrings: The bitstrings whose amplitudes are desired, input as an
            string array where each string is formed from measured qubit values
            according to `qubit_order` from most to least significant qubit,
            i.e. in big-endian ordering.
          param_resolver: 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.

      Returns:
          List of amplitudes.
      """
        if not isinstance(program, qsimc.QSimCircuit):
            program = qsimc.QSimCircuit(program, device=program.device)

        n_qubits = len(program.all_qubits())
        # qsim numbers qubits in reverse order from cirq
        bitstrings = [
            format(bitstring, 'b').zfill(n_qubits)[::-1]
            for bitstring in bitstrings
        ]

        options = {'i': '\n'.join(bitstrings)}
        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)

            amplitudes = qsim.qsim_simulate(options)
            trials_results.append(amplitudes)

        return trials_results
Esempio n. 19
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)
Esempio n. 20
0
    def compute_samples_displays_sweep(
            self,
            program: Union[circuits.Circuit, schedules.Schedule],
            params: Optional[study.Sweepable] = None
    ) -> List[study.ComputeDisplaysResult]:
        """Computes SamplesDisplays in the supplied Circuit or Schedule.

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

        Args:
            program: The circuit or schedule to simulate.
            params: Parameters to run with the program.

        Returns:
            List of ComputeDisplaysResults for this run, one for each
            possible parameter resolver.
        """
        circuit = (program if isinstance(program, circuits.Circuit)
                   else program.to_circuit())
        param_resolvers = study.to_resolvers(params or study.ParamResolver({}))

        compute_displays_results = []  # type: List[study.ComputeDisplaysResult]
        for param_resolver in param_resolvers:
            display_values = {}  # type: Dict[Hashable, Any]
            preceding_circuit = circuits.Circuit()
            for i, moment in enumerate(circuit):
                displays = (op for op in moment
                            if isinstance(op, ops.SamplesDisplay))
                for display in displays:
                    measurement_key = str(display.key)
                    measurement_circuit = circuits.Circuit.from_ops(
                        display.measurement_basis_change(),
                        ops.measure(*display.qubits,
                                    key=measurement_key)
                    )
                    measurements = self._run(
                        preceding_circuit + measurement_circuit,
                        param_resolver,
                        display.num_samples)
                    display_values[display.key] = (
                        display.value_derived_from_samples(
                            measurements[measurement_key]))
                preceding_circuit.append(circuit[i])
            compute_displays_results.append(study.ComputeDisplaysResult(
                params=param_resolver,
                display_values=display_values))

        return compute_displays_results
Esempio n. 21
0
def sample_sweep(
    program: Union[circuits.Circuit, schedules.Schedule],
    params: study.Sweepable,
    *,
    noise: 'cirq.NOISE_MODEL_LIKE' = None,
    repetitions: int = 1,
    dtype: Type[np.number] = np.complex64,
    seed: Optional[Union[int, np.random.RandomState]] = None
) -> List[study.TrialResult]:
    """Runs the supplied Circuit or Schedule, mimicking quantum hardware.

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

    Args:
        program: The circuit or schedule to simulate.
        params: Parameters to run with the program.
        noise: Noise model to use while running the simulation.
        repetitions: The number of repetitions to simulate, per set of
            parameter values.
        dtype: The `numpy.dtype` used by the simulation. Typically one of
            `numpy.complex64` or `numpy.complex128`.
            Favors speed over precision by default, i.e. uses `numpy.complex64`.
        seed: The random seed to use for this simulator.

    Returns:
        TrialResult list for this run; one for each possible parameter
        resolver.
    """
    if seed is None:
        prng = None
    elif isinstance(seed, np.random.RandomState):
        prng = seed
    else:
        prng = np.random.RandomState(seed)

    circuit = (program.to_circuit()
               if isinstance(program, schedules.Schedule) else program)

    trial_results = []  # type: List[study.TrialResult]
    for param_resolver in study.to_resolvers(params):
        measurements = sample(circuit,
                              noise=noise,
                              param_resolver=param_resolver,
                              repetitions=repetitions,
                              dtype=dtype,
                              seed=prng)
        trial_results.append(measurements)
    return trial_results
Esempio n. 22
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.

        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 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.
        """
        circuit = (program if isinstance(program, circuits.Circuit)
                   else program.to_circuit())
        param_resolvers = study.to_resolvers(params)

        trial_results = []
        qubit_order = ops.QubitOrder.as_qubit_order(qubit_order)
        for param_resolver in param_resolvers:
            all_step_results = self.simulate_moment_steps(circuit,
                                                          param_resolver,
                                                          qubit_order,
                                                          initial_state)
            measurements = {}  # type: Dict[str, np.ndarray]
            for step_result in all_step_results:
                for k, v in step_result.measurements.items():
                    measurements[k] = np.array(v, dtype=bool)
            trial_results.append(
                self._create_simulator_trial_result(
                    params=param_resolver,
                    measurements=measurements,
                    final_simulator_state=step_result._simulator_state()))
        return trial_results
Esempio n. 23
0
def sample_sweep(
        program: Union[circuits.Circuit, schedules.Schedule],
        params: study.Sweepable,
        *,
        noise: devices.NoiseModel = devices.NO_NOISE,
        repetitions: int = 1,
        dtype: Type[np.number] = np.complex64,
        seed: Optional[int] = None,
) -> List[study.TrialResult]:
    """Runs the supplied Circuit or Schedule, mimicking quantum hardware.

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

    Args:
        program: The circuit or schedule to simulate.
        params: Parameters to run with the program.
        noise: Noise model to use while running the simulation.
        repetitions: The number of repetitions to simulate, per set of
            parameter values.
        dtype: The `numpy.dtype` used by the simulation. Typically one of
            `numpy.complex64` or `numpy.complex128`.
            Favors speed over precision by default, i.e. uses `numpy.complex64`.
        seed: The random seed to use for this simulator. Sets numpy's
            random seed. Setting numpy's seed different in between
            use of this class will lead to non-seeded behavior.

    Returns:
        TrialResult list for this run; one for each possible parameter
        resolver.
    """
    if seed:
        np.random.seed(seed)
    circuit = (program if isinstance(program, circuits.Circuit)
               else program.to_circuit())
    param_resolvers = study.to_resolvers(params)

    trial_results = []  # type: List[study.TrialResult]
    for param_resolver in param_resolvers:
        measurements = sample(circuit,
                              noise=noise,
                              param_resolver=param_resolver,
                              repetitions=repetitions,
                              dtype=dtype)
        trial_results.append(measurements)
    return trial_results
Esempio n. 24
0
    def simulate_sweep(
        self,
        program: 'cirq.Circuit',
        params: study.Sweepable,
        qubit_order: ops.QubitOrderOrList = ops.QubitOrder.DEFAULT,
        initial_state: Any = None,
    ) -> List[TSimulationTrialResult]:
        """Simulates the supplied Circuit.

        This method returns a result which allows access to the entire
        state vector. 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 can be
                either a raw state or a `TActOnArgs`. The form of the
                raw 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 = []
        qubit_order = ops.QubitOrder.as_qubit_order(qubit_order)
        for param_resolver in study.to_resolvers(params):
            all_step_results = self.simulate_moment_steps(
                program, param_resolver, qubit_order, initial_state)
            measurements = {}  # type: Dict[str, np.ndarray]
            for step_result in all_step_results:
                for k, v in step_result.measurements.items():
                    measurements[k] = np.array(v, dtype=np.uint8)
            trial_results.append(
                self._create_simulator_trial_result(
                    params=param_resolver,
                    measurements=measurements,
                    final_simulator_state=step_result._simulator_state(),
                ))
        return trial_results
Esempio n. 25
0
def sample_sweep(
    program: 'cirq.Circuit',
    params: study.Sweepable,
    *,
    noise: 'cirq.NOISE_MODEL_LIKE' = None,
    repetitions: int = 1,
    dtype: Type[np.number] = np.complex64,
    seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None,
) -> 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.
        noise: Noise model to use while running the simulation.
        repetitions: The number of repetitions to simulate, per set of
            parameter values.
        dtype: The `numpy.dtype` used by the simulation. Typically one of
            `numpy.complex64` or `numpy.complex128`.
            Favors speed over precision by default, i.e. uses `numpy.complex64`.
        seed: The random seed to use for this simulator.

    Returns:
        Result list for this run; one for each possible parameter
        resolver.
    """
    prng = value.parse_random_state(seed)

    trial_results = []  # type: List[study.Result]
    for param_resolver in study.to_resolvers(params):
        measurements = sample(
            program,
            noise=noise,
            param_resolver=param_resolver,
            repetitions=repetitions,
            dtype=dtype,
            seed=prng,
        )
        trial_results.append(measurements)
    return trial_results
Esempio n. 26
0
    def run_sweep(self,
                  program: Union[circuits.Circuit, schedules.Schedule],
                  params: study.Sweepable,
                  repetitions: int = 1) -> List[study.TrialResult]:
        """Samples from the given Circuit or Schedule.

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

        Args:
            program: The circuit or schedule to simulate.
            Should be generated using AQTSampler.generate_circuit_from_list
            params: Parameters to run with the program.
            repetitions: The number of repetitions to simulate.

        The parameters remote_host and access_token are not used.

        Returns:
            TrialResult list for this run; one for each possible parameter
            resolver.
        """
        meas_name = 'm'  # TODO: Get measurement name from circuit
        circuit = (program if isinstance(program, circuits.Circuit) else
                   program.to_circuit())
        assert isinstance(circuit.device, IonDevice)
        param_resolvers = study.to_resolvers(params)
        trial_results = []  # type: List[study.TrialResult]
        for param_resolver in param_resolvers:
            id_str = uuid.uuid1()
            num_qubits = len(circuit.device.qubits)
            json_str = self._generate_json(circuit=circuit,
                                           param_resolver=param_resolver)
            results = self._send_json(json_str=json_str,
                                      id_str=id_str,
                                      repetitions=repetitions,
                                      num_qubits=num_qubits)
            results = results.astype(bool)
            res_dict = {meas_name: results}
            trial_results.append(
                study.TrialResult(params=param_resolver,
                                  measurements=res_dict))
        return trial_results
Esempio n. 27
0
    def run_sweep_iter(
        self,
        program: 'cirq.Circuit',
        params: study.Sweepable,
        repetitions: int = 1,
    ) -> Iterator[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)

        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)
            yield study.Result.from_single_parameter_set(
                params=param_resolver, measurements=measurements)
Esempio n. 28
0
    def run_sweep(self,
                  program: 'cirq.Circuit',
                  params: study.Sweepable,
                  repetitions: int = 1) -> List[study.Result]:
        """Samples from the given Circuit.

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

        Args:
            program: The circuit to simulate.
            Should be generated using AQTSampler.generate_circuit_from_list
            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.
        """
        # TODO: Use measurement name from circuit.
        # Github issue: https://github.com/quantumlib/Cirq/issues/2199
        meas_name = 'm'
        assert isinstance(program.device, IonDevice)
        trial_results = []  # type: List[study.Result]
        for param_resolver in study.to_resolvers(params):
            id_str = uuid.uuid1()
            num_qubits = len(program.device.qubits)
            json_str = self._generate_json(circuit=program,
                                           param_resolver=param_resolver)
            results = self._send_json(json_str=json_str,
                                      id_str=id_str,
                                      repetitions=repetitions,
                                      num_qubits=num_qubits)
            results = results.astype(bool)
            res_dict = {meas_name: results}
            trial_results.append(
                study.Result(params=param_resolver, measurements=res_dict))
        return trial_results
Esempio n. 29
0
    def simulate_expectation_values_sweep(
        self,
        program: 'cirq.Circuit',
        observables: Union['cirq.PauliSumLike', List['cirq.PauliSumLike']],
        params: 'study.Sweepable',
        qubit_order: ops.QubitOrderOrList = ops.QubitOrder.DEFAULT,
        initial_state: Any = None,
        permit_terminal_measurements: bool = False,
    ) -> List[List[float]]:
        """Simulates the supplied circuit and calculates exact expectation
    values for the given observables on its final state.

    This method has no perfect analogy in hardware. Instead compare with
    Sampler.sample_expectation_values, which calculates estimated
    expectation values by sampling multiple times.

    Args:
        program: The circuit to simulate.
        observables: An observable or list of observables.
        param_resolver: 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.
        permit_terminal_measurements: If the provided circuit ends with
            measurement(s), this method will generate an error unless this
            is set to True. This is meant to prevent measurements from
            ruining expectation value calculations.

    Returns:
        A list of expectation values, with the value at index `n`
        corresponding to `observables[n]` from the input.

    Raises:
        ValueError if 'program' has terminal measurement(s) and
        'permit_terminal_measurements' is False. (Note: We cannot test this
        until Cirq's `are_any_measurements_terminal` is released.)
    """
        # TODO: replace with commented check when Cirq v0.10 is released.
        if not permit_terminal_measurements:
            raise ValueError(
                'Automatic terminal measurement checking is not supported in qsim. '
                'Please check that your circuit has no terminal measurements, then '
                'set permit_terminal_measurements=True to bypass this error.')
        # if not permit_terminal_measurements and program.are_any_measurements_terminal():
        #   raise ValueError(
        #     'Provided circuit has terminal measurements, which may '
        #     'skew expectation values. If this is intentional, set '
        #     'permit_terminal_measurements=True.'
        #   )
        if not isinstance(observables, List):
            observables = [observables]
        psumlist = [ops.PauliSum.wrap(pslike) for pslike in observables]

        ordered_qubits = ops.QubitOrder.as_qubit_order(qubit_order).order_for(
            program.all_qubits())
        ordered_qubits = list(reversed(ordered_qubits))
        num_qubits = len(ordered_qubits)
        qubit_map = {
            qubit: index
            for index, qubit in enumerate(ordered_qubits)
        }

        opsums_and_qubit_counts = []
        for psum in psumlist:
            opsum = []
            opsum_qubits = set()
            for pstr in psum:
                opstring = qsim.OpString()
                opstring.weight = pstr.coefficient
                for q, pauli in pstr.items():
                    op = pauli.on(q)
                    opsum_qubits.add(q)
                    qsimc.add_op_to_opstring(op, qubit_map, opstring)
                opsum.append(opstring)
            opsums_and_qubit_counts.append((opsum, len(opsum_qubits)))

        if initial_state is None:
            initial_state = 0
        if not isinstance(initial_state, (int, np.ndarray)):
            raise TypeError('initial_state must be an int or state vector.')
        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)
        if isinstance(initial_state, np.ndarray):
            if initial_state.dtype != np.complex64:
                raise TypeError(
                    f'initial_state vector must have dtype np.complex64.')
            input_vector = initial_state.view(np.float32)
            if len(input_vector) != 2**num_qubits * 2:
                raise ValueError(
                    f'initial_state vector size must match number of qubits.'
                    f'Expected: {2**num_qubits * 2} Received: {len(input_vector)}'
                )

        results = []
        if _needs_trajectories(program):
            translator_fn_name = 'translate_cirq_to_qtrajectory'
            ev_simulator_fn = qsim.qtrajectory_simulate_expectation_values
        else:
            translator_fn_name = 'translate_cirq_to_qsim'
            ev_simulator_fn = qsim.qsim_simulate_expectation_values

        for prs in param_resolvers:
            solved_circuit = protocols.resolve_parameters(program, prs)
            translator_fn = getattr(solved_circuit, translator_fn_name)
            options['c'] = translator_fn(qubit_order)
            options['s'] = self.get_seed()

            if isinstance(initial_state, int):
                evs = ev_simulator_fn(options, opsums_and_qubit_counts,
                                      initial_state)
            elif isinstance(initial_state, np.ndarray):
                evs = ev_simulator_fn(options, opsums_and_qubit_counts,
                                      input_vector)
            results.append(evs)

        return results
Esempio n. 30
0
    def simulate_sweep(
        self,
        program: circuits.Circuit,
        params: study.Sweepable,
        qubit_order: ops.QubitOrderOrList = ops.QubitOrder.DEFAULT,
        initial_state: Optional[Union[int, np.ndarray]] = 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 can either
            be an integer representing a pure state (e.g. 11010) or a numpy
            array containing the full state vector. If none is provided, this
            is assumed to be the all-zeros state.

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

      Raises:
          TypeError: if an invalid initial_state is provided.
      """
        if initial_state is None:
            initial_state = 0
        if not isinstance(initial_state, (int, np.ndarray)):
            raise TypeError('initial_state must be an int or state vector.')
        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)
        qubits = program.all_qubits()
        num_qubits = len(qubits)
        if isinstance(initial_state, np.ndarray):
            if initial_state.dtype != np.complex64:
                raise TypeError(
                    f'initial_state vector must have dtype np.complex64.')
            input_vector = initial_state.view(np.float32)
            if len(input_vector) != 2**num_qubits * 2:
                raise ValueError(
                    f'initial_state vector size must match number of qubits.'
                    f'Expected: {2**num_qubits * 2} Received: {len(input_vector)}'
                )

        trials_results = []
        if _needs_trajectories(program):
            translator_fn_name = 'translate_cirq_to_qtrajectory'
            fullstate_simulator_fn = qsim.qtrajectory_simulate_fullstate
        else:
            translator_fn_name = 'translate_cirq_to_qsim'
            fullstate_simulator_fn = qsim.qsim_simulate_fullstate

        for prs in param_resolvers:
            solved_circuit = protocols.resolve_parameters(program, prs)
            translator_fn = getattr(solved_circuit, translator_fn_name)
            options['c'] = translator_fn(qubit_order)
            options['s'] = self.get_seed()
            ordered_qubits = ops.QubitOrder.as_qubit_order(
                qubit_order).order_for(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)
            }

            if isinstance(initial_state, int):
                qsim_state = fullstate_simulator_fn(options, initial_state)
            elif isinstance(initial_state, np.ndarray):
                qsim_state = fullstate_simulator_fn(options, input_vector)
            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