PyQUBO

PyQUBO allows you to create QUBOs or Ising models from flexible mathematical expressions easily. Some of the features of PyQUBO are

  • Python based (C++ backend).
  • Fully integrated with Ocean SDK. (details)
  • Automatic validation of constraints. (details)
  • Placeholder for parameter tuning. (details)

For more details, see PyQUBO Documentation.

Example Usage

Creating QUBO

This example constructs a simple expression and compile it to model. By calling model.to_qubo(), we get the resulting QUBO. (This example solves Number Partitioning Problem with a set S = {4, 2, 7, 1})

>>> from pyqubo import Spin
>>> s1, s2, s3, s4 = Spin("s1"), Spin("s2"), Spin("s3"), Spin("s4")
>>> H = (4*s1 + 2*s2 + 7*s3 + s4)**2
>>> model = H.compile()
>>> qubo, offset = model.to_qubo()
>>> pprint(qubo)
{('s1', 's1'): -160.0,
('s1', 's2'): 64.0,
('s2', 's2'): -96.0,
('s3', 's1'): 224.0,
('s3', 's2'): 112.0,
('s3', 's3'): -196.0,
('s4', 's1'): 32.0,
('s4', 's2'): 16.0,
('s4', 's3'): 56.0,
('s4', 's4'): -52.0}

Integration with D-Wave Ocean

PyQUBO can output the BinaryQuadraticModel(BQM) which is compatible with Sampler class defined in D-Wave Ocean SDK. In the example below, we solve the problem with SimulatedAnnealingSampler.

>>> import neal
>>> sampler = neal.SimulatedAnnealingSampler()
>>> bqm = model.to_bqm()
>>> sampleset = sampler.sample(bqm, num_reads=10)
>>> decoded_samples = model.decode_sampleset(sampleset)
>>> best_sample = min(decoded_samples, key=lambda x: x.energy)
>>> best_sample.sample # doctest: +SKIP
{'s1': 0, 's2': 0, 's3': 1, 's4': 0}

If you want to solve the problem by actual D-Wave machines, just replace the sampler by a DWaveCliqueSampler instance, for example.

For more examples, see example notebooks.

Benchmarking

Since the core logic of the new PyQUBO (>=1.0.0) is written in C++ and the logic itself is also optimized, the execution time to produce QUBO has become shorter. We benchmarked the execution time to produce QUBOs of TSP with the new PyQUBO (1.0.0) and the previous PyQUBO (0.4.0). The result shows the new PyQUBO runs 1000 times faster as the problem size increases.

https://raw.githubusercontent.com/recruit-communications/pyqubo/master/images/benchmark.svg

Execution time includes building Hamiltonian, compilation, and producing QUBOs. The code to produce the above result is found in here.

Installation

pip install pyqubo

or

python setup.py install

Supported Python Versions

Python 3.5, 3.6, 3.7 and 3.8 are supported.

Supported Operating Systems

  • Linux (32/64bit)
  • OSX (64bit, >=10.9)
  • Win (64bit)

Getting Started

Installation

If you use pip, just type

pip install pyqubo

You can install from the source code like

git clone https://github.com/recruit-communications/pyqubo.git
cd pyqubo
python setup.py install

QUBO and Ising Model

If you want to solve a combinatorial optimization problem by quantum or classical annealing machines, you need to represent your problem in QUBO (Quadratic Unconstrained Binary Optimization) or Ising model. PyQUBO converts your problem into QUBO or Ising model format.

The objective function of QUBO is defined as:

\[\sum_{i \le j}q_{ij}x_{i}x_{j}\]

where \(x_{i}\) represents a binary variable which takes 0 or 1, and \(q_{ij}\) represents a quadratic coefficient. Note that \(q_{ii}x_{i}x_{i}=q_{ii}x_{i}\), since \(x_{i}^2=x_{i}\). Thus, the above expression includes linear terms of \(x_{i}\).

The objective function of Ising model is defined as:

\[\sum_{i}h_{i}s_{i} + \sum_{i<j}J_{ij}s_{i}s_{j}\]

where \(s_{i}\) represents spin variable which takes -1 or 1, \(h_{i}\) represents an external magnetic field and \(J_{ij}\) represents an interaction between spin \(i\) and \(j\).

Basic Usage

With PyQUBO, you can construct QUBOs with 3 steps:

  1. Define the Hamiltonian.
>>> from pyqubo import Spin
>>> s1, s2, s3, s4 = Spin("s1"), Spin("s2"), Spin("s3"), Spin("s4")
>>> H = (4*s1 + 2*s2 + 7*s3 + s4)**2
  1. Compile the Hamiltonian to get a model.
>>> model = H.compile()
  1. Call ‘to_qubo()’ to get QUBO coefficients.
>>> qubo, offset = model.to_qubo()
>>> pprint(qubo) # doctest: +SKIP
{('s1', 's1'): -160.0,
 ('s1', 's2'): 64.0,
 ('s1', 's3'): 224.0,
 ('s1', 's4'): 32.0,
 ('s2', 's2'): -96.0,
 ('s2', 's3'): 112.0,
 ('s2', 's4'): 16.0,
 ('s3', 's3'): -196.0,
 ('s3', 's4'): 56.0,
 ('s4', 's4'): -52.0}
>>> print(offset)
196.0

In this example, you want to solve Number Partitioning Problem with a set S = {4, 2, 7, 1}. The hamiltonian \(H\) is represented as

\[H = (4 s_{1} + 2 s_{2} + 7 s_{3} + s_{4})^2\]

where \(s_{i}\) is a \(i\) th spin variable which indicates a group the \(i\) th number should belong to. In PyQUBO, spin variables are internally converted to binary variables via the relationship \(x_{i} = (s_{i}+1)/2\). The QUBO coefficents and the offset returned from Model.to_qubo() represents the following objective function:

\[\begin{split}&-160 x_{1}x_{1} + 64 x_{1}x_{2} + 224 x_{1}x_{3} + 32 x_{1}x_{4} - 96 x_{2}x_{2}\\ &+ 112 x_{2}x_{3} + 16 x_{2}x_{4} - 196 x_{3}x_{3} + 56 x_{3}x_{4} - 52 x_{4}x_{4} + 196\end{split}\]
  1. Call ‘to_ising()’ to get Ising coefficients.

If you want to get the coefficient of the Ising model, just call to_ising() method like below.

>>> linear, quadratic, offset = model.to_ising()
>>> pprint(linear) # doctest: +SKIP
{'s1': 0.0, 's2': 0.0, 's3': 0.0, 's4': 0.0}
>>> pprint(quadratic) # doctest: +SKIP
{('s1', 's2'): 16.0,
 ('s1', 's3'): 56.0,
 ('s1', 's4'): 8.0,
 ('s2', 's3'): 28.0,
 ('s2', 's4'): 4.0,
 ('s3', 's4'): 14.0}
