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

new: Quilc clients support #1638

Merged
merged 8 commits into from
Sep 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,220 changes: 637 additions & 583 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ rpcq = "^3.10.0"
pydantic = "^1.10.7"
networkx = ">=2.5"
importlib-metadata = { version = ">=3.7.3,<5", python = "<3.8" }
qcs-sdk-python = "0.11.0"
qcs-sdk-python = "0.12.0"
tenacity = "^8.2.2"
types-python-dateutil = "^2.8.19"
types-retry = "^0.9.9"
Expand Down
6 changes: 4 additions & 2 deletions pyquil/api/_abstract_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import json

from qcs_sdk import QCSClient
from qcs_sdk.compiler.quilc import compile_program, CompilerOpts, TargetDevice
from qcs_sdk.compiler.quilc import compile_program, TargetDevice, CompilerOpts, QuilcClient

from pyquil._version import pyquil_version
from pyquil.api._compiler_client import CompilerClient
Expand Down Expand Up @@ -78,6 +78,7 @@ def __init__(
quantum_processor: AbstractQuantumProcessor,
timeout: float,
client_configuration: Optional[QCSClient] = None,
quilc_client: Optional[QuilcClient] = None,
) -> None:
self.quantum_processor = quantum_processor
self._timeout = timeout
Expand All @@ -87,6 +88,7 @@ def __init__(
self._compiler_client = CompilerClient(
client_configuration=self._client_configuration,
request_timeout=timeout,
quilc_client=quilc_client,
)

def get_version_info(self) -> Dict[str, Any]:
Expand All @@ -111,7 +113,7 @@ def quil_to_native_quil(self, program: Program, *, protoquil: Optional[bool] = N
result = compile_program(
quil=program.out(calibrations=False),
target=target_device,
client=self._client_configuration,
client=self._compiler_client.quilc_client,
options=CompilerOpts(protoquil=protoquil, timeout=self._compiler_client.timeout),
)

Expand Down
4 changes: 4 additions & 0 deletions pyquil/api/_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
translate,
TranslationOptions as QPUCompilerAPIOptions,
)
from qcs_sdk.compiler.quilc import QuilcClient
from rpcq.messages import ParameterSpec

from pyquil.api._abstract_compiler import AbstractCompiler, EncryptedProgram, QuantumExecutable
Expand Down Expand Up @@ -76,6 +77,7 @@ def __init__(
timeout: float = 10.0,
client_configuration: Optional[QCSClient] = None,
api_options: Optional[QPUCompilerAPIOptions] = None,
quilc_client: Optional[QuilcClient] = None,
) -> None:
"""
Instantiate a new QPU compiler client.
Expand Down Expand Up @@ -171,6 +173,7 @@ def __init__(
quantum_processor: AbstractQuantumProcessor,
timeout: float = 10.0,
client_configuration: Optional[QCSClient] = None,
quilc_client: Optional[QuilcClient] = None,
) -> None:
"""
Client to communicate with compiler.
Expand All @@ -183,6 +186,7 @@ def __init__(
quantum_processor=quantum_processor,
timeout=timeout,
client_configuration=client_configuration,
quilc_client=quilc_client,
)

def native_quil_to_executable(self, nq_program: Program, **kwargs: Any) -> QuantumExecutable:
Expand Down
17 changes: 13 additions & 4 deletions pyquil/api/_compiler_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
RandomizedBenchmarkingRequest,
GenerateRandomizedBenchmarkingSequenceResponse,
NativeQuilMetadata,
QuilcClient,
)
from rpcq.messages import TargetDevice as TargetQuantumProcessor

