예제 #1
0
def parse_results(model: gp.Model) -> None:
    objVal = model.getObjective().getValue()
    print("Get optimal Obj: {}".format(objVal))
    print("Solution:")
    for name, val in zip(model.getAttr("varName"), model.getAttr("x")):
        print("Var {}: {}".format(name, val))

    for con, val in zip(model.getAttr("constrName"), model.getAttr("Pi")):
        print("Dual var of {}: {}".format(con, val))
예제 #2
0
def select_subset_of_loops(g, eqs, small_loops, max_coverage=1):
    # Select a maximum set of loops such that each edge participates in at most
    # max_coverage loops. The max_coverage=1 means the loops are
    # independent, they do not share edges. The max_coverage=2 means the
    # selected loops share at most 1 edge, in other words, loops share edges at
    # most pairwise.
    m = Model()
    m.setAttr('ModelSense', GRB.MAXIMIZE)
    # * Bipartite, apart from that, duplicate of grb_pcm select_subset_of_loops*
    edges = g.edges(eqs)
    loop_vars = {
        loop: m.addVar(vtype=GRB.BINARY, obj=1)
        for loop in small_loops
    }
    edge_vars = {edge: m.addVar(vtype=GRB.BINARY) for edge in edges}
    m.update()
    # An edge can participate in at most max_coverage loops
    # TODO Takes very long to build the MILP; most likely e in loop which
    # searches in linear time in the loop tuple.
    start = time()
    for e in edges:
        in_loops = [var for loop, var in iteritems(loop_vars) if e in loop]
        if in_loops:
            lhs = LinExpr([1] * len(in_loops), in_loops)
            m.addConstr(lhs, GRB.LESS_EQUAL, max_coverage)
    end = time()
    log('Building the ILP model took {0:0.1f} s'.format(end - start))
    # If a loop is chosen, all of its edges are chosen
    for cycle in small_loops:
        for edge in cycle:
            m.addConstr(edge_vars[edge], GRB.GREATER_EQUAL, loop_vars[cycle])
    success = solve_ilp(m)
    assert success, 'Solver failures are not handled'
    objective = int(round(m.getObjective().getValue()))
    loop_subset = {
        l
        for l, var in iteritems(loop_vars) if int(round(var.x)) == 1
    }
    assert len(loop_subset) == objective
    #log()
    #log('Number of rows in the cycle matrix:', objective)
    return loop_subset
예제 #3
0
def make_model(strong_inequalities=False,
               relax=False,
               callback=False,
               hascapacity=1):
    # Relabel data
    commodities = data.commodities
    arcs = data.arcs
    capacity = data.capacity
    variable_cost = data.variable_cost
    fixed_cost = data.fixed_cost
    nodes = data.nodes
    demand = data.demand
    periods = data.periods

    # Create optimization model
    env = Env(logfilename="")
    m = Model('multi-period-netflow', env)

    # Create variables
    flow, arc_open = {}, {}
    for t in periods:
        for i, j in arcs:
            arc_open[i, j, t] = m.addVar(vtype=GRB.BINARY,
                                         lb=0.0,
                                         ub=1.0,
                                         obj=fixed_cost[(i, j), t],
                                         name='open_{0:d}_{1:d}_{2:d}'.format(
                                             i, j, t))
            for h in commodities:
                origin, destination = [
                    key_val[1] for key_val in demand.keys() if key_val[0] == h
                ][0]
                upper = capacity[i,
                                 j] if has_capacity else demand[(h,
                                                                 (origin,
                                                                  destination),
                                                                 t)]
                flow[h, i, j,
                     t] = m.addVar(obj=variable_cost[i, j],
                                   name='flow_{0:d}_{1:d}_{2:d}_{3:d}'.format(
                                       h, i, j, t))
    m.update()

    # Arc capacity constraints and unique arc setup constraints
    constrs = []
    for (i, j) in arcs:
        m.addConstr(
            quicksum(arc_open[i, j, l]
                     for l in range(1,
                                    len(data.periods) + 1)) <= 1,
            'unique_setup{0:d}_{1:d}'.format(i, j))
        for t in periods:
            if not hascapacity:
                capacity[i, j] = sum(demand[i] for i in demand.keys()
                                     if i[2] == t)
            m.addConstr(
                quicksum(flow[h, i, j, t] for h in commodities) <=
                capacity[i, j] * quicksum(arc_open[i, j, s]
                                          for s in xrange(1, t + 1)),
                'cap_{0:d}_{1:d}_{2:d}'.format(i, j, t))
            if not callback and strong_inequalities:
                for (commodity, (origin, destination), period) in demand:
                    if period == t:
                        constrs.append(
                            m.addConstr(
                                flow[commodity, i, j, t] <=
                                demand[commodity,
                                       (origin, destination), period] *
                                quicksum(arc_open[i, j, l]
                                         for l in range(1, t + 1)),
                                name='strong_com{0:d}_{1:d}-{2:d}_per{3:d}'.
                                format(commodity, i, j, t)))

    # Flow conservation constraints
    for (commodity, (origin, destination), period) in demand:
        for j in nodes:
            if j == origin:
                node_demand = demand[commodity, (origin, destination), period]
            elif j == destination:
                node_demand = -demand[commodity, (origin, destination), period]
            else:
                node_demand = 0
            h = commodity
            m.addConstr(
                -quicksum(flow[h, i, j, period]
                          for i, j in arcs.select('*', j)) +
                quicksum(flow[h, j, k, period]
                         for j, k in arcs.select(j, '*')) == node_demand,
                'node_{0:d}_{1:d}_{2:d}'.format(h, j, period))

    m.update()

    # Compute optimal solution
    m.setParam("TimeLimit", 7200)
    # m.params.NodeLimit = 1
    # m.params.cuts = 0
    # m.setParam("Threads", 2)
    m.setAttr('Lazy', constrs, [3] * len(constrs))
    # m.write("eyes.lp")
    #
    try:
        if strong_inequalities:
            if not relax:
                # m.setParam("NodeLimit", 1000000)
                # m.params.Cuts = 0
                if callback:
                    print 'callback in action! :)'
                    m.params.preCrush = 1
                    m.update()
                    m._vars = m.getVars()
                    m.optimize(strong_inequalities_callback)
                else:
                    m.optimize(time_callback)
            else:
                m = m.relax()
                m.optimize(time_callback)

        else:
            m.optimize(time_callback)
        if PRINT_VARS:
            for var in m.getVars():
                if str(var.VarName[0]) == 'f' and var.X > 0.0001:
                    name = var.VarName.split('_')
                    print 'arc: \t {} \t commodity: {} \t period: {} \t value: \t {}'.format(
                        (int(name[2]), int(name[3])), int(name[1]),
                        int(name[4]), var.x)
            # Grab the positive flows and see how many variables open during the first period
            positive_flows = [
                var for var in m.getVars()
                if var.VarName[0] == 'o' and var.X > 0.5
            ]
            first_period_arcs = sum([
                var.X for var in positive_flows
                if int(var.VarName.split('_')[3]) == 1
            ])
            print '% of arcs that open in first period: {}%'.format(
                100 * first_period_arcs / len(positive_flows))
            print '% of arcs that are utilized: {}%'.format(
                (100. * len(positive_flows)) / len(data.arcs))
            objective = m.getObjective().getValue()
            fixed_cost_percentage = sum([
                fixed_cost[(i, j), t] * arc_open[i, j, t].X
                for i, j in data.arcs for t in data.periods
            ]) / objective
            print 'Fixed cost percentage: {}%'.format(fixed_cost_percentage *
                                                      100.)
            for var in m.getVars():
                if str(var.VarName[0]) == 'o' and var.X > 0.0001:
                    name = var.VarName.split('_')
                    print 'Arc: \t {} \t Period: {} \t Value: \t {}'.format(
                        (int(name[1]), int(name[2])), int(name[3]), var.X)
            # m.write('trial2.lp')
    except:
        if m.status == GRB.status.INFEASIBLE and DEBUG:
            print 'Infeasible model. Computing IIS..'
            m.computeIIS()
            m.write('trial.ilp')
예제 #4
0
def from_gurobipy(model: Model) -> QuadraticProgram:
    """Translate a gurobipy model into a quadratic program.

    Note that this supports only basic functions of gurobipy as follows:
    - quadratic objective function
    - linear / quadratic constraints
    - binary / integer / continuous variables

    Args:
        model: The gurobipy model to be loaded.

    Returns:
        The quadratic program corresponding to the model.

    Raises:
        QiskitOptimizationError: if the model contains unsupported elements.
        MissingOptionalLibraryError: if gurobipy is not installed.
    """

    _check_gurobipy_is_installed("from_gurobipy")

    if not isinstance(model, Model):
        raise QiskitOptimizationError(f"The model is not compatible: {model}")

    quadratic_program = QuadraticProgram()

    # Update the model to make sure everything works as expected
    model.update()

    # get name
    quadratic_program.name = model.ModelName

    # get variables
    # keep track of names separately, since gurobipy allows to have None names.
    var_names = {}
    for x in model.getVars():
        if x.vtype == gp.GRB.CONTINUOUS:
            x_new = quadratic_program.continuous_var(x.lb, x.ub, x.VarName)
        elif x.vtype == gp.GRB.BINARY:
            x_new = quadratic_program.binary_var(x.VarName)
        elif x.vtype == gp.GRB.INTEGER:
            x_new = quadratic_program.integer_var(x.lb, x.ub, x.VarName)
        else:
            raise QiskitOptimizationError(
                f"Unsupported variable type: {x.VarName} {x.vtype}")
        var_names[x] = x_new.name

    # objective sense
    minimize = model.ModelSense == gp.GRB.MINIMIZE

    # Retrieve the objective
    objective = model.getObjective()
    has_quadratic_objective = False

    # Retrieve the linear part in case it is a quadratic objective
    if isinstance(objective, gp.QuadExpr):
        linear_part = objective.getLinExpr()
        has_quadratic_objective = True
    else:
        linear_part = objective

    # Get the constant
    constant = linear_part.getConstant()

    # get linear part of objective
    linear = {}
    for i in range(linear_part.size()):
        linear[var_names[linear_part.getVar(i)]] = linear_part.getCoeff(i)

    # get quadratic part of objective
    quadratic = {}
    if has_quadratic_objective:
        for i in range(objective.size()):
            x = var_names[objective.getVar1(i)]
            y = var_names[objective.getVar2(i)]
            v = objective.getCoeff(i)
            quadratic[x, y] = v

    # set objective
    if minimize:
        quadratic_program.minimize(constant, linear, quadratic)
    else:
        quadratic_program.maximize(constant, linear, quadratic)

    # check whether there are any general constraints
    if model.NumSOS > 0 or model.NumGenConstrs > 0:
        raise QiskitOptimizationError(
            "Unsupported constraint: SOS or General Constraint")

    # get linear constraints
    for constraint in model.getConstrs():
        name = constraint.ConstrName
        sense = constraint.Sense

        left_expr = model.getRow(constraint)
        rhs = constraint.RHS

        lhs = {}
        for i in range(left_expr.size()):
            lhs[var_names[left_expr.getVar(i)]] = left_expr.getCoeff(i)

        if sense == gp.GRB.EQUAL:
            quadratic_program.linear_constraint(lhs, "==", rhs, name)
        elif sense == gp.GRB.GREATER_EQUAL:
            quadratic_program.linear_constraint(lhs, ">=", rhs, name)
        elif sense == gp.GRB.LESS_EQUAL:
            quadratic_program.linear_constraint(lhs, "<=", rhs, name)
        else:
            raise QiskitOptimizationError(
                f"Unsupported constraint sense: {constraint}")

    # get quadratic constraints
    for constraint in model.getQConstrs():
        name = constraint.QCName
        sense = constraint.QCSense

        left_expr = model.getQCRow(constraint)
        rhs = constraint.QCRHS

        linear = {}
        quadratic = {}

        linear_part = left_expr.getLinExpr()
        for i in range(linear_part.size()):
            linear[var_names[linear_part.getVar(i)]] = linear_part.getCoeff(i)

        for i in range(left_expr.size()):
            x = var_names[left_expr.getVar1(i)]
            y = var_names[left_expr.getVar2(i)]
            v = left_expr.getCoeff(i)
            quadratic[x, y] = v

        if sense == gp.GRB.EQUAL:
            quadratic_program.quadratic_constraint(linear, quadratic, "==",
                                                   rhs, name)
        elif sense == gp.GRB.GREATER_EQUAL:
            quadratic_program.quadratic_constraint(linear, quadratic, ">=",
                                                   rhs, name)
        elif sense == gp.GRB.LESS_EQUAL:
            quadratic_program.quadratic_constraint(linear, quadratic, "<=",
                                                   rhs, name)
        else:
            raise QiskitOptimizationError(
                f"Unsupported constraint sense: {constraint}")

    return quadratic_program
