def two_cycle(A, C, gap): """ Solve high-vertex dense graphs by reduction to weighted matching ILP. """ _ = '*' m = Model() m.modelsense = GRB.MAXIMIZE m.params.mipgap = gap m.params.timelimit = 60 * 60 n = A.shape[0] vars = {} edges = tuplelist() # model as undirected graph for i in range(n): for j in range(i + 1, n): if A[i, j] == 1 and A[j, i] == 1: e = (i, j) edges.append(e) w_i = 2 if i in C else 1 w_j = 2 if j in C else 1 w = w_i + w_j var = m.addVar(vtype=GRB.BINARY, obj=w) vars[e] = var m.update() # 2 cycle constraint <=> undirected flow <= 1 for i in range(n): lhs = LinExpr() lhs_vars = [ vars[e] for e in chain(edges.select(i, _), edges.select(_, i)) ] ones = [1.0] * len(lhs_vars) lhs.addTerms(ones, lhs_vars) m.addConstr(lhs <= 1) m.optimize() m.update() cycles = [list(e) for e in edges if vars[e].x == 1.0] return cycles, m.objval
def two_cycle(A, C, gap): """ Solve high-vertex dense graphs by reduction to weighted matching ILP. """ _ = '*' m = Model() m.modelsense = GRB.MAXIMIZE m.params.mipgap = gap m.params.timelimit = 60 * 60 n = A.shape[0] vars = {} edges = tuplelist() # model as undirected graph for i in range(n): for j in range(i+1, n): if A[i, j] == 1 and A[j, i] == 1: e = (i, j) edges.append(e) w_i = 2 if i in C else 1 w_j = 2 if j in C else 1 w = w_i + w_j var = m.addVar(vtype=GRB.BINARY, obj=w) vars[e] = var m.update() # 2 cycle constraint <=> undirected flow <= 1 for i in range(n): lhs = LinExpr() lhs_vars = [vars[e] for e in chain(edges.select(i, _), edges.select(_, i))] ones = [1.0]*len(lhs_vars) lhs.addTerms(ones, lhs_vars) m.addConstr(lhs <= 1) m.optimize() m.update() cycles = [list(e) for e in edges if vars[e].x == 1.0] return cycles, m.objval
def cycle_milp(A, C, k, gap): n = A.shape[0] t_0 = time.clock() _ = '*' m = Model() m.modelsense = GRB.MAXIMIZE m.params.mipgap = gap cycles = [] vars = [] cycles_grouped = [[] for i in range(n)] vars_grouped = [[] for i in range(n)] print('[%.1f] Generating variables...' % (time.clock() - t_0)) print('i = ', end='') for i in range(n): for cycle in dfs_cycles(i, A, k): w = sum([2 if j in C else 1 for j in cycle]) var = m.addVar(vtype=GRB.BINARY, obj=w) vars.append(var) cycles.append(cycle) cycles_grouped[i].append(cycle) vars_grouped[i].append(var) for j in cycle: if j > i: vars_grouped[j].append(var) cycles_grouped[j].append(cycle) if (i + 1) % 10 == 0: print(i + 1) m.update() print('[%.1f] Generated variables...' % (time.clock() - t_0)) print('[%.1f] Generating constraints...' % (time.clock() - t_0)) for i in range(n): vars_i = vars_grouped[i] lhs = LinExpr() ones = [1.0]*len(vars_i) lhs.addTerms(ones, vars_i) m.addConstr(lhs <= 1.0) print('[%.1f] Generated constraints...' % (time.clock() - t_0)) print('[%.1f] Begin Optimizing %d vertex %d cycle model' % (time.clock() - t_0, n, len(cycles))) m.update() m.optimize() m.update() print('[%.1f] Finished Optimizing' % (time.clock() - t_0)) print('[%.1f] Building cycles...' % (time.clock() - t_0)) final_cycles = [] for i in range(len(vars)): var = vars[i] if var.x == 1.0: cycle = cycles[i] final_cycles.append(cycle) print('[%.1f] Finished building cycles' % (time.clock() - t_0)) return final_cycles, m.objval
def constantino(A, C, k, gap): """ Polynomial-sized CCMcP Edge-Extended Model See Constantino et al. (2013) """ t_0 = time.clock() _ = '*' m = Model() m.modelsense = GRB.MAXIMIZE m.params.mipgap = gap # m.params.timelimit = 60 * 60 # m.params.nodefilestart = 1.0 # m.params.nodefiledir = './.nodefiledir' # m.params.presparsify = 0 # m.params.presolve = 0 n = A.shape[0] vars = {} edges = tuplelist() print('[%.1f] Generating variables...' % (time.clock() - t_0)) # Variables for l in range(n): for i in range(l, n): for j in range(l, n): if A[i, j] == 1: e = (l, i, j) edges.append(e) w = 2 if j in C else 1 var = m.addVar(vtype=GRB.BINARY, obj=w) vars[e] = var if l % 100 == 0 and l != 0: print('[%.1f] l = %d' % (time.clock() - t_0, l)) m.update() print('[%.1f] Generated variables' % (time.clock() - t_0)) print('[%.1f] Adding flow constraints...' % (time.clock() - t_0)) # Constraint (2): Flow in = Flow out for l in range(n): for i in range(l, n): # Flow in lhs_vars = [vars[e] for e in edges.select(l, _, i)] ones = [1.0]*len(lhs_vars) lhs = LinExpr() lhs.addTerms(ones, lhs_vars) # Flow out rhs_vars = [vars[e] for e in edges.select(l, i, _)] ones = [1.0]*len(rhs_vars) rhs = LinExpr() rhs.addTerms(ones, rhs_vars) # Flow in = Flow out m.addConstr(lhs == rhs) if l % 100 == 0 and l != 0: print('[%.1f] l = %d' % (time.clock() - t_0, l)) print('[%.1f] Added flow constraints' % (time.clock() - t_0)) print('[%.1f] Adding cycle vertex constraints...' % (time.clock() - t_0)) # Constraint (3): Use a vertex only once per cycle for i in range(n): c_vars = [vars[e] for e in edges.select(_, i, _)] ones = [1.0]*len(c_vars) expr = LinExpr() expr.addTerms(ones, c_vars) m.addConstr(expr <= 1.0) if i % 100 == 0 and i != 0: print('[%.1f] V_i = %d' % (time.clock() - t_0, i)) print('[%.1f] Added cycle vertex constraints' % (time.clock() - t_0)) print('[%.1f] Adding cycle cardinality constraints...' % (time.clock() - t_0)) # Constraint (4): Limit cardinality of cycles to k for l in range(n): c_vars = [vars[e] for e in edges.select(l, _, _)] ones = [1.0]*len(c_vars) expr = LinExpr() expr.addTerms(ones, c_vars) m.addConstr(expr <= k) if l % 100 == 0 and l != 0: print('[%.1f] l = %d' % (time.clock() - t_0, l)) print('[%.1f] Added cycle cardinality constraints' % (time.clock() - t_0)) print('[%.1f] Adding cycle index constraints...' % (time.clock() - t_0)) # Constraint (5): Cycle index is smallest vertex-index for l in range(n): rhs_vars = [vars[e] for e in edges.select(l, l, _)] ones = [1.0]*len(rhs_vars) rhs = LinExpr() rhs.addTerms(ones, rhs_vars) for i in range(l+1, n): lhs_vars = [vars[e] for e in edges.select(l, i, _)] if len(lhs_vars) > 0: ones = [1.0]*len(lhs_vars) lhs = LinExpr() lhs.addTerms(ones, lhs_vars) m.addConstr(lhs <= rhs) if l % 100 == 0 and l != 0: print('[%.1f] l = %d' % (time.clock() - t_0, l)) print('[%.1f] Added cycle index constraints...' % (time.clock() - t_0)) print('[%.1f] Begin Optimizing %d vertex model' % (time.clock() - t_0, n)) m.optimize() m.update() print('[%.1f] Finished Optimizing' % (time.clock() - t_0)) print('[%.1f] Building cycles...' % (time.clock() - t_0)) cycles = [] for l in range(n): c_edges = [(e[1], e[2]) for e in edges.select(l, _, _) if vars[e].x == 1.0] cycles.extend(cycles_from_edges(c_edges)) print('[%.1f] Finished building cycles' % (time.clock() - t_0)) return cycles, m.objval
def lazy_cycle_constraint(A, C, k, gap): """ Lazily generate cycle constraints as potential feasible solutions are generated. """ _ = '*' m = Model() m.modelsense = GRB.MAXIMIZE m.params.mipgap = gap m.params.timelimit = 5 * 60 * 60 m.params.lazyconstraints = 1 n = A.shape[0] edges = tuplelist() vars = {} for i in range(n): for j in range(n): if A[i, j] == 1: e = (i, j) edges.append(e) w = 2 if j in C else 1 var = m.addVar(vtype=GRB.BINARY, obj=w) vars[e] = var m.update() # flow constraints for i in range(n): out_vars = [vars[e] for e in edges.select(i, _)] out_ones = [1.0]*len(out_vars) out_expr = LinExpr() out_expr.addTerms(out_ones, out_vars) in_vars = [vars[e] for e in edges.select(_, i)] in_ones = [1.0]*len(in_vars) in_expr = LinExpr() in_expr.addTerms(in_ones, in_vars) m.addConstr(in_expr <= 1) m.addConstr(out_expr == in_expr) m.update() ith_cycle = 0 def callback(model, where): if where == GRB.Callback.MIPSOL: sols = model.cbGetSolution([vars[e] for e in edges]) c_edges = [edges[i] for i in range(len(edges)) if sols[i] > 0.5] cycles = cycles_from_edges(c_edges) for cycle in cycles: len_cycle = len(cycle) if len_cycle > k: cycle_vars = [vars[(cycle[i], cycle[(i+1) % len_cycle])] for i in range(len_cycle)] ones = [1.0]*len(cycle_vars) expr = LinExpr() expr.addTerms(ones, cycle_vars) model.cbLazy(expr <= len_cycle - 1) m.optimize(callback) m.update() c_edges = [e for e in edges if vars[e].x == 1.0] cycles = cycles_from_edges(c_edges) return cycles, m.objval
def cycle_milp(A, C, k, gap): n = A.shape[0] t_0 = time.clock() _ = '*' m = Model() m.modelsense = GRB.MAXIMIZE m.params.mipgap = gap cycles = [] vars = [] cycles_grouped = [[] for i in range(n)] vars_grouped = [[] for i in range(n)] print('[%.1f] Generating variables...' % (time.clock() - t_0)) print('i = ', end='') for i in range(n): for cycle in dfs_cycles(i, A, k): w = sum([2 if j in C else 1 for j in cycle]) var = m.addVar(vtype=GRB.BINARY, obj=w) vars.append(var) cycles.append(cycle) cycles_grouped[i].append(cycle) vars_grouped[i].append(var) for j in cycle: if j > i: vars_grouped[j].append(var) cycles_grouped[j].append(cycle) if (i + 1) % 10 == 0: print(i + 1) m.update() print('[%.1f] Generated variables...' % (time.clock() - t_0)) print('[%.1f] Generating constraints...' % (time.clock() - t_0)) for i in range(n): vars_i = vars_grouped[i] lhs = LinExpr() ones = [1.0] * len(vars_i) lhs.addTerms(ones, vars_i) m.addConstr(lhs <= 1.0) print('[%.1f] Generated constraints...' % (time.clock() - t_0)) print('[%.1f] Begin Optimizing %d vertex %d cycle model' % (time.clock() - t_0, n, len(cycles))) m.update() m.optimize() m.update() print('[%.1f] Finished Optimizing' % (time.clock() - t_0)) print('[%.1f] Building cycles...' % (time.clock() - t_0)) final_cycles = [] for i in range(len(vars)): var = vars[i] if var.x == 1.0: cycle = cycles[i] final_cycles.append(cycle) print('[%.1f] Finished building cycles' % (time.clock() - t_0)) return final_cycles, m.objval
def constantino(A, C, k, gap): """ Polynomial-sized CCMcP Edge-Extended Model See Constantino et al. (2013) """ t_0 = time.clock() _ = '*' m = Model() m.modelsense = GRB.MAXIMIZE m.params.mipgap = gap # m.params.timelimit = 60 * 60 # m.params.nodefilestart = 1.0 # m.params.nodefiledir = './.nodefiledir' # m.params.presparsify = 0 # m.params.presolve = 0 n = A.shape[0] vars = {} edges = tuplelist() print('[%.1f] Generating variables...' % (time.clock() - t_0)) # Variables for l in range(n): for i in range(l, n): for j in range(l, n): if A[i, j] == 1: e = (l, i, j) edges.append(e) w = 2 if j in C else 1 var = m.addVar(vtype=GRB.BINARY, obj=w) vars[e] = var if l % 100 == 0 and l != 0: print('[%.1f] l = %d' % (time.clock() - t_0, l)) m.update() print('[%.1f] Generated variables' % (time.clock() - t_0)) print('[%.1f] Adding flow constraints...' % (time.clock() - t_0)) # Constraint (2): Flow in = Flow out for l in range(n): for i in range(l, n): # Flow in lhs_vars = [vars[e] for e in edges.select(l, _, i)] ones = [1.0] * len(lhs_vars) lhs = LinExpr() lhs.addTerms(ones, lhs_vars) # Flow out rhs_vars = [vars[e] for e in edges.select(l, i, _)] ones = [1.0] * len(rhs_vars) rhs = LinExpr() rhs.addTerms(ones, rhs_vars) # Flow in = Flow out m.addConstr(lhs == rhs) if l % 100 == 0 and l != 0: print('[%.1f] l = %d' % (time.clock() - t_0, l)) print('[%.1f] Added flow constraints' % (time.clock() - t_0)) print('[%.1f] Adding cycle vertex constraints...' % (time.clock() - t_0)) # Constraint (3): Use a vertex only once per cycle for i in range(n): c_vars = [vars[e] for e in edges.select(_, i, _)] ones = [1.0] * len(c_vars) expr = LinExpr() expr.addTerms(ones, c_vars) m.addConstr(expr <= 1.0) if i % 100 == 0 and i != 0: print('[%.1f] V_i = %d' % (time.clock() - t_0, i)) print('[%.1f] Added cycle vertex constraints' % (time.clock() - t_0)) print('[%.1f] Adding cycle cardinality constraints...' % (time.clock() - t_0)) # Constraint (4): Limit cardinality of cycles to k for l in range(n): c_vars = [vars[e] for e in edges.select(l, _, _)] ones = [1.0] * len(c_vars) expr = LinExpr() expr.addTerms(ones, c_vars) m.addConstr(expr <= k) if l % 100 == 0 and l != 0: print('[%.1f] l = %d' % (time.clock() - t_0, l)) print('[%.1f] Added cycle cardinality constraints' % (time.clock() - t_0)) print('[%.1f] Adding cycle index constraints...' % (time.clock() - t_0)) # Constraint (5): Cycle index is smallest vertex-index for l in range(n): rhs_vars = [vars[e] for e in edges.select(l, l, _)] ones = [1.0] * len(rhs_vars) rhs = LinExpr() rhs.addTerms(ones, rhs_vars) for i in range(l + 1, n): lhs_vars = [vars[e] for e in edges.select(l, i, _)] if len(lhs_vars) > 0: ones = [1.0] * len(lhs_vars) lhs = LinExpr() lhs.addTerms(ones, lhs_vars) m.addConstr(lhs <= rhs) if l % 100 == 0 and l != 0: print('[%.1f] l = %d' % (time.clock() - t_0, l)) print('[%.1f] Added cycle index constraints...' % (time.clock() - t_0)) print('[%.1f] Begin Optimizing %d vertex model' % (time.clock() - t_0, n)) m.optimize() m.update() print('[%.1f] Finished Optimizing' % (time.clock() - t_0)) print('[%.1f] Building cycles...' % (time.clock() - t_0)) cycles = [] for l in range(n): c_edges = [(e[1], e[2]) for e in edges.select(l, _, _) if vars[e].x == 1.0] cycles.extend(cycles_from_edges(c_edges)) print('[%.1f] Finished building cycles' % (time.clock() - t_0)) return cycles, m.objval
def lazy_cycle_constraint(A, C, k, gap): """ Lazily generate cycle constraints as potential feasible solutions are generated. """ _ = '*' m = Model() m.modelsense = GRB.MAXIMIZE m.params.mipgap = gap m.params.timelimit = 5 * 60 * 60 m.params.lazyconstraints = 1 n = A.shape[0] edges = tuplelist() vars = {} for i in range(n): for j in range(n): if A[i, j] == 1: e = (i, j) edges.append(e) w = 2 if j in C else 1 var = m.addVar(vtype=GRB.BINARY, obj=w) vars[e] = var m.update() # flow constraints for i in range(n): out_vars = [vars[e] for e in edges.select(i, _)] out_ones = [1.0] * len(out_vars) out_expr = LinExpr() out_expr.addTerms(out_ones, out_vars) in_vars = [vars[e] for e in edges.select(_, i)] in_ones = [1.0] * len(in_vars) in_expr = LinExpr() in_expr.addTerms(in_ones, in_vars) m.addConstr(in_expr <= 1) m.addConstr(out_expr == in_expr) m.update() ith_cycle = 0 def callback(model, where): if where == GRB.Callback.MIPSOL: sols = model.cbGetSolution([vars[e] for e in edges]) c_edges = [edges[i] for i in range(len(edges)) if sols[i] > 0.5] cycles = cycles_from_edges(c_edges) for cycle in cycles: len_cycle = len(cycle) if len_cycle > k: cycle_vars = [ vars[(cycle[i], cycle[(i + 1) % len_cycle])] for i in range(len_cycle) ] ones = [1.0] * len(cycle_vars) expr = LinExpr() expr.addTerms(ones, cycle_vars) model.cbLazy(expr <= len_cycle - 1) m.optimize(callback) m.update() c_edges = [e for e in edges if vars[e].x == 1.0] cycles = cycles_from_edges(c_edges) return cycles, m.objval