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

PyQVM #552

Merged
merged 48 commits into from Jan 24, 2019
Merged

PyQVM #552

Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
2bc7dfa
PyQVM
Oct 4, 2018
5816d41
Merge branch 'master' into pyqvm
Oct 10, 2018
7a1210e
Latest attempt at figuring out the best semantics for run_and_measure
Oct 11, 2018
cb99448
no print
Oct 11, 2018
3d4b8f3
Update QAM.run()
Oct 11, 2018
fde6481
Fix some tests
Oct 15, 2018
3c92f9f
Merge branch 'master' into pyqvm
Oct 15, 2018
7e64246
Merge branch 'fix-some-tests' into pyqvm
Oct 15, 2018
d06b4fb
Sample from density simulator
Oct 15, 2018
96a59a6
wip random kraus sampling
Oct 15, 2018
bcf4ba2
Merge branch 'qam-run-classical-addresses' into pyqvm
Oct 16, 2018
1142d6c
Merge branch 'run-and-measure' into pyqvm
Oct 16, 2018
1c73ab8
fixup new r_a_m
Oct 16, 2018
a1f4a93
Merge remote-tracking branch 'origin/master' into pyqvm
Oct 16, 2018
2eb7e38
reduce diff and make _all_bitstrings public
Oct 16, 2018
af5ff71
sample_bitstrings
Oct 16, 2018
6b483a4
remove noise stuff
Oct 16, 2018
cb307e6
Fix test
Oct 16, 2018
ddf7220
Merge remote-tracking branch 'origin/master' into pyqvm
Oct 19, 2018
f4fa266
Merge branch 'master' into pyqvm
Oct 29, 2018
e85caeb
Simpler, seperate run-and-measure
Oct 29, 2018
088036b
No SHARING
Oct 29, 2018
47dc68b
Merge remote-tracking branch 'origin/master' into pyqvm
Oct 31, 2018
ea88d5f
Merge remote-tracking branch 'origin/master' into pyqvm
Nov 19, 2018
4cddd7b
Merge remote-tracking branch 'origin/master' into pyqvm
Nov 28, 2018
e1a18d0
Spruce up docstrings
Nov 28, 2018
e0b1ea4
the -> an
Nov 28, 2018
c71f93a
Merge branch 'spruce-up-api-docs' into pyqvm
Nov 28, 2018
db50a04
doc params
Nov 28, 2018
5d96883
pyqvm
Nov 28, 2018
7a98162
Docs
Nov 28, 2018
8d90910
Make numpy_simulator usable standalone
Nov 28, 2018
218ea09
Update migration.ipynb to use pyqvm
Nov 28, 2018
624ceaa
Reference expectation
Nov 28, 2018
b632e5a
Tests and fix expectation
Nov 28, 2018
fddd178
Fix tests; fix noise apply to qubits
Nov 28, 2018
e98bd40
Style "fixes"
Nov 28, 2018
ebdf128
Merge remote-tracking branch 'origin/master' into pyqvm
Jan 2, 2019
18af6dc
Note about tensordot
Jan 3, 2019
7a39a3f
simplify sum
Jan 3, 2019
9708f47
return self for method chaining in accordance with interface
Jan 3, 2019
6cf2f26
simplify sum
Jan 3, 2019
5ad6b89
PyQVM to handle executables
Jan 9, 2019
92c9528
lifted_pauli lets you pick out qubits
Jan 10, 2019
161c0b9
Merge remote-tracking branch 'origin/master' into pyqvm
Jan 11, 2019
589aef8
Revert porting of migration guide
Jan 11, 2019
1924116
PyQVM supports defgate
Jan 21, 2019
561fd07
Fix test for change to lifted_pauli api
Jan 22, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
135 changes: 83 additions & 52 deletions pyquil/api/_quantum_computer.py
Expand Up @@ -114,7 +114,7 @@ def run(self, executable: BinaryExecutableResponse) -> np.ndarray:
.read_from_memory_region(region_name="ro")

