Skip to content

Commit 30f33b8

Browse files
notmgskkalzoo
andauthored
Add quilc_client property to QVMCompiler, improve timeout documentation (#1273)
* Add client property to QPUCompiler, improve timeout documentation Add a client property to QPUCompiler so that it has better feature parity with QVMCompiler. Generally we tell folks that 1. QVMCompiler and QPUCompiler should be largely interchangeable, meaning that you can swap `qc = get_qc("Aspen-8", as_qvm=True)` with `qc = get_qc("Aspen-8", as_qvm=False)`, and things should Just Work. And 2. To set the timeout on a QVMCompiler one does `qc.compiler.client.rpc_timeout = ...` but on a QPUCompiler `qc.compiler.quilc_client.rpc_timeout = ...`. This change brings 1 and 2 into alignment, so that the method for configuring the compiler timeout is the same between the compiler classes. * fix type * Add set_timeout method to {QVM,QPU}Compiler classes * fix doc * Fix: send timeout value in native_quil_to_binary call * Fix: set_timeout docstring * Remove QPUCompiler#client in favour of QVMCompiler#quilc_client * Remove some docs * Remove comment * Add compiler_timeout option to get_qc() * Note timeout units * oops * type int -> float * update changelog * remove duplicate line Co-authored-by: kalzoo <[email protected]>
1 parent 7895633 commit 30f33b8

File tree

4 files changed

+103
-9
lines changed

4 files changed

+103
-9
lines changed

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,14 @@ Changelog
88

99
### Improvements and Changes
1010

11-
### Bugfixes
11+
- Timeout configuration has been revamped. `get_qc` now accepts a `compiler_timeout`
12+
option, and `QVMCompiler` and `QPUCompiler` provide a `set_timeout` method, which should
13+
greatly simplify the task of changing the default timeout. `QVMCompiler` also provides a
14+
`quilc_client` property so that it shares the same interface as
15+
`QPUCompiler`. Documentation has been updated to reflect these changes (@notmgsk,
16+
@kalzoo, #1273).
1217

18+
### Bugfixes
1319

1420
[v2.24.0](https://github.com/rigetti/pyquil/compare/v2.23.1..v2.24.0) (November 5, 2020)
1521
------------------------------------------------------------------------------------

docs/source/compiler.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,25 @@ the previous example snippet is identical to the following:
113113
ep = qc.compiler.native_quil_to_executable(np)
114114
print(ep.program) # here ep is of type PyquilExecutableResponse, which is not always inspectable
115115
116+
Timeouts
117+
--------
118+
119+
If your circuit is sufficiently complex the compiler may require more time than is permitted by
120+
default (``10`` seconds). To change this timeout, either use the `compiler_timeout` option to
121+
`get_qc`
122+
123+
.. code:: python
124+
125+
qc = get_qc(..., compiler_timeout=100) # 100 seconds
126+
127+
or use the `set_timeout` method on the compiler object:
128+
129+
.. code:: python
130+
131+
qc = get_qc(...)
132+
qc.compiler.set_timeout(100) # 100 seconds
133+
134+
The timeout is specified in units of seconds.
116135

117136
Legal compiler input
118137
--------------------

pyquil/api/_compiler.py

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ def __init__(
182182
quilc_endpoint: Optional[str],
183183
qpu_compiler_endpoint: Optional[str],
184184
device: AbstractDevice,
185-
timeout: int = 10,
185+
timeout: float = 10,
186186
name: Optional[str] = None,
187187
*,
188188
session: Optional[ForestSession] = None,
@@ -338,7 +338,9 @@ def native_quil_to_executable(self, nq_program: Program) -> Optional[BinaryExecu
338338
)
339339
response: BinaryExecutableResponse = cast(
340340
BinaryExecutableResponse,
341-
self.qpu_compiler_client.call("native_quil_to_binary", request),
341+
self.qpu_compiler_client.call(
342+
"native_quil_to_binary", request, rpc_timeout=self.timeout
343+
),
342344
)
343345

344346
# hack! we're storing a little extra info in the executable binary that we don't want to
@@ -356,6 +358,19 @@ def reset(self) -> None:
356358
"""
357359
self._qpu_compiler_client = None
358360

361+
def set_timeout(self, timeout: float) -> None:
362+
"""
363+
Set timeout for each individual stage of compilation.
364+
365+
:param timeout: Timeout value for each compilation stage, in seconds. If the stage does not
366+
complete within this threshold, an exception is raised.
367+
"""
368+
if timeout < 0:
369+
raise ValueError(f"Cannot set timeout to negative value {timeout}")
370+
371+
self.timeout = timeout
372+
self.quilc_client.rpc_timeout = timeout
373+
359374

360375
class QVMCompiler(AbstractCompiler):
361376
@_record_call
@@ -365,6 +380,8 @@ def __init__(self, endpoint: str, device: AbstractDevice, timeout: float = 10) -
365380
366381
:param endpoint: TCP or IPC endpoint of the Compiler Server
367382
:param device: PyQuil Device object to use as compilation target
383+
:param timeout: Timeout value for each compilation stage, in seconds. If the stage does not
384+
complete within this threshold, an exception is raised.
368385
"""
369386

370387
if not endpoint.startswith("tcp://"):
@@ -428,6 +445,24 @@ def reset(self) -> None:
428445
self.client.close() # type: ignore
429446
self.client = Client(self.endpoint, timeout=timeout)
430447

448+
@property
449+
def quilc_client(self) -> Client:
450+
"""Return the `Client` for the compiler (i.e. quilc, not translation service)."""
451+
return self.client
452+
453+
def set_timeout(self, timeout: float) -> None:
454+
"""
455+
Set timeout for each individual stage of compilation.
456+
457+
:param timeout: Timeout value for each compilation stage, in seconds. If the stage does not
458+
complete within this threshold, an exception is raised.
459+
"""
460+
if timeout < 0:
461+
raise ValueError(f"Cannot set timeout to negative value {timeout}")
462+
463+
self.timeout = timeout
464+
self.quilc_client.rpc_timeout = timeout
465+
431466

432467
@dataclass
433468
class HTTPCompilerClient:
@@ -443,7 +478,7 @@ class HTTPCompilerClient:
443478
session: ForestSession
444479

445480
def call(
446-
self, method: str, payload: Optional[Message] = None, *, rpc_timeout: int = 30
481+
self, method: str, payload: Optional[Message] = None, *, rpc_timeout: float = 30
447482
) -> Message:
448483
"""
449484
A partially-compatible implementation of rpcq.Client#call, which allows calling rpcq

pyquil/api/_quantum_computer.py

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,7 @@ def _get_qvm_qc(
637637
noise_model: Optional[NoiseModel] = None,
638638
requires_executable: bool = False,
639639
connection: Optional[ForestConnection] = None,
640+
compiler_timeout: float = 10,
640641
) -> QuantumComputer:
641642
"""Construct a QuantumComputer backed by a QVM.
642643
@@ -666,7 +667,9 @@ def _get_qvm_qc(
666667
requires_executable=requires_executable,
667668
),
668669
device=device,
669-
compiler=QVMCompiler(device=device, endpoint=connection.compiler_endpoint),
670+
compiler=QVMCompiler(
671+
device=device, endpoint=connection.compiler_endpoint, timeout=compiler_timeout
672+
),
670673
)
671674

672675

@@ -677,6 +680,7 @@ def _get_qvm_with_topology(
677680
requires_executable: bool = True,
678681
connection: Optional[ForestConnection] = None,
679682
qvm_type: str = "qvm",
683+
compiler_timeout: float = 10,
680684
) -> QuantumComputer:
681685
"""Construct a QVM with the provided topology.
682686
@@ -709,11 +713,16 @@ def _get_qvm_with_topology(
709713
device=device,
710714
noise_model=noise_model,
711715
requires_executable=requires_executable,
716+
compiler_timeout=compiler_timeout,
712717
)
713718

714719

715720
def _get_9q_square_qvm(
716-
name: str, noisy: bool, connection: Optional[ForestConnection] = None, qvm_type: str = "qvm"
721+
name: str,
722+
noisy: bool,
723+
connection: Optional[ForestConnection] = None,
724+
qvm_type: str = "qvm",
725+
compiler_timeout: float = 10,
717726
) -> QuantumComputer:
718727
"""
719728
A nine-qubit 3x3 square lattice.
@@ -735,6 +744,7 @@ def _get_9q_square_qvm(
735744
noisy=noisy,
736745
requires_executable=True,
737746
qvm_type=qvm_type,
747+
compiler_timeout=compiler_timeout,
738748
)
739749

740750

@@ -744,6 +754,7 @@ def _get_unrestricted_qvm(
744754
n_qubits: int = 34,
745755
connection: Optional[ForestConnection] = None,
746756
qvm_type: str = "qvm",
757+
compiler_timeout: float = 10,
747758
) -> QuantumComputer:
748759
"""
749760
A qvm with a fully-connected topology.
@@ -765,6 +776,7 @@ def _get_unrestricted_qvm(
765776
noisy=noisy,
766777
requires_executable=False,
767778
qvm_type=qvm_type,
779+
compiler_timeout=compiler_timeout,
768780
)
769781

770782

@@ -774,6 +786,7 @@ def _get_qvm_based_on_real_device(
774786
noisy: bool,
775787
connection: Optional[ForestConnection] = None,
776788
qvm_type: str = "qvm",
789+
compiler_timeout: float = 10,
777790
) -> QuantumComputer:
778791
"""
779792
A qvm with a based on a real device.
@@ -799,6 +812,7 @@ def _get_qvm_based_on_real_device(
799812
noise_model=noise_model,
800813
requires_executable=True,
801814
qvm_type=qvm_type,
815+
compiler_timeout=compiler_timeout,
802816
)
803817

804818

@@ -809,6 +823,7 @@ def get_qc(
809823
as_qvm: Optional[bool] = None,
810824
noisy: Optional[bool] = None,
811825
connection: Optional[ForestConnection] = None,
826+
compiler_timeout: float = 10,
812827
) -> QuantumComputer:
813828
"""
814829
Get a quantum computer.
@@ -877,6 +892,8 @@ def get_qc(
877892
:param connection: An optional :py:class:`ForestConnection` object. If not specified,
878893
the default values for URL endpoints will be used. If you deign to change any
879894
of these parameters, pass your own :py:class:`ForestConnection` object.
895+
:param compiler_timeout: The number of seconds after which a compilation request will raise
896+
a TimeoutError.
880897
:return: A pre-configured QuantumComputer
881898
"""
882899
# 1. Parse name, check for redundant options, canonicalize names.
@@ -891,7 +908,12 @@ def get_qc(
891908
if qvm_type is None:
892909
raise ValueError("Please name a valid device or run as a QVM")
893910
return _get_unrestricted_qvm(
894-
name=name, connection=connection, noisy=noisy, n_qubits=n_qubits, qvm_type=qvm_type
911+
name=name,
912+
connection=connection,
913+
noisy=noisy,
914+
n_qubits=n_qubits,
915+
qvm_type=qvm_type,
916+
compiler_timeout=compiler_timeout,
895917
)
896918

897919
# 3. Check for "9q-square" qvm
@@ -901,14 +923,25 @@ def get_qc(
901923

902924
if qvm_type is None:
903925
raise ValueError("The device '9q-square' is only available as a QVM")
904-
return _get_9q_square_qvm(name=name, connection=connection, noisy=noisy, qvm_type=qvm_type)
926+
return _get_9q_square_qvm(
927+
name=name,
928+
connection=connection,
929+
noisy=noisy,
930+
qvm_type=qvm_type,
931+
compiler_timeout=compiler_timeout,
932+
)
905933

906934
# 4. Not a special case, query the web for information about this device.
907935
device = get_lattice(prefix)
908936
if qvm_type is not None:
909937
# 4.1 QVM based on a real device.
910938
return _get_qvm_based_on_real_device(
911-
name=name, device=device, noisy=noisy, connection=connection, qvm_type=qvm_type
939+
name=name,
940+
device=device,
941+
noisy=noisy,
942+
connection=connection,
943+
qvm_type=qvm_type,
944+
compiler_timeout=compiler_timeout,
912945
)
913946
else:
914947
# 4.2 A real device
@@ -928,6 +961,7 @@ def get_qc(
928961
device=device,
929962
name=prefix,
930963
session=session,
964+
timeout=compiler_timeout,
931965
)
932966

933967
return QuantumComputer(name=name, qam=qpu, device=device, compiler=compiler)

0 commit comments

Comments
 (0)