GithubHelp home page GithubHelp logo

dwavesystems / dwave-optimization Goto Github PK

View Code? Open in Web Editor NEW
5.0 2.0 8.0 509 KB

Enables the formulation of nonlinear models for industrial optimization problems.

License: Apache License 2.0

Python 17.88% Cython 20.97% C++ 60.99% Makefile 0.17%

dwave-optimization's Introduction

https://circleci.com/gh/dwavesystems/dwave-optimization.svg?style=svg

dwave-optimization

dwave-optimization enables the formulation of nonlinear models for industrial optimization problems. The package includes:

  • a class for nonlinear models used by the Leap service's quantum-classical hybrid nonlinear-program solver.
  • model generators for common optimization problems.

(For explanations of the terminology, see the Ocean glossary.)

Example Usage

The flow-shop scheduling problem is a variant of the renowned job-shop scheduling optimization problem. Given n jobs to schedule on m machines, with specified processing times for each job per machine, minimize the makespan (the total length of the schedule for processing all the jobs). For every job, the i-th operation is executed on the i-th machine. No machine can perform more than one operation simultaneously.

This small example builds a model for optimizing the schedule for processing 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)

See the documentation for more examples.

Installation

Installation from PyPI:

pip install dwave-optimization

License

Released under the Apache License 2.0. See LICENSE file.

Contributing

Ocean's contributing guide has guidelines for contributing to Ocean packages.