Expand Down Expand Up @@ -109,6 +110,7 @@ def __init__(
*,
client_configuration: QCSClient,
request_timeout: float = 10.0,
quilc_client: Optional[QuilcClient] = None,
) -> None:
"""
Instantiate a new compiler client.
Expand All @@ -121,6 +123,13 @@ def __init__(
if not base_url.startswith("tcp://"):
raise ValueError(f"Expected compiler URL '{base_url}' to start with 'tcp://'")

if quilc_client is None:
self.quilc_client = QuilcClient.new_rpcq(base_url)
elif isinstance(quilc_client, QuilcClient):
self.quilc_client = quilc_client
else:
raise TypeError(f"Unsupported type for Quilc client: {quilc_client}")

self.base_url = base_url
self.timeout = request_timeout

Expand All @@ -129,7 +138,7 @@ def get_version(self) -> str:
Get version info for compiler server.
"""

return get_version_info(client=self._client_configuration)
return get_version_info(client=self.quilc_client)

def compile_to_native_quil(self, request: CompileToNativeQuilRequest) -> CompileToNativeQuilResponse:
"""
Expand All @@ -141,7 +150,7 @@ def compile_to_native_quil(self, request: CompileToNativeQuilRequest) -> Compile
result = compile_program(
quil=request.program,
target=target_device,
client=self._client_configuration,
client=self.quilc_client,
options=CompilerOpts(protoquil=request.protoquil, timeout=self.timeout),
)
return CompileToNativeQuilResponse(native_program=result.program, metadata=result.native_quil_metadata)
Expand All @@ -150,12 +159,12 @@ def conjugate_pauli_by_clifford(self, request: ConjugateByCliffordRequest) -> Co
"""
Conjugate a Pauli element by a Clifford element.
"""
return conjugate_pauli_by_clifford(request=request, client=self._client_configuration)
return conjugate_pauli_by_clifford(request=request, client=self.quilc_client)

def generate_randomized_benchmarking_sequence(
self, request: RandomizedBenchmarkingRequest
) -> GenerateRandomizedBenchmarkingSequenceResponse:
"""
Generate a randomized benchmarking sequence.
"""
return generate_randomized_benchmarking_sequence(request=request, client=self._client_configuration)
return generate_randomized_benchmarking_sequence(request=request, client=self.quilc_client)
36 changes: 33 additions & 3 deletions pyquil/api/_quantum_computer.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@

from qcs_sdk import QCSClient
from qcs_sdk.qpu import list_quantum_processors
from qcs_sdk.compiler.quilc import QuilcClient
from qcs_sdk.qvm import QVMClient

from pyquil.api._abstract_compiler import AbstractCompiler, QuantumExecutable
from pyquil.api._compiler import QPUCompiler, QVMCompiler
Expand Down Expand Up @@ -497,14 +499,14 @@ def _canonicalize_name(prefix: str, qvm_type: Optional[str], noisy: bool) -> str

def _get_qvm_or_pyqvm(
*,
client_configuration: QCSClient,
qvm_type: str,
qvm_client: Optional[QVMClient],
noise_model: Optional[NoiseModel],
quantum_processor: Optional[AbstractQuantumProcessor],
execution_timeout: float,
) -> Union[QVM, PyQVM]:
if qvm_type == "qvm":
return QVM(noise_model=noise_model, timeout=execution_timeout, client_configuration=client_configuration)
return QVM(noise_model=noise_model, timeout=execution_timeout, client=qvm_client)
elif qvm_type == "pyqvm":
assert quantum_processor is not None
return PyQVM(n_qubits=quantum_processor.qubit_topology().number_of_nodes())
Expand All @@ -521,6 +523,8 @@ def _get_qvm_qc(
compiler_timeout: float,
execution_timeout: float,
noise_model: Optional[NoiseModel],
quilc_client: Optional[QuilcClient] = None,
qvm_client: Optional[QVMClient] = None,
) -> QuantumComputer:
"""Construct a QuantumComputer backed by a QVM.

