2525
2626@dataclass
2727class PyQrackSimulatorBase (AbstractSimulatorDevice [PyQrackSimulatorTask ]):
28+ """PyQrack simulation device base class.
29+
30+ Args:
31+ options (PyQrackOptions):
32+ Options passed into the PyQrack simulator
33+ """
34+
2835 options : PyQrackOptions = field (default_factory = _default_pyqrack_args )
2936 loss_m_result : Measurement = field (default = Measurement .One , kw_only = True )
3037 rng_state : np .random .Generator = field (
@@ -96,12 +103,48 @@ def pauli_expectation(pauli: list[Pauli], qubits: list[PyQrackQubit]) -> float:
96103 if len (qubit_ids ) != len (set (qubit_ids )):
97104 raise ValueError ("Qubits must be unique." )
98105
99- return sim_reg .pauli_expectation (pauli , qubit_ids )
106+ return sim_reg .pauli_expectation (qubit_ids , pauli )
100107
101108
102109@dataclass
103110class StackMemorySimulator (PyQrackSimulatorBase ):
104- """PyQrack simulator device with precalculated stack of qubits."""
111+ """
112+ PyQrack simulator device with preallocated stack of qubits.
113+
114+ This can be used to simulate kernels where the number of qubits is known
115+ ahead of time.
116+
117+ ## Usage examples
118+
119+ ```
120+ # Define a kernel
121+ @qasm2.main
122+ def main():
123+ q = qasm2.qreg(2)
124+ c = qasm2.creg(2)
125+
126+ qasm2.h(q[0])
127+ qasm2.cx(q[0], q[1])
128+
129+ qasm2.measure(q, c)
130+ return q
131+
132+ # Create the simulator object
133+ sim = StackMemorySimulator(min_qubits=2)
134+
135+ # Execute the kernel
136+ qubits = sim.run(main)
137+ ```
138+
139+ You can also obtain other information from it, such as the state vector:
140+
141+ ```
142+ ket = sim.state_vector(main)
143+
144+ from pyqrack.pauli import Pauli
145+ expectation_vals = sim.pauli_expectation([Pauli.PauliX, Pauli.PauliI], qubits)
146+ ```
147+ """
105148
106149 min_qubits : int = field (default = 0 , kw_only = True )
107150
@@ -111,6 +154,20 @@ def task(
111154 args : tuple [Any , ...] = (),
112155 kwargs : dict [str , Any ] | None = None ,
113156 ):
157+ """
158+ Args:
159+ kernel (ir.Method):
160+ The kernel method to run.
161+ args (tuple[Any, ...]):
162+ Positional arguments to pass to the kernel method.
163+ kwargs (dict[str, Any] | None):
164+ Keyword arguments to pass to the kernel method.
165+
166+ Returns:
167+ PyQrackSimulatorTask:
168+ The task object used to track execution.
169+
170+ """
114171 if kwargs is None :
115172 kwargs = {}
116173
@@ -136,31 +193,67 @@ def task(
136193
137194@dataclass
138195class DynamicMemorySimulator (PyQrackSimulatorBase ):
139- """PyQrack simulator device with dynamic qubit allocation."""
196+ """
197+
198+ PyQrack simulator device with dynamic qubit allocation.
199+
200+ This can be used to simulate kernels where the number of qubits is not known
201+ ahead of time.
202+
203+ ## Usage examples
204+
205+ ```
206+ # Define a kernel
207+ @qasm2.main
208+ def main():
209+ q = qasm2.qreg(2)
210+ c = qasm2.creg(2)
211+
212+ qasm2.h(q[0])
213+ qasm2.cx(q[0], q[1])
214+
215+ qasm2.measure(q, c)
216+ return q
217+
218+ # Create the simulator object
219+ sim = DynamicMemorySimulator()
220+
221+ # Execute the kernel
222+ qubits = sim.run(main)
223+ ```
224+
225+ You can also obtain other information from it, such as the state vector:
226+
227+ ```
228+ ket = sim.state_vector(main)
229+
230+ from pyqrack.pauli import Pauli
231+ expectation_vals = sim.pauli_expectation([Pauli.PauliX, Pauli.PauliI], qubits)
232+
233+ """
140234
141235 def task (
142236 self ,
143237 kernel : ir .Method [Params , RetType ],
144238 args : tuple [Any , ...] = (),
145239 kwargs : dict [str , Any ] | None = None ,
146240 ):
241+ """
242+ Args:
243+ kernel (ir.Method):
244+ The kernel method to run.
245+ args (tuple[Any, ...]):
246+ Positional arguments to pass to the kernel method.
247+ kwargs (dict[str, Any] | None):
248+ Keyword arguments to pass to the kernel method.
249+
250+ Returns:
251+ PyQrackSimulatorTask:
252+ The task object used to track execution.
253+
254+ """
147255 if kwargs is None :
148256 kwargs = {}
149257
150258 memory = DynamicMemory (self .options .copy ())
151259 return self .new_task (kernel , args , kwargs , memory )
152-
153-
154- def test ():
155- from bloqade .qasm2 import extended
156-
157- @extended
158- def main ():
159- return 1
160-
161- @extended
162- def obs (result : int ) -> int :
163- return result
164-
165- res = DynamicMemorySimulator ().task (main )
166- return res .run ()
0 commit comments