Samplers#

Classical and quantum Runnable dimod samplers for problems and subproblems.

Classes#

QPU Samplers and Embedders#

class QPUSubproblemAutoEmbeddingSampler(num_reads=100, num_retries=0, qpu_sampler=None, sampling_params=None, auto_embedding_params=None, **runopts)[source]#

A quantum sampler for a subproblem with automated heuristic minor-embedding.

Parameters:
  • num_reads (int, optional, default=100) – Number of states (output solutions) to read from the sampler.

  • num_retries (int, optional, default=0) – Number of times the sampler will retry to embed if a failure occurs.

  • qpu_sampler (dimod.Sampler, optional, default=DWaveSampler()) – Quantum sampler such as a D-Wave system. Subproblems that do not fit the sampler’s structure are minor-embedded on the fly with AutoEmbeddingComposite.

  • sampling_params (dict) – Dictionary of keyword arguments with values that will be used on every call of the (embedding-wrapped QPU) sampler.

  • auto_embedding_params (dict, optional) – If provided, parameters are passed to the AutoEmbeddingComposite constructor as keyword arguments.

See Examples.

class QPUSubproblemExternalEmbeddingSampler(num_reads=100, qpu_sampler=None, sampling_params=None, logical_srt=False, **runopts)[source]#

A quantum sampler for a subproblem with a defined minor-embedding.

Note

Externally supplied embedding must be present in the input state.

Parameters:
  • num_reads (int, optional, default=100) – Number of states (output solutions) to read from the sampler.

  • qpu_sampler (dimod.Sampler, optional, default=DWaveSampler()) – Quantum sampler such as a D-Wave system.

  • sampling_params (dict) – Dictionary of keyword arguments with values that will be used on every call of the (external-embedding-wrapped QPU) sampler.

  • logical_srt (int, optional, default=False) – Perform a spin-reversal transform over the logical space.

See Examples.

class ReverseAnnealingAutoEmbeddingSampler(num_reads=100, anneal_schedule=None, qpu_sampler=None, sampling_params=None, auto_embedding_params=None, **runopts)[source]#

A quantum reverse annealing sampler for a subproblem with automated heuristic minor-embedding.

Parameters:
  • num_reads (int, optional, default=100) – Number of states (output solutions) to read from the sampler.

  • anneal_schedule (list(list), optional, default=[[0, 1], [0.5, 0.5], [1, 1]]) – An anneal schedule defined by a series of pairs of floating-point numbers identifying points in the schedule at which to change slope. The first element in the pair is time t in microseconds; the second, normalized persistent current s in the range [0,1]. The resulting schedule is the piecewise-linear curve that connects the provided points. For more details, see validate_anneal_schedule().

  • qpu_sampler (dimod.Sampler, optional) –

    Quantum sampler such as a D-Wave system. Subproblems that do not fit the sampler’s structure are minor-embedded on the fly with AutoEmbeddingComposite.

    If sampler is not provided, it defaults to:

    qpu_sampler = DWaveSampler(
        solver=dict(max_anneal_schedule_points__gte=len(anneal_schedule)))
    

  • sampling_params (dict) – Dictionary of keyword arguments with values that will be used on every call of the (embedding-wrapped QPU) sampler.

  • auto_embedding_params (dict, optional) – If provided, parameters are passed to the AutoEmbeddingComposite constructor as keyword arguments.

class SubproblemCliqueEmbedder(sampler, **runopts)[source]#

Subproblem-induced-clique embedder on sampler’s target graph.

Parameters:

sampler (dimod.Structured) – Structured dimod.Sampler such as a DWaveSampler.

Example

To replace QPUSubproblemAutoEmbeddingSampler with a sampler that uses fixed clique embedding (adapted to subproblem on each run), use SubproblemCliqueEmbedder | QPUSubproblemExternalEmbeddingSampler construct:

from dwave.system import DWaveSampler

qpu = DWaveSampler()
qpu_branch = (
    hybrid.EnergyImpactDecomposer(size=50)
    | hybrid.SubproblemCliqueEmbedder(sampler=qpu)
    | hybrid.QPUSubproblemExternalEmbeddingSampler(qpu_sampler=qpu))