>>> print(offset)
70.0

where linear represents external magnetic fields \(h\), quadratic represents interactions \(J\) and offset represents the constant value in the objective function below.

\[16 s_{1}s_{2} + 56 s_{1}s_{3} + 8 s_{1}s_{4} + 28 s_{2}s_{3} + 4 s_{2}s_{4} + 14 s_{3}s_{4} + 70\]

Variable: Binary and Spin

When you define a Hamiltonian, you can use Binary or Spin class to represent \(\{0,1\}\) or \(\{1,-1\}\) variable.

Example: If you want to define a Hamiltonian with binary variables \(x \in \{0, 1\}\), use Binary.

>>> from pyqubo import Binary
>>> x1, x2 = Binary('x1'), Binary('x2')
>>> H = 2*x1*x2 + 3*x1
>>> pprint(H.compile().to_qubo()) # doctest: +SKIP
({('x1', 'x1'): 3.0, ('x1', 'x2'): 2.0, ('x2', 'x2'): 0.0}, 0.0)

Example: If you want to define a Hamiltonian with spin variables \(s \in \{-1, 1\}\), use Spin.

>>> from pyqubo import Spin
>>> s1, s2 = Spin('s1'), Spin('s2')
>>> H = 2*s1*s2 + 3*s1
>>> pprint(H.compile().to_qubo()) # doctest: +SKIP
({('s1', 's1'): 2.0, ('s1', 's2'): 8.0, ('s2', 's2'): -4.0}, -1.0)

Solve QUBO by dimod Sampler

PyQUBO model can output the BinaryQuadraticModel(BQM). You can solve BQM by using Sampler class. Sampler is an abstract class defined by dimod package. Various kinds of sampler class, such as SimulatedAnnealingSampler or DWaveSampler, inherits Sampler class.

First, we craete BQM object using to_bqm() method. (If you want to use DWaveSampler which only takes integer-indexed QUBO, you can simply do like to_bqm(index_label=True).)

>>> from pyqubo import Binary
>>> x1, x2 = Binary('x1'), Binary('x2')
>>> H = (x1 + x2 - 1)**2
>>> model = H.compile()
>>> bqm = model.to_bqm()

Next, we create neal.SimulatedAnnealingSampler and use sample() method to get the solutions of QUBO as SampleSet. You can use Model.decode_sampleset() to interpret the sampleset object, and it returns decoded_samples which is a list of pyqubo.DecodedSample object.

>>> import neal
>>> sa = neal.SimulatedAnnealingSampler()
>>> sampleset = sa.sample(bqm, num_reads=10)
>>> decoded_samples = model.decode_sampleset(sampleset)
>>> best_sample = min(decoded_samples, key=lambda x: x.energy)
>>> pprint(best_sample.sample)
{'x1': 0, 'x2': 1}

Array of Variables

Array class represents a multi-dimensional array of Binary or Spin.

Example: You can access each element of the matrix with an index like:

>>> from pyqubo import Array
>>> x = Array.create('x', shape=(2, 3), vartype='BINARY')
>>> x[0, 1] + x[1, 2]
(Binary(x[0][1])+Binary(x[1][2]))

Example: You can use Array to represent multiple spins in the example of partitioning problem above.

>>> from pyqubo import Array
>>> numbers = [4, 2, 7, 1]
>>> s = Array.create('s', shape=4, vartype='SPIN')
>>> H = sum(n * s for s, n in zip(s, numbers))**2
>>> model = H.compile()
>>> qubo, offset = model.to_qubo()
>>> pprint(qubo) # doctest: +SKIP
{('s[0]', 's[0]'): -160.0,
 ('s[0]', 's[1]'): 64.0,
 ('s[0]', 's[2]'): 224.0,
 ('s[0]', 's[3]'): 32.0,
 ('s[1]', 's[1]'): -96.0,
 ('s[1]', 's[2]'): 112.0,
 ('s[1]', 's[3]'): 16.0,
 ('s[2]', 's[2]'): -196.0,
 ('s[2]', 's[3]'): 56.0,
 ('s[3]', 's[3]'): -52.0}

Placeholder

If you have a parameter that you will probably update, such as the strength of the constraints in your hamiltonian, using Placeholder will save your time. If you define the parameter by Placeholder, you can specify the value of the parameter after compile. This means that you don’t have to compile repeatedly for getting QUBOs with various parameter values. It takes longer time to execute a compile when the problem size is bigger. In that case, you can save your time by using Placeholder.

Example: If you have an objective function \(2a+b\), and a constraint \(a+b=1\) whose hamiltonian is \((a+b-1)^2\) where \(a,b\) is qbit variable, you need to find the penalty strength \(M\) such that the constraint is satisfied. Thus, you need to create QUBO with different values of \(M\). In this example, we create QUBO with \(M=5.0\) and \(M=6.0\).

In the first code, we don’t use placeholder. In this case, you need to compile the hamiltonian twice to get a QUBO with \(M=5.0\) and \(M=6.0\).

>>> from pyqubo import Binary
>>> a, b = Binary('a'), Binary('b')
>>> M = 5.0
>>> H = 2*a + b + M*(a+b-1)**2
>>> model = H.compile()
>>> qubo, offset = model.to_qubo() # QUBO with M=5.0
>>> M = 6.0
>>> H = 2*a + b + M*(a+b-1)**2
>>> model = H.compile()
>>> qubo, offset = model.to_qubo() # QUBO with M=6.0

If you don’t want to compile twice, define \(M\) by Placeholder.

>>> from pyqubo import Placeholder
>>> a, b = Binary('a'), Binary('b')
>>> M = Placeholder('M')
>>> H = 2*a + b + M*(a+b-1)**2
>>> model = H.compile()
>>> qubo, offset = model.to_qubo(feed_dict={'M': 5.0})

You get a QUBO with different value of M without compile

>>> qubo, offset = model.to_qubo(feed_dict={'M': 6.0})

The actual value of the placeholder \(M\) is specified in calling Model.to_qubo() as a value of the feed_dict.

Validation of Constraints

When you get a solution from the Sampler, Model.decode_sample() decodes the sample and returns DecodedSample object.

Example: You are solving a partitioning problem.

>>> from pyqubo import Binary, Constraint
>>> a, b = Binary('a'), Binary('b')
>>> M = 5.0 # strength of the constraint
>>> H = 2*a + b + M * Constraint((a+b-1)**2, label='a+b=1')
>>> model = H.compile()

Let’s assume that you get a solution {'a': 0, 'b': 1} from the solver.