예제 #5
0
                                  name='k0')
aircraft_type_1_amount = m.addVar(obj=-Aircraft_leasecost[1],
                                  lb=0,
                                  vtype=GRB.INTEGER,
                                  name='k1')
aircraft_type_2_amount = m.addVar(obj=-Aircraft_leasecost[2],
                                  lb=0,
                                  vtype=GRB.INTEGER,
                                  name='k2')
aircraft_type_3_amount = m.addVar(obj=-Aircraft_leasecost[3],
                                  lb=0,
                                  vtype=GRB.INTEGER,
                                  name='k3')

m.update()
m.setObjective(m.getObjective(),
               GRB.MAXIMIZE)  # The objective is to maximize revenue
"""
=============================================================================
Constraints:
=============================================================================
"""
for i in airports:
    for j in airports:
        m.addConstr(x[i, j] + w[i, j], GRB.LESS_EQUAL, q[i][j])  #C1
        m.addConstr(w[i, j], GRB.LESS_EQUAL, q[i][j] * g[i] * g[j])  #C1*

        m.addConstr(
            x[i, j] + quicksum(
                (w[i, m] * (1 - g[j])) for m in airports) + quicksum(
                    (w[m, j] * (1 - g[i])) for m in airports), GRB.LESS_EQUAL,
예제 #6
0
def _solve_set_covering(N,
                        active_ptls,
                        relaxed_ptls,
                        forbidden_combos,
                        allow_infeasible=True,
                        D=None,
                        K=None):
    """A helper function that solves a set covering problem. The inputs are
    a list of node sets and corresponding costs for the set.
    --
    Fisher, M. L. and Jaikumar, R. (1981), A generalized assignment 
    heuristic for vehicle routing. Networks, 11: 109-124.
    """

    m = Model("SCPCVRP")
    nactive = len(active_ptls.routes)
    nrelaxed = len(relaxed_ptls.routes)
    nforbidden = len(forbidden_combos)

    # the order of the keys is important when we interpret the results
    X_j_keys = range(nactive + nrelaxed)
    # variables and the objective
    X_j_costs = active_ptls.costs + relaxed_ptls.costs
    X_j_node_sets = active_ptls.nodes + relaxed_ptls.nodes
    #update forbidden indices to match the current active petal set
    X_j_forbidden_combos = []
    for fc in forbidden_combos:
        if all(i < nactive for i in fc):
            X_j_forbidden_combos.append(
                [i if i >= 0 else -i - 1 + nactive for i in fc])

    #print("REMOVEME: Solving with K=%d, %d node sets, and %d solutions forbidden" % (K, nactive+nrelaxed,nforbidden))

    if __debug__:
        log(
            DEBUG, "Solving over-constrained VRP as a set covering problem " +
            "with %d petals, where %d of the possible configurations are forbidden."
            % (nactive + nrelaxed, nforbidden))
        if nforbidden > 0:
            log(DEBUG - 2, " and with following solutions forbidden:")
            log(DEBUG - 3, "(petal indices = %s)" % str(X_j_forbidden_combos))
            for fc in X_j_forbidden_combos:
                fc_sol = [0]
                for i in fc:
                    if i < nactive:
                        fc_sol.extend(active_ptls.routes[i][1:])
                    else:
                        fc_sol.extend(relaxed_ptls.routes[i - nactive][1:])
                fc_sol = without_empty_routes(fc_sol)
                log(DEBUG - 2, "%s (%.2f)" % (fc_sol, objf(fc_sol, D)))

    X_j = m.addVars(X_j_keys, obj=X_j_costs, vtype=GRB.BINARY, name='x')

    ## constraints
    c1_constrs, c2_constrs, c3_constrs = _add_set_covering_constraints(
        m, N, K, X_j, X_j_keys, X_j_node_sets, X_j_forbidden_combos)

    ## update the model and solve
    m._vars = X_j
    m.modelSense = GRB.MINIMIZE
    m.update()
    # disable output
    m.setParam('OutputFlag', 0)
    m.setParam('TimeLimit', MAX_MIP_SOLVER_RUNTIME)
    m.setParam('Threads', MIP_SOLVER_THREADS)
    #m.write("petalout.lp")
    m.optimize()

    # restore SIGINT callback handler which is changed by gurobipy
    signal(SIGINT, default_int_handler)

    if __debug__:
        log(DEBUG - 2, "Gurobi runtime = %.2f" % m.Runtime)
        if m.Status == GRB.OPTIMAL:
            log(DEBUG - 3,
                "Gurobi objective = %.2f" % m.getObjective().getValue())

    if m.Status == GRB.OPTIMAL:
        return _decision_variables_to_petals(m.X, active_ptls,
                                             relaxed_ptls), True
    elif m.Status == GRB.TIME_LIMIT:
        raise GurobiError(
            10023, "Gurobi timeout reached when attempting to solve SCPCVRP")
    elif m.Status == GRB.INTERRUPTED:
        raise KeyboardInterrupt()
    # Sometimes the solution is infeasible, try to relax it a little.
    elif m.Status == GRB.INFEASIBLE and allow_infeasible:
        return _relax_customer_constraints_with_feasRelax(
            m, c1_constrs, active_ptls, relaxed_ptls)
    return None, False
예제 #7
0
                model.addConstr(x[t,
                                  j] == quicksum(y[t, j, k] for k in range(K)),
                                name="R8_{}{}".format(t, j))

        ## Disponibilidad de personas:
        for t in range(T):
            for j in range(m):
                model.addConstr(x[t, j] <= quicksum(a_tji[t][j][i]
                                                    for i in range(n)),
                                name="R9_{}{}".format(t, j))

        ## No negatividad
        for t in range(T):
            for j in range(m):
                model.addConstr(x[t, j] >= 0, name="R10_{}{}".format(t, j))
                for k in range(K):
                    model.addConstr(z[t, j, k] >= 0,
                                    name="R11_{}{}{}".format(t, j, k))
                    model.addConstr(y[t, j, k] >= 0,
                                    name="R12_{}{}{}".format(t, j, k))
                for r in range(R):
                    model.addConstr(s[t, r, j] >= 0,
                                    name="R13_{}{}{}".format(t, j, r))

        # SOLUCIÓN
        model.optimize()
        print("Numero de soluciones: {}".format(model.solCount))
        model.printAttr("X")
        model.write("out.sol")
        print("Valor optimo:", model.getObjective().getValue())
예제 #8
0
def optimize(parameter, obj):
    global ft

    N = parameter[0]
    D = parameter[1]
    A = parameter[2]
    R = parameter[3]
    M = parameter[4]
    u = parameter[5]
    q = parameter[6]
    e = parameter[7]
    l = parameter[8]
    vehicles = parameter[9]
    m = parameter[10]
    clients = parameter[11]
    Q = parameter[12]
    V = parameter[13]
    c = parameter[14]
    xc = parameter[15]
    yc = parameter[16]
    k = parameter[17]
    n = clients

    #model in gurobipy
    mdl = Model("MDCCVRPTW")

    x = mdl.addVars(V, V, R, vtype=GRB.BINARY)  #X variable
    t = mdl.addVars(V, R, vtype=GRB.CONTINUOUS)  #t variable

    if obj == 1:
        mdl.modelSense = GRB.MINIMIZE
        mdl.setObjective(quicksum(t[i, k] for i in N
                                  for k in R))  #objective function 1
    elif obj == 2:
        mdl.modelSense = GRB.MINIMIZE
        mdl.setObjective(quicksum(t[i, k] - e[i] for i in N
                                  for k in R))  #objective function 2
    elif obj == 3:
        mdl.modelSense = GRB.MAXIMIZE
        mdl.setObjective(quicksum(l[i] - t[i, k] for i in N
                                  for k in R))  #objective function 3
    elif obj == 4:
        mdl.modelSense = GRB.MINIMIZE
        mdl.setObjective((1 / n) * quicksum((t[i, k] - e[i]) / (l[i] - e[i])
                                            for i in N
                                            for k in R))  #objective function 4
    #restrictions

    mdl.addConstrs(
        quicksum(x[i, j, k] for i in V for k in R if i != j) == 1
        for j in N)  #(2)
    mdl.addConstrs(
        (quicksum(x[i, j, k]
                  for i in V if i != j) - quicksum(x[j, i, k]
                                                   for i in V if i != j)) == 0
        for j in N for k in R)  #(3)
    mdl.addConstrs(quicksum(x[i, j, k] for i in D for j in V) == 1
                   for k in R)  #(4)
    mdl.addConstrs(quicksum(x[j, i, k] for i in D for j in V) == 1
                   for k in R)  #(5)
    mdl.addConstrs(
        quicksum(q[j] * x[i, j, k] for i in V for j in V if i != j) <= Q
        for k in R)  #(6)
    #mdl.addConstrs(t[i,k]+c[i,j]+u[i]-t[j,k]<=(1-x[i,j,k])*M for i in V for j in N for k in R if i!=j) #(7) NUEVA
    mdl.addConstrs((x[i, j, k] == 1) >>
                   (t[i, k] + c[i, j] + u[i] - t[j, k] <= 0) for i in V
                   for j in N for k in R if i != j)  #(7) NUEVA
    mdl.addConstrs(e[i] <= t[i, k] for i in V for k in R)  #(8) NUEVA
    mdl.addConstrs(t[i, k] + u[i] <= l[i] for i in V for k in R)  #(9) NUEVA
    mdl.addConstrs(t[i, k] >= 0 for i in V for k in R)

    #mdl.Params.MIPGap= 0.1
    mdl.Params.Timelimit = 3600
    mdl.Params.SolFiles
    first_sol = 'Not Found'

    try:
        mdl.optimize(mycallback)
        if len(ft) > 0:
            first_sol = min(ft)
        #print(ft,first_sol)
        ft = []

        obj = mdl.getObjective()
        sol = []

        for i in V:
            for j in V:
                for k in R:
                    if x[i, j, k].x > 0.7:
                        s = "x[{},{},{}]={}, t[{},{}]={}".format(
                            i, j, k, x[i, j, k].x, i, k, t[i, k].x)
                        sol.append(s)
        for i in V:
            plt.annotate("Node_{}".format(i),
                         (xc[i - 1], yc[i - 1])).set_fontsize(3)

        colors = itertools.cycle(["r", "b", "g", "c", "m", "y", "k"])

        #plot active arcs
        #for i,j in active_arcs:
        #    plt.plot([xc[i-1],xc[j-1]],[yc[i-1],yc[j-1]],c=next(colors), linewidth=.85)

        for k in R:
            prox_color = next(colors)
            for i in V:
                for j in V:
                    if x[i, j, k].x > 0.9:
                        plt.plot([xc[i - 1], xc[j - 1]],
                                 [yc[i - 1], yc[j - 1]],
                                 c=prox_color,
                                 linewidth=.45,
                                 zorder=1)
                        #plt.annotate("k={}".format(k),((xc[j-1]+xc[i-1])/2,(yc[j-1]+yc[i-1])/2)).set_fontsize(4)

        plt.scatter(xc[0:clients], yc[0:clients], c='b', s=10, zorder=2)
        plt.scatter(xc[clients:], yc[clients:], c='r', s=10, zorder=2)
        #plt.figure(figsize=(10, 10), dpi=80)
        #plt.axis('auto')
        #fig.suptitle('test title', fontsize=20)
        plt.axis('off')
        #plt.savefig("test.png")
        plt.rcParams.update({'font.size': 4})
        name = str(n) + 'x' + str(m) + '_' + str(k) + '.png'
        plt.savefig('Images\\' + name, dpi=400, bbox_inches=0)

        #plt.show()
        #print(D)

        return obj.getValue(
        ), mdl.Runtime, vehicles, clients, m, mdl.MIPGap, first_sol, sol

    except gp.GurobiError as e:
        print('Error code ' + str(e.errno) + ': ' + str(e))

    except AttributeError:
        print('Encountered an attribute error')
        return [
            'Not Found', mdl.Runtime, vehicles, clients, m, 'Not Found',
            first_sol
        ] + [[None]]
예제 #9
0
    def execute(self):
        model = Model('State migration')
        # print 'Tan list', self.tan_list
        # print 'edge list', self.edge_list
        # Decision variables
        x = model.addVars(self.tan_list, self.edge_list, vtype=GRB.BINARY, name='x')               # edge selection constraint
        y = model.addVars(self.edge_list, vtype=GRB.BINARY, name='y')

        # Constraints
        model.addConstrs((sum(x[ctan, ten] for ten in self.edge_list) == 1 for ctan in self.tan_list), 'edge selection constraint')

        model.addConstrs((x[ctan, ten]*self._e2e_latency(ctan, ten) <= self.service_delay for ctan in self.tan_list for ten in self.edge_list), 'e2e service ')

        # model.addConstrs((x[ctan, ten]*self._est_link_node(edge, ctan) <= self._link_cap(edge) for ctan in self.tan_list for ten in self.edge_list for edge in self._path_list(ctan, ten)), 'link capacity constraint')

        model.addConstrs((self._curr_link_node(edge) + sum(x[ctan, ten]*self.edge_usage(edge, ctan, ten) for ctan in self.tan_list for ten in self.edge_list) <= self._link_cap(edge) for edge in self.all_possible_edges()), 'link capacity constraint')           # noqa

        # print "test mig cost:", self._mig_comm_cost(random.choice(self.tan_list), random.choice(self.edge_list))
        # print "Orig cost:", self._orig_comm_cost()
        # objectives

        # model.addConstrs((y[ten] == 1 if sum(x[otan, ten] for otan in self.tan_list) >= 1 else 0 for ten in self.edge_list), 'edge node constraint')

        model.addConstrs((y[ten] == any([x[otan, ten] for otan in self.tan_list]) for ten in self.edge_list), 'edge node constraint')


        # print 'original objective:', self._orig_comm_cost()
        # model.setObjective(sum(x[otan, ten]*self._mig_comm_cost(otan, ten) for otan in self.tan_list for ten in self.edge_list), GRB.MINIMIZE)

        # total_comm_cost =\
        #     (self._orig_comm_cost() - sum(x[otan, ten]*self._mig_comm_cost(otan, ten) for otan in self.tan_list for ten in self.edge_list))/float(10**6)   # in Mbps

        total_comm_cost = sum(
                x[otan, ten] * self._mig_comm_cost(otan, ten) for otan in self.tan_list for ten in
                self.edge_list) / float(10 ** 6)  # in Mbps

        total_state_transfer_cost = sum(
            x[stan, sten]*self.buffering_cost(stan, sten) for stan in self.tan_list for sten in self.edge_list)/float(10**9)   # in Mb (b --> Mb, ms --> s)

        # model.setObjective(total_comm_cost - total_state_transfer_cost, GRB.MAXIMIZE)

        total_comp_cost = sum(y[ten]*self.is_orig(ten) for ten in self.edge_list)

        model.setObjective(ALPHA*total_comm_cost + BETA*total_state_transfer_cost + GAMMA*total_comp_cost, GRB.MINIMIZE)


        # model.setObjective(total_comm_cost, GRB.MAXIMIZE)

        # model.setObjective(total_state_transfer_cost, GRB.MAXIMIZE)

        model.optimize()

        if model.solCount == 0:
            print("Model is infeasible")

        obj = model.getObjective()
        #
        res_total_comm_cost = \
            (self._orig_comm_cost() - sum(
                getattr(x[otan, ten], 'X') * self._mig_comm_cost(otan, ten) for otan in self.tan_list for ten in
                self.edge_list)) / float(10 ** 6)  # in Mbps

        res_mig_comm_cost = sum(getattr(x[otan, ten], 'X') * self._mig_comm_cost(otan, ten) for otan in self.tan_list for ten in self.edge_list)/float(10 ** 6)  # in Mbps

        res_total_state_transfer_cost =\
            sum(getattr(x[stan, sten], 'X')*self.buffering_cost(stan, sten) for stan in self.tan_list for sten in self.edge_list)/float(10**9)   # in Mb (b --> Mb, ms --> s)

        res_mig_time = \
            sum(getattr(x[stan, sten], 'X') * self.total_mig_time(stan, sten) for stan in self.tan_list for sten in
                self.edge_list)

        # res_total_comp_cost = sum(
        #     sum(getattr(x[stan, sten], 'X') for stan in self.tan_list) for sten in self.edge_list
        # )

        res_total_comp_cost = sum(getattr(y[ten], 'X') * self.is_orig(ten) for ten in self.edge_list)

        res_state_trans_time = \
            sum(getattr(x[stan, sten], 'X') * self.state_transmission_time(stan, sten) for stan in self.tan_list for sten in
                self.edge_list)

        print "Optimal"
        print 'Total cost:', obj.getValue()
        #
        # print 'Total comm cost:', res_total_comm_cost
        # print 'Orig cost:', self._orig_comm_cost()/float(10**6)
        print "Comm cost:", res_mig_comm_cost
        #
        print 'Buffering cost:', res_total_state_transfer_cost

        print "Comp cost:", res_total_comp_cost
        # print 'Total migration time:', res_mig_time
        # print 'State Transmission time:', res_state_trans_time

        # print 'Benefit:', self._orig_comm_cost() - obj.getValue()
        # for v in model.getVars():
        #     print('%s %g' % (v.varName, v.x))
        # time.sleep(2)

        return obj.getValue(), res_mig_comm_cost, res_total_state_transfer_cost, res_mig_time, res_total_comp_cost