Skip to content

Commit

Permalink
feat: Final memory values are now available on QAMExecutionResults
Browse files Browse the repository at this point in the history
  • Loading branch information
MarquessV committed Nov 27, 2023
1 parent 35acdcd commit a199797
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 21 deletions.
44 changes: 28 additions & 16 deletions pyquil/api/_qam.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from deprecated import deprecated
import numpy as np
from qcs_sdk import ExecutionData
from qcs_sdk.qpu import RawQPUReadoutData
from qcs_sdk.qpu import RawQPUReadoutData, MemoryValues
from qcs_sdk.qvm import RawQVMReadoutData

from pyquil.api._abstract_compiler import QuantumExecutable
Expand Down Expand Up @@ -50,21 +50,6 @@ class QAMExecutionResult:
to get at the data in a more convenient format.
"""

def get_raw_readout_data(self) -> Union[RawQVMReadoutData, RawQPUReadoutData]:
"""
Get the raw result data. This will be a flattened structure derived
from :class:`qcs_sdk.qvm.QVMResultData` or :class:`qcs_sdk.qpu.QPUResultData`
depending on where the job was run. See their respective documentation
for more information on the data format.
This property should be used when running programs that use features like
mid-circuit measurement and dynamic control flow on a QPU, since they can
produce irregular result shapes that don't necessarily fit in a
rectangular matrix. If the program was run on a QVM, or doesn't use those
features, consider using the ``register_map`` property instead.
"""
return self.data.result_data.to_raw_readout_data()

def get_register_map(self) -> Dict[str, Optional[np.ndarray]]:
"""
A mapping of a register name (ie. "ro") to a ``np.ndarray`` containing the values for the
Expand All @@ -90,6 +75,33 @@ def get_register_map(self) -> Dict[str, Optional[np.ndarray]]:
register_map = self.data.result_data.to_register_map()
return {key: matrix.to_ndarray() for key, matrix in register_map.items()}

def get_raw_readout_data(self) -> Union[RawQVMReadoutData, RawQPUReadoutData]:
"""
Get the raw result data. This will be a flattened structure derived
from :class:`qcs_sdk.qvm.QVMResultData` or :class:`qcs_sdk.qpu.QPUResultData`
depending on where the job was run. See their respective documentation
for more information on the data format.
This property should be used when running programs that use features like
mid-circuit measurement and dynamic control flow on a QPU, since they can
produce irregular result shapes that don't necessarily fit in a
rectangular matrix. If the program was run on a QVM, or doesn't use those
features, consider using the ``register_map`` property instead.
"""
return self.data.result_data.to_raw_readout_data()

def get_memory_values(self) -> Mapping[str, Optional[MemoryValues]]:
"""
Get the final memory values for any memory region that was both read from
and written to during execution. This method will only return the final
value in memory after the job has completed. Because of this, memory
values should not be used to get readout data. Instead, use `get_register_map()`
or `get_raw_readout_data()`.
"""
if self.data.result_data.is_qpu():
return self.data.result_data.to_qpu().memory_values
return {}

@property
@deprecated(
version="4.0.0",
Expand Down
2 changes: 1 addition & 1 deletion pyquil/api/_qpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ def get_result(self, execute_response: QPUExecuteResponse) -> QAMExecutionResult
for mref, readout_name in execute_response._executable.ro_sources.items()
if mref.name in execute_response._executable.memory_descriptors
}
result_data = QPUResultData(mappings=mappings, readout_values=readout_values)
result_data = QPUResultData(mappings=mappings, readout_values=readout_values, memory_values=results.memory)
result_data = ResultData(result_data)
duration = None
if results.execution_duration_microseconds is not None:
Expand Down
15 changes: 11 additions & 4 deletions test/unit/test_qpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from pyquil.api._abstract_compiler import EncryptedProgram
from pyquil.quil import Program
from qcs_sdk.qpu.api import Register, ExecutionResult, ExecutionResults
from qcs_sdk.qpu import MemoryValues
from rpcq.messages import ParameterSpec

from pyquil.quilatom import MemoryReference
Expand Down Expand Up @@ -70,13 +71,15 @@ def test_qpu_execute(
{
"q0": ExecutionResult.from_register(Register.from_i32([1, 1, 1, 1])),
"q1": ExecutionResult.from_register(Register.from_i32([1, 1, 1, 1])),
}
},
{"stash": MemoryValues.from_binary([0, 1, 0, 1])},
)

result = qpu.get_result(execute_response)

assert np.all(result.get_register_map()["ro"] == np.array([[1, 1], [1, 1], [1, 1], [1, 1]]))
assert np.all(result.get_register_map()["ro"] == result.readout_data["ro"])
assert result.get_memory_values() == {"stash": MemoryValues.from_binary([0, 1, 0, 1])}


@patch("pyquil.api._qpu.retrieve_results")
Expand All @@ -93,7 +96,8 @@ def test_qpu_execute_jagged_results(
{
"q0": ExecutionResult.from_register(Register.from_i32([1, 1])),
"q1": ExecutionResult.from_register(Register.from_i32([1, 1, 1, 1])),
}
},
{"stash": MemoryValues.from_binary([0, 1, 0, 1])},
)

result = qpu.get_result(execute_response)
Expand All @@ -105,6 +109,7 @@ def test_qpu_execute_jagged_results(

assert raw_readout_data.mappings == {"ro[0]": "q0", "ro[1]": "q1"}
assert raw_readout_data.readout_values == {"q0": [1, 1], "q1": [1, 1, 1, 1]}
assert raw_readout_data.memory_values == {"stash": [0, 1, 0, 1]}


class TestQPUExecutionOptions:
Expand Down Expand Up @@ -133,7 +138,8 @@ def test_submit_with_class_options(
{
"q0": ExecutionResult.from_register(Register.from_i32([1, 1])),
"q1": ExecutionResult.from_register(Register.from_i32([1, 1, 1, 1])),
}
},
{"stash": MemoryValues.from_binary([0, 1, 0, 1])},
)

qpu.get_result(execute_response)
Expand Down Expand Up @@ -168,7 +174,8 @@ def test_submit_with_options(
{
"q0": ExecutionResult.from_register(Register.from_i32([1, 1])),
"q1": ExecutionResult.from_register(Register.from_i32([1, 1, 1, 1])),
}
},
{"stash": MemoryValues.from_binary([0, 1, 0, 1])},
)

qpu.get_result(execute_response)
Expand Down

0 comments on commit a199797

Please sign in to comment.