Classical Samplers#

class RandomSubproblemSampler[source]#

A random sample generator for a subproblem.

class SimulatedAnnealingProblemSampler(num_reads=None, num_sweeps=1000, beta_range=None, beta_schedule_type='geometric', initial_states_generator='random', **runopts)[source]#

A simulated annealing sampler for a complete problem.

Parameters:
  • num_reads (int, optional, default=len(state.samples) or 1) – Number of states (output solutions) to read from the sampler.

  • num_sweeps (int, optional, default=1000) – Number of sweeps or steps.

  • beta_range (tuple, optional) – A 2-tuple defining the beginning and end of the beta schedule, where beta is the inverse temperature. The schedule is applied linearly in beta. Default range is set based on the total bias associated with each node.

  • beta_schedule_type (string, optional, default='geometric') – Beta schedule type, or how the beta values are interpolated between the given ‘beta_range’. Supported values are: linear and geometric.

  • initial_states_generator (str, 'none'/'tile'/'random', optional, default='random') – Defines the expansion of input state samples into initial_states for the simulated annealing, if fewer than num_reads samples are present. See sample().

class SimulatedAnnealingSubproblemSampler(num_reads=None, num_sweeps=1000, beta_range=None, beta_schedule_type='geometric', initial_states_generator='random', **runopts)[source]#

A simulated annealing sampler for a subproblem.

Parameters:
  • num_reads (int, optional, default=len(state.subsamples) or 1) – Number of states (output solutions) to read from the sampler.

  • num_sweeps (int, optional, default=1000) – Number of sweeps or steps.

  • beta_range (tuple, optional) – A 2-tuple defining the beginning and end of the beta schedule, where beta is the inverse temperature. The schedule is applied linearly in beta. Default range is set based on the total bias associated with each node.

  • beta_schedule_type (string, optional, default='geometric') – Beta schedule type, or how the beta values are interpolated between the given ‘beta_range’. Supported values are: linear and geometric.

  • initial_states_generator (str, 'none'/'tile'/'random', optional, default='random') – Defines the expansion of input state subsamples into initial_states for the simulated annealing, if fewer than num_reads subsamples are present. See sample().

See Examples.

class SteepestDescentProblemSampler(num_reads=None, initial_states_generator='random', **runopts)[source]#

A steepest descent solver for a complete problem.

Parameters:
  • num_reads (int, optional, default=len(state.samples) or 1) – Number of states (output solutions) to read from the sampler.

  • initial_states_generator (str, 'none'/'tile'/'random', optional, default='random') – Defines the expansion of input state samples into initial_states for the steepest descent, if fewer than num_reads samples are present. See greedy.sampler.SteepestDescentSolver.sample().

class SteepestDescentSubproblemSampler(num_reads=None, initial_states_generator='random', **runopts)[source]#

A steepest descent solver for a subproblem.

Parameters:
  • num_reads (int, optional, default=len(state.subsamples) or 1) – Number of states (output solutions) to read from the sampler.

  • initial_states_generator (str, 'none'/'tile'/'random', optional, default='random') – Defines the expansion of input state subsamples into initial_states for the steepest descent, if fewer than num_reads subsamples are present. See greedy.sampler.SteepestDescentSolver.sample().

See Examples.

class TabuProblemSampler(num_reads=None, tenure=None, timeout=100, initial_states_generator='random', **runopts)[source]#

A tabu sampler for a binary quadratic problem.

Parameters:
  • num_reads (int, optional, default=len(state.samples) or 1) – Number of states (output solutions) to read from the sampler.

  • tenure (int, optional) – Tabu tenure, which is the length of the tabu list, or number of recently explored solutions kept in memory. Default is a quarter of the number of problem variables up to a maximum value of 20.

  • timeout (int, optional, default=100) – Total running time in milliseconds.

  • initial_states_generator (str, 'none'/'tile'/'random', optional, default='random') – Defines the expansion of input state samples into initial_states for the Tabu search, if fewer than num_reads samples are present. See sample().

See Examples.

class TabuSubproblemSampler(num_reads=None, tenure=None, timeout=100, initial_states_generator='random', **runopts)[source]#

A tabu sampler for a subproblem.

Parameters:
  • num_reads (int, optional, default=len(state.subsamples) or 1) – Number of states (output solutions) to read from the sampler.

  • tenure (int, optional) – Tabu tenure, which is the length of the tabu list, or number of recently explored solutions kept in memory. Default is a quarter of the number of problem variables up to a maximum value of 20.

  • timeout (int, optional, default=100) – Total running time in milliseconds.

  • initial_states_generator (str, 'none'/'tile'/'random', optional, default='random') – Defines the expansion of input state subsamples into initial_states for the Tabu search, if fewer than num_reads subsamples are present. See sample().

See Examples.

Interruptable Variants#

class InterruptableTabuSampler(max_time=None, **tabu)[source]#

An interruptable tabu sampler for a binary quadratic problem.

Parameters:
  • num_reads (int, optional, default=1) – Number of states (output solutions) to read from the sampler.

  • tenure (int, optional) – Tabu tenure, which is the length of the tabu list, or number of recently explored solutions kept in memory. Default is a quarter of the number of problem variables up to a maximum value of 20.

  • timeout (int, optional, default=20) – Timeout for non-interruptable operation of tabu search. At the completion of each loop of tabu search through its problem variables, if this time interval has been exceeded, the search can be stopped by an interrupt signal or expiration of the timeout parameter.

  • initial_states_generator (str, 'none'/'tile'/'random', optional, default='random') – Defines the expansion of input state samples into initial_states for the Tabu search, if fewer than num_reads samples are present. See sample().

  • max_time (float, optional, default=None) – Total running time in milliseconds.

See Examples.

class InterruptableSimulatedAnnealingProblemSampler(num_reads=None, num_sweeps=1000, beta_range=None, beta_schedule_type='geometric', initial_states_generator='random', **runopts)[source]#

SimulatedAnnealingProblemSampler is already interruptable.

class InterruptableSimulatedAnnealingSubproblemSampler(num_reads=None, num_sweeps=1000, beta_range=None, beta_schedule_type='geometric', initial_states_generator='random', **runopts)[source]#

SimulatedAnnealingSubproblemSampler is already interruptable.

Examples#

QPUSubproblemExternalEmbeddingSampler#

This example works on a binary quadratic model of two AND gates in series by sampling a BQM representing just one of the gates. Output \(z\) of gate \(z = x \wedge y\) connects to input \(a\) of gate \(c = a \wedge b\). An initial state is manually set with invalid solution \(x=y=0, z=1; a=b=1, c=0\). The state is updated by sampling the subproblem 100 times on a D-Wave system. The execution results shown here were three valid solutions to the subproblem; for example, \(x=0, y=1, z=0\) occurred 22 times.

import dimod
import minorminer
from dwave.system.samplers import DWaveSampler
from hybrid.samplers import QPUSubproblemExternalEmbeddingSampler
from hybrid.core import State

# Define a problem and a subproblem
bqm = dimod.BinaryQuadraticModel({'x': 0.0, 'y': 0.0, 'z': 8.0, 'a': 2.0, 'b': 0.0, 'c': 6.0},
                                 {('y', 'x'): 2.0, ('z', 'x'): -4.0, ('z', 'y'): -4.0,
                                 ('b', 'a'): 2.0, ('c', 'a'): -4.0, ('c', 'b'): -4.0, ('a', 'z'): -4.0},
                                 -1.0, 'BINARY')
sub_bqm = dimod.BinaryQuadraticModel({'x': 0.0, 'y': 0.0, 'z': 8.0},
                                     {('x', 'y'): 2.0, ('x', 'z'): -4.0, ('y', 'z'): -4.0},
                                     -1.0, dimod.Vartype.BINARY)

# Find a minor-embedding for the subproblem
qpu_sampler = DWaveSampler()
sub_embedding = minorminer.find_embedding(list(sub_bqm.quadratic.keys()), qpu_sampler.edgelist)

