Skip to content

Reduce required boilerplate for implementing external simulators and samplers  #2178

Closed
@cduck

Description

@cduck

I wrote a custom simulator recently and I had to copy quite a bit of boilerplate code out of cirq/sim/sparse_simulator.py. Below is my code with the boilerplate pointed out. It would be nice if the code in SimulatesSamples and SimulatesIntermediateState parent classes were rearranged to reduce this. @Strilanc

class MySimulator(cirq.SimulatesSamples,
                  cirq.SimulatesIntermediateState):
    # Boilerplate
    def _run(self, circuit, param_resolver, repetitions):
        param_resolver = param_resolver or cirq.ParamResolver({})
        resolved_circuit = cirq.resolve_parameters(circuit, param_resolver)
        assert not cirq.is_parameterized(resolved_circuit)
        return self._run_sweep_repeat(resolved_circuit, repetitions)

    # Boilerplate
    def _run_sweep_repeat(self, circuit, repetitions):
        measurements = defaultdict(list)
        for _ in range(repetitions):
            all_step_results = self._base_iterator(
                circuit,
                qubit_order=cirq.QubitOrder.DEFAULT,
                initial_state=0)
            for step_result in all_step_results:
                for k, v in step_result.measurements.items():
                    measurements[k].append(np.array(v, dtype=np.uint8))
        return {k: np.array(v, dtype=np.uint8) for k, v in measurements.items()}

    # Boilerplate
    def _simulator_iterator(self, circuit, param_resolver, qubit_order,
                            initial_state):
        param_resolver = param_resolver or cirq.ParamResolver({})
        resolved_circuit = cirq.resolve_parameters(circuit, param_resolver)
        assert not cirq.is_parameterized(resolved_circuit)
        actual_initial_state = 0 if initial_state is None else initial_state
        return self._base_iterator(resolved_circuit, qubit_order,
                                   actual_initial_state,
                                   perform_measurements=True)

    def _base_iterator(self, circuit, qubit_order, initial_state,
                       perform_measurements=True):
        # Boilerplate
        qubits = cirq.QubitOrder.as_qubit_order(qubit_order).order_for(
            circuit.all_qubits())
        num_qubits = len(qubits)
        qid_shape = cirq.qid_shape(qubits)
        qubit_map = {q: i for i, q in enumerate(qubits)}
        if len(circuit) == 0:
            yield MySimulatorStep(<default state>, {}, qubit_map)
        def on_stuck(bad_op):
            return TypeError(
                "Can't simulate unknown operations that don't specify a"
                "unitary or a decomposition. {!r}".format(bad_op))
        def keep(potential_op):
            return (cirq.has_unitary(potential_op) or
                    cirq.has_mixture(potential_op) or
                    cirq.is_measurement(potential_op) or
                    cirq.op_gate_isinstance(potential_op, cirq.ResetChannel))

        simulator_state = ...  # New code
        for moment in circuit:
            measurements = defaultdict(list)
            known_ops = cirq.decompose(moment, keep=keep,
                                       on_stuck_raise=on_stuck)
            for op in known_ops:
                self.simulate_op(op, simulator_state)  # New code
            yield MySimulatorStep(simulator_state, measurements, qubit_map)

    def simulate_op(op, state):
        # Actual simulation code here
        ...


class MySimulatorStep(cirq.StepResult):
    # Boilerplate
    def __init__(self, state, measurements, qubit_map):
        super().__init__(measurements)
        self.state = state
        self.qubit_map = qubit_map

    # Boilerplate
    def _simulator_state(self):
        return self.state

    def sample(self, qubits, repetitions=1):
        # Actual sampling code here
        return ...

Metadata

Metadata

Assignees

Labels

area/simulationkind/healthFor CI/testing/release process/refactoring/technical debt items

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions