Number Partitioning
Here we show how to solve the number partitioning problem using JijZept and JijModeling. This problem is also mentioned in 2.1. Number Partitioning on Lucas, 2014, "Ising formulations of many NP problems".
What is number partitioning?
Number partitioning is the problem of dividing a given set of numbers into two sets such that the sum of the numbers is equal. Let us consider a simple example.
For example, we have such a set of numbers . It is easy to divide to and we can get the sum of each subset as 5. Thus, when the size of the set is small, the answer is relatively easy to obtain. However, the larger problem size is hard to solve quickly. For this reason, we explain to solve this problem using annealing in this tutorial.
Mathematical model
First, let us model the Hamiltonian of this problem. Let be the set to be partitioned, and has elements , where is the number of elements in this set. We consider to divide into two sets and . We define a binary variable that is 0 when is contained in and 1 when is contained in . Using , the total value of the numbers into can be written as , and the sum of is . We need to find a solution that satisfies the constraint that the sum of each of the two subsets is equal.
Applying the penalty method to (1) yields the Hamiltonian for the number partitioning.
Modeling by JijModeling
Next, we show how to implement above equation using JijModeling. We first define variables for the mathematical model described above.
import jijmodeling as jm
a = jm.Placeholder("a",ndim = 1)
N = a.shape[0]
x = jm.BinaryVar("x",shape=(N,))
i = jm.Element("i",belong_to=(0,N))
a
is a one-dimensional array representing the elements in .
We can get the number of elements N
from the length of a
.
We define a binary variable x
.
Finally, we define subscripts i
used in (2).
Then, we implement the Hamiltonian of number partitioning.
problem = jm.Problem("number partition")
s_i = 2*x[i] - 1
problem += (jm.sum(i, a[i]*s_i)) ** 2
We can check the implementation of the mathematical model on the Jupyter Notebook.
problem
Prepare an instance
We prepare a set of numbers . Here, we consider the problem of partitioning numbers from 1 to 40. In the problem of partitioning consecutive numbers from to and the number of numbers is even, there are various patterns of partitioning. However, the total value of the partitioned set can be calculated as follows:
In this case, the total value is expected to be 410. Let's check it.
import numpy as np
N = 40
instance_data = {"a":np.arange(1,N+1)}
Solve by JijZept's SA
We solve this problem using JijZept JijSASampler
.
In this case, we have no constraints. Thus multipliers
dictionary is empty.
import jijzept as jz
# set sampler
sampler = jz.JijSASampler(config="config.toml")
# solve problem
response = sampler.sample_model(problem, instance_data)
Visualize the solution
Let's check the result obtained. We separate the indices classified as and . Finally, we sum over them.
# get sampleset & a specific sample
sampleset = response.get_sampleset()
sample = sampleset.data[0]
# extract components of x == 1
class_1_index = sample.var_values["x"].to_dense()
class_1 = instance_data["a"][class_1_index==1]
# extract components of x == 0
class_0 = instance_data["a"][class_1_index==0]
# show results
print(f"class 1 : {class_1} , total value = {np.sum(class_1)}")
print(f"class 0 : {class_0} , total value = {np.sum(class_0)}")
class 1 : [ 3 4 7 8 10 11 12 14 15 16 19 20 23 24 25 29 30 31 33 37 39] , total value = 410
class 0 : [ 1 2 5 6 9 13 17 18 21 22 26 27 28 32 34 35 36 38 40] , total value = 410
As we expected, we obtain both total values are 410.