# Set up the sampler with an initial state
sampler = QPUSubproblemExternalEmbeddingSampler(num_reads=100)
state = State.from_sample({'x': 0, 'y': 0, 'z': 1, 'a': 1, 'b': 1, 'c': 0}, bqm)
state.update(subproblem=sub_bqm, embedding=sub_embedding)
# Sample the subproblem on the QPU (REPL)
>>> new_state = sampler.run(state).result()
>>> print(new_state.subsamples.record)
[([0, 1, 0], -1., 22) ([0, 0, 0], -1., 47) ([1, 0, 0], -1., 31)]

QPUSubproblemAutoEmbeddingSampler#

This example works on a binary quadratic model of two AND gates in series by sampling a BQM representing just one of the gates. Output \(z\) of gate \(z = x \wedge y\) connects to input \(a\) of gate \(c = a \wedge b\). An initial state is manually set with invalid solution \(x=y=0, z=1; a=b=1, c=0\). The state is updated by sampling the subproblem 100 times on a D-Wave system. The execution results shown here were four valid solutions to the subproblem; for example, \(x=0, y=0, z=0\) occurred 53 times.

import dimod
from hybrid.samplers import QPUSubproblemAutoEmbeddingSampler
from hybrid.core import State

# Define a problem and a subproblem
bqm = dimod.BinaryQuadraticModel({'x': 0.0, 'y': 0.0, 'z': 8.0, 'a': 2.0, 'b': 0.0, 'c': 6.0},
                                {('y', 'x'): 2.0, ('z', 'x'): -4.0, ('z', 'y'): -4.0,
                                 ('b', 'a'): 2.0, ('c', 'a'): -4.0, ('c', 'b'): -4.0, ('a', 'z'): -4.0},
                                -1.0, 'BINARY')
sub_bqm = dimod.BinaryQuadraticModel({'x': 0.0, 'y': 0.0, 'z': 8.0},
                                    {('x', 'y'): 2.0, ('x', 'z'): -4.0, ('y', 'z'): -4.0},
                                    -1.0, dimod.Vartype.BINARY)

# Set up the sampler with an initial state
sampler = QPUSubproblemAutoEmbeddingSampler(num_reads=100)
state = State.from_sample({'x': 0, 'y': 0, 'z': 1, 'a': 1, 'b': 1, 'c': 0}, bqm)
state.update(subproblem=sub_bqm)
# Sample the subproblem on the QPU (REPL)
>>> new_state = sampler.run(state).result()
>>> print(new_state.subsamples.record)
[([0, 0, 0], -1., 53) ([0, 1, 0], -1., 15) ([1, 0, 0], -1., 31) ([1, 1, 1],  1.,  1)]

SimulatedAnnealingSubproblemSampler#

This example works on a binary quadratic model of two AND gates in series by sampling a BQM representing just one of the gates. Output \(z\) of gate \(z = x \wedge y\) connects to input \(a\) of gate \(c = a \wedge b\). An initial state is manually set with invalid solution \(x=y=0, z=1; a=b=1, c=0\). The state is updated by sampling the subproblem 10 times. The execution results shown here were valid solutions to the subproblem; for example, \(x=0, y=1, z=0\).

import dimod
from hybrid.samplers import SimulatedAnnealingSubproblemSampler
from hybrid.core import State

# Define a problem and a subproblem
bqm = dimod.BinaryQuadraticModel({'x': 0.0, 'y': 0.0, 'z': 8.0, 'a': 2.0, 'b': 0.0, 'c': 6.0},
                                {('y', 'x'): 2.0, ('z', 'x'): -4.0, ('z', 'y'): -4.0,
                                ('b', 'a'): 2.0, ('c', 'a'): -4.0, ('c', 'b'): -4.0, ('a', 'z'): -4.0},
                                -1.0, 'BINARY')
sub_bqm = dimod.BinaryQuadraticModel({'x': 0.0, 'y': 0.0, 'z': 8.0},
                                    {('x', 'y'): 2.0, ('x', 'z'): -4.0, ('y', 'z'): -4.0},
                                    -1.0, dimod.Vartype.BINARY)

