def solve_worker(app_name, method, form, args, output=sys.stdout): """Worker for solving the problem in a separate process.""" VPSolver.PLIST = [] def signal_handler(sig, frame): """Signal handler for cleaner exit.""" for p in VPSolver.PLIST: try: os.killpg(p.pid, signal.SIGTERM) except Exception as e: pass sys.exit(0) signal.signal(signal.SIGTERM, signal_handler) sys.stdout = output sys.stderr = output input_ = form["input"].strip("\n") if DEBUG: print("Input:\n{0}\n\nOutput:".format(input_)) output.flush() if app_name == "vbp": tmpfile = VPSolver.new_tmp_file(ext=".vbp") with open(tmpfile, "w") as f: f.write(input_) instance = VBP.from_file(tmpfile, verbose=False) afg = AFG(instance, verbose=True) lp_model = LP(afg, verbose=False) out, sol = VPSolver.script(form["script"], lp_model, afg, pyout=False, verbose=True) elif app_name == "mvp": tmpfile = VPSolver.new_tmp_file(ext=".mvp") with open(tmpfile, "w") as f: f.write(input_) instance = MVP.from_file(tmpfile, verbose=False) afg = AFG(instance, verbose=True) lp_model = LP(afg, verbose=False) out, sol = VPSolver.script(form["script"], lp_model, afg, pyout=False, verbose=True) print("EOF\n") output.flush()
def _generate_graph(self, Ws, ws, labels, bounds, binary, S, Ts, LOSS): """Generate an arc-flow graph.""" from pyvpsolver import MVP, AFG m = len(ws) ndims = len(Ws[0]) if bounds is not None: b = bounds else: maxW = [max(Wi[d] for Wi in Ws) for d in range(ndims)] b = [None] * m for i in range(m): minw = [min(wi[d] for wi in ws[i]) for d in range(ndims)] b[i] = min(maxW[d] // minw[d] for d in range(ndims) if minw[d] != 0) Cs = [1] * len(Ws) Qs = [-1] * len(Ws) instance = MVP(Ws, Cs, Qs, ws, b, binary=binary, verbose=False) graph = AFG(instance, verbose=Tools.VERBOSE).graph() vlbl = {} assert Ts is None or len(Ts) == len(graph.Ts) for u in graph.V: if u == graph.S: vlbl[u] = S elif u in graph.Ts: vlbl[u] = Ts[graph.Ts.index(u)] else: vlbl[u] = str(u) graph.relabel(lambda u: vlbl.get(u), lambda lbl: labels[lbl] if lbl != graph.LOSS else LOSS) return graph
def test_scripts(): """Test scripts.""" from pyvpsolver import VPSolver, VBP, MVP, AFG, LP, MPS VPSolver.clear() vbp = VBP(W=(1, ), w=[(1, )], b=[1], verbose=True) mvp = MVP(Ws=[(1, )], Cs=[1], Qs=[inf], ws=[[(1, )]], b=[1], verbose=True) for instance in [vbp, mvp]: afg = AFG(instance, verbose=True) lp = LP(afg, verbose=True) mps = MPS(afg, verbose=True) VPSolver.set_verbose(False) output, solution = VPSolver.script("vpsolver_glpk.sh", instance, options="--seed 1234") assert solution[0] == 1 if isinstance(instance, (VBP, MVP)): instance_file = instance.filename output, solution = VPSolver.script("vpsolver_glpk.sh", instance_file) assert solution[0] == 1 output, solution = VPSolver.script("vpsolver_glpk.sh", afg) assert solution[0] == 1 output, solution = VPSolver.script("vpsolver_glpk.sh", afg, lp) assert solution[0] == 1 output, solution = VPSolver.script("vpsolver_glpk.sh", afg, mps) assert solution[0] == 1 output, solution = VPSolver.script("vpsolver_glpk.sh", lp) assert solution is None output, solution = VPSolver.script("vpsolver_glpk.sh", mps) assert solution is None output, solution = VPSolver.script("vpsolver_glpk.sh", afg.filename) assert solution[0] == 1 output, solution = VPSolver.script("vpsolver_glpk.sh", lp.filename) assert solution is None output, solution = VPSolver.script("vpsolver_glpk.sh", mps.filename) assert solution is None
def test_lowlevel(): """Test low-level API.""" from pyvpsolver import VPSolver, VBP, MVP, AFG vbp = VBP(W=(1, ), w=[(1, )], b=[1]) mvp = MVP(Ws=[(1, )], Cs=[1], Qs=[inf], ws=[[(1, )]], b=[1]) afg_file = VPSolver.new_tmp_file(".afg") lp_file = VPSolver.new_tmp_file(".lp") mps_file = VPSolver.new_tmp_file(".mps") svg_file = VPSolver.new_tmp_file(".svg") VPSolver.vbp2afg(vbp, afg_file) VPSolver.vbp2afg(mvp, afg_file) VPSolver.vbp2afg(vbp.filename, afg_file) VPSolver.vbp2afg(mvp.filename, afg_file) VPSolver.afg2lp(afg_file, lp_file) VPSolver.afg2mps(afg_file, mps_file) VPSolver.afg2lp(AFG(vbp), lp_file) VPSolver.afg2mps(AFG(mvp), mps_file)
def test_vbpsol(): """Test vbpsol.""" from pyvpsolver import VPSolver, VBP, MVP, AFG, LP, MPS vbp = VBP(W=(1, ), w=[(1, )], b=[1], verbose=True) afg = AFG(vbp, verbose=True) lp = LP(afg, verbose=True) sol_file = VPSolver.new_tmp_file(".sol") output, solution = VPSolver.script_wsol("vpsolver_glpk.sh", lp) assert isinstance(solution, dict) with open(sol_file, "w") as f: lst = [] for var, value in solution.items(): lst.append(str(var)) lst.append(str(value)) print(" ".join(lst), file=f) obj, patterns = VPSolver.vbpsol(afg, sol_file) assert obj == 1
def _generate_graph(self, W, w, labels, bounds, binary, S, T, LOSS): """Generate an arc-flow graph.""" from pyvpsolver import VBP, AFG m = len(w) ndims = len(W) if bounds is not None: b = bounds else: b = [ min(W[d] // w[i][d]) for d in range(ndims) if w[i][d] != 0 for i in range(m) ] instance = VBP(W, w, b, binary=binary, verbose=False) graph = AFG(instance, verbose=Tools.VERBOSE).graph() graph.relabel( lambda u: S if u == graph.S else T if u == graph.Ts[0] else str(u), lambda lbl: labels[lbl] if lbl != graph.LOSS else LOSS) return graph
def test_draw(): """Test scripts.""" from pyvpsolver import VPSolver, VBP, MVP, AFG vbp = VBP(W=(1, ), w=[(1, )], b=[1]) mvp = MVP(Ws=[(1, )], Cs=[1], Qs=[inf], ws=[[(1, )]], b=[1]) svg_file = VPSolver.new_tmp_file(".svg") for instance in [vbp, mvp]: afg = AFG(instance) try: afg.draw(svg_file, lpaths=True, graph_attrs={"size": "8,8"}) except Exception as e: print(repr(e)) try: VPSolver.afg2svg(afg, svg_file) except Exception as e: print(repr(e)) try: VPSolver.afg2svg(afg.filename, svg_file) except Exception as e: print(repr(e))
def _generate_model(self, zvars, Ws, ws, b, bounds=None, binary=False, labels=None, prefix=""): """Generate an arc-flow model.""" from pyvpsolver import MVP, AFG ndims = len(Ws[0]) m = len(ws) bb = [0] * m bvars = [] maxW = [max(Wi[d] for Wi in Ws) for d in range(ndims)] for i in range(m): if isinstance(b[i], six.string_types): minw = [min(wi[d] for wi in ws[i]) for d in range(ndims)] bb[i] = min(maxW[d] // minw[d] for d in range(ndims) if minw[d] != 0) if bounds is not None: bb[i] = min(bb[i], bounds[i]) bvars.append(b[i]) else: bb[i] = b[i] Cs = [1] * len(Ws) Qs = [-1] * len(Ws) instance = MVP(Ws, Cs, Qs, ws, bb, binary=binary, verbose=False) graph = AFG(instance, verbose=Tools.VERBOSE).graph() vnames = {(T, graph.S, graph.LOSS): zvar for zvar, T in zip(zvars, graph.Ts)} ub = {} varl, cons = graph.get_flow_cons(vnames) assocs = graph.get_assocs(vnames) graph.names = vnames nopts = [len(ws[i]) for i in range(m)] if labels is None: names = ["i={}".format(i + 1) for i in range(m)] for i in range(m): if isinstance(b[i], six.string_types): names[i] = b[i] labels = {(i, j): "{} opt={}".format(names[i], j + 1) for i, j in instance.labels} elif isinstance(labels, list): labels = dict(enumerate(labels)) graph.set_labels({(u, v, lbl): [labels[lbl]] for (u, v, lbl) in graph.A if lbl in labels}) for i in range(m): lincomb = [] for j in range(nopts[i]): lincomb += assocs.get((i, j), []) if bounds is not None: for var in lincomb: ub[var] = bounds[i] if isinstance(b[i], six.string_types): varl.append(b[i]) cons.append((lincomb, "=", b[i])) else: if b[i] > 1: cons.append((lincomb, ">=", b[i])) else: cons.append((lincomb, "=", b[i])) model = Model() for var in varl: model.add_var(name=var, lb=0, ub=ub.get(var, None), vtype="I") for lincomb, sign, rhs in cons: model.add_con(lincomb, sign, rhs) for i, zvar in enumerate(zvars): flowvar = "_total_flow_{}".format(i) model.add_var(name=flowvar, vtype="I") model.add_con(flowvar, "=", zvar) declared_vars = set(bvars) def var_name(name): if name in zvars: return name elif name in declared_vars: return name else: return prefix + name def con_name(name): return prefix + name model.rename_vars(var_name) model.rename_cons(con_name) return graph, model, declared_vars
def _generate_model(self, zvar, W, w, b, bounds=None, binary=False, labels=None, prefix=""): """Generate an arc-flow model.""" from pyvpsolver import VBP, AFG m = len(w) bb = [0] * m bvars = [] for i in range(m): if isinstance(b[i], six.string_types): bb[i] = min(W[d] // w[i][d] for d in range(len(w[i])) if w[i][d] != 0) if bounds is not None: bb[i] = min(bb[i], bounds[i]) bvars.append(b[i]) else: bb[i] = b[i] instance = VBP(W, w, bb, binary=binary, verbose=False) graph = AFG(instance, verbose=Tools.VERBOSE).graph() feedback = (graph.Ts[0], graph.S, graph.LOSS) vnames = {} vnames[feedback] = zvar ub = {} varl, cons = graph.get_flow_cons(vnames) assocs = graph.get_assocs(vnames) graph.names = vnames if labels is None: labels = {i: "i={0}".format(i + 1) for i in instance.labels} for i in range(m): if isinstance(b[i], six.string_types): labels[i] = b[i] elif isinstance(labels, list): labels = dict(enumerate(labels)) graph.set_labels({(u, v, i): [labels[i]] for (u, v, i) in graph.A if i in labels}) for i in range(m): if i not in assocs: assocs[i] = [] if bounds is not None: for var in assocs[i]: ub[var] = bounds[i] if isinstance(b[i], six.string_types): varl.append(b[i]) cons.append((assocs[i], "=", b[i])) else: if b[i] > 1: cons.append((assocs[i], ">=", b[i])) else: cons.append((assocs[i], "=", b[i])) model = Model() for var in varl: model.add_var(name=var, lb=0, ub=ub.get(var, None), vtype="I") for lincomb, sign, rhs in cons: model.add_con(lincomb, sign, rhs) model.add_var(name="_total_flow", vtype="I") model.add_con("_total_flow", "=", zvar) declared_vars = set(bvars) def var_name(name): if name == zvar: return name elif name in declared_vars: return name else: return prefix + name def con_name(name): return prefix + name model.rename_vars(var_name) model.rename_cons(con_name) return graph, model, declared_vars
def main(): """Examples: how to use VBP, MVP, AFG, MPS, LP and VPSolver""" from pyvpsolver import VPSolver, VBP, MVP, AFG, MPS, LP from pyvpsolver.solvers import vbpsolver, mvpsolver os.chdir(os.path.dirname(__file__) or os.curdir) # Create instanceA: instanceA = VBP((5180, ), [(1120, ), (1250, ), (520, ), (1066, ), (1000, ), (1150, )], [9, 5, 91, 18, 11, 64]) # Create instanceB from a .vbp file instanceB = VBP.from_file("instance.vbp") # Create an arc-flow graph for instanceA afg = AFG(instanceA, verbose=False) # Create .mps and .lp models for instanceA mps_model = MPS(afg, verbose=False) lp_model = LP(afg, verbose=False) # Draw the arc-flow graph for instanceA (requires pygraphviz) try: afg.draw("tmp/graph1.svg") except ImportError as e: print(repr(e)) # Solve instanceA using bin/vpsolver (requires Gurobi) try: out, sol = VPSolver.vpsolver(instanceA, verbose=True) except Exception as e: print("Failed to call vpsolver") print(repr(e)) # Solve instanceA using any vpsolver script (i.e., any MIP solver): # The scripts accept models with and without the underlying graphs. # However, the graphs are required to extract the solution. out, sol = VPSolver.script("vpsolver_glpk.sh", lp_model, afg, verbose=True) try: out, sol = VPSolver.script("vpsolver_gurobi.sh", mps_model, verbose=True) except Exception as e: print(repr(e)) # Solve an instance directly without creating AFG, MPS or LP objects: out, solution = VPSolver.script("vpsolver_glpk.sh", instanceB, verbose=True) # Print the solution: obj, patterns = solution print("Objective:", obj) print("Solution:", patterns) # Pretty-print the solution: vbpsolver.print_solution(solution) # check the solution objective value obj, patterns = solution assert obj == 21 # Create instanceC: W1 = (100, 100) W2 = (50, 120) W3 = (150, 25) ws1, b1 = [(50, 25), (25, 50), (0, 75)], 1 ws2, b2 = [(40, 40), (60, 25), (25, 60)], 1 ws3, b3 = [(30, 10), (20, 40), (10, 50)], 1 Ws = [W1, W2, W3] # capacities Cs = [3, 7, 2] # costs Qs = [-1, -1, -1] # number of bins available ws = [ws1, ws2, ws3] # items b = [b1, b2, b3] # demands instanceC = MVP(Ws, Cs, Qs, ws, b) # Solve an instance directly without creating AFG, MPS or LP objects: out, solution = VPSolver.script("vpsolver_glpk.sh", instanceC, verbose=True) mvpsolver.print_solution(solution) # check the solution objective value obj, patterns = solution assert obj == 3 # Create instanceD from a .mvp file instanceD = MVP.from_file("instance.mvp") # Draw the arc-flow graph for instanceD (requires pygraphviz) try: AFG(instanceD).draw("tmp/graph2.svg") except ImportError as e: print(repr(e)) # Solve an instance directly without creating AFG, MPS or LP objects: out, solution = VPSolver.script("vpsolver_glpk.sh", instanceD, verbose=True) mvpsolver.print_solution(solution) # check the solution objective value obj, patterns = solution assert obj == 8