>>> raw_solution = {'a': 0, 'b': 1} # solution from the solver
>>> decoded_sample = model.decode_sample(raw_solution, vartype='BINARY')
>>> pprint(decoded_sample.sample)
{'a': 0, 'b': 1}
>>> pprint(decoded_sample.constraints())
{'a+b=1': (True, 0.0)}
>>> pprint(decoded_sample.constraints(only_broken=True))
{}

You can access to the dict of the sample via decoded_sample.sample. You can also access to the value of the constraint of the Hamiltonian via decoded_sample.constraints(). If you specify the argument only_broken=True, only broken constraint will be returned. If the empty dict is returned, it indicates that there is no broken constraint corresponding to the given sample.

Contribution

Thank you for contributing to PyQUBO.

Propose a new feature and implement

  1. If you have a proposal of new features, send a pull request with your idea and we will discuss it.
  2. Once we agree with the new feature, implement the feature. If you implement a new module on top of PyQUBO, create your module inside the pyqubo/contrib directory.

Implement a feature or bug-fix for an existing issue

  1. See the issue list of github.
  2. Choose an issue and comment on the task that you will work on.
  3. Send a pull request.

Implementing unittests for your feature helps a review process.

Installation

If you already installed PyQUBO, uninstall it.

pip uninstall pyqubo

Install PyQUBO with development mode

python setup.py develop

Coding Conventions

  • Follow PEP8.
  • Write docstring with Google docstrings convention.
  • Write unit tests.
  • Write comments when the code is complicated. But the best documentation is clean code with good variable names.

Unit Testing

To run unit tests, you have two options. One option is to run with unittest or coverage command. To run all tests with unittest, execute

python -m unittest discover tests

To generate coverage reports, execute

coverage run -m unittest discover
coverage html

You will see html files of the report in htmlcov directory.

Second option is to run test using docker container with circleci CLI locally. To run test with circleci CLI, execute

circleci build --job $JOBNAME

$JOBNAME needs to be replaced with a job name such as test-3.6, listed in .circleci/config.yml. To install circleci CLI, refer to https://circleci.com/docs/2.0/local-cli/.

Documentation

Documents are created by sphinx from the docstring in Python code. When you add a new class, please create a new rst file in docs/reference directory. If the information of the class is not important for library users, create a file under internal directory. To build html files of document locally, execute

make clean html

You can see built htmls in docs/_build directory. When you write an example code in docstring, you can test the code with doctest. To run doctest, execute

make doctest

Expression

class Base

Abstract class of pyqubo expression.

All basic component class such as Binary, Spin or Add inherits Base.

For example, an expression \(2ab+1\) (where \(a, b\) is Binary variable) is represented by the binary tree above.

Note

This class is an abstract class of all component of expressions.

Example:

We write mathematical expressions with objects such as Binary or Spin which inherit Base.

>>> from pyqubo import Binary
>>> a, b = Binary("a"), Binary("b")
>>> 2*a*b + 1
(Binary(a)*Num(2.000000)*Binary(b)+Num(1.000000))
compile(strength=5.0)

Returns the compiled Model.

This method reduces the degree of the expression if the degree is higher than 2, and convert it into Model which has information about QUBO.

Parameters:strength (float) – The strength of the reduction constraint. Insufficient strength can result in the binary quadratic model not having the same minimizations as the polynomial.
Returns:The model compiled from the Base.
Return type:Model

Examples:

In this example, there are higher order terms \(abc\) and \(abd\). It is decomposed as [[a*b, c], d] hierarchically and converted into QUBO. By calling to_qubo() of the model, we get the QUBO.

>>> from pyqubo import Binary
>>> a, b, c, d = Binary("a"), Binary("b"), Binary("c"), Binary("d")
>>> model = (a*b*c + a*b*d).compile()
>>> pprint(model.to_qubo()) # doctest: +SKIP
({('a', 'a'): 0.0,
  ('a', 'a*b'): -10.0,
  ('a', 'b'): 5.0,
  ('a*b', 'a*b'): 15.0,
  ('a*b', 'b'): -10.0,
  ('a*b', 'c'): 1.0,
  ('a*b', 'd'): 1.0,
  ('b', 'b'): 0.0,
  ('c', 'c'): 0,
  ('d', 'd'): 0},
 0.0)

Binary

class Binary(label)

Binary variable i.e. {0, 1}.

Parameters:label (str) – The label of a variable. A variable is identified by this label.

Example:

Example code to create an expression.

>>> from pyqubo import Binary
>>> a, b = Binary('a'), Binary('b')
>>> exp = 2*a*b + 3*a
>>> pprint(exp.compile().to_qubo())   # doctest: +SKIP
({('a', 'a'): 3.0, ('a', 'b'): 2.0, ('b', 'b'): 0}, 0.0)

Spin

class Spin(label)

Spin variable i.e. {-1, 1}.

Parameters:label (str) – The label of a variable. A variable is identified by this label.

Example:

Example code to create an expression.

>>> from pyqubo import Spin
>>> a, b = Spin('a'), Spin('b')
>>> exp = 2*a*b + 3*a
>>> pprint(exp.compile().to_qubo()) # doctest: +SKIP
({('a', 'a'): 2.0, ('a', 'b'): 8.0, ('b', 'b'): -4.0}, -1.0)

Placeholder

class Placeholder(label)

Placeholder expression.

You can specify the value of the Placeholder when creating the QUBO. By using Placeholder, you can change the value without compiling again. This is useful when you need to update the strength of constraint gradually.

Parameters:label (str) – The label of the placeholder.

Example:

The value of the placeholder is specified when you call to_qubo().

>>> from pyqubo import Binary, Placeholder
>>> x, y, a = Binary('x'), Binary('y'), Placeholder('a')
>>> exp = a*x*y + 2.0*x
>>> pprint(exp.compile().to_qubo(feed_dict={'a': 3.0})) # doctest: +SKIP
({('x', 'x'): 2.0, ('x', 'y'): 3.0, ('y', 'y'): 0}, 0.0)
>>> pprint(exp.compile().to_qubo(feed_dict={'a': 5.0})) # doctest: +SKIP
({('x', 'x'): 2.0, ('x', 'y'): 5.0, ('y', 'y'): 0}, 0.0)

SubH

class SubH(hamiltonian, label, as_constraint=False)

SubH expression. The parent class of Constraint. You can specify smaller sub-hamiltonians in your expression.

Parameters:
  • hamiltonian (Base) – The expression you want to specify as a sub-hamiltonian.
  • label (str) – The label of the sub-hamiltonian. Sub-hamiltonians can be identified by their labels.
  • as_constraint (boolean) – Whether or not the sub-hamiltonian should also be treated as a constraint. False by default.

Example:

You can call namespaces to identify the labels defined in a model.