@_record_call
def run_symmetrized_readout(self, program, trials, classical_addresses):
def run_symmetrized_readout(self, program, trials):
"""
Run a quil program in such a way that the readout error is made collectively symmetric

Expand Down Expand Up @@ -142,8 +142,8 @@ def run_symmetrized_readout(self, program, trials, classical_addresses):
flipped_executable = self.compile(flipped_program)

executable = self.compile(program.wrap_in_numshots_loop(half_trials))
samples = self.run(executable, classical_addresses=classical_addresses)
flipped_samples = self.run(flipped_executable, classical_addresses=classical_addresses)
samples = self.run(executable)
flipped_samples = self.run(flipped_executable)
double_flipped_samples = np.logical_not(flipped_samples).astype(int)
results = np.concatenate((samples, double_flipped_samples), axis=0)
np.random.shuffle(results)
Expand Down Expand Up @@ -226,7 +226,8 @@ def _parse_name(name, as_qvm, noisy):

See :py:func:`get_qc` for examples of valid names + flags.
"""
if name.endswith('noisy-qvm'):
parts = name.split('-')
if len(parts) >= 2 and parts[-2] == 'noisy' and parts[-1] in ['qvm', 'pyqvm']:
if as_qvm is not None and (not as_qvm):
raise ValueError("The provided qc name indicates you are getting a noisy QVM, "
"but you have specified `as_qvm=False`")
Expand All @@ -235,31 +236,36 @@ def _parse_name(name, as_qvm, noisy):
raise ValueError("The provided qc name indicates you are getting a noisy QVM, "
"but you have specified `noisy=False`")

as_qvm = True
qvm_type = parts[-1]
noisy = True
prefix = name[:-len('-noisy-qvm')]
return prefix, as_qvm, noisy
prefix = '-'.join(parts[:-2])
return prefix, qvm_type, noisy

if name.endswith('qvm'):
if len(parts) >= 1 and parts[-1] in ['qvm', 'pyqvm']:
if as_qvm is not None and (not as_qvm):
raise ValueError("The provided qc name indicates you are getting a QVM, "
"but you have specified `as_qvm=False`")
as_qvm = True
qvm_type = parts[-1]
if noisy is not None:
noisy = False
prefix = name[:-len('-qvm')]
return prefix, as_qvm, noisy
prefix = '-'.join(parts[:-1])
return prefix, qvm_type, noisy

if as_qvm is None:
as_qvm = False
if as_qvm is not None and as_qvm:
qvm_type = 'qvm'
else:
qvm_type = None

if noisy is None:
noisy = False

return name, as_qvm, noisy
return name, qvm_type, noisy


def _get_qvm_compiler(qvm_type, endpoint, device):
if qvm_type not in ['pyqvm', 'qvm']:
raise ValueError("Unknown qvm type {}".format(qvm_type))

def _get_qvm_compiler_based_on_endpoint(endpoint=None, device=None):
if endpoint.startswith("http"):
return LocalQVMCompiler(endpoint=endpoint, device=device)
elif endpoint.startswith("tcp"):
Expand All @@ -268,7 +274,17 @@ def _get_qvm_compiler_based_on_endpoint(endpoint=None, device=None):
raise ValueError("Protocol for QVM compiler endpoints must be HTTP or TCP.")


def _get_9q_generic_qvm(connection: ForestConnection, noisy: bool):
def _get_qvm_or_pyqvm(qvm_type, connection, noise_model=None, device=None):
if qvm_type == 'qvm':
return QVM(connection=connection, noise_model=noise_model)
elif qvm_type == 'pyqvm':
from pyquil.reference_simulator import ReferenceQAM
return ReferenceQAM(n_qubits=device.qubit_topology().number_of_nodes())

raise ValueError("Unknown qvm type {}".format(qvm_type))


def _get_9q_generic_qvm(name: str, qvm_type: str, connection: ForestConnection, noisy: bool):
"""
A nine-qubit 3x3 square lattice.

Expand All @@ -278,27 +294,30 @@ def _get_9q_generic_qvm(connection: ForestConnection, noisy: bool):
Users interested in building their own QuantumComputer from parts may wish to look
to this function for inspiration, but should not use this private function directly.

:param qvm_type: Whether to construct a QVM or a PyQVM
:param connection: The connection to use to talk to external services
:param noisy: Whether to construct a noisy quantum computer
:return: A pre-configured QuantumComputer
"""
nineq_square = nx.convert_node_labels_to_integers(nx.grid_2d_graph(3, 3))
nineq_device = NxDevice(topology=nineq_square)
device = NxDevice(topology=nineq_square)
if noisy:
noise_model = decoherence_noise_with_asymmetric_ro(
gates=gates_in_isa(nineq_device.get_isa()))
gates=gates_in_isa(device.get_isa()))
else:
noise_model = None

