def classical_exactcover_solver(A, w=None, num_threads=4): nrows, ncolumns = np.shape(A) if w is None: w = np.ones(ncolumns) assert(len(w) == ncolumns) assert(sum(w >= 0)) model = CyLPModel() # Decision variables, one for each cover x = model.addVariable('x', ncolumns, isInt=True) # Adding the box contraints model += 0 <= x <= 1 # Adding the cover constraints # Sum_j x_ij == 1 for i in range(nrows): model += CyLPArray(A[i,:]) * x == 1 # Adding the objective function model.objective = CyLPArray(w) * x lp = CyClpSimplex(model) lp.logLevel = 0 lp.optimizationDirection = 'min' 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']]
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']]
def plpd2d(xs, zs, ys, x_0, z_0): x, z, y = xs, zs, ys dim_p = len(x) rhs_p = np.array([x_0, z_0, 1], dtype=np.double) dim_d = len(rhs_p) s = CyClpSimplex() u = s.addVariable('u', dim_p) l = s.addVariable('l', dim_d) A_p = np.vstack([y, x, z, np.ones(dim_p)]) A_p = np.matrix(A_p) b_p = CyLPArray([0, x_0, z_0, 1]) A_d = np.hstack( [x.reshape(-1, 1), z.reshape(-1, 1), np.ones(len(x)).reshape(-1, 1)]) A_d = np.matrix(A_d) b_d = CyLPArray(y) A_d1 = np.matrix(np.vstack([-rhs_p, np.zeros((3, 3))])) s += A_p * u + A_d1 * l == b_p s += A_d * l <= b_d for i in range(dim_p): s += u[i] >= 0 s.optimizationDirection = 'max' s.objective = u[0] s.primal() cond = s.primalVariableSolution['u'] y_res = np.dot(cond, y) return y_res
x0, z0 = 0.5, 0.5 rhs_p = np.array([x0, z0, 1], dtype=np.double) dim_d = len(rhs_p) A_d = np.hstack( [x.reshape(-1, 1), z.reshape(-1, 1), np.ones(len(x)).reshape(-1, 1)]) A_d = np.matrix(A_d) s = CyClpSimplex() l = s.addVariable('l', dim_d) b_d = CyLPArray(y) s += A_d * l >= b_d s.optimizationDirection = 'max' s.objectiveCoefficients = rhs_p s.primal() print(s.primalVariableSolution) print(s.dualVariableSolution) print(s.dualConstraintSolution) print(s.primalConstraintSolution)
# s_pos += A_p_pos*u_pos + A_d1*l_pos == b_p # s_neg += A_p_neg*u_neg + A_d1*l_neg == b_p for i in range(dim_p): s += u[i] >= 0 # s_pos += u_pos[i] >= 0 # s_neg += u_neg[i] >= 0 # s_pos += A_d*l_pos <= b_d_pos # s_neg += A_d*l_neg >= b_d_neg # s_pos.objective = u_pos[0] # s_neg.objective = u_neg[0] s.optimizationDirection = 'min' s.objectiveCoefficients = y # s_pos.primal() # s_neg.primal() s.primal() # print(s_pos.primalVariableSolution) # print(s_pos.dualVariableSolution) # cond_pos = s_pos.primalVariableSolution['u'] # x1_pos = np.dot(cond_pos, x) # y1_pos = np.dot(cond_pos, y_pos) # cond_neg = s_neg.primalVariableSolution['u']
def classical_maxkcut_solver(G, num_partitions, num_threads=4): # G: NetworkX graph # num_partitions: the number partitions or groups in which we should # subdivide the nodes (i.e., the value of K) N = len(G) model = CyLPModel() # Decision variables, one for each node x = model.addVariable('x', num_partitions * 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 selection constraints for i in range(N): indices = [i + k * N for k in range(num_partitions)] model += x[indices].sum() == 1 # Adding the cutting constraints for i in z_ind: for j in z_ind[i]: for k in range(num_partitions): shift = k * N model += z[z_ind[i][j]] + x[i + shift] + x[j + shift] <= 2 model += z[z_ind[i][j]] + x[i + shift] - x[j + shift] >= 0 model += z[z_ind[i][j]] - x[i + shift] + x[j + shift] >= 0 # 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() sol = [int(i) for i in mip.primalVariableSolution['x']] sol_formatted = [] for i in range(N): indices = [i + k * N for k in range(num_partitions)] for j in range(num_partitions): if (sol[indices[j]] == 1): sol_formatted.append(j) break assert (len(sol_formatted) == N) return mip.objectiveValue, sol_formatted