>>> from pyqubo import Spin, SubH
>>> s1, s2, s3 = Spin('s1'), Spin('s2'), Spin('s3')
>>> exp = (SubH(s1 + s2, 'n1'))**2 + (SubH(s1 + s3, 'n2'))**2
>>> model = exp.compile()
>>> model.namespaces  #doctest: +SKIP
({'n1': {'s1', 's2'}, 'n2': {'s1', 's3'}}, {'s1', 's2', 's3'})

Constraint

class Constraint(hamiltonian, label, condition=lambda x: x==0.0)

Constraint expression. You can specify the constraint part in your expression.

Parameters:
  • child (Express) – The expression you want to specify as a constraint.
  • label (str) – The label of the constraint. You can identify constraints by the label.
  • (float => boolean) condition (func) – function to indicate whether the constraint is satisfied or not. Default is lambda x: x == 0.0. function takes float value and returns boolean value. You can define the condition where the constraint is satisfied.

Example:

When the Hamiltonian contains Constraint, you know whether each constraint is satisfied or not by accessing to DecodedSample.

>>> from pyqubo import Binary, Constraint
>>> a, b = Binary('a'), Binary('b')
>>> H = Constraint(a+b-2, "const1") + Constraint(a+b-1, "const2")
>>> model = H.compile()
>>> dec = model.decode_sample({'a': 1, 'b': 0}, vartype='BINARY')
>>> pprint(dec.constraints())
{'const1': (False, -1.0), 'const2': (True, 0.0)}
>>> pprint(dec.constraints(only_broken=True))
{'const1': (False, -1.0)}

Add

class Add(left, right)

Addition of expressions.

Parameters:
  • left (Base) – An expression
  • right (Base) – An expression

Example:

You can add expressions with either the built-in operator or Add.

>>> from pyqubo import Binary, Add
>>> a, b = Binary('a'), Binary('b')
>>> a + b
(Binary(a)+Binary(b))
>>> Add(a, b)
(Binary(a)+Binary(b))

Mul

class Mul(left, right)

Product of expressions.

Parameters:
  • left (Base) – An expression
  • right (Base) – An expression

Example:

You can multiply expressions with either the built-in operator or Mul.

>>> from pyqubo import Binary, Mul
>>> a, b = Binary('a'), Binary('b')
>>> a * b
Binary(a)*Binary(b)
>>> Mul(a, b)
Binary(a)*Binary(b)

Num

class Num(value)

Expression of number

Parameters:value (float) – the value of the number.

Example:

Example code to create an expression.

>>> from pyqubo import Binary, Num
>>> a = Binary('a')
>>> a + 1
(Binary(a)+Num(1.000000))
>>> a + Num(1)
(Binary(a)+Num(1.000000))

UserDefinedExpress

class UserDefinedExpress

User defined express.

User can define their own expression by inheriting UserDefinedExpress.

Example:

Define the LogicalAnd class by inheriting UserDefinedExpress.

>>> from pyqubo import UserDefinedExpress, Binary
>>> class LogicalAnd(UserDefinedExpress):
...     def __init__(self, bit_a, bit_b):
...         express = bit_a * bit_b
...         super().__init__(express)
>>> a, b = Binary('a'), Binary('b')
>>> logical_and = LogicalAnd(a, b)

WithPenalty

class WithPenalty

You can define the custum penalty class by inheriting WithPenalty. The penalty argument will be added to the generated Hamiltonian. Integer classes with constraints, such as OneHotEncInteger, are defined using this class.

Example:

Define the custom penalty class inheriting WithPenalty. We initialize this class with hamiltonian \(h\). The constraint term \((h-1)^2\) will be added to the generated Hamiltonian.

>>> from pyqubo import WithPenalty
>>> class CustomPenalty(WithPenalty):
...     def __init__(self, hamiltonian, label, strength):
...         penalty = strength * (hamiltonian-1)**2
...         super().__init__(hamiltonian, penalty, label)
>>> a, b = Binary("a"), Binary("b")
>>> p = CustomPenalty(a+b, label="penalty", strength=2.0)
>>> model = (p+1).compile()
>>> qubo, offset = model.to_qubo()

Model

Model

class Model

Model represents binary quadratic optimization problem.

By compiling Express object, you get a Model object. It contains the information about QUBO (or equivalent Ising Model), and it also has the function to decode the solution into the original variable structure.

Note

We do not need to create this object directly. Instead, we get this by compiling Express objects.

Generate QUBO, Ising model, and BQM

to_qubo() Returns QUBO and energy offset.
to_ising() Returns Ising Model and energy offset.
to_bqm() Returns dimod.BinaryQuadraticModel.

Interpret samples returned from solvers

energy() Returns energy of the sample.
decode_sample() Returns Ising Model and energy offset.
decode_sampleset() Decode the sample represented by dimod.SampleSet.
to_qubo(index_label=False, feed_dict=None)

Returns QUBO and energy offset.

Parameters:
  • index_label (bool) – If true, the keys of returned QUBO are indexed with a positive integer number.
  • feed_dict (dict[str,float]) – If the expression contains Placeholder objects, you have to specify the value of them by Placeholder. Please refer to Placeholder for more details.
Returns:

Tuple of QUBO and energy offset. QUBO takes the form of dict[(str, str), float].

Return type:

tuple[QUBO, float]

Examples:

This example creates the model from the expression, and we get the resulting QUBO by calling model.to_qubo().

>>> from pyqubo import Binary
>>> x, y, z = Binary("x"), Binary("y"), Binary("z")
>>> model = (x*y + y*z + 3*z).compile()
>>> pprint(model.to_qubo()) # doctest: +SKIP
({('x', 'x'): 0.0,
('x', 'y'): 1.0,
('y', 'y'): 0.0,
('z', 'y'): 1.0,
('z', 'z'): 3.0},
0.0)

If you want a QUBO which has index labels, specify the argument index_label=True. The mapping of the indices and the corresponding labels is stored in model.variables.

>>> pprint(model.to_qubo(index_label=True)) # doctest: +SKIP
({(0, 0): 3.0, (0, 2): 1.0, (1, 1): 0.0, (1, 2): 1.0, (2, 2): 0.0}, 0.0)
>>> model.variables
['z', 'x', 'y']
to_ising(index_label=False, feed_dict=None)

Returns Ising Model and energy offset.

Parameters:
  • index_label (bool) – If true, the keys of returned QUBO are indexed with a positive integer number.
  • feed_dict (dict[str,float]) – If the expression contains Placeholder objects, you have to specify the value of them by Placeholder. Please refer to Placeholder for more details.
Returns:

Tuple of Ising Model and energy offset. Where linear takes the form of (dict[str, float]), and quadratic takes the form of dict[(str, str), float].

Return type:

tuple(linear, quadratic, float)

Examples:

This example creates the model from the expression, and we get the resulting Ising model by calling to_ising().