return QuantumComputer(name='9q-generic-qvm',
qam=QVM(connection=connection, noise_model=noise_model),
device=nineq_device,
compiler=_get_qvm_compiler_based_on_endpoint(
device=nineq_device,
return QuantumComputer(name=name,
qam=_get_qvm_or_pyqvm(qvm_type, connection, noise_model, device),
device=device,
compiler=_get_qvm_compiler(
qvm_type=qvm_type,
device=device,
endpoint=connection.compiler_endpoint))


def _get_unrestricted_qvm(connection: ForestConnection, noisy: bool, n_qubits: int = 34):
def _get_unrestricted_qvm(name: str, qvm_type: str, connection: ForestConnection, noisy: bool,
n_qubits: int = 34):
"""
A qvm with a fully-connected topology.

Expand All @@ -307,25 +326,43 @@ def _get_unrestricted_qvm(connection: ForestConnection, noisy: bool, n_qubits: i
Users interested in building their own QuantumComputer from parts may wish to look
to this function for inspiration, but should not use this private function directly.

:param qvm_type: Whether to construct a QVM or a PyQVM
:param connection: The connection to use to talk to external services
:param noisy: Whether to construct a noisy quantum computer
:param n_qubits: 34 qubits ought to be enough for anybody.
:return: A pre-configured QuantumComputer
"""
fully_connected_device = NxDevice(topology=nx.complete_graph(n_qubits))
device = NxDevice(topology=nx.complete_graph(n_qubits))
if noisy:
# note to developers: the noise model specifies noise for each possible gate. In a fully
# connected topology, there are a lot.
noise_model = decoherence_noise_with_asymmetric_ro(
gates=gates_in_isa(fully_connected_device.get_isa()))
gates=gates_in_isa(device.get_isa()))
else:
noise_model = None

return QuantumComputer(name='9q-generic-qvm',
qam=QVM(connection=connection, noise_model=noise_model),
device=fully_connected_device,
compiler=_get_qvm_compiler_based_on_endpoint(
device=fully_connected_device,
return QuantumComputer(name=name,
qam=_get_qvm_or_pyqvm(qvm_type, connection, noise_model, device),
device=device,
compiler=_get_qvm_compiler(
qvm_type=qvm_type,
device=device,
endpoint=connection.compiler_endpoint))


def _get_qvm_based_on_real_device(name: str, qvm_type: str, device: AbstractDevice, noisy: bool,
connection: ForestConnection):
if noisy:
noise_model = device.noise_model
else:
noise_model = None

return QuantumComputer(name=name,
qam=_get_qvm_or_pyqvm(qvm_type, connection, noise_model, device),
device=device,
compiler=_get_qvm_compiler(
qvm_type=qvm_type,
device=device,
endpoint=connection.compiler_endpoint))


Expand Down Expand Up @@ -393,17 +430,23 @@ def get_qc(name: str, *, as_qvm: bool = None, noisy: bool = None,
if connection is None:
connection = ForestConnection()

name, as_qvm, noisy = _parse_name(name, as_qvm, noisy)
prefix, qvm_type, noisy = _parse_name(name, as_qvm, noisy)
_prefix_with_dash = f'{prefix}-' if prefix != '' else prefix
if noisy:
name = '{prefix}noisy-{qvm_type}'.format(prefix=_prefix_with_dash, qvm_type=qvm_type)
else:
name = '{prefix}{qvm_type}'.format(prefix=_prefix_with_dash, qvm_type=qvm_type)

if name == '':
if not as_qvm:
raise ValueError("Please name a valid device or run as a QVM")
return _get_unrestricted_qvm(connection=connection, noisy=noisy)
if prefix == '':
if qvm_type is None:
raise ValueError("Please prefix a valid device or run as a QVM")
return _get_unrestricted_qvm(name=name, qvm_type=qvm_type, connection=connection,
noisy=noisy)

if name == '9q-generic':
if not as_qvm:
if prefix == '9q-generic':
if qvm_type is None:
raise ValueError("The device '9q-generic' is only available as a QVM")
return _get_9q_generic_qvm(connection=connection, noisy=noisy)
return _get_9q_generic_qvm(name=name, qvm_type=qvm_type, connection=connection, noisy=noisy)

device = get_lattice(name)
if not as_qvm:
Expand All @@ -416,16 +459,4 @@ def get_qc(name: str, *, as_qvm: bool = None, noisy: bool = None,
compiler=QPUCompiler(endpoint=pyquil_config.compiler_url,
device=device))

if noisy:
noise_model = device.noise_model
name = "{name}-noisy-qvm".format(name=name)
else:
noise_model = None
name = "{name}-qvm".format(name=name)

return QuantumComputer(name=name,
qam=QVM(connection=connection, noise_model=noise_model),
device=device,
compiler=_get_qvm_compiler_based_on_endpoint(
device=device,
endpoint=connection.compiler_endpoint))
return _get_qvm_based_on_real_device(prefix, qvm_type, device, noisy, connection)