Solutions

samplers sample from low-energy states of a problem’s objective functionBQM samplers sample from low-energy states in models such as those defined by an Ising equation or a QUBO problem—and return an iterable of samples, in order of increasing energy.

When the D‑Wave quantum computer solves a problem, it uses quantum phenomena such as superposition and tunneling to explore all possible solutions simultaneously and find a set of the best ones. At the end of the computation (anneal), a single solution is sampled from a set of good solutions, with some probability, and returned. Because the sampled solution is probabilistic, different solutions may be returned in different runs. The standard way of submitting a problem to the system requests many samples, not just one. This not only returns multiple “best” answers but also reduces the probability of settling on a suboptimal answer.

Some classical samplers might return non-probabilistic solutions; for example, the dimod ExactSolver deterministically returns the best solution or solutions to small problems by calculating the result for every configuration of variable values. Such samplers are called solvers.

Some Ocean functions might return a single best solution; for example, some dwave-networkx graph algorithms return only the lowest-energy sample.

SampleSets

Ocean uses the dimod SampleSet class to hold samples and some additional information (e.g., timing information from some samplers).

For the simple example three-variable “triangular” BQM,

\[E(\bf{s}) = - s_0 s_1 - s_0 s_2 + s_1 s_2 \qquad\qquad s_i\in\{-1,+1\}\]

might be solved directly on a D-Wave 2000Q system by sampling 1000 times as follows, where the EmbeddingComposite composite maps the symbolic BQM to qubits on the quantum processor, which is called by the DWaveSampler sampler:

>>> bqm = dimod.BQM({}, {('s0', 's1'): -1, ('s0', 's2'): -1, ('s1', 's2'): 1}, 0, dimod.Vartype.SPIN)
>>> sampler = EmbeddingComposite(DWaveSampler(solver={'qpu': True}))
>>> sampleset = sampler.sample(bqm, num_reads=1000)
>>> print(sampleset)                                                     # doctest: +SKIP
  s0 s1 s2 energy num_oc. chain_b.
0 -1 -1 +1   -1.0     141      0.0
1 +1 +1 +1   -1.0     132      0.0
2 -1 -1 -1   -1.0     159      0.0
3 -1 +1 -1   -1.0     143 0.333333
4 +1 +1 -1   -1.0      91      0.0
5 -1 +1 -1   -1.0      86      0.0
6 +1 +1 +1   -1.0     129 0.333333
7 +1 -1 +1   -1.0     119      0.0
['SPIN', 8 rows, 1000 samples, 3 variables]

The returned SampleSet, in this case, shows eight solutions of equal energy \(-1.0\). Solution \(s_0=-1, s_1=-1, s_2=+1\) occurred in 141 of the 1000 samples. Two solutions, shown in line 3 and 6, were based on a broken chain of qubits that represented one of the variables.

For this submission to a D-Wave 2000Q, the sampleset also contained the following additional information:

>>> print(sampleset.info.keys())    # doctest: +SKIP
dict_keys(['timing', 'problem_id', 'embedding_context', 'warnings'])

For example, the timing information for the problem might look something like:

>>> print(sampleset.info["timing"])  # doctest: +SKIP
{'qpu_sampling_time': 314960,
'qpu_anneal_time_per_sample': 20,
'qpu_readout_time_per_sample': 274,
'qpu_access_time': 324321,
'qpu_access_overhead_time': 5362,
'qpu_programming_time': 9361,
'qpu_delay_time_per_sample': 21,
'total_post_processing_time': 409,
'post_processing_overhead_time': 409,
'total_real_time': 324321,
'run_time_chip': 314960,
'anneal_time_per_run': 20,
'readout_time_per_run': 274}