>>> from pyqubo import Binary
>>> x, y, z = Binary("x"), Binary("y"), Binary("z")
>>> model = (x*y + y*z + 3*z).compile()
>>> pprint(model.to_ising()) # doctest: +SKIP
({'x': 0.25, 'y': 0.5, 'z': 1.75}, {('x', 'y'): 0.25, ('z', 'y'): 0.25}, 2.0)

If you want a Ising model which has index labels, specify the argument index_label=True. The mapping of the indices and the corresponding labels is stored in model.variables.

>>> pprint(model.to_ising(index_label=True)) # doctest: +SKIP
({0: 1.75, 1: 0.25, 2: 0.5}, {(0, 2): 0.25, (1, 2): 0.25}, 2.0)
>>> model.variables
['z', 'x', 'y']
to_bqm(index_label=False, feed_dict=None)

Returns dimod.BinaryQuadraticModel.

For more details about dimod.BinaryQuadraticModel, see dimod.BinaryQuadraticModel.

Parameters:
  • index_label (bool) – If true, the keys of returned QUBO are indexed with a positive integer number.
  • feed_dict (dict[str,float]) – If the expression contains Placeholder objects, you have to specify the value of them by Placeholder.
Returns:

dimod.BinaryQuadraticModel with vartype set to dimod.BINARY.

Return type:

dimod.BinaryQuadraticModel

Examples:

>>> from pyqubo import Binary, Constraint
>>> from dimod import ExactSolver
>>> a, b = Binary('a'), Binary('b')
>>> H = Constraint(2*a-3*b, "const1") + Constraint(a+b-1, "const2")
>>> model = H.compile()
>>> bqm = model.to_bqm()
>>> sampleset = ExactSolver().sample(bqm)
>>> decoded_samples = model.decode_sampleset(sampleset)
>>> best_sample = min(decoded_samples, key=lambda s: s.energy)
>>> print(best_sample.energy)
-3.0
>>> pprint(best_sample.sample)
{'a': 0, 'b': 1}
>>> pprint(best_sample.constraints())
{'const1': (False, -3.0), 'const2': (True, 0.0)}
energy(solution, vartype, feed_dict=None)

Returns energy of the sample.

Parameters:
  • sample (list[int]/dict[str,int]) – The sample returned from solvers.
  • vartype (str) – Variable type of the solution. Specify either 'BINARY' or 'SPIN'.
  • feed_dict (dict[str,float]) – Specify the placeholder values.
Returns:

Calculated energy.

Return type:

float

decode_sample(sample, vartype, feed_dict=None)

Decode sample from solvers.

Parameters:
  • sample (list[int]/dict[str,int]) – The sample returned from solvers.
  • vartype (str) – Variable type of the solution. Specify either 'BINARY' or 'SPIN'.
  • feed_dict (dict[str,float]) – Specify the placeholder values.
Returns:

DecodedSample object.

Return type:

DecodedSample

Examples

>>> from pyqubo import Binary, SubH
>>> a, b = Binary('a'), Binary('b')
>>> H = SubH(a+b-2, "subh1") + 2*a + b
>>> model = H.compile()
>>> decoded_sample = model.decode_sample({'a': 1, 'b': 0}, vartype='BINARY')
>>> print(decoded_sample.energy)
1.0
>>> pprint(decoded_sample.sample)
{'a': 1, 'b': 0}
>>> print(decoded_sample.subh)
{'subh1': -1.0}
decode_sampleset(sampleset, feed_dict=None)

Decode the sample represented by dimod.SampleSet.

For more details about dimod.SampleSet, see dimod.SampleSet.

Parameters:
  • sample (dimod.SampleSet) – The solution returned from dimod sampler.
  • feed_dict (dict[str,float]) – Specify the placeholder values. Default=None
Returns:

DecodedSample object.

Return type:

DecodedSample

Examples

>>> from pyqubo import Binary, Constraint
>>> from dimod import ExactSolver
>>> a, b = Binary('a'), Binary('b')
>>> H = Constraint(2*a-3*b, "const1") + Constraint(a+b-1, "const2")
>>> model = H.compile()
>>> bqm = model.to_bqm()
>>> sampleset = ExactSolver().sample(bqm)
>>> decoded_samples = model.decode_sampleset(sampleset)
>>> best_sample = min(decoded_samples, key=lambda s: s.energy)
>>> print(best_sample.energy)
-3.0
>>> pprint(best_sample.sample)
{'a': 0, 'b': 1}
>>> pprint(best_sample.constraints())
{'const1': (False, -3.0), 'const2': (True, 0.0)}

DecodedSample

class DecodedSample

DecodedSample contains the informatin like whether the constraint is satisfied or not, or the value of the SubHamiltonian.

Examples

>>> from pyqubo import Binary, SubH
>>> a, b = Binary('a'), Binary('b')
>>> H = SubH(a+b-2, "subh1") + 2*a + b
>>> model = H.compile()
>>> decoded_sample = model.decode_sample({'a': 1, 'b': 0}, vartype='BINARY')
>>> print(decoded_sample.energy)
1.0
>>> pprint(decoded_sample.sample)
{'a': 1, 'b': 0}
>>> print(decoded_sample.subh)
{'subh1': -1.0}

Methods

array() Get the value of the array element specified.
constraints() Returns the information about constraints.
array(array_name, index)

Get the value of the array specified by array_name and index.

Parameters:
  • array_name (str) – The name of the array.
  • index (int/tuple) – The index of the array.
Returns:

The value of the array calculated by the sample.

Return type:

float

Examples

>>> from pyqubo import Array
>>> x = Array.create('x', shape=(2, 1), vartype="BINARY")
>>> H = (x[0, 0] + x[1, 0] - 1)**2
>>> model = H.compile()
>>> qubo, offset = model.to_qubo()
>>> pprint(qubo)
{('x[0][0]', 'x[0][0]'): -1.0,
('x[0][0]', 'x[1][0]'): 2.0,
('x[1][0]', 'x[1][0]'): -1.0}
>>> dec = model.decode_sample({'x[0][0]': 1, 'x[1][0]': 0}, vartype='BINARY')
>>> print(dec.array('x', (0, 0)))
1
>>> print(dec.array('x', (1, 0)))
0
constraints(only_broken)

Get the value of the array specified by array_name and index.

Parameters:only_broken (bool) – Whether to select only broken constraints.
Returns:Dictionary with the key being the label of the constraint and the value being the boolean and the corresponding energy value. The boolean value indicates whether the constraint is satisfied or not.
Return type:dict[str, tuple[bool, float]]

Examples

