Commit 1b55a361 authored by msurl's avatar msurl
Browse files

added callback function for gurobi to lazily add connectivity constraints and refactored code

parent f1dd6676
...@@ -11,7 +11,7 @@ from gurobipy import GRB ...@@ -11,7 +11,7 @@ from gurobipy import GRB
import datetime import datetime
import sys import sys
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
# import lp_to_nx_graph import lp_to_nx_graph
class DominatingSet: class DominatingSet:
...@@ -60,10 +60,18 @@ class KHopDominatingSet(DominatingSet): ...@@ -60,10 +60,18 @@ class KHopDominatingSet(DominatingSet):
class ConnectedKHopDominatingSet(KHopDominatingSet): class ConnectedKHopDominatingSet(KHopDominatingSet):
def __init__(self, G, k, name = "CkDS"): def __init__(self, G, k, name = "CkDS", exclude = {}):
self.G = G self.G = G
super().__init__(G, k, name) super().__init__(G, k, name)
self.m.addConstrs(self.nodes[v] <= gp.quicksum(self.nodes[w] for w in G.neighbors(v)) for v in G.nodes)
# self.m.addConstr(gp.quicksum(gp.quicksum(self.nodes[w] for w in G.neighbors(v)) -2*self.nodes[v] for v in G.nodes) >= -2)
if exclude:
self.m.addConstrs(self.nodes[v] <= gp.quicksum(self.nodes[w] for w in G.neighbors(v)) for v in G.nodes if v not in exclude)
else:
self.m.addConstrs(self.nodes[v] <= gp.quicksum(self.nodes[w] for w in G.neighbors(v)) for v in G.nodes)
def min_ij_separator(G, i, j, C_i): def min_ij_separator(G, i, j, C_i):
...@@ -77,64 +85,48 @@ class ConnectedKHopDominatingSet(KHopDominatingSet): ...@@ -77,64 +85,48 @@ class ConnectedKHopDominatingSet(KHopDominatingSet):
return R_j.intersection(N_ci) return R_j.intersection(N_ci)
def solve(self): def solve(self):
return self.solve_iteratively(float("inf")) self.m._vars = self.nodes
self.m._G = self.G
def solve_iteratively(self, maxIterations): self.m.Params.lazyConstraints = 1
iterations = 0 self.m.optimize(RootedConnectecKHopDominatingSet.elim_unconnectivity)
self.m.optimize()
ds = {i for i,x_i in enumerate(self.m.getVars()) if x_i.x == 1} ds = {i for i,x_i in enumerate(self.m.getVars()) if x_i.x > 0.5}
return ds
G_prime_prime = self.G.subgraph(ds)
while(not nx.is_connected(G_prime_prime)) and iterations < maxIterations:
iterations+=1
C = [c for c in nx.algorithms.components.connected_components(G_prime_prime)]
for i in range(len(C)-1):
C_i = C[i]
for j in range(i+1, len(C)):
C_j = C[j]
h = next(iter(C_i))
l = next(iter(C_j))
min_ij_sep = ConnectedKHopDominatingSet.min_ij_separator(self.G, h, l, C_i)
self.m.addConstr(gp.quicksum(self.nodes[s] for s in min_ij_sep) >= self.nodes[h] + self.nodes[l] - 1)
self.m.optimize()
ds = {i for i,x_i in enumerate(self.m.getVars()) if x_i.x == 1}
G_prime_prime = self.G.subgraph(ds)
return ds, iterations
def solve_and_draw(self, iterations = float("inf")): def elim_unconnectivity(model, where):
starttime = datetime.datetime.now() if where == GRB.Callback.MIPSOL:
ds, iterations = self.solve_iteratively(iterations) vals = model.cbGetSolution(model._vars)
endtime = datetime.datetime.now() ds = {i for i in model._vars.keys() if vals[i] > 0.5}
duration = endtime- starttime
duration_sec = duration.total_seconds() G_prime_prime = model._G.subgraph(ds)
color_map = ['red' if i in ds else 'green' for i in self.G.nodes] if(not nx.is_connected(G_prime_prime)):
print(f"iterations: {iterations}, duration in seconds: {duration_sec}") C = [c for c in nx.algorithms.components.connected_components(G_prime_prime)]
nx.draw_kamada_kawai(self.G, node_color = color_map, with_labels = True) for i in range(len(C)-1):
plt.show() C_i = C[i]
for j in range(i+1, len(C)):
C_j = C[j]
h = next(iter(C_i))
l = next(iter(C_j))
min_ij_sep = ConnectedKHopDominatingSet.min_ij_separator(model._G, h, l, C_i)
model.cbLazy(gp.quicksum(model._vars[s] for s in min_ij_sep) >= model._vars[h] + model._vars[l] - 1)
class RootedConnectecKHopDominatingSet(ConnectedKHopDominatingSet): class RootedConnectecKHopDominatingSet(ConnectedKHopDominatingSet):
def __init__(self, G, k, root = 0, name = "RCkDS"): def __init__(self, G, k, root = 0, name = "RCkDS"):
super().__init__(G, k, name) super().__init__(G, k, name, exclude = {root})
self.root = root self.root = root
self.m.addConstr(self.nodes[root] >= 1) self.m.addConstr(self.nodes[root] >= 1)
# if __name__ == '__main__': if __name__ == '__main__':
# G = lp_to_nx_graph.read(sys.argv[1]) G = lp_to_nx_graph.read(sys.argv[1])
# if(len(sys.argv) > 2): if(len(sys.argv) > 2):
# k = int(sys.argv[2]) k = int(sys.argv[2])
# else: else:
# k = 1 k = 1
# if(len(sys.argv) > 3):
# maxIterations = int(sys.argv[3])
# else:
# maxIterations = float("inf")
# dsProb = RootedConnectecKHopDominatingSet(G, k, 0) dsProb = RootedConnectecKHopDominatingSet(G, k, 0)
# dsProb.solve_and_draw() dsProb.solve_and_draw()
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment