23
23
import copy
24
24
import collections .abc as abc
25
25
from collections import defaultdict
26
+ from contextlib import AbstractContextManager
26
27
from typing import Optional , Dict
27
28
28
29
import dimod
@@ -86,7 +87,7 @@ def qpu_graph(topology_type, topology_shape, nodelist, edgelist):
86
87
return G
87
88
88
89
89
- class DWaveSampler (dimod .Sampler , dimod .Structured ):
90
+ class DWaveSampler (dimod .Sampler , dimod .Structured , AbstractContextManager ):
90
91
"""A class for using D-Wave quantum computers as samplers for binary quadratic models.
91
92
92
93
You can configure your :term:`solver` selection and usage by setting parameters,
@@ -127,12 +128,29 @@ class DWaveSampler(dimod.Sampler, dimod.Structured):
127
128
**config:
128
129
Keyword arguments passed to :meth:`~dwave.cloud.client.Client.from_config`.
129
130
131
+ .. versionadded:: 1.29.0
132
+ Support for context manager protocol.
133
+
130
134
Note:
131
135
Prior to version 1.0.0, :class:`.DWaveSampler` used the ``base`` client,
132
136
allowing non-QPU solvers to be selected.
133
137
To reproduce the old behavior, instantiate :class:`.DWaveSampler` with
134
138
``client='base'``.
135
139
140
+ Note:
141
+ The recommended way to use :class:`DWaveSampler` is from a
142
+ `runtime context <https://docs.python.org/3/reference/datamodel.html#with-statement-context-managers>`_:
143
+
144
+ >>> with DWaveSampler() as sampler:
145
+ ... sampler.sample_ising(...) # doctest: +SKIP
146
+
147
+ Alternatively, call the :meth:`~DWaveSampler.close` method to
148
+ terminate the sampler resources:
149
+
150
+ >>> sampler = DWaveSampler()
151
+ ...
152
+ >>> sampler.close()
153
+
136
154
Examples:
137
155
This example submits a two-variable Ising problem mapped directly to two
138
156
adjacent qubits on a D-Wave system. ``qubit_a`` is the first qubit in
@@ -148,16 +166,14 @@ class DWaveSampler(dimod.Sampler, dimod.Structured):
148
166
149
167
>>> from dwave.system import DWaveSampler
150
168
...
151
- >>> sampler = DWaveSampler()
152
- ...
153
- >>> qubit_a = sampler.nodelist[0]
154
- >>> qubit_b = next(iter(sampler.adjacency[qubit_a]))
155
- >>> sampleset = sampler.sample_ising({qubit_a: -1, qubit_b: 1},
156
- ... {},
157
- ... num_reads=100)
158
- >>> print(sampleset.first.sample[qubit_a] == 1 and sampleset.first.sample[qubit_b] == -1)
169
+ >>> with DWaveSampler() as sampler:
170
+ ... qubit_a = sampler.nodelist[0]
171
+ ... qubit_b = next(iter(sampler.adjacency[qubit_a]))
172
+ ... sampleset = sampler.sample_ising({qubit_a: -1, qubit_b: 1},
173
+ ... {},
174
+ ... num_reads=100)
175
+ ... print(sampleset.first.sample[qubit_a] == 1 and sampleset.first.sample[qubit_b] == -1)
159
176
True
160
- >>> sampler.close()
161
177
162
178
See `Ocean Glossary <https://docs.ocean.dwavesys.com/en/stable/concepts/index.html>`_
163
179
for explanations of technical terms in descriptions of Ocean tools.
@@ -194,6 +210,13 @@ def close(self):
194
210
"""
195
211
self .client .close ()
196
212
213
+ def __exit__ (self , exc_type , exc_value , traceback ):
214
+ """Release system resources allocated and raise any exception triggered
215
+ within the runtime context.
216
+ """
217
+ self .close ()
218
+ return None
219
+
197
220
def _get_solver (self , * , refresh : bool = False , penalty : Optional [Dict [str , int ]] = None ):
198
221
"""Get the least penalized solver from the list of solvers filtered and
199
222
ordered according to user config.
@@ -234,8 +257,8 @@ def properties(self):
234
257
Examples:
235
258
236
259
>>> from dwave.system import DWaveSampler
237
- >>> sampler = DWaveSampler()
238
- >>> sampler.properties # doctest: +SKIP
260
+ >>> with DWaveSampler() as sampler: # doctest: +SKIP
261
+ ... sampler.properties
239
262
{'anneal_offset_ranges': [[-0.2197463755538704, 0.03821687759418928],
240
263
[-0.2242514597680286, 0.01718456460967399],
241
264
[-0.20860153999435985, 0.05511969218508182],
@@ -265,8 +288,8 @@ def parameters(self):
265
288
Examples:
266
289
267
290
>>> from dwave.system import DWaveSampler
268
- >>> sampler = DWaveSampler()
269
- >>> sampler.parameters # doctest: +SKIP
291
+ >>> with DWaveSampler() as sampler: # doctest: +SKIP
292
+ ... sampler.parameters
270
293
{'anneal_offsets': ['parameters'],
271
294
'anneal_schedule': ['parameters'],
272
295
'annealing_time': ['parameters'],
@@ -296,8 +319,8 @@ def edgelist(self):
296
319
First 5 entries of the coupler list for one Advantage system.
297
320
298
321
>>> from dwave.system import DWaveSampler
299
- >>> sampler = DWaveSampler()
300
- >>> sampler.edgelist[:5] # doctest: +SKIP
322
+ >>> with DWaveSampler() as sampler: # doctest: +SKIP
323
+ ... sampler.edgelist[:5]
301
324
[(30, 31), (30, 45), (30, 2940), (30, 2955), (30, 2970)]
302
325
303
326
See `Ocean Glossary <https://docs.ocean.dwavesys.com/en/stable/concepts/index.html>`_
@@ -320,8 +343,8 @@ def nodelist(self):
320
343
First 5 entries of the node list for one Advantage system.
321
344
322
345
>>> from dwave.system import DWaveSampler
323
- >>> sampler = DWaveSampler()
324
- >>> sampler.nodelist[:5] # doctest: +SKIP
346
+ >>> with DWaveSampler() as sampler: # doctest: +SKIP
347
+ ... sampler.nodelist[:5]
325
348
[30, 31, 32, 33, 34]
326
349
327
350
See `Ocean Glossary <https://docs.ocean.dwavesys.com/en/stable/concepts/index.html>`_
@@ -403,14 +426,13 @@ def sample(self, bqm, warnings=None, **kwargs):
403
426
404
427
>>> from dwave.system import DWaveSampler
405
428
...
406
- >>> sampler = DWaveSampler()
407
- ...
408
- >>> qubit_a = sampler.nodelist[0]
409
- >>> qubit_b = next(iter(sampler.adjacency[qubit_a]))
410
- >>> sampleset = sampler.sample_ising({qubit_a: -1, qubit_b: 1},
411
- ... {},
412
- ... num_reads=100)
413
- >>> print(sampleset.first.sample[qubit_a] == 1 and sampleset.first.sample[qubit_b] == -1)
429
+ >>> with DWaveSampler() as sampler:
430
+ ... qubit_a = sampler.nodelist[0]
431
+ ... qubit_b = next(iter(sampler.adjacency[qubit_a]))
432
+ ... sampleset = sampler.sample_ising({qubit_a: -1, qubit_b: 1},
433
+ ... {},
434
+ ... num_reads=100)
435
+ ... print(sampleset.first.sample[qubit_a] == 1 and sampleset.first.sample[qubit_b] == -1)
414
436
True
415
437
416
438
See `Ocean Glossary <https://docs.ocean.dwavesys.com/en/stable/concepts/index.html>`_
@@ -523,10 +545,9 @@ def validate_anneal_schedule(self, anneal_schedule):
523
545
This example sets a quench schedule on a D-Wave system.
524
546
525
547
>>> from dwave.system import DWaveSampler
526
- >>> sampler = DWaveSampler()
527
- >>> quench_schedule=[[0.0, 0.0], [12.0, 0.6], [12.8, 1.0]]
528
- >>> DWaveSampler().validate_anneal_schedule(quench_schedule) # doctest: +SKIP
529
- >>>
548
+ >>> with DWaveSampler() as sampler: # doctest: +SKIP
549
+ ... quench_schedule=[[0.0, 0.0], [12.0, 0.6], [12.8, 1.0]]
550
+ ... DWaveSampler().validate_anneal_schedule(quench_schedule)
530
551
531
552
"""
532
553
if 'anneal_schedule' not in self .parameters :
@@ -597,9 +618,9 @@ def to_networkx_graph(self):
597
618
598
619
>>> from dwave.system import DWaveSampler
599
620
...
600
- >>> sampler = DWaveSampler()
601
- >>> g = sampler.to_networkx_graph() # doctest: +SKIP
602
- >>> len(g.nodes) > 5000 # doctest: +SKIP
621
+ >>> with DWaveSampler() as sampler: # doctest: +SKIP
622
+ ... g = sampler.to_networkx_graph()
623
+ ... len(g.nodes) > 5000
603
624
True
604
625
"""
605
626
return qpu_graph (self .properties ['topology' ]['type' ],
0 commit comments