Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable more memory regions on the QVM #873

Merged
merged 14 commits into from
Aug 23, 2019
Merged
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ Changelog
readout symmetrization (@joshcombes, gh-919).
- The ProtoQuil restrictions built in to PyQVM have been removed
(@ecpeterson, gh-874).
- Add the ability to query for other memory regions after both QPU and QVM
runs. This removes a previously unnecessary restriction on the QVM, although
`ro` remains the only QPU-writeable memory region during Quil execution
(@ecpeterson, gh-873).

### Bugfixes

Expand Down
18 changes: 5 additions & 13 deletions pyquil/api/_qam.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import warnings

from abc import ABC, abstractmethod
from collections import defaultdict

from rpcq.messages import ParameterAref

Expand Down Expand Up @@ -54,7 +55,7 @@ def load(self, executable):

self._variables_shim = {}
self._executable = executable
self._bitstrings = None
self._memory_results = defaultdict(lambda: None)
self.status = 'loaded'
return self

Expand Down Expand Up @@ -104,12 +105,8 @@ def read_memory(self, *, region_name: str):
:return: A list of values of the appropriate type.
"""
assert self.status == 'done'
if region_name != "ro":
raise QAMError("Currently only allowed to read measurement data from ro.")
if self._bitstrings is None:
raise QAMError("Bitstrings have not yet been populated. Something has gone wrong.")

return self._bitstrings
return self._memory_results[region_name]

@_record_call
def read_from_memory_region(self, *, region_name: str):
Expand All @@ -125,13 +122,8 @@ def read_from_memory_region(self, *, region_name: str):
warnings.warn("pyquil.api._qam.QAM.read_from_memory_region is deprecated, please use "
"pyquil.api._qam.QAM.read_memory instead.",
DeprecationWarning)
assert self.status == 'done'
if region_name != "ro":
raise QAMError("Currently only allowed to read measurement data from ro.")
if self._bitstrings is None:
raise QAMError("Bitstrings have not yet been populated. Something has gone wrong.")

return self._bitstrings
return self.read_memory(region_name=region_name)

@_record_call
def reset(self):
Expand All @@ -142,6 +134,6 @@ def reset(self):
"""
self._variables_shim = {}
self._executable = None
self._bitstrings = None
self._memory_results = defaultdict(lambda: None)

self.status = 'connected'
7 changes: 6 additions & 1 deletion pyquil/api/_qpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
##############################################################################
from collections import defaultdict
import uuid
import warnings
from typing import Dict, List, Optional, Tuple, Union
Expand Down Expand Up @@ -168,8 +169,12 @@ def run(self, run_priority: Optional[int] = None):
else:
bitstrings = None

self._bitstrings = bitstrings
self._memory_results = defaultdict(lambda: None)
for aref, vals in self._variables_shim.items():
self._memory_results[aref] = [vals] * ro_sources[0].shape[0]
self._memory_results["ro"] = bitstrings
self._last_results = results

return self

def _get_buffers(self, job_id: str) -> Dict[str, np.ndarray]:
Expand Down
14 changes: 6 additions & 8 deletions pyquil/api/_qvm.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,18 +510,16 @@ def run(self):
quil_program = apply_noise_model(quil_program, self.noise_model)

quil_program = self.augment_program_with_memory_values(quil_program)
try:
self._bitstrings = self.connection._qvm_run(quil_program=quil_program,

self._memory_results = self.connection._qvm_run(quil_program=quil_program,
classical_addresses=classical_addresses,
trials=trials,
measurement_noise=self.measurement_noise,
gate_noise=self.gate_noise,
random_seed=self.random_seed)['ro']
except KeyError:
warnings.warn("You are running a QVM program with no MEASURE instructions. "
"The result of this program will always be an empty array. Are "
"you sure you didn't mean to measure some of your qubits?")
self._bitstrings = np.zeros((trials, 0), dtype=np.int64)
random_seed=self.random_seed)

if "ro" not in self._memory_results or self._memory_results["ro"] == []:
self._memory_results["ro"] = np.zeros((trials, 0), dtype=np.int64)

return self

Expand Down
4 changes: 2 additions & 2 deletions pyquil/pyqvm.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ def __init__(self, n_qubits, quantum_simulator_type: Type[AbstractQuantumSimulat
# private implementation details
self._qubit_to_ram = None # type: Dict[int, int]
self._ro_size = None # type :int
self._bitstrings = None # type: np.ndarray
self._memory_results = None # type: Dict[str, np.ndarray]

self.rs = np.random.RandomState(seed=seed)
self.wf_simulator = quantum_simulator_type(n_qubits=n_qubits, rs=self.rs)
Expand All @@ -201,7 +201,7 @@ def load(self, executable):
# initialize program counter
self.program = program
self.program_counter = 0
self._bitstrings = None
self._memory_results = None

# clear RAM, although it's not strictly clear if this should happen here
self.ram = {}
Expand Down
6 changes: 3 additions & 3 deletions pyquil/tests/test_quantum_computer.py
Original file line number Diff line number Diff line change
Expand Up @@ -536,15 +536,15 @@ def test_reset(forest):
aref = ParameterAref(name='theta', index=0)
assert qc.qam._variables_shim[aref] == np.pi
assert qc.qam._executable == p
assert qc.qam._bitstrings.shape == (1000, 1)
assert all([bit == 1 for bit in qc.qam._bitstrings])
assert qc.qam._memory_results["ro"].shape == (1000, 1)
assert all([bit == 1 for bit in qc.qam._memory_results["ro"]])
assert qc.qam.status == 'done'

qc.reset()

assert qc.qam._variables_shim == {}
assert qc.qam._executable is None
assert qc.qam._bitstrings is None
assert qc.qam._memory_results["ro"] is None
assert qc.qam.status == 'connected'


Expand Down