In the Number Partitioning Problem [1] we need to find how to partition a set of integers into two subsets of equal sums. In case such a partition does not exist, we can ask for a partition where the difference between the sums is minimal.
Given a set of numbers S={s1,s2,...,sn}, a partition is defined as P1,P2⊂{1,...,n}, with P1∪P2={1,...,n} and P1∩P2=∅. In the Number Partitioning Problem we need to determine a partition such that ∣∑j∈P1sj−∑j∈P2sj∣ is minimal. A partition can be represented by a binary vector x of size n, where we assign 0 or 1 for being in P1 or P2, respectively.The quantity we ask to minimize is ∣x⋅s−(1−x)⋅s∣=∣(2x−1)⋅s∣. In practice we will minimize the square of this expression.
We go through the steps of solving the problem with the Classiq platform, using QAOA algorithm [2].The solution is based on defining a pyomo model for the optimization problem we would like to solve.
import networkx as nximport numpy as npimport pyomo.core as pyofrom matplotlib import pyplot as plt
We proceed by defining the Pyomo model that will be used on the Classiq platform, using the mathematical formulation defined above:
# we define a matrix which gets a set of integers s and returns a pyomo model for the partitioning problemdef partite(s) -> pyo.ConcreteModel: model = pyo.ConcreteModel() SetSize = len(s) # the set size model.x = pyo.Var( range(SetSize), domain=pyo.Binary ) # our variable is a binary vector # we define a cost function model.cost = pyo.Objective( expr=sum(((2 * model.x[i] - 1) * s[i]) for i in range(SetSize)) ** 2, sense=pyo.minimize, ) return model
Myset = np.random.randint(1, 12, 10)mylist = [int(x) for x in Myset]print("This is my list: ", mylist)set_partition_model = partite(mylist)
In order to solve the Pyomo model defined above, we use the CombinatorialProblem python class.Under the hood it tranlates the Pyomo model to a quantum model of the QAOA algorithm, with cost hamiltonian translated from the Pyomo model. We can choose the number of layers for the QAOA ansatz using the argument num_layers, and the penalty_factor, which will be the coefficient of the constraints term in the cost hamiltonian.
We also set the quantum backend we want to execute on:
from classiq.execution import *execution_preferences = ExecutionPreferences( backend_preferences=ClassiqBackendPreferences(backend_name="simulator"),)
We now solve the problem by calling the optimize method of the CombinatorialProblem object.For the classical optimization part of the QAOA algorithm we define the maximum number of classical iterations (maxiter) and the α-parameter (quantile) for running CVaR-QAOA, an improved variation of the QAOA algorithm [3]:
p1 = [mylist[i] for i in range(len(mylist)) if best_solution["x"][i] == 0]p2 = [mylist[i] for i in range(len(mylist)) if best_solution["x"][i] == 1]print("P1=", p1, ", total sum: ", sum(p1))print("P2=", p2, ", total sum: ", sum(p2))print("difference= ", abs(sum(p1) - sum(p2)))
classical_solution = [pyo.value(set_partition_model.x[i]) for i in range(len(mylist))]
p1 = [mylist[i] for i in range(len(mylist)) if round(classical_solution[i]) == 0]p2 = [mylist[i] for i in range(len(mylist)) if round(classical_solution[i]) == 1]print("P1=", p1, ", total sum: ", sum(p1))print("P2=", p2, ", total sum: ", sum(p2))print("difference= ", abs(sum(p1) - sum(p2)))