Expand All @@ -539,16 +543,17 @@ def _get_qvm_qc(
return QuantumComputer(
name=name,
qam=_get_qvm_or_pyqvm(
client_configuration=client_configuration,
qvm_type=qvm_type,
noise_model=noise_model,
quantum_processor=quantum_processor,
execution_timeout=execution_timeout,
qvm_client=qvm_client,
),
compiler=QVMCompiler(
quantum_processor=quantum_processor,
timeout=compiler_timeout,
client_configuration=client_configuration,
quilc_client=quilc_client,
),
)

Expand All @@ -562,6 +567,8 @@ def _get_qvm_with_topology(
qvm_type: str,
compiler_timeout: float,
execution_timeout: float,
quilc_client: Optional[QuilcClient] = None,
qvm_client: Optional[QVMClient] = None,
) -> QuantumComputer:
"""Construct a QVM with the provided topology.

Expand Down Expand Up @@ -593,6 +600,8 @@ def _get_qvm_with_topology(
noise_model=noise_model,
compiler_timeout=compiler_timeout,
execution_timeout=execution_timeout,
quilc_client=quilc_client,
qvm_client=qvm_client,
)


Expand All @@ -604,6 +613,8 @@ def _get_9q_square_qvm(
qvm_type: str,
compiler_timeout: float,
execution_timeout: float,
quilc_client: Optional[QuilcClient] = None,
qvm_client: Optional[QVMClient] = None,
) -> QuantumComputer:
"""
A nine-qubit 3x3 square lattice.
Expand All @@ -628,6 +639,8 @@ def _get_9q_square_qvm(
qvm_type=qvm_type,
compiler_timeout=compiler_timeout,
execution_timeout=execution_timeout,
quilc_client=quilc_client,
qvm_client=qvm_client,
)


Expand All @@ -640,6 +653,8 @@ def _get_unrestricted_qvm(
qvm_type: str,
compiler_timeout: float,
execution_timeout: float,
quilc_client: Optional[QuilcClient] = None,
qvm_client: Optional[QVMClient] = None,
) -> QuantumComputer:
"""
A qvm with a fully-connected topology.
Expand All @@ -664,6 +679,8 @@ def _get_unrestricted_qvm(
qvm_type=qvm_type,
compiler_timeout=compiler_timeout,
execution_timeout=execution_timeout,
quilc_client=quilc_client,
qvm_client=qvm_client,
)


Expand All @@ -676,6 +693,8 @@ def _get_qvm_based_on_real_quantum_processor(
qvm_type: str,
compiler_timeout: float,
execution_timeout: float,
quilc_client: Optional[QuilcClient] = None,
qvm_client: Optional[QVMClient] = None,
) -> QuantumComputer:
"""
A qvm with a based on a real quantum_processor.
Expand Down Expand Up @@ -704,6 +723,8 @@ def _get_qvm_based_on_real_quantum_processor(
qvm_type=qvm_type,
compiler_timeout=compiler_timeout,
execution_timeout=execution_timeout,
quilc_client=quilc_client,
qvm_client=qvm_client,
)


Expand All @@ -716,6 +737,8 @@ def get_qc(
execution_timeout: float = 30.0,
client_configuration: Optional[QCSClient] = None,
endpoint_id: Optional[str] = None,
quilc_client: Optional[QuilcClient] = None,
qvm_client: Optional[QVMClient] = None,
) -> QuantumComputer:
"""
Get a quantum computer.
Expand Down Expand Up @@ -814,6 +837,8 @@ def get_qc(
qvm_type=qvm_type,
compiler_timeout=compiler_timeout,
execution_timeout=execution_timeout,
quilc_client=quilc_client,
qvm_client=qvm_client,
)

# 3. Check for "9q-square" qvm
Expand All @@ -827,6 +852,8 @@ def get_qc(
qvm_type=qvm_type,
compiler_timeout=compiler_timeout,
execution_timeout=execution_timeout,
quilc_client=quilc_client,
qvm_client=qvm_client,
)

if noisy:
Expand All @@ -849,6 +876,8 @@ def get_qc(
qvm_type=qvm_type,
compiler_timeout=compiler_timeout,
execution_timeout=execution_timeout,
quilc_client=quilc_client,
qvm_client=qvm_client,
)
else:
qpu = QPU(
Expand All @@ -862,6 +891,7 @@ def get_qc(
quantum_processor=quantum_processor,
timeout=compiler_timeout,
client_configuration=client_configuration,
quilc_client=quilc_client,
)

return QuantumComputer(name=name, qam=qpu, compiler=compiler)
Expand Down
13 changes: 9 additions & 4 deletions pyquil/api/_qvm.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@
from typing import Any, Optional, Sequence, Tuple, Dict

import numpy as np

from qcs_sdk import QCSClient, qvm, ResultData, ExecutionData
from qcs_sdk.qvm import QVMOptions, QVMResultData
from qcs_sdk.qvm import QVMOptions, QVMResultData, QVMClient

from pyquil._version import pyquil_version
from pyquil.api import QAM, QuantumExecutable, QAMExecutionResult, MemoryMap
Expand Down Expand Up @@ -65,7 +66,7 @@ def __init__(
measurement_noise: Optional[Tuple[float, float, float]] = None,
random_seed: Optional[int] = None,
timeout: float = 10.0,
client_configuration: Optional[QCSClient] = None,
client: Optional[QVMClient] = None,
) -> None:
"""
A virtual machine that classically emulates the execution of Quil programs.
Expand Down Expand Up @@ -112,7 +113,11 @@ def __init__(
raise TypeError("random_seed should be None or a non-negative int")

self.timeout = timeout
self._client = client_configuration or QCSClient.load()

if client is None:
client = QVMClient.new_http(QCSClient.load().qvm_url)
self._client = client

self.connect()

def connect(self) -> None:
Expand Down Expand Up @@ -146,10 +151,10 @@ def execute(
trials,
addresses,
memory_map or {},
self._client,
self.measurement_noise,
self.gate_noise,
self.random_seed,
self._client,
options=QVMOptions(timeout_seconds=self.timeout),
)

Expand Down
9 changes: 6 additions & 3 deletions pyquil/api/_wavefunction_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ def __init__(

self.timeout = timeout
self._client = client_configuration or QCSClient.load()
self._qvm_client = qvm.QVMClient.new_http(self._client.qvm_url)

def wavefunction(self, quil_program: Program, memory_map: Optional[MemoryMap] = None) -> Wavefunction:
"""
Expand Down Expand Up @@ -99,7 +100,7 @@ def wavefunction(self, quil_program: Program, memory_map: Optional[MemoryMap] =
self.random_seed,
)
wavefunction = bytes(
qvm.api.get_wavefunction(request, self._client, options=QVMOptions(timeout_seconds=self.timeout))
qvm.api.get_wavefunction(request, self._qvm_client, options=QVMOptions(timeout_seconds=self.timeout))
)
return Wavefunction.from_bit_packed_string(wavefunction)

Expand Down Expand Up @@ -146,7 +147,7 @@ def expectation(

request = qvm.api.ExpectationRequest(prep_prog.out(), [prog.out() for prog in progs])
expectations = qvm.api.measure_expectation(
request, self._client, options=QVMOptions(timeout_seconds=self.timeout)
request, self._qvm_client, options=QVMOptions(timeout_seconds=self.timeout)
)
bare_results = np.asarray(expectations)
results = coeffs * bare_results
Expand Down Expand Up @@ -202,7 +203,9 @@ def run_and_measure(
trials,
qubits,
)
measured_qubits = qvm.api.run_and_measure(request, options=QVMOptions(timeout_seconds=self.timeout))
measured_qubits = qvm.api.run_and_measure(
request, client=self._qvm_client, options=QVMOptions(timeout_seconds=self.timeout)
)
return np.asarray(measured_qubits)

@staticmethod
Expand Down
Loading
Loading