Skip to content

Commit 0721919

Browse files
committed
ensure 'run...' API matches QuantumComputer signatures
1 parent 810cee6 commit 0721919

File tree

1 file changed

+76
-53
lines changed

1 file changed

+76
-53
lines changed

pyquil_for_azure_quantum/__init__.py

Lines changed: 76 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,11 @@
3232
from numpy import split
3333
from pyquil.api import QAM, MemoryMap, QAMExecutionResult, QuantumComputer, get_qc
3434
from pyquil.quil import Program
35-
from qcs_sdk import ExecutionData, RegisterData, ResultData # pylint: disable=no-name-in-module
35+
from qcs_sdk import ( # pylint: disable=no-name-in-module
36+
ExecutionData,
37+
RegisterData,
38+
ResultData,
39+
)
3640
from qcs_sdk.qvm import QVMResultData # pylint: disable=no-name-in-module
3741
from wrapt import ObjectProxy
3842

@@ -103,19 +107,82 @@ def compile(
103107
"""
104108
return AzureProgram(program, skip_quilc=not to_native_gates)
105109

106-
def run_batch(
110+
111+
def run_with_memory_map_batch(
107112
self,
108113
executable: AzureProgram,
109114
memory_maps: Sequence[MemoryMap],
110115
**__kwargs: Any,
111116
) -> List[QAMExecutionResult]:
112-
"""Run a sequence of memory values through the program.
117+
"""Run the executable for each of the ``memory_maps``.
118+
119+
Args:
120+
executable: The AzureProgram to run.
121+
memory_maps: An iterable containing ``MemoryMaps`` with desired mappings of parameter names to parameter values.
122+
Each value is a list as long as the number of elements in the register. So if the register was ``DECLARE theta REAL[2]``
123+
then the key in the dictionary would be ``theta`` and the value would be a list of length 2. The entire program
124+
will be run (for shot count) once for each ``MemoryMap``. (If no memory maps are provided, the program will be run once.)
125+
name: An optional name for the job which will show up in the Azure Quantum UI.
126+
127+
Returns:
128+
A list of ``QAMExecutionResult`` objects, one for each ``MemoryMap``.
129+
130+
```pycon
131+
132+
>>> import numpy as np
133+
>>> from pyquil import Program
134+
>>> from pyquil.gates import CNOT, MEASURE, RX, H
135+
>>> from pyquil.quilatom import MemoryReference
136+
>>> from pyquil.quilbase import Declare
137+
>>> from pyquil_for_azure_quantum import get_qvm
138+
>>> qvm = get_qvm()
139+
>>> program = Program(\
140+
Declare("ro", "BIT", 1), \
141+
Declare("theta", "REAL", 1), \
142+
RX(MemoryReference("theta"), 0), \
143+
MEASURE(0, ("ro", 0)), \
144+
).wrap_in_numshots_loop(1000)
145+
>>> compiled = qvm.compile(program)
146+
>>> results = qvm.run_batch(compiled, [{"theta": [value]} for value in [0.0, np.pi, 2 * np.pi]}])
147+
>>> assert len(results) == 3 # 3 values for theta—each a list of length 1
148+
>>> results_0 = results[0].readout_data["ro"]
149+
>>> assert len(results_0) == 1000 # 1000 shots
150+
>>> assert np.mean(results_0) == 0
151+
>>> results_pi = results[1].readout_data["ro"]
152+
>>> assert len(results_pi) == 1000
153+
>>> assert np.mean(results_pi) == 1
154+
155+
```
113156
114157
See Also:
115158
* [`AzureQuantumMachine.execute_with_memory_map_batch`][pyquil_for_azure_quantum.AzureQuantumMachine.execute_with_memory_map_batch]
116159
"""
117160
qam = cast(AzureQuantumMachine, self.qam)
118-
return qam.execute_with_memory_map_batch(executable, memory_maps)
161+
azure_job = qam.execute_with_memory_map_batch(executable, memory_maps)
162+
# `execute_with_memory_map_batch` always returns a list of length 1.
163+
assert len(azure_job) == 1
164+
165+
combined_result = qam.get_result(azure_job[0])
166+
167+
num_executions = len(memory_maps)
168+
if num_executions in (0, 1):
169+
return combined_result
170+
171+
ro_matrix = combined_result.data.result_data.to_register_map().get_register_matrix("ro")
172+
if ro_matrix is None:
173+
return []
174+
175+
return [
176+
QAMExecutionResult(
177+
executable,
178+
ExecutionData(
179+
ResultData.from_qvm(
180+
QVMResultData.from_memory_map(memory={"ro": RegisterData(split_result.tolist())})
181+
)
182+
),
183+
)
184+
for split_result in split(ro_matrix.to_ndarray(), num_executions)
185+
]
119186

120187

121188
def get_qpu(qpu_name: str) -> AzureQuantumComputer:
@@ -269,7 +336,7 @@ def execute_with_memory_map_batch(
269336
memory_maps: Iterable[MemoryMap],
270337
name: str = "pyquil-azure-job",
271338
**_kwargs: Any,
272-
) -> List[QAMExecutionResult]:
339+
) -> List[AzureJob]:
273340
"""Run the executable for each of the ``memory_maps``.
274341
275342
Args:
@@ -281,34 +348,10 @@ def execute_with_memory_map_batch(
281348
name: An optional name for the job which will show up in the Azure Quantum UI.
282349
283350
Returns:
284-
A list of ``QAMExecutionResult`` objects, one for each ``MemoryMap``.
285-
286-
```pycon
287-
288-
>>> import numpy as np
289-
>>> from pyquil import Program
290-
>>> from pyquil.gates import CNOT, MEASURE, RX, H
291-
>>> from pyquil.quilatom import MemoryReference
292-
>>> from pyquil.quilbase import Declare
293-
>>> from pyquil_for_azure_quantum import get_qvm
294-
>>> qvm = get_qvm()
295-
>>> program = Program(\
296-
Declare("ro", "BIT", 1), \
297-
Declare("theta", "REAL", 1), \
298-
RX(MemoryReference("theta"), 0), \
299-
MEASURE(0, ("ro", 0)), \
300-
).wrap_in_numshots_loop(1000)
301-
>>> compiled = qvm.compile(program)
302-
>>> results = qvm.execute_with_memory_map_batch(compiled, [{"theta": [value]} for value in [0.0, np.pi, 2 * np.pi]}])
303-
>>> assert len(results) == 3 # 3 values for theta—each a list of length 1
304-
>>> results_0 = results[0].readout_data["ro"]
305-
>>> assert len(results_0) == 1000 # 1000 shots
306-
>>> assert np.mean(results_0) == 0
307-
>>> results_pi = results[1].readout_data["ro"]
308-
>>> assert len(results_pi) == 1000
309-
>>> assert np.mean(results_pi) == 1
351+
A list of ``AzureJob`` object; because ``AzureJob`` is not
352+
considered done until the entire batch is done, this is always a
353+
list of length one.
310354
311-
```
312355
"""
313356
executable = executable.copy()
314357
memory_maps = list(memory_maps)
@@ -323,27 +366,7 @@ def execute_with_memory_map_batch(
323366
input_params=input_params,
324367
)
325368
azure_job = AzureJob(job=job, executable=executable)
326-
combined_result = self.get_result(azure_job)
327-
328-
num_executions = len(memory_maps)
329-
if num_executions in (0, 1):
330-
return [combined_result]
331-
332-
ro_matrix = combined_result.data.result_data.to_register_map().get_register_matrix("ro")
333-
if ro_matrix is None:
334-
return []
335-
336-
return [
337-
QAMExecutionResult(
338-
executable,
339-
ExecutionData(
340-
ResultData.from_qvm(
341-
QVMResultData.from_memory_map(memory={"ro": RegisterData(split_result.tolist())})
342-
)
343-
),
344-
)
345-
for split_result in split(ro_matrix.to_ndarray(), num_executions)
346-
]
369+
return [azure_job]
347370

348371

349372
def _make_substitutions_from_memory_maps(

0 commit comments

Comments
 (0)