/
temperatures.py
594 lines (495 loc) · 27.4 KB
/
temperatures.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
# Copyright 2022 D-Wave Systems Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""The following effective temperature estimators are provided:
- Maximum pseudo-likelihood is an efficient estimator for the temperature
describing a classical Boltzmann distribution P(x) = \exp(-H(x)/T)/Z(T)
given samples from that distribution, where H(x) is the classical energy
function. The following links describe features of the estimator in
application to equilibrium distribution drawn from binary quadratic models and
non-equilibrium distributions generated by annealing:
https://www.jstor.org/stable/25464568
https://doi.org/10.3389/fict.2016.00023
- An effective temperature can be inferred assuming freeze-out during the
anneal at s=t/t_a, an annealing schedule, and a device physical temperature.
Necessary device-specific properties are published for online solvers:
https://docs.dwavesys.com/docs/latest/doc_physical_properties.html
"""
import warnings
import numpy as np
import dimod
from scipy import optimize
from typing import Tuple
__all__ = ['effective_field', 'maximum_pseudolikelihood_temperature',
'freezeout_effective_temperature', 'fast_effective_temperature']
def effective_field(bqm,
samples=None,
current_state_energy=False) -> (np.ndarray,list):
'''Returns the effective field for all variables and all samples.
The effective field with ``current_state_energy = False`` is the energy
attributable to setting a variable to value 1, conditioned on fixed values
for all neighboring variables (relative to exclusion of the variable, and
associated energy terms, from the problem).
The effective field with ``current_state_energy = True`` is the energy gained
by flipping the variable state against its current value (from say -1 to 1
in the Ising case, or 0 to 1 in the QUBO case). A positive value indicates
that the energy can be decreased by flipping the variable, hence the
variable is in a locally excited state.
If all values are negative (positive) within a sample, that sample is a
local minima (maxima).
Any BQM can be converted to an Ising model with
.. math::
H(s) = Constant + \sum_i h_i s_i + 0.5 \sum_{i,j} J_{i,j} s_i s_j
with unique values of :math:`J` (symmetric) and :math:`h`. The sample dependent effect field on variable i, :math:`f_i(s)`, is then defined
if current_state_energy == False:
.. math::
f_i(s) = h_i + \sum_j J_{i,j} s_j
else:
.. math::
f_i(s) = 2 s_i [h_i + \sum_j J_{i,j} s_j]
Args:
bqm (:obj:`dimod.BinaryQuadraticModel`):
Binary quadratic model.
samples (samples_like or :obj:`.SampleSet`,optional):
A collection of raw samples. `samples_like` is an extension of
NumPy's array like structure. See :func:`dimod.sampleset.as_samples`.
By default, a single sample with all +1 assignments is used.
current_state_energy (bool, optional, default=False):
By default, returns the effective field (the energy
contribution associated to a state assignment of 1). When set to
True, returns the energy lost in flipping the value of each
variable. Note current_state_energy is typically negative for
positive temperature samples, meaning energy is not decreased
by flipping the spin against its current assignment.
Returns:
samples_like:
A Tuple of the effective_fields, and the variable labels.
Effective fields are returned as a :obj:`numpy.ndarray`.
Rows index samples, and columns index variables in the order
returned by variable labels.
Examples:
For a ferromagnetic Ising chain :math:`H = - 0.5 \sum_i s_i s_{i+1}`
and for a ground state sample (all +1), the energy lost when flipping
any spin is equal to the number of couplers frustrated: -2 in the center
of the chain (variables 1,2,..,N-2), and -1 at the end (variables 0 and N-1).
>>> import dimod
>>> import numpy as np
>>> from dwave.system.temperatures import effective_field
>>> N = 5
>>> bqm = dimod.BinaryQuadraticModel.from_ising({}, {(i,i+1) : -0.5 for i in range(N-1)})
>>> var_labels = list(range(N))
>>> samples = (np.ones(shape=(1,N)), var_labels)
>>> E = effective_field(bqm,samples,current_state_energy=True)
>>> print('Cost to flip spin against current assignment', E)
Cost to flip spin against current assignment (array([[-1., -2., -2., -2., -1.]]), [0, 1, 2, 3, 4])
'''
if samples is None:
samples = np.ones(shape=(1,bqm.num_variables))
labels = bqm.variables
else:
samples, labels = dimod.sampleset.as_samples(samples)
if bqm.vartype is dimod.BINARY:
bqm = bqm.change_vartype('SPIN', inplace=False)
samples = 2*samples - 1
h, (irow, icol, qdata), offset = bqm.to_numpy_vectors(
variable_order=labels)
# eff_field = h + J*s OR diag(Q) + (Q-diag(Q))*b
effective_fields = np.tile(h[np.newaxis,:],(samples.shape[0],1))
for sI in range(samples.shape[0]):
np.add.at(effective_fields[sI,:],irow,qdata*samples[sI,icol])
np.add.at(effective_fields[sI,:],icol,qdata*samples[sI,irow])
if current_state_energy is True:
#Ising: eff_field = 2*s*(h + J*s)
effective_fields = 2*samples*effective_fields
return (effective_fields,labels)
def maximum_pseudolikelihood_temperature(bqm=None,
sampleset=None,
site_energy=None,
num_bootstrap_samples=0,
seed=None,
T_guess=None,
optimize_method='bisect',
T_bracket=(1e-3,1000)) -> Tuple[float,np.ndarray]:
'''Returns a sampling-based temperature estimate.
The temperature T parameterizes the Boltzmann distribution as
:math:`P(x) = \exp(-H(x)/T)/Z(T)`, where :math:`P(x)` is a probability over a state space,
:math:`H(x)` is the energy function (BQM) and :math:`Z(T)` is a normalization.
Given a sample set (:math:`S`), a temperature estimate establishes the
temperature that is most likely to have produced the sample set.
An effective temperature can be derived from a sample set by considering the
rate of excitations only. A maximum-pseudo-likelihood (MPL) estimator
considers local excitations only, which are sufficient to establish a
temperature efficiently (in compute time and number of samples). If the BQM
consists of uncoupled variables then the estimator is equivalent to a
maximum likelihood estimator.
The effective MPL temperature is defined by the solution T to
.. math::
0 = \sum_i \sum_{s \in S} f_i(s) \exp(f_i(s)/T),
where f is the energy lost in flipping spin i against its current
assignment (the effective field).
The problem is a convex root solving problem, and is solved with SciPy
optimize.
If the distribution is not Boltzmann with respect to the BQM provided, as
may be the case for heuristic samplers (such as annealers), the temperature
estimate can be interpreted as characterizing only a rate of local
excitations. In the case of sample sets obtained from D-Wave annealing
quantum computers the temperature can be identified with a physical
temperature via a late-anneal freeze-out phenomena.
Args:
bqm (:obj:`dimod.BinaryQuadraticModel`, optional):
Binary quadratic model describing sample distribution.
If ``bqm`` and ``site_energy`` are both None, then by default
100 samples are drawn using :class:`~dwave.system.samplers.DWaveSampler`,
with ``bqm`` defaulted as described.
sampleset (:class:`dimod.SampleSet`, optional):
A set of samples, assumed to be fairly sampled from
a Boltzmann distribution characterized by ``bqm``.
site_energy (samples_like, optional):
A Tuple of effective fields and site labels.
Derived from the ``bqm`` and ``sampleset`` if not provided.
num_bootstrap_samples (int, optional, default=0):
Number of bootstrap estimators to calculate.
seed (int, optional)
Seeds the bootstrap method (if provided) allowing reproducibility
of the estimators.
T_guess (float, optional):
User approximation to the effective temperature, must be
a positive scalar value.
Seeding the root-search method can enable faster convergence.
By default, T_guess is ignored if it falls outside the range
of ``T_bracket``.
optimize_method (str,optional,default='bisect'):
SciPy method used for optimization. Options are 'bisect' and
None (the default SciPy optimize method).
T_bracket (list or Tuple of 2 floats, optional, default=(0.001,1000)):
If excitations are absent, temperature is defined as zero, otherwise
this defines the range of Temperatures over which to attempt a fit when
using the 'bisect' ``optimize_method`` (the default).
Returns:
Tuple of float and NumPy array:
(T_estimate,T_bootstrap_estimates)
*T_estimate*: a temperature estimate
*T_bootstrap_estimates*: a numpy array of bootstrap estimators
Examples:
Draw samples from a D-Wave Quantum Computer for a large spin-glass
problem (random couplers J, zero external field h).
Establish a temperature estimate by maximum pseudo-likelihood.
Note that due to the complicated freeze-out properties of hard models,
such as large scale spin-glasses, deviation from a classical Boltzmann
distribution is anticipated.
Nevertheless, the T estimate can always be interpreted as an estimator
of local excitations rates. For example T will be 0 if only
local minima are returned (even if some of the local minima are not
ground states).
>>> import dimod
>>> from dwave.system.temperatures import maximum_pseudolikelihood_temperature
>>> from dwave.system import DWaveSampler
>>> from random import random
>>> sampler = DWaveSampler()
>>> bqm = dimod.BinaryQuadraticModel.from_ising({}, {e : 1-2*random() for e in sampler.edgelist})
>>> sampleset = sampler.sample(bqm, num_reads=100, auto_scale=False)
>>> T,T_bootstrap = maximum_pseudolikelihood_temperature(bqm,sampleset)
>>> print('Effective temperature ',T) # doctest: +SKIP
Effective temperature 0.24066488780293813
See also:
https://doi.org/10.3389/fict.2016.00023
https://www.jstor.org/stable/25464568
'''
T_estimate = 0
T_bootstrap_estimates = np.zeros(num_bootstrap_samples)
#Check for largest local excitation in every sample, and over all samples
if site_energy is None:
if bqm is None or sampleset is None:
raise ValueError('site_energy can only be derived if both'
'bqm and sampleset are provided as arguments')
site_energy = effective_field(bqm,
sampleset,
current_state_energy = True)
max_excitation = np.max(site_energy[0],axis=1)
max_excitation_all = np.max(max_excitation)
if max_excitation_all <= 0:
#There are no local excitations present in the sample set, therefore
#the temperature is estimated as 0.
pass
else:
def d_mean_log_pseudo_likelihood(x):
#Derivative of mean (w.r.t samples) log pseudo liklihood amounts
#to local energy matching criteria
#O = sum_i \sum_s f_i(s) P(s,i) #s = sample, i = variable index
#f_i(s) is energy lost in flipping spin s_i against current assignment.
#P(s,i) = 1/(1 + exp[x f_i(s)]), probability to flip against current state.
#x = -1/T
with warnings.catch_warnings():
#Overflow errors are safe:
warnings.simplefilter(action='ignore', category=RuntimeWarning)
expFactor = np.exp(site_energy[0]*x)
return np.sum(site_energy[0]/(1 + expFactor))
#Ensures good gradient method, except pathological cases
if T_guess is None:
x0 = -1/max_excitation_all
else:
if T_guess < T_bracket[0]:
x0 = -1/T_bracket[0]
elif T_guess > T_bracket[1]:
x0 = -1/T_bracket[1]
else:
x0 = -1/T_guess
root_results = None
if optimize_method == 'bisect':
#Check T_bracket
if not 0 <= T_bracket[0] < T_bracket[1]:
raise ValueError('Bad T_bracket, must be positive ordered scalars.')
#Convert to bisection bracket for -1/T
bisect_bracket = [-1/T_bracket[i] for i in range(2)]
if d_mean_log_pseudo_likelihood(bisect_bracket[0]) <0:
warnings.warn(
'Temperature is less than T_bracket[0], or perhaps negative: '
'rescaling the Hamiltonian, modification of T_bracket[0], or '
'a change of the optimize_method (to None) '
'can resolve this issue assuming a numerical precision issue '
'induced by very large or small effective fields is not the cause. '
'Automated precision requirements mean that this routine works '
'best when excitations (effective fields) are O(1).')
T_estimate = T_bracket[0]
elif d_mean_log_pseudo_likelihood(bisect_bracket[1]) > 0:
warnings.warn(
'Temperature is greater than T_bracket[1], or perhaps negative:'
'rescaling the Hamiltonian, modification of T_bracket[1] or '
'a change of the optimize_method (to None) '
'can resolve this issue assuming a numerical precision issue '
'induced by very large or small effective fields is not the cause. '
'Automated precision requirements mean that this routine works '
'best when excitations (effective fields) are O(1).')
T_estimate = T_bracket[1]
else:
#Bounds are good:
if x0 < bisect_bracket[0] or x0 > bisect_bracket[1]:
x0 = (bisect_bracket[0] + bisect_bracket[1])/2
root_results = optimize.root_scalar(f=d_mean_log_pseudo_likelihood, x0 = x0,
method=optimize_method, bracket=bisect_bracket)
T_estimate = -1/(root_results.root)
else:
#For very large or small site energies this may be numerically
#unstable, therefore bisection search is the default.
def dd_mean_log_pseudo_likelihood(x):
import warnings
with warnings.catch_warnings():
warnings.simplefilter(action='ignore', category=RuntimeWarning)
#overflow errors are harmless, +Inf is a safe value.
expFactor = np.exp(site_energy[0]*x)
#divide by zero (1/expFactor) and divide by +Inf errors are harmless
return np.sum(-site_energy[0]*site_energy[0]/(expFactor + 2 + 1/expFactor))
root_results = optimize.root_scalar(f=d_mean_log_pseudo_likelihood, x0 = x0,
fprime=dd_mean_log_pseudo_likelihood)
T_estimate = -1/root_results.root
if num_bootstrap_samples > 0:
#By bootstrapping with respect to samples we
if root_results is not None:
x0 = root_results.root
prng = np.random.RandomState(seed)
num_samples = site_energy[0].shape[0]
for bs in range(num_bootstrap_samples):
indices = np.random.choice(
num_samples,
num_bootstrap_samples,
replace=True)
T_bootstrap_estimates[bs],_ = maximum_pseudolikelihood_temperature(
site_energy = (site_energy[0][indices,:],site_energy[1]),
num_bootstrap_samples = 0,
T_guess = T_estimate)
return T_estimate, T_bootstrap_estimates
def freezeout_effective_temperature(freezeout_B, temperature, units_B = 'GHz', units_T = 'mK') -> float:
'''Provides an effective temperature as a function of freezeout information.
See https://docs.dwavesys.com/docs/latest/c_qpu_annealing.html for a
complete summary of D-Wave annealing quantum computer operation.
A D-Wave annealing quantum computer is assumed to implement a Hamiltonian
:math:`H(s) = B(s)/2 H_P - A(s)/2 H_D`, where: :math:`H_P` is the unitless
diagonal problem Hamiltonian,
:math:`H_D` is the unitless driver Hamiltonian, :math:`B(s)` is the problem energy scale; A(s)
is the driver energy scale, amd :math:`s` is the normalized anneal
time :math:`s = t/t_a` (in [0,1]).
Diagonal elements of :math:`H_P`, indexed by the spin state :math:`x`, are equal to
the energy of a classical Ising spin system
.. math::
E_{Ising}(x) = \sum_i h_i x_i + \sum_{i>j} J_{i,j} x_i x_j
If annealing achieves a thermally equilibrated distribution
over decohered states at large :math:`s` where :math:`A(s) \ll B(s)`,
and dynamics stop abruptly at :math:`s=s^*`, the distribution of returned
samples is well described by a Boltzmann distribution:
.. math::
P(x) = \exp(- B(s^*) R E_{Ising}(x) / 2 k_B T)
where T is the physical temperature, and :math:`k_B` is the Boltzmann constant.
R is a Hamiltonain rescaling factor, if a QPU is operated with auto_scale=False,
then R=1.
The function calculates the unitless effective temperature as :math:`T_{eff} = 2 k_B T/B(s^*)`.
Device temperature :math:`T`, annealing schedules {:math:`A(s)`, :math:`B(s)`} and
single-qubit freeze-out (:math:`s^*`, for simple uncoupled Hamltonians) are reported
device properties: https://docs.dwavesys.com/docs/latest/doc_physical_properties.html
These values (typically specified in mK and GHz) allows the calculation of an effective
temperature for simple Hamiltonians submitted to D-Wave quantum computers. Complicated
problems exploiting embeddings, or with many coupled variables, may freeze out at
different values of s or piecemeal). Large problems may have slow dynamics at small
values of s, so :math:`A(s)` cannot be ignored as a contributing factor to the distribution.
Note that for QPU solvers this temperature estimate applies to problems
submitted with no additional scaling factors (sampling with ``auto_scale = False``).
If ``auto_scale=True`` (default) additional scaling factors must be accounted for.
Args:
freezeout_B (float):
:math:`B(s^*)`, the problem Hamiltonian energy scale at freeze-out.
temperature (float):
:math:`T`, the physical temperature of the quantum computer.
units_B (string, optional, 'GHz'):
Units in which ``freezeout_B`` is specified. Allowed values:
'GHz' (Giga-Hertz) and 'J' (Joules).
units_T (string, optional, 'mK'):
Units in which the ``temperature`` is specified. Allowed values:
'mK' (milli-Kelvin) and 'K' (Kelvin).
Returns:
float : The effective (unitless) temperature.
Examples:
This example uses the
published parameters <https://docs.dwavesys.com/docs/latest/doc_physical_properties.html>
for the Advantage_system4.1 QPU solver as of November 22nd 2021:
:math:`B(s=0.612) = 3.91` GHz , :math:`T = 15.4`mK.
>>> from dwave.system.temperatures import freezeout_effective_temperature
>>> T = freezeout_effective_temperature(freezeout_B = 3.91, temperature = 15.4)
>>> print('Effective temperature at single qubit freeze-out is', T) # doctest: +ELLIPSIS
Effective temperature at single qubit freeze-out is 0.164...
See also:
The function :class:`~dwave.system.temperatures.fast_effective_temperature`
estimates the temperature for single-qubit Hamiltonians, in approximate
agreement with estimates by this function at reported single-qubit
freeze-out values :math:`s^*` and device physical parameters.
'''
#Convert units_B to Joules
if units_B == 'GHz':
h = 6.626068e-34 #J/Hz
freezeout_B = freezeout_B *h
freezeout_B *= 1e9
elif units_B == 'J':
pass
else:
raise ValueException("Units must be 'J' (Joules) "
"or 'mK' (milli-Kelvin)")
if units_T == 'mK':
temperature = temperature * 1e-3
elif units_T == 'K':
pass
else:
raise ValueException("Units must be 'K' (Kelvin) "
"or 'mK' (milli-Kelvin)")
kB = 1.3806503e-23 # J/K
return 2*temperature*kB/freezeout_B
def fast_effective_temperature(sampler=None, num_reads=None, seed=None,
h_range=(-1/6.1,1/6.1), sampler_params=None,
optimize_method=None,
num_bootstrap_samples=0) -> Tuple[np.float64,np.float64]:
'''Provides an estimate to the effective temperature, :math:`T`, of a sampler.
This function submits a set of single-qubit problems to a sampler and
uses the rate of excitations to infer a maximum-likelihood estimate of temperature.
Args:
sampler (:class:`dimod.Sampler`, optional, default=\ :class:`~dwave.system.samplers.DWaveSampler`):
A dimod sampler.
num_reads (int, optional):
Number of reads to use. Default is 100 if not specified in
``sampler_params``.
seed (int, optional):
Seeds the problem generation process. Allowing reproducibility
from pseudo-random samplers.
h_range (float, optional, default = [-1/6.1,1/6.1]):
Determines the range of external fields probed for temperature
inference. Default is based on a D-Wave Advantage processor, where
single-qubit freeze-out implies an effective temperature of 6.1
(see :class:`~dwave.system.temperatures.freezeout_effective_temperature`).
The range should be chosen inversely proportional to the anticipated
temperature for statistical efficiency, and to accomodate precision
and other nonidealities such as precision limitations.
sampler_params (dict, optional):
Any additional non-defaulted sampler parameterization. If
``num_reads`` is a key, must be compatible with ``num_reads``
argument.
optimize_method (str, optional):
Optimize method used by SciPy ``root_scalar`` method. The default
method works well under default operation, 'bisect' can be
numerically more stable when operated without defaults.
num_bootstrap_samples (int, optional, default=0):
Number of bootstrap samples to use for estimation of the
standard error. By default no bootstrapping is performed
and the standard error is defaulted to 0.
Returns:
Tuple[float, float]:
The effective temperature describing single qubit problems in an
external field, and a standard error (+/- 1 sigma).
By default the confidence interval is set as 0.
See also:
https://doi.org/10.3389/fict.2016.00023
https://www.jstor.org/stable/25464568
Examples:
Draw samples from a :class:`~dwave.system.samplers.DWaveSampler`, and establish the temperature
>>> from dwave.system.temperatures import fast_effective_temperature
>>> from dwave.system import DWaveSampler
>>> sampler = DWaveSampler()
>>> T, _ = fast_effective_temperature(sampler)
>>> print('Effective temperature at freeze-out is',T) # doctest: +SKIP
0.21685104745347336
See also:
The function :class:`~dwave.system.temperatures.freezeout_effective_temperature`
may be used in combination with published device values to estimate single-qubit
freeze-out, in approximate agreement with empirical estimates of this function.
https://doi.org/10.3389/fict.2016.00023
https://www.jstor.org/stable/25464568
'''
if sampler is None:
from dwave.system import DWaveSampler
sampler = DWaveSampler()
if 'h_range' in sampler.properties:
if h_range[0] < sampler.properties['h_range'][0]:
raise ValueError('h_range[0] exceeds programmable range')
if h_range[1] > sampler.properties['h_range'][1]:
raise ValueError('h_range[1] exceeds programmable range')
prng = np.random.RandomState(seed)
h_values = h_range[0] + (h_range[1]-h_range[0])*prng.rand(len(sampler.nodelist))
bqm = dimod.BinaryQuadraticModel.from_ising({var: h_values[idx] for idx,var in enumerate(sampler.nodelist)}, {})
#Create local sampling_params copy - default necessary additional fields:
if sampler_params is None:
sampler_params0 = {}
else:
sampler_params0 = sampler_params.copy()
if num_reads is None:
#Default is 100, makes efficient use of QPU access time:
if 'num_reads' not in sampler_params0:
sampler_params0['num_reads'] = 100
elif ('num_reads' in sampler_params0
and sampler_params0['num_reads'] != num_reads):
raise ValueError("sampler_params['num_reads'] != num_reads, "
"incompatible input arguments.")
else:
sampler_params0['num_reads'] = num_reads
if ('auto_scale' in sampler_params0
and sampler_params0['auto_scale'] is not False):
raise ValueError("sampler_params['auto_scale'] == False, "
"is required by this method.")
else:
sampler_params0['auto_scale'] = False
if num_bootstrap_samples is None:
num_bootstrap_samples = sampler_params0['num_reads']
sampleset = sampler.sample(bqm, **sampler_params0)
T,Tboot = maximum_pseudolikelihood_temperature(
bqm,
sampleset,
optimize_method=optimize_method,
num_bootstrap_samples=num_bootstrap_samples)
if num_bootstrap_samples == 0:
return T, np.float64(0.0)
else:
return T, np.sqrt(np.var(Tboot))