>>> from pyqubo import Binary, Constraint
>>> a, b = Binary('a'), Binary('b')
>>> H = Constraint(a+b-2, "const1") + Constraint(a+b-1, "const2")
>>> model = H.compile()
>>> dec = model.decode_sample({'a': 1, 'b': 0}, vartype='BINARY')
>>> pprint(dec.constraints())
{'const1': (False, -1.0), 'const2': (True, 0.0)}
>>> pprint(dec.constraints(only_broken=True))
{'const1': (False, -1.0)}

Array

class Array(bit_list)[source]

Multi-dimensional array.

Parameters:bit_list (list/numpy.ndarray) –

The object from which a new array is created. Accepted input:

  • (Nested) list of Express, Array, int or float.
  • numpy.ndarray
shape

Shape of this array.

Type:tuple[int]

Example

Create a new array with Binary.

>>> from pyqubo import Array, Binary
>>> Array.create('x', shape=(2, 2), vartype='BINARY')
Array([[Binary(x[0][0]), Binary(x[0][1])],
       [Binary(x[1][0]), Binary(x[1][1])]])

Create a new array from a nested list of Express.

>>> array = Array([[Binary('x0'), Binary('x1')], [Binary('x2'), Binary('x3')]])
>>> array
Array([[Binary(x0), Binary(x1)],
       [Binary(x2), Binary(x3)]])

Get the shape of the array.

>>> array.shape
(2, 2)

Access an element with index.

>>> array[0, 0]  # = array[(0, 0)]
Binary(x0)

Use slice “:” to select a subset of the array.

>>> array[:, 1]  # = array[(slice(None), 1)]
Array([Binary(x1), Binary(x3)])
>>> sum(array[:, 1])
(Binary(x1)+Binary(x3))

Use list or tuple to select a subset of the array.

>>> array[[0, 1], 1]
Array([Binary(x1), Binary(x3)])
>>> array[(0, 1), 1]
Array([Binary(x1), Binary(x3)])

Create an array from numpy array.

>>> import numpy as np
>>> Array(np.array([[1, 2], [3, 4]]))
Array([[1, 2],
       [3, 4]])

Create an array from list of Array.

>>> Array([Array([1, 2]), Array([3, 4])])
Array([[1, 2],
       [3, 4]])
static Array.create(name, shape, vartype)[source]

Create a new array with Spins or Binary.

Parameters:
  • name (str) – Name of the matrix. It is used as a part of the label of variables. For example, if the name is ‘x’, the label of (i, j) th variable will be x[i][j].
  • shape (int/tuple[int]) – Dimensions of the array.
  • vartype (dimod.Vartype/str/set, optional) –

    Variable type of the solution. Accepted input values:

    • Vartype.SPIN, 'SPIN', {-1, 1}
    • Vartype.BINARY, 'BINARY', {0, 1}

Example

>>> from pyqubo import Array
>>> array = Array.create('x', shape=(2, 2), vartype='BINARY')
>>> array # doctest: +SKIP
Array([[Binary(x[0][0]), Binary(x[0][1])],
       [Binary(x[1][0]), Binary(x[1][1])]])
>>> array[0] # doctest: +SKIP
Array([Binary(x[0][0]), Binary(x[0][1])])

Matrix Operation

Array.T Returns a transposed array.
Array.dot(other) Returns a dot product of two arrays.
Array.matmul(other) Returns a matrix product of two arrays.
Array.reshape(new_shape) Returns a reshaped array.

Arithmetic Operation

Array.add(other) Returns a sum of self and other.
Array.subtract(other) Returns a difference between other and self.
Array.mul(other) Returns a multiplicity of self by other.
Array.div(other) Returns division of self by other.

Construction

Array.fill(obj, shape) Create a new array with the given shape, all filled with the given object.

Integer

Summary of each integer encoding, whose value takes [0, n].

Encoding Value Constraint #vars Max abs. coeff of value
UnaryEncInteger \(\sum_{i=1}^{n}x_{i}\) No constraint \(n\) \(1\)
LogEncInteger \(\sum_{i=1}^{d}2^i x_{i}\) No constraint \(\lceil\log_{2}n\rceil(=d)\) \(2^d\)
OneHotEncInteger \(\sum_{i=0}^{n}ix_{i}\) \((\sum_{i=0}^{n}x_{i}-1)^2\) \(n+1\) \(n\)
OrderEncInteger \(\sum_{i=1}^{n}x_{i}\) \(\sum_{i=1}^{n-1}x_{i+1}(1-x_{i})\) \(n\) \(1\)

UnaryEncInteger

class UnaryEncInteger(label, value_range)[source]

Unary encoded integer. The value that takes \([0, n]\) is represented by \(\sum_{i=1}^{n}x_{i}\) without any constraint.

Parameters:
  • label (str) – Label of the integer.
  • lower (int) – Lower value of the integer.
  • upper (int) – Upper value of the integer.

Examples

This example finds the value a, b such that \(a+b=3\) and \(2a-b=0\).

>>> from pyqubo import UnaryEncInteger
>>> import dimod
>>> a = UnaryEncInteger("a", (0, 3))
>>> b = UnaryEncInteger("b", (0, 3))
>>> M=2.0
>>> H = (2*a-b)**2 + M*(a+b-3)**2
>>> model = H.compile()
>>> bqm = model.to_bqm()
>>> import dimod
>>> sampleset = dimod.ExactSolver().sample(bqm)
>>> decoded_samples = model.decode_sampleset(sampleset)
>>> best_sample = min(decoded_samples, key=lambda s: s.energy)
>>> print(best_sample.subh['a'])
1.0
>>> print(best_sample.subh['b'])
2.0

LogEncInteger

class LogEncInteger(label, value_range)[source]

Log encoded integer. The value that takes \([0, n]\) is represented by \(\sum_{i=1}^{\lceil\log_{2}n\rceil}2^ix_{i}\) without any constraint.

Parameters:
  • label (str) – Label of the integer.
  • lower (int) – Lower value of the integer.
  • upper (int) – Upper value of the integer.

Examples

This example finds the value a, b such that \(a+b=5\) and \(2a-b=1\).

>>> from pyqubo import LogEncInteger
>>> import dimod
>>> a = LogEncInteger("a", (0, 4))
>>> b = LogEncInteger("b", (0, 4))
>>> M=2.0
>>> H = (2*a-b-1)**2 + M*(a+b-5)**2
>>> model = H.compile()
>>> bqm = model.to_bqm()
>>> import dimod
>>> sampleset = dimod.ExactSolver().sample(bqm)
>>> decoded_samples = model.decode_sampleset(sampleset)
>>> best_sample = min(decoded_samples, key=lambda s: s.energy)
>>> print(best_sample.subh['a'])
2.0
>>> print(best_sample.subh['b'])
3.0

OneHotEncInteger

class OneHotEncInteger(label, value_range, strength)[source]