# Set up the sampler with an initial state
sampler = SimulatedAnnealingSubproblemSampler(num_reads=10)
state = State.from_sample({'x': 0, 'y': 0, 'z': 1, 'a': 1, 'b': 1, 'c': 0}, bqm)
state.update(subproblem=sub_bqm)
# Sample the subproblem (REPL)
>>> new_state = sampler.run(state).result()
>>> print(new_state.subsamples.record)
[([0, 1, 0], -1., 1) ([0, 1, 0], -1., 1) ([0, 0, 0], -1., 1)
([0, 0, 0], -1., 1) ([0, 0, 0], -1., 1) ([1, 0, 0], -1., 1)
([1, 0, 0], -1., 1) ([0, 0, 0], -1., 1) ([0, 1, 0], -1., 1)
([1, 0, 0], -1., 1)]

TabuSubproblemSampler#

This example works on a binary quadratic model of two AND gates in series by sampling a BQM representing just one of the gates. Output \(z\) of gate \(z = x \wedge y\) connects to input \(a\) of gate \(c = a \wedge b\). An initial state is manually set with invalid solution \(x=y=0, z=1; a=b=1, c=0\). The state is updated by a tabu search on the subproblem. The execution results shown here was a valid solution to the subproblem: example, \(x=0, y=1, z=0\).

import dimod
from hybrid.samplers import TabuSubproblemSampler
from hybrid.core import State

# Define a problem and a subproblem
bqm = dimod.BinaryQuadraticModel({'x': 0.0, 'y': 0.0, 'z': 8.0, 'a': 2.0, 'b': 0.0, 'c': 6.0},
                                 {('y', 'x'): 2.0, ('z', 'x'): -4.0, ('z', 'y'): -4.0,
                                  ('b', 'a'): 2.0, ('c', 'a'): -4.0, ('c', 'b'): -4.0, ('a', 'z'): -4.0},
                                 -1.0, 'BINARY')
sub_bqm = dimod.BinaryQuadraticModel({'x': 0.0, 'y': 0.0, 'z': 8.0},
                                     {('x', 'y'): 2.0, ('x', 'z'): -4.0, ('y', 'z'): -4.0},
                                     -1.0, dimod.Vartype.BINARY)

# Set up the sampler with an initial state
sampler = TabuSubproblemSampler(tenure=2, timeout=5)
state = State.from_sample({'x': 0, 'y': 0, 'z': 1, 'a': 1, 'b': 1, 'c': 0}, bqm)
state.update(subproblem=sub_bqm)
>>> # Sample the subproblem (REPL)
>>> print(new_state.subsamples.record)
[([0, 1, 0], -1., 1)]

TabuProblemSampler#

This example works on a binary quadratic model of two AND gates in series, where output \(z\) of gate \(z = x \wedge y\) connects to input \(a\) of gate \(c = a \wedge b\). An initial state is manually set with invalid solution \(x=y=0, z=1; a=b=1, c=0\). The state is updated by a tabu search. The execution results shown here was a valid solution to the problem: example, \(x=y=z=a=b=c=1\).

import dimod
from hybrid.samplers import TabuProblemSampler
from hybrid.core import State

# Define a problem
bqm = dimod.BinaryQuadraticModel({'x': 0.0, 'y': 0.0, 'z': 8.0, 'a': 2.0, 'b': 0.0, 'c': 6.0},
                                 {('y', 'x'): 2.0, ('z', 'x'): -4.0, ('z', 'y'): -4.0,
                                  ('b', 'a'): 2.0, ('c', 'a'): -4.0, ('c', 'b'): -4.0, ('a', 'z'): -4.0},
                                 -1.0, 'BINARY')

# Set up the sampler with an initial state
sampler = TabuProblemSampler(tenure=2, timeout=5)
state = State.from_sample({'x': 0, 'y': 0, 'z': 1, 'a': 1, 'b': 1, 'c': 0}, bqm)
# Sample the problem (REPL)
>>> new_state = sampler.run(state).result()
>>> print(new_state.samples)
Response(rec.array([([1, 1, 1, 1, 1, 1], -1., 1)],
    dtype=[('sample', 'i1', (6,)), ('energy', '<f8'), ('num_occurrences', '<i4')]),
    ['a', 'b', 'c', 'x', 'y', 'z'], {}, 'BINARY')

