forked from OpenQuantumComputing/optimization
-
Notifications
You must be signed in to change notification settings - Fork 0
/
classical_maxcut_solver.py
56 lines (53 loc) · 1.75 KB
/
classical_maxcut_solver.py
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# Classical (i.e., not Quantum) algorithms to solve the MaxCut problem.
#
# All functions take as input a NetworkX graph and return the optimal solution.
import networkx as nx
import numpy as np
from cylp.cy import CyCbcModel, CyClpSimplex
from cylp.py.modeling.CyLPModel import CyLPModel, CyLPArray
def branch_and_bound(G, num_threads=4):
N = len(G)
model = CyLPModel()
# Decision variables, one for each node
x = model.addVariable('x', N, isInt=True)
# Adjacency matrix (possibly weighted)
W = nx.to_numpy_matrix(G)
z_ind = dict()
ind = 0
w = []
for i in range(N):
j_range = range(N)
if (not nx.is_directed(G)):
# Reduced range for undirected graphs
j_range = range(i, N)
for j in j_range:
if (W[i,j] == 0):
continue
if (i not in z_ind):
z_ind[i] = dict()
z_ind[i][j] = ind
w.append(W[i,j])
ind += 1
# Aux variables, one for each edge
z = model.addVariable('z', len(w), isInt=True)
# Adding the box contraints
model += 0 <= x <= 1
model += 0 <= z <= 1
# Adding the cutting constraints
# If x_i == x_j then z_ij = 0
# If x_i != x_j then z_ij = 1
for i in z_ind:
for j in z_ind[i]:
model += z[z_ind[i][j]] - x[i] - x[j] <= 0
model += z[z_ind[i][j]] + x[i] + x[j] <= 2
# Adding the objective function
model.objective = CyLPArray(w) * z
lp = CyClpSimplex(model)
lp.logLevel = 0
lp.optimizationDirection = 'max'
mip = lp.getCbcModel()
mip.logLevel = 0
# Setting number of threads
mip.numberThreads = num_threads
mip.solve()
return mip.objectiveValue, [int(i) for i in mip.primalVariableSolution['x']]