One-hot encoded integer. The value that takes \([1, n]\) is represented by \(\sum_{i=1}^{n}ix_{i}\). Also we have the penalty function \(strength \times (\sum_{i=1}^{n}x_{i}-1)^2\) in the Hamiltonian.

Parameters:
  • label (str) – Label of the integer.
  • lower (int) – Lower value of the integer.
  • upper (int) – Upper value of the integer.
  • strength (float/Placeholder) – Strength of the constraint.

Examples

This example is equivalent to the following Hamiltonian.

\[H = \left(\left(\sum_{i=1}^{3}ia_{i}+1\right) - 2\right)^2 + strength \times \left(\sum_{i=1}^{3}a_{i}-1\right)^2\]
>>> from pyqubo import OneHotEncInteger
>>> a = OneHotEncInteger("a", (1, 3), strength=5)
>>> H = (a-2)**2
>>> model = H.compile()
>>> bqm = model.to_bqm()
>>> import dimod
>>> sampleset = dimod.ExactSolver().sample(bqm)
>>> decoded_samples = model.decode_sampleset(sampleset)
>>> best_sample = min(decoded_samples, key=lambda s: s.energy)
>>> print(best_sample.subh['a'])
2.0
equal_to(k)[source]

Variable representing whether the value is equal to k.

Note

You cannot use this method alone. You should use this variable with the entire integer.

Parameters:k (int) – Integer value.
Returns:Express

OrderEncInteger

class OrderEncInteger(label, value_range, strength)[source]

Order encoded integer. This encoding is useful when you want to know whether the integer is more than k or not. The value that takes \([0, n]\) is represented by \(\sum_{i=1}^{n}x_{i}\). Also we have the penalty function \(strength \times \left(\sum_{i=1}^{n-1} \left(x_{i+1}-x_{i}x_{i+1}\right)\right)\) in the Hamiltonian. See the reference [TaTK09] for more details.

Parameters:
  • label (str) – Label of the integer.
  • lower (int) – Lower value of the integer.
  • upper (int) – Upper value of the integer.
  • strength (float/Placeholder) – Strength of the constraint.

Examples

Create an order encoded integer a that takes [0, 3] with the strength = 5.0. Solution of a represents 2 which is the optimal solution of the Hamiltonian.

>>> from pyqubo import OrderEncInteger
>>> a = OrderEncInteger("a", (0, 3), strength = 5.0)
>>> model = ((a-2)**2).compile()
>>> bqm = model.to_bqm()
>>> import dimod
>>> sampleset = dimod.ExactSolver().sample(bqm)
>>> decoded_samples = model.decode_sampleset(sampleset)
>>> best_sample = min(decoded_samples, key=lambda s: s.energy)
>>> print(best_sample.subh['a'])
2.0
less_than(k)[source]

Binary variable that represents whether the value is less than k.

Note

You cannot use this method alone. You should use this variable with the entire integer. See an example below.

Parameters:k (int) – Integer value.
Returns:Express

Examples

This example finds the value of integer a and b such that \(a=b\) and \(a>1\) and \(b<3\). The obtained solution is \(a=b=2\).

>>> from pyqubo import OrderEncInteger
>>> a = OrderEncInteger("a", (0, 4), strength = 5.0)
>>> b = OrderEncInteger("b", (0, 4), strength = 5.0)
>>> model = ((a-b)**2 + (1-a.more_than(1))**2 + (1-b.less_than(3))**2).compile()
>>> bqm = model.to_bqm()
>>> import dimod
>>> sampleset = dimod.ExactSolver().sample(bqm)
>>> decoded_samples = model.decode_sampleset(sampleset)
>>> best_sample = min(decoded_samples, key=lambda s: s.energy)
>>> print(best_sample.subh['a'])
2.0
>>> print(best_sample.subh['b'])
2.0
more_than(k)[source]

Binary variable that represents whether the value is more than k.

Note

You cannot use this method alone. You should use this variable with the entire integer. See an example below.

Parameters:k (int) – Integer value.
Returns:Express

Examples

This example finds the value of integer a and b such that \(a=b\) and \(a>1\) and \(b<3\). The obtained solution is \(a=b=2\).

>>> from pyqubo import OrderEncInteger
>>> a = OrderEncInteger("a", (0, 4), strength = 5.0)
>>> b = OrderEncInteger("b", (0, 4), strength = 5.0)
>>> model = ((a-b)**2 + (1-a.more_than(1))**2 + (1-b.less_than(3))**2).compile()
>>> bqm = model.to_bqm()
>>> import dimod
>>> sampleset = dimod.ExactSolver().sample(bqm)
>>> decoded_samples = model.decode_sampleset(sampleset)
>>> best_sample = min(decoded_samples, key=lambda s: s.energy)
>>> print(best_sample.subh['a'])
2.0
>>> print(best_sample.subh['b'])
2.0

References

[TaTK09]Tamura, N., Taga, A., Kitagawa, S., & Banbara, M. (2009). Compiling finite linear CSP into SAT. Constraints, 14(2), 254-272.

Logical Constraint

NOT Constraint

class NotConst(a, b, label)[source]

Constraint: Not(a) = b.

Parameters:
  • a (Express) – expression to be binary
  • b (Express) – expression to be binary
  • label (str) – label to identify the constraint

Examples

In this example, when the binary variables satisfy the constraint, the energy is 0.0. On the other hand, when they break the constraint, the energy is 1.0 > 0.0.

>>> from pyqubo import NotConst, Binary
>>> a, b = Binary('a'), Binary('b')
>>> exp = NotConst(a, b, 'not')
>>> model = exp.compile()
>>> model.energy({'a': 1, 'b': 0}, vartype='BINARY')
0.0
>>> model.energy({'a': 1, 'b': 1}, vartype='BINARY')
1.0

AND Constraint

class AndConst(a, b, c, label)[source]

Constraint: AND(a, b) = c.

Parameters:
  • a (Express) – expression to be binary
  • b (Express) – expression to be binary
  • c (Express) – expression to be binary
  • label (str) – label to identify the constraint

Examples

In this example, when the binary variables satisfy the constraint, the energy is 0.0. On the other hand, when they break the constraint, the energy is 1.0 > 0.0.

>>> from pyqubo import AndConst, Binary
>>> a, b, c = Binary('a'), Binary('b'), Binary('c')
>>> exp = AndConst(a, b, c, 'and')
>>> model = exp.compile()
>>> model.energy({'a': 1, 'b': 0, 'c': 0}, vartype='BINARY')
0.0
>>> model.energy({'a': 0, 'b': 1, 'c': 1}, vartype='BINARY')
1.0

OR Constraint

class OrConst(a, b, c, label)[source]

Constraint: OR(a, b) = c.