dwave-optimization` includes some formatting customization in the .clang-format and setup.cfg files.

dwave-optimization's People

Contributors

arcondello avatar joelpasvolsky avatar kevinchern avatar randomir avatar k8culver avatar

Stargazers

Evan Thacker avatar Alexandre avatar Tong Qin avatar William Bernoudy avatar  avatar

Watchers

 avatar sysadmin@dwavesys.com avatar

dwave-optimization's Issues

Consider adding `as_symbol()` method or similar

Similar to numpy.asarray. This would basically be

def as_symbol(model, symbol):
    if isinstance(symbol, Symbol):
        return symbol
    return model.constant(np.asarray(symbol, dtype=double))

or something like that. We could then use it in a bunch of function signatures. Because right now it's clunky to have to do model.constant(...) absolutely everywhere.

Consider changing `Symbol.__repr__()` to report underlying node ID rather than python symbol ID

Right now if you have two different symbols pointing to the same underlying C++ node, you get different reprs. E.g.,

In [4]: from dwave.optimization import Model

In [5]: model = Model()

In [6]: c0 = model.constant(5)

In [7]: c1, = model.iter_symbols()

In [8]: c0
Out[8]: <dwave.optimization.symbols.Constant at 0x7f5d22e28400>

In [9]: c1
Out[9]: <dwave.optimization.symbols.Constant at 0x7f5d203da3e0>

Both of these symbols are referencing the same underlying C++ node, but the repr does not reflect that.

We should consider replacing the 0x... with one pointing to the underlying node pointer.

The cost of course is losing information about the Python object uniqueness, as opposed to the quantity represented uniqueness.

Model allows and creates junk for broadcast operations

For a broadcast operation, junk replaces the smaller symbol in the operation with the bigger symbol:

>>> model = Model()
>>> i = model.integer(10, lower_bound=-50, upper_bound=50)
>>> j = model.integer(1, lower_bound=0, upper_bound=10)
>>> k = i + j
>>> with model.lock():
       model.states.resize(1)
       i.set_state(0, 10*[3])
       j.set_state(0, 4)
       print(k.state(0))
[ 7.00000000e+000  0.00000000e+000  1.58101007e-322  7.95445690e-322
  4.75476306e-310 -1.97001056e+152  0.00000000e+000  0.00000000e+000
  0.00000000e+000  4.75378957e-310]

Expected either that the operation be rejected or a broadcast similar to NumPy:

>>> a = np.asarray([1, 2, 3])
>>> b = np.asarray([5])
>>> a+b
array([6, 7, 8])

Consider adding node removal

Right now it's not possible to remove nodes from a model at any level. It would be nice to have ways to remove extraneous nodes generated as part of construction, or duplicate nodes, etc.

Consider different inheritance patterns

There are two approaches if we want to go this direction:

Virtual inheritance

See #74 for an example.

The advantage is that we can mix several different inheritances. E.g.

struct Node {};
struct Decision {};
struct Array {};

struct ArrayNode : public Array, public virtual Node {};
struct DecisionNode: public Decision, public virtual Node {};

struct ListNode : public ArrayNode, public DecisionNode {};   //<- this is allowed with virtual inheritance.

The downside is a minor performance hit. Because now ListNode does not necessarily know where in memory the "node parts" are.

Direct inheritance

In this case we just do

struct ArrayNode : public Array, public Node {};

The upside is performance. All the array/node points know their relative position. The downside is that we cannot as easily add/compose new node types. So we end up doing things like

struct Node {};
struct Decision {};
struct Array {};

struct ArrayNode : public Array, public Node {};

struct ListNode : public ArrayNode, public Decision {};

Next steps

Performance testing needed.

Inconsistent shape between variable types

A single-valued integer or binary is considered a 1D array but a single-valued constant is a scalar. So it cannot interoperate with the other two as one would expect:

>>> i = np.asarray(5)
>>> i_do = model.integer(1)
>>> print(i.shape, i_do.shape())
() (1,)
>>> x = np.asarray(True, dtype=bool)
>>> x_do = model.binary(1)
>>> print(x.shape, x_do.shape())
() (1,)
...
>>> c_do = model.constant(5)
>>>  print(i.shape, c_do.shape())
() ()

>>> i*x
5
>>> good_mul = i_do*x_do 
>>> c_do*x_do
ValueError: arrays must have the same shape

CopyNode or similar

When reshaping, it's not always possible to return a view. In that case, NumPy makes a copy of the array to be reshaped, and then reshapes the copy.

In [1]: arr = np.arange(40).reshape(10, 4)

In [2]: arr
Out[2]: 
array([[ 0,  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]])

In [3]: arr.base
Out[3]: 
array([ 0,  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])

In [4]: arr[::3, ::2]
Out[4]: 
array([[ 0,  2],
       [12, 14],
       [24, 26],
       [36, 38]])

In [5]: arr[::3, ::2].base
Out[5]: 
array([ 0,  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])

In [6]: arr[::3, ::2].reshape(-1)
Out[6]: array([ 0,  2, 12, 14, 24, 26, 36, 38])

In [7]: arr[::3, ::2].reshape(-1).base
Out[7]: 
array([[ 0,  2],
       [12, 14],
       [24, 26],
       [36, 38]])

In [8]: arr[::3, ::2].reshape(-1).base.base

The CopyNode would take a non-contiguous node and make a contiguous copy.

Model remains locked on erroneous context exit

An error in the lock() context will exit the context but leave the model locked.

>>> from dwave.optimization.model import Model
>>> model = Model()
>>> with model.lock():
            duckbilledplatypus

exits context with error NameError: name 'duckbilledplatypus' is not defined but keeps the model locked:

>>> model.is_locked()
True

Should the lock context have a try context so it can exit gracefully (undo the lock)?

Add symbol labels

We need the ability to label symbols and then retrieve them from their labels. Unfortunately for after launch though.

Silent casting of int symbol's state in some cases

Silent casting of int only when boundaries are defined:

  1. Got what I expected:
>>> i = model.integer()
>>> with model.lock():
            model.states.resize(1)
            i.set_state(0, -2.5)
            print(i.state(0))
ValueError: Invalid data provided for node
  1. Got surprised:
 j = model.integer(lower_bound=-5, upper_bound=0)
>>> with model.lock():
            model.states.resize(1)
            j.set_state(0, -2.5)
            print(j.state(0))
-2.0

Inconsistency for returned value type of `maybe_equals()`

Originally reported by @JoelPasvolsky

Depending on whether it's tested on another symbol or on itself, maybe_equals() returns Boolean or integer:

>>> model = Model()
>>> i = model.integer(100, lower_bound=0, upper_bound=20)
>>> j = model.integer(3, lower_bound=-10, upper_bound=10)
>>> j.maybe_equals(j)
True
>>> j.maybe_equals(i)
0

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.