InterruptableTabuSampler#

This example works on a binary quadratic model of two AND gates in series, where output \(z\) of gate \(z = x \wedge y\) connects to input \(a\) of gate \(c = a \wedge b\). An initial state is manually set with invalid solution \(x=y=0, z=1; a=b=1, c=0\). The state is updated by a tabu search. The execution results shown here was a valid solution to the problem: example, \(x=y=z=a=b=c=1\).

import dimod
from hybrid.samplers import InterruptableTabuSampler
from hybrid.core import State

# Define a problem
bqm = dimod.BinaryQuadraticModel({'x': 0.0, 'y': 0.0, 'z': 8.0, 'a': 2.0, 'b': 0.0, 'c': 6.0},
                                 {('y', 'x'): 2.0, ('z', 'x'): -4.0, ('z', 'y'): -4.0,
                                  ('b', 'a'): 2.0, ('c', 'a'): -4.0, ('c', 'b'): -4.0, ('a', 'z'): -4.0},
                                 -1.0, 'BINARY')

# Set up the sampler with an initial state
sampler = InterruptableTabuSampler(tenure=2, quantum_timeout=30, timeout=5000)
state = State.from_sample({'x': 0, 'y': 0, 'z': 1, 'a': 1, 'b': 1, 'c': 0}, bqm)
>>> # Sample the problem (REPL)
>>> new_state = sampler.run(state)
>>> new_state
<Future at 0x179eae59898 state=running>
>>> sampler.stop()
>>> new_state
<Future at 0x179eae59898 state=finished returned State>
>>> print(new_state.result())
State(samples=Response(rec.array([([1, 1, 1, 1, 1, 1], -1., 1)],
    dtype=[('sample', 'i1', (6,)), ('energy', '<f8'), ('num_occurrences', '<i4')]),
    ['a', 'b', 'c', 'x', 'y', 'z'], {}, 'BINARY'))

RandomSubproblemSampler#

This example works on a binary quadratic model of two AND gates in series by sampling a BQM representing just one of the gates. Output \(z\) of gate \(z = x \wedge y\) connects to input \(a\) of gate \(c = a \wedge b\). An initial state is manually set with invalid solution \(x=y=0, z=1; a=b=1, c=0\). The state is updated with a random sample..

import dimod
from hybrid.samplers import RandomSubproblemSampler
from hybrid.core import State

# Define a problem and a subproblem
bqm = dimod.BinaryQuadraticModel({'x': 0.0, 'y': 0.0, 'z': 8.0, 'a': 2.0, 'b': 0.0, 'c': 6.0},
                                 {('y', 'x'): 2.0, ('z', 'x'): -4.0, ('z', 'y'): -4.0,
                                  ('b', 'a'): 2.0, ('c', 'a'): -4.0, ('c', 'b'): -4.0, ('a', 'z'): -4.0},
                                 -1.0, 'BINARY')
sub_bqm = dimod.BinaryQuadraticModel({'x': 0.0, 'y': 0.0, 'z': 8.0},
                                     {('x', 'y'): 2.0, ('x', 'z'): -4.0, ('y', 'z'): -4.0},
                                     -1.0, dimod.Vartype.BINARY)

# Set up the sampler with an initial state
sampler = RandomSubproblemSampler()
state = State.from_sample({'x': 0, 'y': 0, 'z': 1, 'a': 1, 'b': 1, 'c': 0}, bqm)
state.update(subproblem=sub_bqm)
# Sample the subproblem a couple of times (REPL)
>>> new_state = sampler.run(state).result()
>>> print(new_state.subsamples.record)
[([0, 0, 0], -1., 1)]
>>> new_state = sampler.run(state).result()
>>> print(new_state.subsamples.record)
[([1, 1, 1], 1., 1)]