Parameters:
  • a (Express) – expression to be binary
  • b (Express) – expression to be binary
  • c (Express) – expression to be binary
  • label (str) – label to identify the constraint

Examples

In this example, when the binary variables satisfy the constraint, the energy is 0.0. On the other hand, when they break the constraint, the energy is 1.0 > 0.0.

>>> from pyqubo import OrConst, Binary
>>> a, b, c = Binary('a'), Binary('b'), Binary('c')
>>> exp = OrConst(a, b, c, 'or')
>>> model = exp.compile()
>>> model.energy({'a': 1, 'b': 0, 'c': 1}, vartype='BINARY')
0.0
>>> model.energy({'a': 0, 'b': 1, 'c': 0}, vartype='BINARY')
1.0

XOR Constraint

class XorConst(a, b, c, label)[source]

Constraint: OR(a, b) = c.

Parameters:
  • a (Express) – expression to be binary
  • b (Express) – expression to be binary
  • c (Express) – expression to be binary
  • label (str) – label to identify the constraint

Examples

In this example, when the binary variables satisfy the constraint, the energy is 0.0. On the other hand, when they break the constraint, the energy is 1.0 > 0.0.

>>> from pyqubo import XorConst, Binary
>>> a, b, c = Binary('a'), Binary('b'), Binary('c')
>>> exp = XorConst(a, b, c, 'xor')
>>> model = exp.compile()
>>> model.energy({'a': 1, 'b': 0, 'c': 1, 'aux_xor': 0}, vartype='BINARY')
0.0
>>> model.energy({'a': 0, 'b': 1, 'c': 0, 'aux_xor': 0}, vartype='BINARY')
1.0

Logical Gate

Not

class Not(bit)[source]

Logical NOT of input.

Parameters:bit (Express) – expression to be binary

Examples

>>> from pyqubo import Binary, Not
>>> a = Binary('a')
>>> exp = Not(a)
>>> model = exp.compile()
>>> for a in (0, 1):
...   print(a, int(model.energy({'a': a}, vartype='BINARY')))
0 1
1 0

And

class And(bit_a, bit_b)[source]

Logical AND of inputs.

Parameters:
  • bit_a (Express) – expression to be binary
  • bit_b (Express) – expression to be binary

Examples

>>> from pyqubo import Binary, And
>>> import itertools
>>> a, b = Binary('a'), Binary('b')
>>> exp = And(a, b)
>>> model = exp.compile()
>>> for a, b in itertools.product(*[(0, 1)] * 2):
...   print(a, b, int(model.energy({'a': a, 'b': b}, vartype='BINARY')))
0 0 0
0 1 0
1 0 0
1 1 1

Or

class Or(bit_a, bit_b)[source]

Logical OR of inputs.

Parameters:
  • bit_a (Express) – expression to be binary
  • bit_b (Express) – expression to be binary

Examples

>>> from pyqubo import Binary, Or
>>> import itertools
>>> a, b = Binary('a'), Binary('b')
>>> exp = Or(a, b)
>>> model = exp.compile()
>>> for a, b in itertools.product(*[(0, 1)] * 2):
...   print(a, b, int(model.energy({'a': a, 'b': b}, vartype='BINARY')))
0 0 0
0 1 1
1 0 1
1 1 1

Xor

class Xor(bit_a, bit_b)[source]

Logical XOR of inputs.

Parameters:
  • bit_a (Express) – expression to be binary
  • bit_b (Express) – expression to be binary

Examples

>>> from pyqubo import Binary, Xor
>>> import itertools
>>> a, b = Binary('a'), Binary('b')
>>> exp = Xor(a, b)
>>> model = exp.compile()
>>> for a, b in itertools.product(*[(0, 1)] * 2):
...   print(a, b, int(model.energy({'a': a, 'b': b}, vartype='BINARY')))
0 0 0
0 1 1
1 0 1
1 1 0

Utils

Solvers

solve_ising(linear, quad, num_reads=10, sweeps=1000, beta_range=(1.0, 50.0))[source]

[deprecated] Solve Ising model with Simulated Annealing (SA) provided by neal.

Parameters:
  • linear (dict[label, float]) – The linear parameter of the Ising model.
  • quad (dict[(label, label), float]) – The quadratic parameter of the Ising model.
  • num_reads (int, default=10) – Number of run repetitions of SA.
  • sweeps (int, default=1000) – Number of iterations in each run of SA.
  • beta_range (tuple(float, float), default=(1.0, 50.0)) – Tuple of start beta and end beta.

Note

solve_ising() is deprecated. Use dwave-neal package instead like below.

>>> from pyqubo import Spin
>>> import neal
>>> s1, s2, s3 = Spin("s1"), Spin("s2"), Spin("s3")
>>> H = (2*s1 + 4*s2 + 6*s3)**2
>>> model = H.compile()
>>> bqm = model.to_bqm()
>>> sa = neal.SimulatedAnnealingSampler()
>>> sampleset = sa.sample(bqm, num_reads=10)
>>> samples = model.decode_sampleset(sampleset)
>>> best_sample = min(samples, key=lambda s: s.energy)
>>> pprint(best_sample.sample) # doctest: +SKIP
{'s1': 0, 's2': 0, 's3': 1}
solve_qubo(qubo, num_reads=10, sweeps=1000, beta_range=(1.0, 50.0))[source]

[deprecated] Solve QUBO with Simulated Annealing (SA) provided by neal.

Parameters:
  • qubo (dict[(label, label), float]) – The QUBO to be solved.
  • num_reads (int, default=10) – Number of run repetitions of SA.
  • sweeps (int, default=1000) – Number of iterations in each run of SA.
  • beta_range (tuple(float, float), default=(1.0, 50.0)) – Tuple of start beta and end beta.
Returns:

The solution of SA.

Return type:

dict[label, bit]

Note

solve_qubo() is deprecated. Use dwave-neal package instead like below.

>>> from pyqubo import Spin
>>> import neal
>>> s1, s2, s3 = Spin("s1"), Spin("s2"), Spin("s3")
>>> H = (2*s1 + 4*s2 + 6*s3)**2
>>> model = H.compile()
>>> bqm = model.to_bqm()
>>> sa = neal.SimulatedAnnealingSampler()
>>> sampleset = sa.sample(bqm, num_reads=10)
>>> samples = model.decode_sampleset(sampleset)
>>> best_sample = min(samples, key=lambda s: s.energy)
>>> pprint(best_sample.sample) # doctest: +SKIP
{'s1': 0, 's2': 0, 's3': 1}

Asserts

assert_qubo_equal(qubo1, qubo2)[source]

Assert the given QUBOs are identical.

Parameters:
  • qubo1 (dict[(label, label), float]) – QUBO to be compared.
  • qubo2 (dict[(label, label), float]) – QUBO to be compared.

Indices and tables