D-Wave
D-Wave π offers an impressive range of optimization solvers, from Advantage Systems to their Leap Hybrid solvers.
Solversβ
Model | Solvers |
---|---|
Quadratic Unconstrained Binary Optimization (QUBO) | dwave.Advantage_system4.1 , dwave.Advantage_system5.4 , dwave.Advantage_system6.4 , dwave.Advantage2_prototype2.6 , dwave.hybrid_binary_quadratic_model_version2p |
Constrained Quadratic Model (CQM) | dwave.hybrid_constrained_quadratic_model_version1p |
Discrete Quadratic Model (DQM) | dwave.hybrid_discrete_quadratic_model_version1p |
Non-linear Program (NLP) | dwave.hybrid_nonlinear_program_version1p |
Advantage Systemsβ
D-Wave Advantage samplers are designed to solve problems that can be formulated as binary quadratic models (BQM). The samplers are used to find the lowest energy state of the BQM.
Quadratic Unconstrained Binary Optimization (QUBO)β
import strangeworks as sw
from strangeworks_optimization import StrangeworksOptimizer
from strangeworks_optimization_models.parameter_models import DwaveSamplerParameterModel
from dimod import BinaryQuadraticModel
sw.authenticate(api_key)
linear = {1: -2, 2: -2, 3: -3, 4: -3, 5: -2}
quadratic = {(1, 2): 2, (1, 3): 2, (2, 4): 2, (3, 4): 2, (3, 5): 2, (4, 5): 2}
model = BinaryQuadraticModel(linear, quadratic, "BINARY")
# solver = "dwave.Advantage_system6.4"
solver = "dwave.Advantage2_prototype2.6"
options = DwaveSamplerParameterModel(num_reads=100, chain_strength=50)
so = StrangeworksOptimizer(model=model, solver=solver, options=options)
sw_job = so.run()
print(f"Job slug: {sw_job.slug}")
print(f"Job status: {so.status(sw_job.slug)}")
results = so.results(sw_job.slug)
print(f"Best solution:\n{results.solution.first}")
Parametersβ
from strangeworks_optimization_models.parameter_models import DwaveSamplerParameterModel
options = DwaveSamplerParameterModel(.....)
Solvers
- dwave.Advantage_system4.1
- dwave.Advantage_system5.4
- dwave.Advantage_system6.4
- dwave.Advantage2_prototype2.6
- sim.SimulatedAnnealingSampler
- sim.RandomSampler
Name | Type | Description | Default | Values (Range) |
---|---|---|---|---|
num_reads | int | Specifies the number of reads (solutions) to be obtained. | 1 | [1, max_num_reads] |
chain_strength | int | Sets the strength of the chains in the embedding. | Determined by solver | [Depends on system] |
anneal_offsets | List[float] | Provides offsets to annealing paths, per qubit. | No offsets | Specified per qubit |
anneal_schedule | List[List[float]] | Specifies the custom annealing schedule as time and fraction. | Standard schedule | Specified per system |
annealing_time | float | Sets the duration of the annealing process per read. | Default system value | Specified per system |
auto_scale | bool | Automatically rescales h and J values to the QPU's range. | True | [True, False] |
flux_biases | List[float] | Applies manual flux biases for qubit calibration. | No biases | [Depends on system] |
flux_drift_compensation | bool | Compensates for flux drift in qubits. | True | [True, False] |
h_gain_schedule | List[List[float]] | Sets time-dependent gains for qubit biases. | Not specified | [Depends on system] |
initial_state | dict | Sets the initial state for reverse annealing. | Not specified | [Depends on system] |
max_answers | int | Limits the number of answers returned. | num_reads | [1, num_reads] |
num_spin_reversal_transforms | int | Applies spin reversal transforms to reduce noise. | 0 | [0, max_transforms] |
programming_thermalization | float | Time to wait post-programming for thermalization. | 1000 ΞΌs | [0ΞΌs, max_thermal] |
readout_thermalization | float | Time to wait post-readout for thermalization. | 0 ΞΌs | [0ΞΌs, max_thermal] |
reduce_intersample_correlation | bool | Adds delays between samples to reduce correlations. | False | [True, False] |
reinitialize_state | bool | Reinitializes to the initial state for each anneal cycle. | False | [True, False] |
embedding_parameters | dict | Specifies the embedding parameters. | False | [True, False] |
Embeddingβ
Embedding refers to the process of mapping a binary quadratic model (BQM) or an Ising model onto the physical qubits of a processor, such as those provided by D-Wave or Hitachi systems.
Embedding ensures that each variable in the problem is represented by a chain of qubits, which collectively act as a single logical variable.
This is necessary because the structure of the problem graph (source graph) often does not directly match the hardware graph (target graph) of the quantum processing unit (QPU).
Embedding is a non-deterministic process, meaning that the same problem may be embedded differently on different runs. If an embedding is not found either due to the problem being too large or the solver not being able to find an embedding, the solver will return an error.
If the problem is not too large, submitting the problem again may find an embedding.
If you need to ensure that the same embedding is used for a given problem, you can use the embedding_parameters
parameter to specify the embedding parameters.
Embedding Parametersβ
Use the EmbeddingParameterModel
to set the parameters for the minorminer.find_embedding
function.
This algorithm is a heuristic method that attempts to find an embedding that minimizes the number of chains and the chain lengths.
from strangeworks_optimization_models.parameter_models import EmbeddingParameterModel
embedding = EmbeddingParameterModel(.....)
Solvers
- DwaveSamplerParameterModel(embedding_parameters)
- HitachiParameterModel(embedding_parameters)
Parameter | Type | Default | Description |
---|---|---|---|
max_no_improvement | int | None | Maximum number of failed iterations to improve the current solution. Each iteration attempts to find an embedding for each variable such that it is adjacent to all its neighbours. |
random_seed | int | None | Seed for the random number generator. If set to None, the seed is initialized using os.random(). |
timeout | int | None | Maximum time (in seconds) before the algorithm gives up. |
max_beta | float | None | Qubits are assigned weight based on a formula (beta^n) where n is the number of chains containing that qubit. This value should be greater than 1. If None, max_beta is effectively infinite. |
tries | int | None | Number of restart attempts before the algorithm stops. A typical restart takes between 1 and 60 seconds. |
inner_rounds | int | None | Maximum number of iterations between restart attempts. If None, inner_rounds is effectively infinite. |
chainlength_patience | int | None | Maximum number of failed iterations to improve chain lengths in the current solution. |
max_fill | int | None | Restricts the number of chains that can simultaneously incorporate the same qubit during the search. Values above 63 are treated as 63. If None, max_fill is effectively infinite. |
threads | int | None | Maximum number of threads to use. Parallelization is only advantageous where the expected degree of variables is significantly greater than the number of threads. |
return_overlap | bool | None | Determines the functionβs return value. If True, a 2-tuple is returned with the embedding and a boolean representing the embedding validity. If False, only an embedding is returned. |
skip_initialization | bool | None | Skips the initialization pass if the chains passed through initial_chains and fixed_chains are semi-valid. |
verbose | int | None | Level of output verbosity. Ranges from 0 (quiet) to 4 (detailed debugging). |
interactive | bool | None | If True, the verbose output will be printed to stdout/stderr and keyboard interrupts will stop the embedding process, returning the current state to the user. |
initial_chains | dict | None | Initial chains to be inserted into an embedding before fixed_chains are placed. |
fixed_chains | dict | None | Fixed chains that are inserted into an embedding before the initialization pass and do not change during the algorithm. |
restrict_chains | dict | None | Ensures that each chain is a subset of restrict_chains throughout the algorithm. |
suspend_chains | dict | None | A metafeature implemented in the Python interface. Each entry is an iterable of iterables representing the target node labels. |
To use embedding pass the embedding_parameters
parameter to the solver.
from strangeworks_optimization_models.parameter_models import DwaveSamplerParameterModel
options = DwaveSamplerParameterModel(embedding_parameters={
"chain_strength": 10,
"anneal_schedule": [[0, 0], [1, 1]],
"anneal_offsets": [0, 0],
"annealing_time": 1,
"auto_scale": True,
})
Leap Hybridβ
Solvers | Variables | Constraints |
---|---|---|
hybrid_binary_quadratic_model_version2p , hybrid_constrained_quadratic_model_version1p , hybrid_discrete_quadratic_model_version1p | Up to 1 million | Up to 100,000 |
Quadratic Unconstrained Binary Optimization (QUBO)β
QUBO is represented as a binary quadratic model (BQM) with a linear term for each variable and a quadratic term for each pair of variables.
import strangeworks as sw
from strangeworks_optimization import StrangeworksOptimizer
from strangeworks_optimization_models.parameter_models import DwaveLeapParameterModel
from dimod import BinaryQuadraticModel
sw.authenticate(api_key)
linear = {1: -2, 2: -2, 3: -3, 4: -3, 5: -2}
quadratic = {(1, 2): 2, (1, 3): 2, (2, 4): 2, (3, 4): 2, (3, 5): 2, (4, 5): 2}
model = BinaryQuadraticModel(linear, quadratic, "BINARY")
solver = "dwave.hybrid_binary_quadratic_model_version2p"
options = DwaveLeapParameterModel(time_limit=1)
so = StrangeworksOptimizer(model=model, solver=solver, options=options)
sw_job = so.run()
Constrained Quadratic Model (CQM)β
CQM is a type of optimization problem that involves constraints on the variables. Whereas a QUBO problem is unconstrained, meaning that problems with constraints must be approximated and constraints may become violated, CQM allows for constraints to be added to the problem.
import strangeworks as sw
from strangeworks_optimization import StrangeworksOptimizer
from strangeworks_optimization_models.parameter_models import DwaveLeapParameterModel
from dimod import Binary, ConstrainedQuadraticModel
sw.authenticate(api_key)
weights = [0.9, 0.7, 0.2, 0.1]
capacity = 1
y = [Binary(f"y_{j}") for j in range(len(weights))]
x = [[Binary(f"x_{i}_{j}") for j in range(len(weights))] for i in range(len(weights))]
model = ConstrainedQuadraticModel()
model.set_objective(sum(y))
for i in range(len(weights)):
model.add_constraint(sum(x[i]) == 1, label=f"item_placing_{i}")
for j in range(len(weights)):
model.add_constraint(
sum(weights[i] * x[i][j] for i in range(len(weights))) - y[j] * capacity <= 0,
label=f"capacity_bin_{j}",
)
solver = "dwave.hybrid_constrained_quadratic_model_version1p"
options = DwaveLeapParameterModel(time_limit=1)
so = StrangeworksOptimizer(model=model, solver=solver, options=options)
sw_job = so.run()
Discrete Quadratic Model (DQM)β
DQM is a type of optimization problem that involves discrete variables. Discrete variables are variables that can only take on a finite set of values, as opposed to being continuous. This opens up the possibility of using DQM to solve problems that are not easily represented as a QUBO or CQM.
import strangeworks as sw
from strangeworks_optimization import StrangeworksOptimizer
from strangeworks_optimization_models.parameter_models import DwaveLeapParameterModel
from dimod import DiscreteQuadraticModel
import random
sw.authenticate(api_key)
model = DiscreteQuadraticModel()
for i in range(10):
model.add_variable(4)
for i in range(9):
for j in range(i + 1, 10):
model.set_quadratic_case(i, random.randrange(0, 4), j, random.randrange(0, 4), random.random())
solver = "dwave.hybrid_discrete_quadratic_model_version1p"
options = DwaveLeapParameterModel(time_limit=1)
so = StrangeworksOptimizer(model=model, solver=solver, options=options)
sw_job = so.run()
Non-linear Program (NLP)β
Non-linear programs are a type of optimization problem that involve non-linear constraints, meaning that they are not a simple sum of variables. This increases the complexity of the problem but requires more computational resources to solve.
import strangeworks as sw
from strangeworks_optimization import StrangeworksOptimizer
from strangeworks_optimization_models.parameter_models import DwaveLeapParameterModel
from dwave.optimization import Model
model = Model()
i = model.integer(lower_bound=-5, upper_bound=5)
c = model.constant(4)
y = i**2 - c * i
model.minimize(y)
solver = "dwave.hybrid_nonlinear_program_version1p"
options = DwaveLeapParameterModel(time_limit=5)
so = StrangeworksOptimizer(model=model, solver=solver)
sw_job = so.run()
print(f"Job slug: {sw_job.slug}")
print(f"Job status: {so.status(sw_job.slug)}")
results = so.results(sw_job.slug)
print(f"Best solution:\n{results.solution.first}")
Parametersβ
D-Wave Leap Hybrid solvers have a time_limit
parameter that can be used to set the time limit for the solver, the minimum time is 5 seconds.
from strangeworks_optimization_models.parameter_models import DwaveLeapParameterModel
options = DwaveLeapParameterModel(time_limit)
Solvers
- dwave.hybrid_binary_quadratic_model_version2p
- dwave.hybrid_constrained_quadratic_model_version1p
- dwave.hybrid_discrete_quadratic_model_version1p
- dwave.hybrid_nonlinear_program_version1p
Name | Type | Description | Minimum |
---|---|---|---|
time_limit | int | Specifies the time limit (seconds) for the solver | 5 |