Nonlinear Models#
This page describes the dwave-optimization package’s nonlinear model: classes, attributes, and methods.
For an introduction to formulating problems as nonlinear models, see the Model Construction section. The Traveling Salesperson: Simple Nonlinear Model demonstrates a simple use of the Leap hybrid nonlinear solver on a problem formulated as a nonlinear model; for a more-advanced end-to-end example, see the Vehicle Routing: Using a Nonlinear Model section.
Nonlinear models are especially suited for use with decision variables that represent a common logic, such as subsets of choices or permutations of ordering. For example, in a traveling salesperson problem permutations of the variables representing cities can signify the order of the route being optimized and in a knapsack problem the variables representing items can be divided into subsets of packed and not packed.
Model Class#
- class Model[source]#
Nonlinear model.
The nonlinear model represents a general optimization problem with an objective function and/or constraints over variables of various types.
The
Modelclass can contain this model and its methods provide convenient utilities for working with representations of a problem.Examples
This example creates a model for a
flow-shop-schedulingproblem with two jobs on three machines.>>> from dwave.optimization.generators import flow_shop_scheduling ... >>> processing_times = [[10, 5, 7], [20, 10, 15]] >>> model = flow_shop_scheduling(processing_times=processing_times)
- add_constraint(value)[source]#
Add a constraint to the model.
For a solution to the model to be feasible, the constraint must be satisfied.
- Parameters:
value – Value that must evaluate to True for the state of the model to be feasible.
- Returns:
The symbol associated with the constraint.
Examples
This example adds a single constraint to a model.
>>> from dwave.optimization.model import Model >>> model = Model() >>> i = model.integer() >>> c = model.constant(5) >>> constraint_sym = model.add_constraint(i <= c)
The returned constraint symbol (a
LessEqualfor this example) can be assigned, and evaluated for, a model state:>>> with model.lock(): ... model.states.resize(1) ... i.set_state(0, 1) # Feasible state ... print(constraint_sym.state(0)) 1.0 >>> with model.lock(): ... i.set_state(0, 6) # Infeasible state ... print(constraint_sym.state(0)) 0.0
See also
feasible(),iter_constraints(),num_constraints(),objective(),
- binary(shape: None | _ShapeLike = None, lower_bound: None | np.typing.ArrayLike = None, upper_bound: None | np.typing.ArrayLike = None, sum_subject_to: None | list[tuple[str, float]] = None, axes_sums_subject_to: None | list[tuple[int, str | list[str], float | list[float]]] = None) BinaryVariable[source]#
Add a binary decision variable to the model.
A binary symbol is an array of True/False values assigned as a solution to the problem being modeled.
- Parameters:
shape (optional) – Shape of the binary array to create, formatted as an integer or a tuple of integers. If None, creates a zero-dimensional (scalar) binary variable.
lower_bound (optional) – Lower bound(s) for the symbol. Can be scalar (one bound for all variables) or an array (one bound for each variable). Non-Boolean values are rounded up to the domain [0,1]. If None, the default value of 0 is used.
upper_bound (optional) – Upper bound(s) for the symbol. Can be scalar (one bound for all variables) or an array (one bound for each variable). Non-Boolean values are rounded down to the domain [0,1]. If None, the default value of 1 is used.
sum_subject_to (optional) – Constraint on the sum of the values in the array. Must be an array of tuples where each tuple has the form: (operator, bound). - operator (str): The constraint operator (“<=”, “==”, or “>=”). - bound (float): The constraint bound. If provided, the sum of values within the array must satisfy the corresponding operator–bound pair. Note 1: At most one sum constraint may be provided. Note 2: If provided, axes_sums_subject_to must None.
axes_sums_subject_to (optional) – Constraint on the sum of the values in each slice along a fixed axis in the array. Must be an array of tuples where each tuple has the form: (axis, operator(s), bound(s)). - axis (int): The axis that the constraint is applied to. - operator(s) (str | array[str]): The constraint operator(s) (“<=”, “==”, or “>=”). A single operator applies to all slice along the axis; an array specifies one operator per slice. - bound(s) (float | array[float]): The constraint bound. A single value applies to all slices; an array specifies one bound per slice. If provided, the sum of values within each slice along the specified axis must satisfy the corresponding operator–bound pair. Note 1: At most one sum constraint may be provided. Note 2: If provided, sum_subject_to must None.
- Returns:
A binary symbol at the root of the directed acyclic graph for the model.
Examples
This example adds a \(20 \times 30\)-sized binary variable to a model.
>>> from dwave.optimization.model import Model >>> model = Model() >>> x = model.binary((20, 30)) >>> x.shape() (20, 30)
This example adds a \(2\)-sized binary symbol with a scalar lower bound and index-wise upper bounds to a model.
>>> from dwave.optimization.model import Model >>> import numpy as np >>> model = Model() >>> b = model.binary(2, lower_bound=-1.1, upper_bound=[1.1, 0.9]) >>> b.upper_bound() array([1., 0.])
This example adds a \((2x3)\)-sized binary symbol with index-wise lower bounds and a sum constraint along axis 1. Let x_i (int i : 0 <= i <= 2) denote the sum of the values within slice i along axis 1. For each state defined for this symbol: (x_0 <= 0), (x_1 == 2), and (x_2 >= 1).
>>> from dwave.optimization.model import Model >>> import numpy as np >>> model = Model() >>> b = model.binary([2, 3], lower_bound=[[0, 1, 1], [0, 1, 0]], ... axes_sums_subject_to=[(1, ["<=", "==", ">="], [0, 2, 1])]) >>> np.all(b.sum_constraints() == [(1, ["<=", "==", ">="], [0, 2, 1])]) True
This example adds a \(6\)-sized binary symbol such that the sum of the values within the array is equal to 2.
>>> from dwave.optimization.model import Model >>> import numpy as np >>> model = Model() >>> b = model.binary(6, sum_subject_to=[("==", 2)]) >>> np.all(b.sum_constraints() == [(["=="], [2])]) True
Changed in version 0.6.7: Beginning in version 0.6.7, user-defined index-wise bounds are supported.
Changed in version 0.6.13: Beginning in version 0.6.13, user-defined sum constraints are supported.
- constant(array_like: numpy.typing.ArrayLike) Constant[source]#
Add a constant to the model.
A constant symbol is an array of floats used in the model’s formulation.
To prevent redundancy, constants are cached. Repeated calls to
constant()with the samearray_likeargument return the firstConstantinstance. You can clear cache by calling theclear_cache()method.- Parameters:
array_like – An array-like representing a constant. Can be a scalar or a NumPy array. If the
numpy.dtypeof the array isnumpy.double, the array is not copied.- Returns:
A constant symbol at the root of the directed acyclic graph for the model.
Examples
This example creates a \(1 \times 4\)-sized constant symbol with the specified values.
>>> from dwave.optimization.model import Model >>> model = Model() >>> time_limits = model.constant([10, 15, 5, 8.5])
Changed in version 0.6.4: Beginning in version 0.6.4, constants are cached. Also known as memoization.
- decision_state_size()[source]#
Estimate the size, in bytes, of a model’s decision states.
For more details, see the
state_size()method. This method differs by counting the states of only the decision variables.- Returns:
Estimated state size of the model’s decision variables.
- Return type:
Examples
This example estimates the size of a model’s decision state. In this example a single value is added to a \(5\times4\) array. The output of the addition is also a \(5\times4\) array. Each element of each array requires \(8\) bytes to represent in memory. The total state size is \((5*4 + 1 + 5*4) * 8 = 328\) bytes, but the decision state size is only \(5*4*8 = 160\).
>>> from dwave.optimization.model import Model >>> model = Model() >>> i = model.integer((5, 4)) # 5x4 array of integers >>> c = model.constant(1) # one scalar value, not a decision >>> y = i + c # 5x4 array of values, not a decision >>> model.state_size() # (5*4 + 1 + 5*4) * 8 bytes 328 >>> model.decision_state_size() # 5*4*8 bytes 160
See also
Symbol.state_size()Estimates the size of a symbol’s stateArraySymbol.state_size()Estimates the size of an array symbol’s stateModel.state_size()Estimates the size of all of a model’s states
- disjoint_bit_sets(primary_set_size: int, num_disjoint_sets: int) tuple[DisjointBitSets, tuple[DisjointBitSet, ...]][source]#
Add a disjoint-sets decision variable to the model.
A disjoint-sets symbol divides a set of elements into ordered partitions of bit sets, with ones signifying elements in the set, where the placement of these ones is assigned as a solution to the problem being modeled.
The elements are values of
range(primary_set_size). Each of thenum_disjoint_setsordered partitions is a bit set (array) of lengthprimary_set_sizewith ones at the indices of elements currently in the set, and zeros elsewhere. The set is disjoint in that for every index \(i\) between zero andprimary_set_size, there is a single partition assigned a value of one at that position.Also creates from the symbol
num_disjoint_setssuccessors that output the disjoint sets as arrays.- Parameters:
primary_set_size – Number of elements in the primary set that are partitioned into disjoint sets. Must be non-negative.
num_disjoint_sets – Number of disjoint sets. Must be positive.
- Returns:
A tuple where the first element is a disjoint-sets symbol at the root of the directed acyclic graph for the model and the second is a set of
num_disjoint_setssuccessors.
Examples
This example creates a symbol of five elements that is divided into two sets, which could be part a
bin_packing()problem of packing five items into two bins with an interest in the number of items packed in the first bin (three in the example solution shown here).>>> from dwave.optimization.model import Model >>> model = Model() >>> bins_set, bins_subsets = model.disjoint_bit_sets(5, 2) >>> in_bin0 = bins_subsets[0].sum() >>> with model.lock(): ... model.states.resize(1) ... bins_set.set_state(0, [[0, 1, 1, 1, 0], [1, 0, 0, 0, 1]]) # Example solution ... print(in_bin0.state(0)) 3.0
Fig. 254 Visualization of the model as a directed acyclic graph. See the
to_networkx()function for information on visualizing models.#
- disjoint_lists(primary_set_size: int, num_disjoint_lists: int) tuple[DisjointLists, tuple[DisjointList, ...]][source]#
Add a disjoint-lists decision variable to the model.
Deprecated since version 0.6.7: The return behavior of this method will be changed in dwave.optimization 0.8.0. Use
disjoint_lists_symbol().A disjoint-lists symbol divides a set of the elements of
range(primary_set_size)intonum_disjoint_listsordered partitions, with the division being assigned as a solution to the problem being modeled.Also creates from the symbol
num_disjoint_listssuccessors that output the disjoint lists as arrays.- Parameters:
primary_set_size – Number of elements in the primary set to be partitioned into disjoint lists. Must be non-negative.
num_disjoint_lists – Number of disjoint lists. Must be positive.
- Returns:
A tuple where the first element is the disjoint-lists symbol at the root of the directed acyclic graph for the model and the second is a list of
num_disjoint_listssuccessors.
Examples
This example creates a symbol of 10 elements that is divided into 4 lists.
>>> from dwave.optimization.model import Model >>> model = Model() >>> destinations, routes = model.disjoint_lists(10, 4)
See also
DisjointLists,DisjointList: Generated symbols
- disjoint_lists_symbol(primary_set_size: int, num_disjoint_lists: int) DisjointLists[source]#
Create a disjoint-lists symbol as a decision variable.
A disjoint-lists symbol divides a set of the elements of
range(primary_set_size)intonum_disjoint_listsordered partitions, where the division is assigned as a solution to the problem being modeled.Also creates from the symbol
num_disjoint_listssuccessors that output the disjoint lists as arrays.- Parameters:
primary_set_size – Number of elements in the primary set to be partitioned into disjoint lists. Must be non-negative.
num_disjoint_lists – Number of disjoint lists. Must be positive.
- Returns:
A disjoint-lists symbol at the root of the directed acyclic graph for the model.
Examples
This example creates a symbol of 10 elements that is divided into 4 lists.
>>> from dwave.optimization.model import Model >>> model = Model() >>> disjoint_lists = model.disjoint_lists_symbol(10, 4) >>> disjoint_lists.primary_set_size() 10 >>> disjoint_lists.num_disjoint_lists() 4 >>> with model.lock(): ... model.states.resize(1) ... disjoint_lists.set_state(0, [[0, 1, 2], [3, 5, 6], [4], [7, 8, 9]]) ... for i, disjoint_list in enumerate(disjoint_lists): ... print(f"Element {i}: {disjoint_list.state(0)}") Element 0: [0. 1. 2.] Element 1: [3. 5. 6.] Element 2: [4.] Element 3: [7. 8. 9.]
Fig. 255 Visualization of the model as a directed acyclic graph. See the
to_networkx()function for information on visualizing models.#
- feasible(index: int = 0) bool[source]#
Check the feasibility of a state.
- Parameters:
index – Index of the state to check for feasibility.
- Returns:
Feasibility of the state.
Examples
This example demonstrates checking the feasibility of a simple model with feasible and infeasible states.
>>> from dwave.optimization.model import Model >>> model = Model() >>> b = model.binary() >>> _ = model.add_constraint(b) >>> model.states.resize(2) >>> b.set_state(0, 1) # Feasible >>> b.set_state(1, 0) # Infeasible >>> with model.lock(): ... model.feasible(0) True >>> with model.lock(): ... model.feasible(1) False
See also
- classmethod from_file(file, *, check_header=True, substitute=None, lock=False)[source]#
Construct a model from the given file.
- Parameters:
file – File pointer to a readable, seekable file-like object encoding a model. Strings are interpreted as a file name. Files are not rewound to the beginning.
substitute – A mapping of symbol substitutions to make when loading the file. The keys are strings giving the node class name to be substituted. The values are callables to create a different node. The callable should have the same signature as the substituted symbol’s constructor.
lock – Whether to return a locked model. Only locked models will include any saved intermediate states.
- Returns:
A model.
Examples
This example serializes a model to a buffered I/O object, then creates a new model from that object.
>>> from dwave.optimization.generators import flow_shop_scheduling ... >>> processing_times = [[10, 5, 7], [20, 10, 15]] >>> model = flow_shop_scheduling(processing_times=processing_times) >>> my_file = model.to_file() ... >>> from dwave.optimization import Model >>> new_model = Model.from_file(my_file)
Changed in version 0.6.0: Add the
substituteandlockkeyword-only arguments.
- input(shape: tuple[int, ...] = (), lower_bound: None | float = -inf, upper_bound: None | float = inf, integral: None | bool = None) Input[source]#
Add an input symbol as a placeholder for a decision variable.
An input symbol functions similarly to a decision variable, in that it takes no predecessors, but its state is always set manually (and not updated if the model is submitted for solution to a solver). Used as a placeholder for input to a model.
The shape of the output array is fixed at initialization and cannot be changed.
The provided bounds and integrality are used to validate the state when set manually; for example, supplied values cannot violate the lower bound.
- Parameters:
shape – Shape of the output array, formatted as an integer or a tuple of integers. If None, creates a zero-dimensional (scalar) input.
lower_bound – Lower bound on any possible output of the node.
upper_bound – Upper bound on any possible output of the node.
integral – Whether the output of the node should always be integral.
- Returns:
An input symbol at the root of the directed acyclic graph for the model.
Examples
This example creates an integer decision symbol and an input symbol it uses to multiply the sums of the integer symbol’s rows.
>>> from dwave.optimization.model import Model >>> model = Model() >>> i = model.integer(shape=(2, 3), lower_bound=-5, upper_bound=5) >>> x = model.input(shape=(2, 1), lower_bound=-2, upper_bound=2, integral=True) >>> y = x*i.sum(axis=1) >>> with model.lock(): ... model.states.resize(1) ... i.set_state(0, [[1, 2, 3], [1, 1, 2]]) ... x.set_state(0, [[1], [-1]]) ... print(y.state(0)) [[ 6. 4.] [-6. -4.]]
Added in version 0.6.2.
- integer(shape: None | _ShapeLike = None, lower_bound: None | numpy.typing.ArrayLike = None, upper_bound: None | numpy.typing.ArrayLike = None, sum_subject_to: None | list[tuple[str, float]] = None, axes_sums_subject_to: None | list[tuple[int, str | list[str], float | list[float]]] = None) IntegerVariable[source]#
Add an integer decision variable to the model.
An integer symbol is an array of integer values assigned as a solution to the problem being modeled.
- Parameters:
shape (optional) – Shape of the integer array to create, formatted as an integer or a tuple of integers. If None, creates a zero-dimensional (scalar) variable.
lower_bound (optional) – Lower bound(s) for the symbol. Can be scalar (one bound for all variables) or an array (one bound for each variable). Non-integer values are rounded up. If None, the default value, zero, is used.
upper_bound (optional) – Upper bound(s) for the symbol. Can be scalar (one bound for all variables) or an array (one bound for each variable). Non-integer values are down up. If None, the default value is used.
sum_subject_to (optional) – Constraint on the sum of the values in the array. Must be an array of tuples where each tuple has the form: (operator, bound). - operator (str): The constraint operator (“<=”, “==”, or “>=”). - bound (float): The constraint bound. If provided, the sum of values within the array must satisfy the corresponding operator–bound pair. Note 1: At most one sum constraint may be provided. Note 2: If provided, axes_sums_subject_to must None.
axes_sums_subject_to (optional) – Constraint on the sum of the values in each slice along a fixed axis in the array. Must be an array of tuples where each tuple has the form: (axis, operator(s), bound(s)). - axis (int): The axis that the constraint is applied to. - operator(s) (str | array[str]): The constraint operator(s) (“<=”, “==”, or “>=”). A single operator applies to all slice along the axis; an array specifies one operator per slice. - bound(s) (float | array[float]): The constraint bound. A single value applies to all slices; an array specifies one bound per slice. If provided, the sum of values within each slice along the specified axis must satisfy the corresponding operator–bound pair. Note 1: At most one sum constraint may be provided. Note 2: If provided, sum_subject_to must None.
- Returns:
An integer symbol at the root of the directed acyclic graph for the model.
Examples
This example adds a \(5\)-sized integer decision variable with scalar bounds to a model, and takes the logarithm of its elements.
>>> from dwave.optimization.model import Model >>> from dwave.optimization.mathematical import log ... >>> model = Model() >>> i = model.integer(5, lower_bound=1, upper_bound=10) >>> i.shape() (5,) >>> a = log(i) >>> with model.lock(): ... model.states.resize(1) ... i.set_state(0, [[1, 2, 3, 1, 2]]) ... print(a.state(0)[0]) 0.0
This example adds a \(2\)-sized integer symbol with a scalar lower bound and index-wise upper bounds to a model.
>>> from dwave.optimization.model import Model >>> import numpy as np >>> model = Model() >>> i = model.integer(2, lower_bound=-1.1, upper_bound=[1.1, 2.9]) >>> np.all([-1, -1] == i.lower_bound()) True >>> np.all([1, 2] == i.upper_bound()) True
This example adds a \((2x3)\)-sized integer symbol with general lower and upper bounds and a sum constraint along axis 1. Let x_i (int i : 0 <= i <= 2) denote the sum of the values within slice i along axis 1. For each state defined for this symbol: (x_0 <= 2), (x_1 <= 4), and (x_2 <= 5).
>>> from dwave.optimization.model import Model >>> import numpy as np >>> model = Model() >>> i = model.integer([2, 3], lower_bound=1, upper_bound=3, ... axes_sums_subject_to=[(1, "<=", [2, 4, 5])]) >>> np.all(i.sum_constraints() == [(1, ["<="], [2, 4, 5])]) True
This example adds a \(6\)-sized integer symbol such that the sum of the values within the array is less than or equal to 20.
>>> from dwave.optimization.model import Model >>> import numpy as np >>> model = Model() >>> i = model.integer(6, sum_subject_to=[("<=", 20)]) >>> np.all(i.sum_constraints() == [(["<="], [20])]) True
Changed in version 0.6.7: Beginning in version 0.6.7, user-defined index-wise bounds are supported.
Changed in version 0.6.13: Beginning in version 0.6.13, user-defined sum constraints are supported.
- into_file(file, *, max_num_states=0, only_decision=False, version=None)[source]#
Serialize the model into an existing file.
- Parameters:
file – File pointer to an existing writeable, seekable file-like object encoding a model. Strings are interpreted as a file name.
max_num_states – Maximum number of states to serialize along with the model. The number of states serialized is the minimum between
size()and the specifiedmax_num_statesvalue.only_decision – If
True, only decision variables are serialized. IfFalse, all symbols are serialized.version – A 2-tuple indicating which serialization version to use.
Format Specification (Version 1.0):
This format is inspired by the NPY format
The first 4 bytes are a magic string: exactly “DWNL”.
The next 1 byte is an unsigned byte: the major version of the file format.
The next 1 byte is an unsigned byte: the minor version of the file format.
The next 4 bytes form a little-endian unsigned int, the length of the header data HEADER_LEN.
The next HEADER_LEN bytes form the header data. This is a json-serialized dictionary. The dictionary contains the following key/values:
decision_state_size,num_nodes,num_states, andstate_size. It is terminated by a newline character and padded with spaces to make the entire length of the entire header divisible by 64.Following the header, the remaining data is encoded as a zip file. All arrays are saved using the NumPy serialization format, see
numpy.save().The information in the header is also saved in a json-formatted file
info.json.The serialization version is saved in a file
version.txt.Each node is listed by type in a file
nodetypes.txt.The adjacency of the nodes is saved in an adjacency format file,
adj.adjlist. E.g., a graph with edges a->b, a->c, b->d would be saved asa b c b d c d
The id of the object is stored in
objective.json, and the list of constraint symbols are stored by id inconstraints.json.Finally each symbol has symbol-specific storage in a directory.
nodes/ <symbol id>/ <symbol-specific storage> ...
The states, if also saved, are saved according to
States.into_file().Format Specification (Version 0.1):
Prior to version 1.0, states were saved differently.
Changed in version 0.5.2: Added the
versionkeyword-only argument.Changed in version 0.6.0: Added support for serialization format version 1.0.
- is_locked()[source]#
Lock status of the model.
No new symbols can be added to a locked model.
- Returns:
True if the model is locked.
- Return type:
Examples
>>> from dwave.optimization.model import Model >>> model = Model() >>> model.is_locked() False
- iter_constraints()[source]#
Iterate over all constraints in the model.
- Yields:
Symbols associated with the constraints.
Examples
This example adds a single constraint to a model and iterates over it.
>>> from dwave.optimization.model import Model >>> model = Model() >>> i = model.integer() >>> c = model.constant(5) >>> _ = model.add_constraint(i <= c) >>> constraint = next(model.iter_constraints()) >>> print(type(constraint)) <class 'dwave.optimization.symbols.binaryop.LessEqual'>
See also
- iter_decisions()[source]#
Iterate over all decision variables in the model.
- Yields:
Decision variables; for example, an
IntegerVariablesymbol.
Examples
This example adds a single decision symbol to a model and iterates over it.
>>> from dwave.optimization.model import Model >>> model = Model() >>> i = model.integer() >>> c = model.constant(5) >>> _ = model.add_constraint(i <= c) >>> decisions = next(model.iter_decisions())
See also
- iter_inputs()[source]#
Iterate over all inputs in the model.
- Yields:
Inputsymbols.
Examples
This example iterates over a model’s inputs.
>>> from dwave.optimization.model import Model >>> model = Model() >>> i0, i1 = model.input(), model.input() >>> c = model.constant(7) >>> inputs = list(model.iter_inputs()) >>> len(inputs) 2
Added in version 0.6.2.
See also
- iter_symbols()[source]#
Iterate over all symbols in the model.
- Yields:
Symbol– Symbols of the model.
Examples
This example iterates over a model’s symbols.
>>> from dwave.optimization.model import Model >>> model = Model() >>> i = model.integer(1, lower_bound=10) >>> c = model.constant([[2, 3], [5, 6]]) >>> symbol_1, symbol_2 = model.iter_symbols()
See also
- list(n: int, min_size: None | int = None, max_size: None | int = None) ListVariable[source]#
Add a list decision variable to the model.
A list symbol is a list containing a permutation of the values in \([0, n-1]\), where the permutation is assigned as a solution to the problem being modeled.
- Parameters:
n – Range of values in the permutations list (zero to \(n - 1\)).
min_size – Minimum list size. Defaults to
max_size.max_size – Maximum list size. Defaults to
n.
- Returns:
A list symbol at the root of the directed acyclic graph for the model.
Examples
This example creates a list symbol of 200 elements.
>>> from dwave.optimization.model import Model >>> model = Model() >>> routes = model.list(200)
This example creates a list symbol with at least 2 elements and at most 4 elements with values between 0 to 99. It sets two states of the decision variable with different lengths.
>>> from dwave.optimization.model import Model >>> model = Model() >>> routes = model.list(99, min_size=2, max_size=4) >>> with model.lock(): ... model.states.resize(2) ... routes.set_state(0, [10, 2, 44]) ... routes.set_state(1, [67, 1])
Changed in version 0.6.12: Beginning in version 0.6.12, sub-lists are supported.
- lock() AbstractContextManager[source]#
Lock the model.
No new symbols can be added to a locked model. Unlocked models do not allow access to methods such as
state()andtopological_index()for successor (non-decision) variables.- Returns:
A context manager. If the context is subsequently exited, the
unlock()method is called.
Examples
This example checks the status of a model after locking it and subsequently unlocking it.
>>> from dwave.optimization.model import Model >>> model = Model() >>> i = model.integer(20, upper_bound=100) >>> cntx = model.lock() >>> model.is_locked() True >>> model.unlock() >>> model.is_locked() False
This example locks a model temporarily with a context manager.
>>> model = Model() >>> with model.lock(): ... # no nodes can be added within the context ... print(model.is_locked()) True >>> model.is_locked() False
See also
- minimize(value: ArraySymbol)[source]#
Set the objective value to minimize.
Optimization problems have an objective and/or constraints. The objective expresses one or more aspects of the problem that should be minimized (equivalent to maximization when multiplied by a minus sign). For example, an optimized itinerary might minimize the value of distance traveled or cost of transportation or travel time.
- Parameters:
value – Value of the cost function to minimize.
Examples
This example minimizes a simple polynomial, \(y = i^2 - 4i\), within bounds.
>>> from dwave.optimization import Model >>> model = Model() >>> i = model.integer(lower_bound=-5, upper_bound=5) >>> c = model.constant(4) >>> y = i*i - c*i >>> model.minimize(y)
See also
- num_constraints()[source]#
Return the number of constraints in the model.
- Returns:
Number of constraints.
- Return type:
Examples
This example checks the number of constraints in the model after adding a couple of constraints.
>>> from dwave.optimization.model import Model >>> model = Model() >>> i = model.integer() >>> c = model.constant([5, -14]) >>> _ = model.add_constraint(i <= c[0]) >>> _ = model.add_constraint(c[1] <= i) >>> model.num_constraints() 2
See also
feasible(),iter_constraints(),num_decisions(),num_symbols()
- num_decisions()[source]#
Return the number of decision variables in the model.
An array-of-integers symbol, for example, counts as a single decision symbol.
- Returns:
Number of independent decision symbols.
- Return type:
Examples
This example checks the number of decisions in a model after adding a single (size 20) decision symbol.
>>> from dwave.optimization.model import Model >>> model = Model() >>> c = model.constant([1, 5, 8.4]) >>> i = model.integer(20, upper_bound=100) >>> model.num_decisions() 1
See also
- num_edges()[source]#
Return the number of edges in the model’s graph.
- Returns:
Number of edges in the directed acyclic graph for the model.
- Return type:
Examples
This example minimizes the sum of a single constant symbol and a single decision symbol, then checks the number of edges in the model.
>>> from dwave.optimization.model import Model >>> model = Model() >>> c = model.constant(5) >>> i = model.integer() >>> model.minimize(c + i) >>> model.num_edges() 2
See also
- num_inputs()[source]#
Return the number of input symbols in the model.
Examples
This example adds two inputs and a constant to a model and checks the number of inputs.
>>> from dwave.optimization.model import Model >>> model = Model() >>> i0, i1 = model.input(), model.input() >>> c = model.constant(7) >>> model.num_inputs() 2
Added in version 0.6.2.
- num_nodes()[source]#
Return the number of nodes in the model’s graph.
- Returns:
Number of nodes in the directed acyclic graph for the model.
- Return type:
Examples
This example adds a single (size 20) decision symbol and a single (size 3) constant symbol, and checks the number of nodes in the model.
>>> from dwave.optimization.model import Model >>> model = Model() >>> c = model.constant([1, 5, 8.4]) >>> i = model.integer(20, upper_bound=100) >>> model.num_nodes() 2
See also
- num_symbols()[source]#
Return the number of symbols in the model.
Equivalent to the number of nodes in the directed acyclic graph for the model.
- Returns:
Number of symbols in the model.
- Return type:
Examples
This example adds a single (size 20) decision symbol and a single (size 3) constant symbol, and checks the number of symbols in the model.
>>> from dwave.optimization.model import Model >>> model = Model() >>> c = model.constant([1, 5, 8.4]) >>> i = model.integer(20, upper_bound=100) >>> model.num_symbols() 2
See also
- property objective: None | ArraySymbol[source]#
Objective to be minimized.
Created when you use the
minimize()method and associated with theArraySymbolbeing minimized; as such, supports such methods asstate(),reshape(),max(), etc.Examples
This example prints the value of the objective of a model representing the simple polynomial, \(y = i^2 - 4i\), for a state with value \(i=2.0\).
>>> 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) >>> with model.lock(): ... model.states.resize(1) ... i.set_state(0, 2.0) ... print(f"Objective = {model.objective.state(0)}") Objective = -4.0
- quadratic_model(x: ArraySymbol, quadratic, linear=None) QuadraticModel[source]#
Add a quadratic model to the model.
Creates a quadratic model from a predecessor
ArraySymboland a quadratic model, such as a QUBO.- Parameters:
x – Predecessor array symbol.
quadratic – Quadratic values for the quadratic model. Can also include linear values as self loops (e.g.,
(3, 3): 2.5).linear – Linear values for the quadratic model.
- Returns:
A successor symbol that outputs the values of a quadratic model on its predecessor symbol’s state.
Examples
This example creates a binary quadratic model (BQM).
>>> from dwave.optimization.model import Model >>> model = Model() >>> x = model.binary(3) >>> Q = {(0, 0): 0, (0, 1): 1, (0, 2): 2, (1, 1): 1, (1, 2): 3, (2, 2): 2} >>> qm = model.quadratic_model(x, Q)
This example creates a quadratic example and prints a state.
>>> from dwave.optimization.model import Model >>> model = Model() >>> i = model.integer(3, lower_bound=-5, upper_bound=10) >>> quad = {(0, 1): 1, (0, 2): 2, (1, 2): 3} >>> lin = {0: 0.5, 1: 1.2, 2: 2.0} >>> qm = model.quadratic_model(i, quadratic=quad, linear=lin) ... >>> with model.lock(): ... model.states.resize(1) ... i.set_state(0, [1, 3, 0]) ... print(qm.state(0).round()) 7.0
See also
QuadraticModel: Generated symbol
- remove_unused_symbols()[source]#
Remove unused symbols from the model.
A symbol is considered unused if all of the following are true :
It is not a decision.
It is not an ancestor of the objective.
It is not an ancestor of a constraint.
It has no
ArraySymbolobject(s) referring to it.
See examples below.
- Returns:
Number of symbols removed.
- Return type:
Examples
This example creates a mix of unused and used symbols, and then removes the unused symbols.
>>> from dwave.optimization import Model >>> model = Model() >>> x = model.binary(5) >>> x.sum() # create a symbol that will never be used <dwave.optimization...Sum at ...> >>> model.minimize(x.prod()) >>> model.num_symbols() 3 >>> model.remove_unused_symbols() 1 >>> model.num_symbols() 2
This example creates a mix of unused and used symbols; however, unlike in the previous example, the unused symbol is assigned to a name in the namespace, preventing from being removed.
>>> from dwave.optimization import Model >>> model = Model() >>> x = model.binary(5) >>> y = x.sum() # create a symbol and assign it a name >>> model.minimize(x.prod()) >>> model.num_symbols() 3 >>> model.remove_unused_symbols() 0 >>> model.num_symbols() 3
See also
- set(n: int, min_size: int = 0, max_size: None | int = None) SetVariable[source]#
Add a set decision variable to the model.
A set symbol is an unordered collection of values in \([0, n-1]\), with the values assigned as a solution to the problem being modeled.
- Parameters:
n – Range of values (zero to \(n-1)\) for the set.
min_size – Minimum set size. Defaults to
0.max_size – Maximum set size. Defaults to
n.
- Returns:
A set symbol at the root of the directed acyclic graph for the model.
Examples
This example creates a set symbol of up to four elements with values between 0 to 99, and sets a set of three elements as a state of the decision variable.
>>> from dwave.optimization.model import Model >>> model = Model() >>> destinations = model.set(100, max_size=4) ... >>> with model.lock(): ... model.states.resize(1) ... destinations.set_state(0, [0, 22, 58])
- state_size()[source]#
Return an estimate of the size, in bytes, of a model’s state.
For a model encoding several array operations, the state of each array must be held in memory. This method returns an estimate of the total memory needed to hold a state for every symbol in the model.
The number of bytes returned by this method is only an estimate. Some symbols hold additional information that is not accounted for.
- Returns:
Size of the state for the model.
- Return type:
Examples
This example estimates the size of a model’s state. In this example a single value is added to a \(5\times4\) array. The output of the addition is also a \(5\times4\) array. Each element of each array requires \(8\) bytes to represent in memory. Therefore the total state size is \((5*4 + 1 + 5*4) * 8 = 328\) bytes.
>>> from dwave.optimization.model import Model >>> model = Model() >>> i = model.integer((5, 4)) # 5x4 array of integers >>> c = model.constant(1) # one scalar value >>> y = i + c # 5x4 array of values >>> model.state_size() # (5*4 + 1 + 5*4) * 8 bytes 328
See also
Symbol.state_size()Estimates the size of a symbol’s stateArraySymbol.state_size()Estimates the size of an array symbol’s stateModel.decision_state_size()Estimates the size of a model’s decision statesStride Solver Properties Properties of the Leap service’s quantum-classical hybrid nonlinear solver, including limits on the maximum state size of a model.
- states: States[source]#
States of the model.
The States class represents assignments of values to a symbol.
Examples
This example resizes the
Statesclass of a simple model to enable the setting of a binary variable. It then clears the set state and the allocated memory.>>> from dwave.optimization.model import Model >>> model = Model() >>> x = model.binary((2, 2)) >>> model.states.resize(1) >>> with model.lock(): ... x.set_state(0, [[0, 0], [1, 0]]) >>> model.states.clear() >>> model.states.size() 0
See also
Statesmethods to read, save, and manipulate the states of a model.
- to_file(**kwargs) BinaryIO[source]#
Serialize the model to a new file-like object.
Examples
This example serializes a model to a buffered I/O object.
>>> from dwave.optimization.generators import flow_shop_scheduling ... >>> processing_times = [[10, 5, 7], [20, 10, 15]] >>> model = flow_shop_scheduling(processing_times=processing_times) ... >>> my_file = model.to_file()
The temporary file created above can be saved to disk, for example, using Python’s
shutilmodule.import shutil my_file.seek(0) # Move cursor to start with open("my_file.bin", "wb") as f: shutil.copyfileobj(my_file, f)
- to_networkx() object[source]#
Convert the model to a NetworkX graph.
- Returns:
A
NetworkXgraph.
Examples
This example converts a model to a graph.
>>> from dwave.optimization.model import Model >>> model = Model() >>> one = model.constant(1) >>> two = model.constant(2) >>> i = model.integer() >>> model.minimize(two * i - one) >>> G = model.to_networkx()
One advantage of converting to NetworkX is the wide availability of drawing tools. See NetworkX’s drawing documentation.
This example uses DAGVIZ to draw the NetworkX graph created in the example above.
>>> import dagviz >>> r = dagviz.render_svg(G) >>> with open("model.svg", "w") as f: ... f.write(r)
This creates the following image:
- unlock()[source]#
Release a lock and decrement the lock count.
Symbols can be added to unlocked models only. Unlocked models do not allow access to methods such as
state()andtopological_index()for successor (non-decision) variables.Examples
This example checks the status of a model.
>>> from dwave.optimization.model import Model >>> model = Model() >>> i = model.integer(20, upper_bound=100) >>> model.is_locked() False
See also
Expressions#
- expression(function: Callable, **kwargs) Expression[source]#
- expression(**kwargs) Callable
Transform a function into an
Expression.Such expressions are used as input by some symbols.
- Parameters:
function – Callable function that is executed once to generate the
Expression.
Examples
>>> from dwave.optimization import expression
>>> @expression ... def func(a, b, c): ... return (a + b) * c
>>> @expression(a=dict(lower_bound=0), b=dict(upper_bound=1)) ... def func(a, b, c): ... return (a + b) * c
See also
Added in version 0.6.4.
- class Expression[source]#
An expression that can be used as an input to other symbols.
Instantiated through the
expression()function.Examples
This example creates expression \(v_0 + 2*(v_1 + 1)\) and uses it for an
AccumulateZipsymbol that calculates the cumulative value of sequential elements of anIntegerVariablesymbol, \(v_1\), where \(v_0\) is the result from the previous elements.For example, for input \(v_1 = [1, 1, 0, 1]\) and an initial value, \(v_0[0]\) of 2, the first element of the
AccumulateZipsymbol is \(2 + 2*(1 + 1) = 6\), the 2nd is therefore \(6 + 2*(1 + 1) = 10\), the 3rd is \(10 + 2*(0 + 1) = 12\), etc.>>> from dwave.optimization import expression, Model >>> from dwave.optimization.symbols import AccumulateZip ... >>> model = Model() >>> i1 = model.integer(4, lower_bound=0, upper_bound=10) ... >>> @expression(v1=dict(lower_bound=-10, upper_bound=20)) ... def func(v0, v1): ... return 2*(v1 + 1) + v0 ... >>> j = AccumulateZip(func, (i1, ), initial=2) ... >>> with model.lock(): ... model.states.resize(1) ... i1.set_state(0,[1, 1, 0, 1]) ... print(j.state(0)) [ 6. 10. 12. 16.]
See also
Added in version 0.6.4.
States Class#
- class States#
States of a model.
States represent assignments of values to the symbols of a model. For example, an
IntegerVariablesymbol of size \(1 \times 5\) might have state[3, 8, 0, 12, 8], representing one assignment of values to the symbol. When the symbol is a decision variable in the model, the state might be (part of) a solution to the modeled problem.You can set the states of a model’s symbols for the purpose of testing your model or providing an initial state for a solver; a model submitted to a solver can have its states updated by returned solutions.
Examples
This example creates a model that includes the polynomial \(k = i^2 + j^2 + 1\) on integer variables and manipulates its states to test that it behaves as expected.
>>> from dwave.optimization import Model ... >>> model = Model() >>> i = model.integer(5, lower_bound=-10, upper_bound=10) # Array of 5 int elements >>> j = model.integer(lower_bound=-4, upper_bound=6) # scalar integer >>> k = i**2 + j**2 + 1
At this point the size of the size of the newly created model’s state is zero: to set states on its symbols, resize it to the number of wanted states using the
resize()method.>>> model.states.size() 0 >>> model.states.resize(2)
Lock the model to enable access to the states of successor symbols (non-decision variables) such as \(k\).
>>> with model.lock(): ... i.set_state(0, [-10, -5, 0, 5, 10]) ... j.set_state(0, 0) ... print(k.state(0)) ... i.set_state(1, [-10, -5, 0, 5, 10]) ... j.set_state(1, 2) ... print(k.state(1)) [101. 26. 1. 26. 101.] [105. 30. 5. 30. 105.]
You can clear the states you set.
>>> model.states.clear() >>> model.states.size() 0
See also
- clear()#
Clear any saved states.
Clears any memory allocated to the states.
Examples
This example clears a state set on an integer decision symbol.
>>> from dwave.optimization.model import Model >>> model = Model() >>> i = model.integer(2) >>> model.states.resize(3) >>> i.set_state(0, [3, 5]) >>> print(i.state(0)) [3. 5.] >>> model.states.clear() >>> model.states.size() 0
- from_file(file, *, replace=True, check_header=True)#
Construct states from the given file.
- Parameters:
- Returns:
States as assigned in the file.
Examples
This example creates a simple model, sets two states, and then saves those states to a buffered I/O object. It clears and then restores the states from file.
>>> from dwave.optimization import Model >>> model = Model() >>> i = model.integer(5, lower_bound=-10, upper_bound=10) >>> j = i**2 + 1 ... >>> with model.lock(): ... model.states.resize(2) ... i.set_state(0, [-10, -5, 0, 5, 10]) ... i.set_state(1, [-8, -3, 1, 4, 9]) ... my_file = model.states.to_file() # Save the states ... >>> model.states.clear() # Clear the states >>> model.states.size() 0 >>> model.states.from_file(my_file) # Restore the states >>> with model.lock(): ... print(j.state(0)) ... print(j.state(1)) [101. 26. 1. 26. 101.] [65. 10. 2. 17. 82.]
- from_future(future, result_hook)#
Populate the states from the result of a future computation.
A
Futureobject is returned by the solver to which you submit your problem model. This enables asynchronous problem submission.This method is intended for use by developers of the Ocean SDK.
- initialize()#
Initialize any uninitialized states.
This method is intended for use by developers of the Ocean SDK.
- into_file(file, *, version=None)#
Serialize the states into an existing file.
- Parameters:
file – File pointer to an existing writeable, seekable file-like object encoding a model. Strings are interpreted as a file name.
version – A 2-tuple indicating which serialization version to use; for example,
(1, 0)represents version 1.0. By default, uses the latest version.
Examples
This example creates a simple model, sets two states, and then saves those states to a buffered I/O object. It then changes a state and saves into the previously created file.
>>> from dwave.optimization import Model >>> model = Model() >>> i = model.integer(5, lower_bound=-10, upper_bound=10) >>> j = i**2 + 1 ... >>> with model.lock(): ... model.states.resize(2) ... i.set_state(0, [-10, -5, 0, 5, 10]) ... i.set_state(1, [-8, -3, 1, 4, 9]) ... my_file = model.states.to_file() # Save the states >>> my_file.seek(0) 0 >>> with model.lock(): # Change a state ... model.states.resize(2) ... i.set_state(0, [-10, -5, 0, 5, 10]) ... i.set_state(1, [-10, -4, 2, 6, 10]) ... model.states.into_file(my_file) # Save into file
Format Specification (Version 1.0):
The first section of the file is the header, as described in
Model.into_file().Following the header, the remaining data is encoded as a zip file. All arrays are saved using the NumPy serialization format, see
numpy.save().The information in the header is also saved in a json-formatted file
info.json.The serialization version is saved in a file
version.txt.The states have the following structure.
Symbols with a state that’s uniquely determined by their predecessor’s states and
Constantsymbols do not have their states serialized.For symbols with a fixed shape and which have all states initialized, the states are stored as a
(num_states, *symbol.shape())array.nodes/ <symbol id>/ states.npy ...
For symbols without a fixed shape, or for which not all states are initialized, the states are each saved in a separate array.
nodes/ <node id>/ states/ <state index>/ array.npy ... ...
This format allows the states and the model to be saved in the same file, sharing the header.
Format Specification (Version 0.1):
Saved as a
Modelencoding only the decision symbols.Changed in version 0.5.2: Added the
versionkeyword-only argument.Changed in version 0.6.0: Added support for serialization format version 1.0.
- resize(n)#
Resize the number of states.
To set the states of a model’s symbols, for the purpose of testing your model or providing an initial state for a solver, you must first set the size of the model’s states. A newly created model has a state size of zero.
Resizing to 0 is not guaranteed to clear the memory allocated to states.
- Parameters:
n (int) – Required number of states. If smaller than the current
size(), states are reduced to the firstnstates by removing those beyond. If greater than the currentsize(), new uninitialized states are added as needed to reach a size ofn.
Examples
This example adds three uninitialized states to a model.
>>> from dwave.optimization.model import Model >>> model = Model() >>> i = model.integer(2) >>> model.states.resize(3)
- resolve()#
Block until states are retrieved from any pending future computations.
A
Futureobject is returned by the solver to which you submit your problem model. This enables asynchronous problem submission.This method is intended for use by developers of the Ocean SDK.
See also
- size()#
Number of model states.
Examples
This example adds three uninitialized states to a model and verifies the number of model states.
>>> from dwave.optimization.model import Model >>> model = Model() >>> model.states.resize(3) >>> model.states.size() 3
See also
- to_file(**kwargs)#
Serialize the states to a new file-like object.
Examples
This example creates a simple model, sets two states, and then saves those states to a buffered I/O object.
>>> from dwave.optimization import Model >>> model = Model() >>> i = model.integer(5, lower_bound=-10, upper_bound=10) >>> j = i**2 + 1 ... >>> with model.lock(): ... model.states.resize(2) ... i.set_state(0, [-10, -5, 0, 5, 10]) ... i.set_state(1, [-8, -3, 1, 4, 9]) ... my_file = model.states.to_file() # Save the states
The temporary file created above can be saved to disk, for example, using Python’s
shutilmodule.import shutil my_file.seek(0) # Move cursor to start with open("my_file.bin", "wb") as f: shutil.copyfileobj(my_file, f)
Functions#
- constant.clear_cache()#
Clear the cache for constant symbols.
To prevent redundancy, constants are cached: Repeated calls to the
constant()method with the same argument, return the firstConstantinstance. After clearing the cache, subsequent such calls create new symbols.Examples
>>> from dwave.optimization import Model ... >>> model = Model() >>> a = model.constant(4) >>> b = model.constant(4) >>> model.constant.clear_cache() >>> c = model.constant(4) >>> b is a True >>> c is a False
See also
- locked(model: _Graph)[source]#
Context manager that holds a locked model and unlocks it upon exiting.
Instantiated through the
lock()method.Examples
This example creates a model, locks it, sets a state for a decision variable, and prints a successor symbol.
>>> from dwave.optimization import Model ... >>> model = Model() >>> i = model.integer(lower_bound=-5, upper_bound=5) >>> j = i**2 >>> with model.lock(): ... model.states.resize(1) ... i.set_state(0, 2) ... print(j.state(0)) 4.0