Ejemplo n.º 1
0
def generate_row_model(row_matrix, b, v, c):
    """
    rows_matrix: The matrix, represented as a list of rows
    b: List of variables in b
    v: The target vector
    c: The weights of each column
    """

    # Initializes a model
    mdl = Model('persistenthomologylocalization')

    # Add matrix variables
    x = mdl.addVars(list(b), vtype=GRB.BINARY)

    # Add the dummy variable needed to do arithmetics mod 2
    y = mdl.addVars(list(range(len(row_matrix))), vtype=GRB.INTEGER)

    # Set model to minimization
    mdl.modelSense = GRB.MINIMIZE

    # Set objective function to minimize
    mdl.setObjective(quicksum(x[j] * c[j] for j in b))

    # Set the constrains
    for i in list(range(len(row_matrix))):
        mdl.addConstr(quicksum(x[j] for j in row_matrix[i]) + v[i] == y[i] * 2)
    return mdl, x, y
    def create_model(self):
        model = Model()
        _A = [(i,t) for i in self.tasks for t in self.periods]
        x = model.addVars(_A, vtype = GRB.BINARY) # create decision variables
        b = model.addVars(_A, vtype = GRB.BINARY) # create decision variables

        # create constraints
        model.addConstrs(quicksum(self.p[i,t] * (1 - x[i,t]) for i in self.tasks) - \
            self.d[t] >= 0 for t in self.periods) # 1
        model.addConstrs(quicksum(b[i,t] for t in self.periods) == 1 \
            for i in self.tasks) # 2
        model.addConstrs(x[i,t] >= b[i,t] for i in self.tasks for t in self.periods) # 3
        model.addConstrs(x[i,t] - x[i,t-1] <= b[i,t] for i in self.tasks \
            for t in self.periods[1:]) # 3, t >= 2
        _tmp =  self.periods[1:]
        # model.addConstrs(x[i,t] <= b[i,t] for t in _tmp \
        #     for i in self.tasks) # 4
        model.addConstrs(x[i,t] + x[i,t-1] + b[i,t] <= 1+self.LP[i] for t in self.periods[1:] \
            for i in self.tasks) # 4
        model.addConstrs(quicksum(x[i,t] for t in self.periods) == self.LP[i] \
            for i in self.tasks) # 5
        model.addConstrs(quicksum(x[i,t] for i in self.tasks) <= self.LT[t] \
            for t in self.periods) # 6
        model.addConstrs(quicksum(b[i,k] for k in self.periods) - b[j,t] >= 0 \
            for t in self.periods for i in self.tasks for j in self.tasks if j!=i) # 7
        model.addConstrs(x[i,t] + x[j,t] <= 1 for t in self.periods \
            for i in self.tasks for j in self.tasks if j!=i) # 8
        model.addConstrs(quicksum(b[i,t] for t in self.periods[:self.L[i]-self.LP[i]+2]) == 1 \
            for i in self.tasks) # 9
        # model.addConstrs(quicksum(x[i,t] == 0 for t in self.U) for i in self.tasks) # 10
        model.addConstrs(x[i,t] == 0 for t in self.U for i in self.tasks) # 10
        model.addConstrs(quicksum((self.MV[i] + self.MH[i] + self.ML[i]) * x[i,t] \
            for i in self.tasks) <= self.AM[t] for t in self.periods) # 11
        model.addConstrs(quicksum(self.V[i] * x[i,t] for i in self.tasks) \
            <= self.AV[t] for t in self.periods) # 12
        model.addConstrs(quicksum(self.H[i] * x[i,t] for i in self.tasks) <= \
            self.AH[t] for t in self.periods) # 13

        # create costs
        C_M, C_T = {}, {}
        for i in self.tasks:
            for t in self.periods:
                C_M[i,t] = self.C_MV[t] * self.MV[i] + self.C_MH[t] * self.MH[i] + \
                    self.C_ML[t] * self.ML[i]
                C_T[i,t] = (self.C_FV * self.V[i] + self.C_FH * self.H[i])/self.LP[i] + \
                    self.C_SV[i,t] * self.V[i] + self.C_SH[i,t] * self.H[i]

        model.modelSense = GRB.MINIMIZE
        # create ojective function
        model.setObjective(quicksum((C_M[i,t] + self.C_EQ[i,t] + self.C_I[i,t] + \
            C_T[i,t]) * x[i,t] for t in self.periods for i in self.tasks))
        # model.setParam('OutputFlag', 0)
        model.optimize()
        return
Ejemplo n.º 3
0
    def generateInstance(self):

        def euc_dist(bor, sh):
            dx = bor["x_coord"] - sh["x_coord"]
            dy = bor["y_coord"] - sh["y_coord"]
            return math.sqrt(dx * dx + dy * dy)

        model = Model('FireSolver')

        # Generate variables
        x = {}
        for bor in self.boroughs:
            # New firehouses
            for fh in self.new_firehouses + self.old_firehouses:
                name = "x_" + fh["loc_id"] + "_" + bor["loc_id"]
                x[bor["loc_id"], fh["loc_id"]] = model.addVar(name=name, vtype ="b", obj=self.cost_coef * euc_dist(bor, fh))

        # Open variables
        openfh = {}
        for fh in self.new_firehouses:
            openfh[fh["loc_id"]] = model.addVar(name = "open_" + fh["loc_id"], vtype ="b", obj=fh["construction_cost"])

        # Close variables
        closefh = {}
        for fh in self.old_firehouses:
            closefh[fh["loc_id"]] = model.addVar(name = "close_" + fh["loc_id"], vtype ="b", obj=fh["destruction_cost"])

        model.modelSense = GRB.MINIMIZE
        model.update()

        # Constraints: one firehouse / borough
        for bor in self.boroughs:
            model.addConstr(quicksum(x[key] for key in x if key[0] == bor["loc_id"]) == 1)

        # capacity of firehouses
        for fh in self.new_firehouses:
            model.addConstr(quicksum(x[key] for key in x if key[1] == fh["loc_id"]) <= self.capacity * openfh[fh["loc_id"]])

        # If it is not removed, the initial assignment needs to be respected
        for fh in self.old_firehouses:
            for bor in self.boroughs:
                if bor["currently_protected_by"] == fh["loc_id"]:
                    model.addConstr(x[bor["loc_id"], fh["loc_id"]] == 1 - closefh[fh["loc_id"]])
                else:
                    model.addConstr(x[bor["loc_id"], fh["loc_id"]] == 0)
        
        # solve it
        model.optimize()

        self.model = model
Ejemplo n.º 4
0
def _mmp_solve(w1_ij, x_ij_keys, n, w2_ij=None):
    """A helper function that solves a weighted maximum matching problem.
    """

    m = Model("MBSA")

    if __debug__:
        log(DEBUG, "")
        log(
            DEBUG, "Solving a weighted maximum matching problem with " +
            "%d savings weights." % len(w1_ij))

    # build model
    x_ij = m.addVars(x_ij_keys, obj=w1_ij, vtype=GRB.BINARY, name='x')
    _mmp_add_cnts_sum(m, x_ij, x_ij_keys, w1_ij, n)
    m._vars = x_ij
    m.modelSense = GRB.MAXIMIZE
    m.update()

    # disable output
    m.setParam('OutputFlag', 0)
    m.setParam('TimeLimit', MAX_MIP_SOLVER_RUNTIME)
    m.setParam('Threads', MIP_SOLVER_THREADS)
    #m.write("out.lp")
    m.optimize()

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

    if __debug__:
        log(DEBUG - 1, "Gurobi runtime = %.2f" % m.Runtime)

    if m.Status == GRB.OPTIMAL:
        if w2_ij == None:
            max_wt, max_merge = max(
                (w1_ij[k], x_ij_keys[k]) for k, v in enumerate(m.X) if v)
        else:
            max_wt, _, max_merge = max((w1_ij[k], w2_ij[k], x_ij_keys[k])
                                       for k, v in enumerate(m.X) if v)

        return max_wt, max_merge[0], max_merge[1]
    elif m.Status == GRB.TIME_LIMIT:
        raise GurobiError(
            10023, "Gurobi timeout reached when attempting to solve GAP")
    elif m.Status == GRB.INTERRUPTED:
        raise KeyboardInterrupt()
    return None
Ejemplo n.º 5
0
def vrproutes(n, xc, yc, cost_func):
    rnd = np.random
    rnd.seed(0)
    plt.plot(xc[0], yc[0], c='r', marker='s')
    plt.scatter(xc[1:], yc[1:], c='b')
    N = [i for i in range(1, n + 1)]
    V = [0] + N
    A = [(i, j) for i in V for j in V if i != j]
    # c = {(i, j): np.hypot(xc[i]-xc[j], yc[i]-yc[j]) for i, j in A}
    c = {(i, j): cost_func(i, j) for i, j in A}
    print(c)
    Q = 20
    q = {i: rnd.randint(1, 10) for i in N}

    mdl = Model('CVRP')

    x = mdl.addVars(A, vtype=GRB.BINARY)
    u = mdl.addVars(N, vtype=GRB.CONTINUOUS)

    mdl.modelSense = GRB.MINIMIZE
    mdl.params.LogToConsole = False
    mdl.setObjective(quicksum(x[i, j] * c[i, j] for i, j in A))

    mdl.addConstrs(quicksum(x[i, j] for j in V if j != i) == 1 for i in N)
    mdl.addConstrs(quicksum(x[i, j] for i in V if i != j) == 1 for j in N)
    mdl.addConstrs((x[i, j] == 1) >> (u[i] + q[j] == u[j]) for i, j in A
                   if i != 0 and j != 0)
    mdl.addConstrs(u[i] >= q[i] for i in N)
    mdl.addConstrs(u[i] <= Q for i in N)

    mdl.Params.MIPGap = 0.001
    mdl.Params.TimeLimit = 60  # seconds
    mdl.optimize()

    active_arcs = [a for a in A if x[a].x > 0.5]
    return active_arcs
    def schedule_all(self, timelimit=0):

        if not self.reservation_list:
            return self.schedule_dict

        # populate all the windows, requests, etc
        self.build_data_structures()

        # weight the priorities in each timeslice by airmass
        self.weight_by_airmass()

        # Instantiate a Gurobi Model object
        m = Model("LCOGT Schedule")

        # Constraint: Decision variable (isScheduled) must be binary (eq 4)
        requestLocations = tuplelist()
        scheduled_vars = []
        for r in self.Yik:
            # convert self.Yik to a tuplelist for optimized searches
            # [(reqID, window idx, priority, resource, isScheduled)]
            var = m.addVar(vtype=GRB.BINARY, name=str(r[0]))
            scheduled_vars.append(var)
            requestLocations.append((r[0], r[1], r[2], r[3], var))

        # update the Gurobi model to use isScheduled variables in constraints
        m.update()

        for i, r in enumerate(self.Yik):
            scheduled_vars[i].start = r[4]

        m.update()

        # Constraint: One-of (eq 5)
        i = 0
        for oneof in self.oneof_constraints:
            match = tuplelist()
            for r in oneof:
                reqid = r.get_ID()
                match += requestLocations.select(reqid, '*', '*', '*', '*')
                r.skip_constraint2 = True  # does this do what I think it does?
            nscheduled = quicksum(isScheduled for reqid, winidx, priority, resource, isScheduled in match)
            m.addConstr(nscheduled <= 1, "oneof_constraint_" + str(i))
            i = i + 1

        # Constraint: And (all or nothing) (eq 6)
        i = 0
        andtuple = tuplelist()
        for andconstraint in self.and_constraints:
            # add decision variable that must be equal to all "and"ed blocks
            andVar = m.addVar(vtype=GRB.BINARY, name="and_var_" + str(i))
            m.update()
            j = 0
            for r in andconstraint:
                reqid = r.get_ID()
                match = requestLocations.select(reqid, '*', '*', '*', '*')
                nscheduled = quicksum(isScheduled for reqid, winidx, priority, resource, isScheduled in match)
                m.addConstr(andVar == nscheduled, "and_constraint_" + str(i) + "_" + str(j))
                j = j + 1
            i = i + 1

        # Constraint: No more than one request should be scheduled in each (timeslice, resource) (eq 3)
        # self.aikt.keys() indexes the requests that occupy each (timeslice, resource)
        #        for s in self.aikt: # faster??
        for s in self.aikt.keys():
            match = tuplelist()
            for timeslice in self.aikt[s]:
                match.append(requestLocations[timeslice])
            nscheduled = quicksum(isScheduled for reqid, winidx, priority, resource, isScheduled in match)
            m.addConstr(nscheduled <= 1, 'one_per_slice_constraint_' + s)

        # Constraint: No request should be scheduled more than once (eq 2)
        # skip if One-of (redundant)
        for r in self.reservation_list:
            if not hasattr(r, 'skip_constraint2'):
                reqid = r.get_ID()
                match = requestLocations.select(reqid, '*', '*', '*', '*')
                nscheduled = quicksum(isScheduled for reqid, winidx, priority, resource, isScheduled in match)
                m.addConstr(nscheduled <= 1, 'one_per_reqid_constraint_' + str(reqid))

        # Objective: Maximize the merit functions of all scheduled requests (eq 1);
        objective = quicksum(
            [isScheduled * (priority + 0.1 / (winidx + 1.0)) for req, winidx, priority, resource, isScheduled in
             requestLocations])

        # set the objective, and maximize it
        m.setObjective(objective)
        m.modelSense = GRB.MAXIMIZE

        # impose a time limit on the solve
        if timelimit > 0:
            m.params.timeLimit = timelimit
        # Set the tolerance for the model solution to be within 1% of what it thinks is the best solution
        m.params.MIPGap = 0.01

        # Set the Method of solving the root relaxation of the MIPs model to concurrent (default is dual simplex)
        m.params.Method = 3

        # add all the constraints to the model
        m.update()

        # Solve the model
        m.optimize()

        # Return the optimally-scheduled windows
        r = Result()
        r.xf = []
        for request, winidx, priority, resource, isScheduled in requestLocations: r.xf.append(isScheduled.x)
        return self.unpack_result(r)
Ejemplo n.º 7
0
y = m.addVars(species, vtype=GRB.BINARY, name="select")

D = m.addVar(name="max_diss", obj = 1)

m.addConstrs(
    (x.sum(i,'*') <= 10 * y[i] for i in species), "group")

m.addConstrs(
    (x.sum('*',j) == 1 for j in species), "assign")

m.addConstr(y.sum() == 1)

m.addConstrs(dissimilarity[i][j] * x[i,j] <= D for i in species for j in species)

# The objective is to minimize the group dissimilarity within group and maximize the group dissimilarity between groups
m.modelSense = GRB.MINIMIZE

# Solve
m.optimize()


# Create an empty directed graph
G = nx.DiGraph()
for i in species:
    for j in species:
        if x[i,j].x > 0:
			G.add_edge(i, j, cost=dissimilarity[i][j])

print('SUB GRAPH NODE LIST: ')
for i in species:
	subNodeList = [];
#!/usr/bin/env python
 
# This is the GAP per Wolsey, pg 182, using Lagrangian Relaxation
 
from gurobipy import GRB, Model
 
model = Model('GAP per Wolsey with Lagrangian Relaxation')
model.modelSense = GRB.MAXIMIZE
model.setParam('OutputFlag', False) # turns off solver chatter
 
b = [15, 15, 15]
c = [
    [ 6, 10,  1],
    [12, 12,  5],
    [15,  4,  3],
    [10,  3,  9],
    [ 8,  9,  5]
]
a = [
    [ 5,  7,  2],
    [14,  8,  7],
    [10,  6, 12],
    [ 8,  4, 15],
    [ 6, 12,  5]
]
 
# x[i][j] = 1 if i is assigned to j
x = []
for i in range(len(c)):
    x_i = []
    for j in c[i]:
Ejemplo n.º 9
0
def _solve_gap(N, D_s, d, C, K, L=None, L_ctr_multipiler=1.0):
    """A helper function that Solves VRP as a Generalized Assignment Problem
    to assign customers to vehicles with a objective function that the delivery
    cost as described in (Fisher & Jaikumar 1981).
    
    D_s is the distance matrix complemented with distances to K seed points.
    That is:
          [D_0]
    D_s = [S  ], where D_0 is the first row of the full distance matrix and
                         S is the distances from seed points to node points
    d is the list of customer demands with d[0]=0 being the depot node
    C is the capacity of the K identical trucks
    
    also, additional (and optional) constraints can be given:
    
    L is the maximum tour cost/duration/length
    L_ctr_multipiler allows iteratively adjusting the max route cost
     approximation constraint in order to avoid producing assignments that are
     ruled infeasible by the feasibility checker. 
    --
    Fisher, M. L. and Jaikumar, R. (1981), A generalized assignment 
    heuristic for vehicle routing. Networks, 11: 109-124.
    """

    ## build the cost approximation matrix "insertion_cost"

    # it is ~ a insertion cost matrix, where each coefficient is the cost
    #  of inserting customer i to the route consisting visit to seed k.
    #
    # we assume that distances are symmetric, but if asymmetric
    #  distances are to be used, take min
    # d_{ik} = min(c_{0i}+c_{i{i_k}}+c_{i{i_k}},
    #              c_{0{i_k}}+c_[{i_k}i}+c_{i0})
    #              -(c_{0{i_k}}+c_{{i_k}0})

    m = Model("GAPCVRP")

    # the order of the keys is important when we interpret the results
    Y_ik_keys = [(i, k) for k in range(K) for i in range(1, N)]

    # delivery cost approximation coefficients for the objective function
    insertion_cost = {(i,k): D_s[0,i]+D_s[k,i]-D_s[k,0] \
                              for i,k in Y_ik_keys}

    # variables and the objective
    Y_ik = m.addVars(Y_ik_keys, obj=insertion_cost, vtype=GRB.BINARY, name='y')

    ## constraints

    # c1, the capacity constraint and optional tour cost constraint cl
    approx_route_cost_constraints = []
    if C: c1_coeffs = d[1:]
    for k in range(K):
        ck_vars = [Y_ik[i, k] for i in range(1, N)]
        if C:
            c1_lhs = LinExpr(c1_coeffs, ck_vars)
            #c1_lhs = Y_ik.prod(c1_coeffs, '*', k)
            m.addConstr(c1_lhs <= C, "c1_k%d" % k)

        # ct = optional tour cost constraints
        #  it is a bit hidden, but the additional side constraint can be found
        #  from Fisher & Jaikumar (1981) p121, 2. paragraph.
        # However, for whatever reason, this does not seem to produce the
        #  same results as reported in their paper as the constraint easily
        #  starts to make the problem infeasible and the exact mechanism to
        #  recover that is not specified in the paper.
        if L:
            ct_coeffs = [
                insertion_cost[(i, k)] * L_ctr_multipiler for i in range(1, N)
            ]
            ct_lhs = LinExpr(ct_coeffs, ck_vars)
            #ct_lhs = Y_ik.prod(ct_coeffs, '*', k)
            constr_l = m.addConstr(ct_lhs <= L, "cl_k%d" % k)
            approx_route_cost_constraints.append(constr_l)

    # c2, the assignment constraints
    for i in range(1, N):
        # c2_1..N every node assigned only to 1 route
        m.addConstr(Y_ik.sum(i, '*') == 1, "c1_i%d" % i)

    ## update the model and solve
    m._vars = Y_ik
    m.modelSense = GRB.MINIMIZE
    m.update()
    #m.write("gapvrp_model.lp")
    # disable output
    m.setParam('OutputFlag', 0)
    m.setParam('Threads', MIP_SOLVER_THREADS)
    # REMOVEME
    m.setParam('MIPFocus', 3)
    m.setParam('TimeLimit', MAX_MIP_SOLVER_RUNTIME)

    m.optimize()

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

    if __debug__:
        log(DEBUG - 1, "Gurobi runtime = %.2f" % m.Runtime)

    if m.Status == GRB.OPTIMAL:
        return _decision_variables_to_assignments(m, Y_ik, N, K)
    elif m.Status == GRB.INFEASIBLE and L:
        # relax the model and allow violating minimal number of the approximate
        #  route length constraints
        pens = [1.0] * len(approx_route_cost_constraints)
        m.feasRelax(1, True, None, None, None, approx_route_cost_constraints,
                    pens)
        # TODO: not sure if feasRelax can change Status, test it someday
        if m.Status == GRB.INTERRUPTED:
            raise KeyboardInterrupt()  # pass it on
        m.optimize()

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

        status = m.Status
        if __debug__:
            log(DEBUG - 1, "Relaxed problem Gurobi runtime = %.2f" % m.Runtime)
        if status == GRB.OPTIMAL:
            return _decision_variables_to_assignments(m, Y_ik, N, K)
        elif status == GRB.TIME_LIMIT:
            raise GurobiError(
                10023,
                "Gurobi timeout reached when attempting to solve relaxed SCPCVRP"
            )
        elif m.Status == GRB.INTERRUPTED:
            raise KeyboardInterrupt()  # pass it on
        return None
    elif m.Status == GRB.TIME_LIMIT:
        raise GurobiError(
            10023, "Gurobi timeout reached when attempting to solve GAP")
    elif m.Status == GRB.INTERRUPTED:
        raise KeyboardInterrupt()  # pass it on
    return None
Ejemplo n.º 10
0
    def generateInstance(self):
        # Check that variables have been intialized correctly
        if (not self.planes) or (self.n == 0) or (self.T == 0):
            logging.error('Store is not initialized correctly. Check for completeness of input-file.')
            return None

        model = Model("PlaneSolver")

        """
            r: Earliest landing possibility
            b: Best landing
            d: latest landing
            g: penalty for each time earlier from best
            h: penalty for each time later from best
            s_ij: if i lands before j: s needs to pass in time

            x_i: Landing time for i
            p_i: positive divertion from bi
            n_i: negative divertion from bi

        """

        bigM = max([max(x["s"]) for x in self.planes])
        logging.debug("Using bigM punishment: " + str(bigM))

        # generate Variables
        x = {}  # Landing time
        p = {}  # Positive divertion from optimal landing time
        n = {}  # Negative divertion from optimal landing time
        s = {}  # 1 iff plane i lands before j + buffer is invalid
        s1 = {}  # for these, see constraints
        s2 = {}
        h1 = {}
        h2 = {}
        for i in range(len(self.planes)):
            x[i] = model.addVar(name="x_%d" % (i+1), vtype="i", lb=self.planes[i]["r"], ub=self.planes[i]["d"])
            p[i] = model.addVar(name="p_%d" % (i+1), vtype="i", obj=self.planes[i]["h"], lb=0, ub=self.planes[i]["d"] - self.planes[i]["b"])
            n[i] = model.addVar(name="n_%d" % (i+1), vtype="i", obj=self.planes[i]["g"], lb=0, ub=self.planes[i]["b"] - self.planes[i]["r"])

            for j in range(len(self.planes)):
                s[i, j] = model.addVar(name="s_%d_%d" % (i+1, j+1), vtype="b", obj=bigM, lb=0, ub=1)
                s1[i, j] = model.addVar(name="s1_%d_%d" % (i+1, j+1), vtype="b", obj=0, lb=0, ub=1)
                s2[i, j] = model.addVar(name="s2_%d_%d" % (i+1, j+1), vtype="b", obj=0, lb=0, ub=1)
                h1[i, j] = model.addVar(name="h1_%d_%d" % (i+1, j+1), vtype="i", obj=0, lb=0)
                h2[i, j] = model.addVar(name="h2_%d_%d" % (i+1, j+1), vtype="i", obj=0, lb=0)

        model.modelSense = GRB.MINIMIZE
        model.update()

        for y in model.getVars():
            if y.ub < 10000:
                logging.debug("%10s\t[%5d:%5d]\tobj %4d", y.varName, y.lb, y.ub, y.obj)

        # Constraints
        for i in range(len(self.planes)):
            logging.debug("{} == {} + {} - {}".format(x[i].varName, self.planes[i]["b"], p[i].varName, n[i].varName))
            model.addConstr(x[i] == self.planes[i]["b"] + p[i] - n[i])

            for j in range(len(self.planes)):
                if j == i:
                    continue
                # model.addConstr(x[j] - x[i] )
                # Force s = s1 AND s2
                model.addConstr(s[i, j] <= s1[i, j])
                model.addConstr(s[i, j] <= s2[i, j])
                model.addConstr(s[i, j] >= s1[i, j] + s2[i, j] - 1)

                # s2 == xj - xi > 0
                logging.debug("{}\t <= {}\t - {}\t - {}\t".format(s2[i, j].varName, x[j].varName, x[i].varName, h1[i, j].varName))
                model.addConstr(s2[i, j] <= x[j] - x[i] + h1[i, j])
                logging.debug("{}\t >= 1\t".format(h1[i, j].varName))
                model.addConstr(h1[i, j] >= 1)
                logging.debug("{}\t - {}\t + {}\t <= {}\t*{}\t".format(x[j].varName, x[i].varName, h1[i, j].varName, s2[i, j].varName, bigM))
                model.addConstr(x[j] - x[i] + h1[i, j] <= s2[i, j]*bigM)

                # s1 == xi + sij - xj > 0
                logging.debug("{}\t + {}\t - {}\t >= {}\t".format(x[i].varName, self.planes[i]["s"][j], x[j].varName, s1[i, j].varName))
                model.addConstr(s1[i, j] <= x[i] + self.planes[i]["s"][j] - x[j] + h2[i, j])
                logging.debug("{}\t + {}\t - {}\t <= {}\t*{}\t".format(x[i].varName, self.planes[i]["s"][j], x[j].varName, s1[i, j].varName, bigM))
                model.addConstr(x[i] + self.planes[i]["s"][j] - x[j] <= s1[i, j]*bigM)

        # solve it
        model.optimize()

        # Debugging printouts
        dbgStrs = {}
        for y in model.getVars():
            if y.varName[0:2] not in dbgStrs:
                dbgStrs[y.varName[0:2]] = []
            dbgStrs[y.varName[0:2]].append("%8s = %4s [%4s]" % (y.varName, int(y.x), int(y.x*y.obj) if y.obj else ""))
        for x in dbgStrs:
            dbgStrs[x].sort()

        while dbgStrs:
            printed = False
            keys = [x for x in dbgStrs.keys()]
            keys.sort()
            logStr = ""
            for x in keys:
                if dbgStrs[x]:
                    logStr += dbgStrs[x][0]
                    dbgStrs[x] = dbgStrs[x][1::]
                    printed = True
                else:
                    logStr += " "*22
            logging.debug(logStr)
            if not printed:
                break

        self.model = model
Ejemplo n.º 11
0
    def generateInstance(self):
        # Check that variables have been intialized correctly
        if (not self.planes) or (self.n == 0) or (self.T == 0):
            logging.error(
                'Store is not initialized correctly. Check for completeness of input-file.'
            )
            return None

        model = Model("PlaneSolver")
        """
            r: Earliest landing possibility
            b: Best landing
            d: latest landing
            g: penalty for each time earlier from best
            h: penalty for each time later from best
            s_ij: if i lands before j: s needs to pass in time

            x_i: Landing time for i
            p_i: positive divertion from bi
            n_i: negative divertion from bi

        """

        bigM = max([max(x["s"]) for x in self.planes])
        logging.debug("Using bigM punishment: " + str(bigM))

        # generate Variables
        x = {}  # Landing time
        p = {}  # Positive divertion from optimal landing time
        n = {}  # Negative divertion from optimal landing time
        s = {}  # 1 iff plane i lands before j + buffer is invalid
        s1 = {}  # for these, see constraints
        s2 = {}
        h1 = {}
        h2 = {}
        for i in range(len(self.planes)):
            x[i] = model.addVar(name="x_%d" % (i + 1),
                                vtype="i",
                                lb=self.planes[i]["r"],
                                ub=self.planes[i]["d"])
            p[i] = model.addVar(name="p_%d" % (i + 1),
                                vtype="i",
                                obj=self.planes[i]["h"],
                                lb=0,
                                ub=self.planes[i]["d"] - self.planes[i]["b"])
            n[i] = model.addVar(name="n_%d" % (i + 1),
                                vtype="i",
                                obj=self.planes[i]["g"],
                                lb=0,
                                ub=self.planes[i]["b"] - self.planes[i]["r"])

            for j in range(len(self.planes)):
                s[i, j] = model.addVar(name="s_%d_%d" % (i + 1, j + 1),
                                       vtype="b",
                                       obj=bigM,
                                       lb=0,
                                       ub=1)
                s1[i, j] = model.addVar(name="s1_%d_%d" % (i + 1, j + 1),
                                        vtype="b",
                                        obj=0,
                                        lb=0,
                                        ub=1)
                s2[i, j] = model.addVar(name="s2_%d_%d" % (i + 1, j + 1),
                                        vtype="b",
                                        obj=0,
                                        lb=0,
                                        ub=1)
                h1[i, j] = model.addVar(name="h1_%d_%d" % (i + 1, j + 1),
                                        vtype="i",
                                        obj=0,
                                        lb=0)
                h2[i, j] = model.addVar(name="h2_%d_%d" % (i + 1, j + 1),
                                        vtype="i",
                                        obj=0,
                                        lb=0)

        model.modelSense = GRB.MINIMIZE
        model.update()

        for y in model.getVars():
            if y.ub < 10000:
                logging.debug("%10s\t[%5d:%5d]\tobj %4d", y.varName, y.lb,
                              y.ub, y.obj)

        # Constraints
        for i in range(len(self.planes)):
            logging.debug("{} == {} + {} - {}".format(x[i].varName,
                                                      self.planes[i]["b"],
                                                      p[i].varName,
                                                      n[i].varName))
            model.addConstr(x[i] == self.planes[i]["b"] + p[i] - n[i])

            for j in range(len(self.planes)):
                if j == i:
                    continue
                # model.addConstr(x[j] - x[i] )
                # Force s = s1 AND s2
                model.addConstr(s[i, j] <= s1[i, j])
                model.addConstr(s[i, j] <= s2[i, j])
                model.addConstr(s[i, j] >= s1[i, j] + s2[i, j] - 1)

                # s2 == xj - xi > 0
                logging.debug("{}\t <= {}\t - {}\t - {}\t".format(
                    s2[i, j].varName, x[j].varName, x[i].varName,
                    h1[i, j].varName))
                model.addConstr(s2[i, j] <= x[j] - x[i] + h1[i, j])
                logging.debug("{}\t >= 1\t".format(h1[i, j].varName))
                model.addConstr(h1[i, j] >= 1)
                logging.debug("{}\t - {}\t + {}\t <= {}\t*{}\t".format(
                    x[j].varName, x[i].varName, h1[i, j].varName,
                    s2[i, j].varName, bigM))
                model.addConstr(x[j] - x[i] + h1[i, j] <= s2[i, j] * bigM)

                # s1 == xi + sij - xj > 0
                logging.debug("{}\t + {}\t - {}\t >= {}\t".format(
                    x[i].varName, self.planes[i]["s"][j], x[j].varName,
                    s1[i, j].varName))
                model.addConstr(s1[i, j] <= x[i] + self.planes[i]["s"][j] -
                                x[j] + h2[i, j])
                logging.debug("{}\t + {}\t - {}\t <= {}\t*{}\t".format(
                    x[i].varName, self.planes[i]["s"][j], x[j].varName,
                    s1[i, j].varName, bigM))
                model.addConstr(
                    x[i] + self.planes[i]["s"][j] - x[j] <= s1[i, j] * bigM)

        # solve it
        model.optimize()

        # Debugging printouts
        dbgStrs = {}
        for y in model.getVars():
            if y.varName[0:2] not in dbgStrs:
                dbgStrs[y.varName[0:2]] = []
            dbgStrs[y.varName[0:2]].append(
                "%8s = %4s [%4s]" %
                (y.varName, int(y.x), int(y.x * y.obj) if y.obj else ""))
        for x in dbgStrs:
            dbgStrs[x].sort()

        while dbgStrs:
            printed = False
            keys = [x for x in dbgStrs.keys()]
            keys.sort()
            logStr = ""
            for x in keys:
                if dbgStrs[x]:
                    logStr += dbgStrs[x][0]
                    dbgStrs[x] = dbgStrs[x][1::]
                    printed = True
                else:
                    logStr += " " * 22
            logging.debug(logStr)
            if not printed:
                break

        self.model = model
Ejemplo n.º 12
0
def populate_dual_subproblem(data, upper_cost=None, flow_cost=None):
    """
    Function that populates the Benders Dual Subproblem, as suggested by the
    paper "Minimal Infeasible Subsystems and Bender's cuts" by Fischetti,
    Salvagnin and Zanette.
    :param data:        Problem data structure
    :param upper_cost:  Link setup decisions fixed in the master
    :param flow_cost:   This is the cost of the continuous variables of the
                        master problem, as explained in the paper
    :return:            Numpy array of Gurobi model objects
    """

    # Gurobi model objects
    subproblems = np.empty(shape=(data.periods, data.commodities),
                           dtype=object)

    # Construct model for period/commodity 0.
    # Then, copy this and change the coefficients
    dual_subproblem = Model('dual_subproblem_(0,0)')

    # Ranges we are going to need
    arcs, periods, commodities = xrange(data.arcs.size), xrange(
        data.periods), xrange(data.commodities)

    # Origins and destinations of commodities
    origins, destinations = data.origins, data.destinations

    # We use arrays to store variable indexes and variable objects. Why use
    # both? Gurobi wont let us get the values of individual variables
    # within a callback.. We just get the values of a large array of
    # variables, in the order they were initially defined. To separate them
    # in variable categories, we will have to use index arrays
    flow_index = np.zeros(shape=data.nodes, dtype=int)
    flow_duals = np.empty_like(flow_index, dtype=object)
    ubounds_index = np.zeros(shape=len(arcs), dtype=int)
    ubounds_duals = np.empty_like(ubounds_index, dtype=object)

    # Makes sure we don't add variables more than once
    flow_duals_names = set()

    if upper_cost is None:
        upper_cost = np.zeros(shape=(len(periods), len(arcs)), dtype=float)
    if flow_cost is None:
        flow_cost = np.zeros(shape=(len(periods), len(commodities)),
                             dtype=float)

    # Populate all variables in one loop, keep track of their indexes
    # Data for period = 0, com = 0
    count = 0
    for arc in arcs:
        ubounds_duals[arc] = dual_subproblem.addVar(
            obj=-upper_cost[0, arc], lb=0., name='ubound_dual_a{}'.format(arc))
        ubounds_index[arc] = count
        count += 1
        start_node, end_node = get_2d_index(data.arcs[arc], data.nodes)
        start_node, end_node = start_node - 1, end_node - 1
        for node in (start_node, end_node):
            var_name = 'flow_dual_n{}'.format(node)
            if var_name not in flow_duals_names:
                flow_duals_names.add(var_name)
                obj, ub = 0., GRB.INFINITY
                if data.origins[0] == node:
                    obj = 1.
                if data.destinations[0] == node:
                    obj = -1.
                    ub = 0.
                flow_duals[node] = \
                    dual_subproblem.addVar(
                        obj=obj, lb=0., name=var_name)
                flow_index[node] = count
                count += 1
    opt_var = dual_subproblem.addVar(obj=-flow_cost[0, 0],
                                     lb=0.,
                                     name='optimality_var')
    dual_subproblem.params.threads = 2
    dual_subproblem.params.LogFile = ""
    dual_subproblem.update()

    # Add constraints
    demand = data.demand[0, 0]
    for arc in arcs:
        start_node, end_node = get_2d_index(data.arcs[arc], data.nodes)
        start_node, end_node = start_node - 1, end_node - 1
        lhs = flow_duals[start_node] - flow_duals[end_node] \
              - ubounds_duals[arc] - \
              opt_var * data.variable_cost[arc] * demand
        dual_subproblem.addConstr(lhs <= 0., name='flow_a{}'.format(arc))

    # Original Fischetti model
    lhs = quicksum(ubounds_duals) + opt_var
    dual_subproblem.addConstr(lhs == 1, name='normalization_constraint')

    # Store variable indices
    dual_subproblem._ubounds_index = ubounds_index
    dual_subproblem._flow_index = flow_index
    dual_subproblem._all_variables = np.array(dual_subproblem.getVars())
    dual_subproblem._flow_duals = np.take(dual_subproblem._all_variables,
                                          flow_index)
    dual_subproblem._ubound_duals = np.take(dual_subproblem._all_variables,
                                            ubounds_index)

    dual_subproblem.setParam('OutputFlag', 0)
    dual_subproblem.modelSense = GRB.MAXIMIZE
    dual_subproblem.update()

    subproblems[0, 0] = dual_subproblem

    for period, com in product(periods, commodities):
        if (period, com) != (0, 0):
            model = dual_subproblem.copy()
            optimality_var = model.getVarByName('optimality_var')
            optimality_var.Obj = -flow_cost[period, com]
            demand = data.demand[period, com]
            for node in xrange(data.nodes):
                variable = model.getVarByName('flow_dual_n{}'.format(node))
                if origins[com] == node:
                    obj = 1.
                elif destinations[com] == node:
                    obj = -1.
                else:
                    obj = 0.
                variable.obj = obj
            for arc in arcs:
                variable = model.getVarByName('ubound_dual_a{}'.format(arc))
                variable.Obj = -np.sum(upper_cost[:period + 1, arc])
                constraint = model.getConstrByName('flow_a{}'.format(arc))
                model.chgCoeff(constraint, optimality_var,
                               -demand * data.variable_cost[arc])
            model._all_variables = np.array(model.getVars())
            model.update()
            subproblems[period, com] = model
    return subproblems
Ejemplo n.º 13
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]]
Ejemplo n.º 14
0
def populate_dual_subproblem(data):
    """
    Function that populates the Benders Dual Subproblem, as suggested by the
    paper "Minimal Infeasible Subsystems and Bender's cuts" by Fischetti,
    Salvagnin and Zanette.
    :param data:        Problem data structure
    :param upper_cost:  Link setup decisions fixed in the master
    :param flow_cost:   This is the cost of the continuous variables of the
                        master problem, as explained in the paper
    :return:            Numpy array of Gurobi model objects
    """

    # Gurobi model objects
    subproblems = np.empty(shape=(data.periods, data.commodities),
                           dtype=object)

    # Construct model for period/commodity 0.
    # Then, copy this and change the coefficients
    subproblem = Model('subproblem_(0,0)')

    # Ranges we are going to need
    arcs, periods, commodities, nodes = xrange(data.arcs.size), xrange(
        data.periods), xrange(data.commodities), xrange(data.nodes)

    # Other data
    demand, var_cost = data.demand, data.variable_cost

    # Origins and destinations of commodities
    origins, destinations = data.origins, data.destinations

    # We use arrays to store variable indexes and variable objects. Why use
    # both? Gurobi wont let us get the values of individual variables
    # within a callback.. We just get the values of a large array of
    # variables, in the order they were initially defined. To separate them
    # in variable categories, we will have to use index arrays
    flow_vars = np.empty_like(arcs, dtype=object)

    # Populate all variables in one loop, keep track of their indexes
    # Data for period = 0, com = 0
    for arc in arcs:
        flow_vars[arc] = subproblem.addVar(obj=demand[0, 0] * var_cost[arc],
                                           lb=0.,
                                           ub=1.,
                                           name='flow_a{}'.format(arc))

    subproblem.update()
    # Add constraints
    for node in nodes:
        out_arcs = get_2d_index(data.arcs, data.nodes)[0] == node + 1
        in_arcs = get_2d_index(data.arcs, data.nodes)[1] == node + 1
        lhs = quicksum(flow_vars[out_arcs]) - quicksum(flow_vars[in_arcs])
        subproblem.addConstr(lhs == 0., name='flow_bal{}'.format(node))
    subproblem.update()

    # Store variables
    subproblem._all_variables = flow_vars.tolist()

    # Set parameters
    subproblem.setParam('OutputFlag', 0)
    subproblem.modelSense = GRB.MINIMIZE
    subproblem.params.threads = 2
    subproblem.params.LogFile = ""
    subproblem.update()

    subproblems[0, 0] = subproblem

    for period, com in product(periods, commodities):
        if (period, com) != (0, 0):
            model = subproblem.copy()
            model.ModelName = 'subproblem_({},{})'.format(period, com)
            flow_cost = data.demand[period, com] * var_cost
            model.setObjective(LinExpr(flow_cost.tolist(), model.getVars()))
            model.setAttr('rhs', model.getConstrs(), [0.0] * data.nodes)

            model._all_variables = model.getVars()
            model.update()
            subproblems[period, com] = model

    return subproblems
Ejemplo n.º 15
0
    def generateInstance(self):
        # Check that store has been intialized correctly
        if not all([x in self.store for x in ["Timehorizon", "h", "K", "a", "d", "s", "st"]]):
            logging.error('Store is not initialized correctly. Check for completeness of input-file.')
            return None

        model = Model("LotSolver")

        tHor = self.store["Timehorizon"]
        nPr = self.store["nProducts"]

        timeRange = range(1, tHor + 1)
        prodRange = range(1, nPr + 1)

        # Assume that production of products costs at least 1h, so a max of K products can be produced per period
        bigM = max(self.store["K"])

        # generate Variables
        # boolean production
        bx = {}
        # lager
        l = {}
        # production
        x = {}
        for t in timeRange:
            for p in prodRange:
                x[p, t] = model.addVar(name="x_%d_%d" % (p, t), vtype="i")
                bx[p, t] = model.addVar(name="bx_%d_%d" % (p, t), vtype="b")
        for t in range(0, tHor + 1):
            for p in prodRange:
                l[p, t] = model.addVar(name="l_%d_%d" % (p, t), vtype="i", obj=float(self.store["h"][p-1]))

        # switch costs
        s = {}
        for t in range(0, tHor+1):
            for p1 in prodRange:
                for p2 in prodRange:
                    # Switching to the same product does not cost anything - even if the file may say otherwise
                    objective = float(self.store["s"][p1-1][p2-1]) if p1 != p2 else 0
                    s[p1, p2, t] = model.addVar(name="s_%d_%d_%d" % (p1, p2, t), vtype="b", obj=objective)

        model.modelSense = GRB.MINIMIZE
        model.update()

        for y in model.getVars():
            logging.debug("%s obj %s", y.varName, y.obj)

        # Constraints

        # Initially only allow a single product
        logging.debug("%s == 1", [s[key].varName for key in s if key[2] == 0])
        model.addConstr(quicksum(s[key] for key in s if key[2] == 0) == 1, name="single_switch_" + str(t))

        # Only allow products in each period that actually has been switched to
        for t in timeRange:
            for p in prodRange:
                logging.debug("(%s) == %s", [s[key].varName for key in s if key[2] == t and (key[1] == p or key[0] == p)], bx[p, t].varName)
                model.addConstr(quicksum(s[key] for key in s if key[2] == t and (key[1] == p or key[0] == p)) >= bx[p,t], name="single_switch_" + str(t))

                # Force bx = 1 iff x != 0
                model.addConstr(x[p,t] >= bx[p,t])
                model.addConstr(x[p,t] <= bigM * bx[p,t])

        for t in timeRange:
            # Allow only a single switch each period
            logging.debug('Single switch constraint for ' + str([s[key].varName for key in s if key[2] == t]))
            model.addConstr(quicksum(s[key] for key in s if key[2] == t) == 1, name="single_switch_" + str(t))

            # Only allow connected switches between t-1 and t
            for p in prodRange:
                logging.debug('valid_switch for ' + str([s[key].varName for key in s if key[2] == (t-1) and key[1] == p]) + " and " + str([s[key].varName for key in s if key[2] == t and key[0] == p]))
                model.addConstr(quicksum(s[key] for key in s if key[2] == (t-1) and key[1] == p) == quicksum(s[key] for key in s if key[2] == t and key[0] == p), 
                    name="valid_switch_%d_%d" % (p, t))

        # Machine can't be occupied for more then K hours / period
        for t in timeRange:
            logging.debug("sum {} + sum {} <= {}".format([x[key].varName + "*" + str(self.store["a"][key[0]-1]) for key in x if key[1] == t],
                [s[key].varName + "*" + str(self.store["st"][key[0]-1][key[1]-1]) for key in s if key[2] == t], self.store["K"][t-1]))
            model.addConstr(quicksum(x[key]*self.store["a"][key[0]-1] for key in x if key[1] == t) + quicksum(s[key]*self.store["st"][key[0]-1][key[1]-1] for key in s if key[2] == t) <= self.store["K"][t-1])

        # Initial warehouse stock
        for p in prodRange:
            logging.debug("%s == %s", l[p, 0].varName, self.store["l"][p-1])
            model.addConstr(l[p, 0] == self.store["l"][p-1])
        # Update warehouse stock inbetween periods + enforce demand to be met
        for t in range(1, tHor+1):
            for p in prodRange:
                logging.debug("{} = {} + {} - {}".format(l[p, t].varName, l[p, t-1].varName, x[p, t].varName, self.store["d"][p-1][t-1]))
                model.addConstr(l[p, t] == l[p, t-1] + x[p, t] - self.store["d"][p-1][t-1])

        # solve it
        model.optimize()

        # Debugging printouts
        for y in model.getVars():
            if y.x >= 0.001:
                logging.debug("%s = %s cost %d", y.varName, y.x, y.x*y.obj)

        for t in timeRange:
            logging.debug("%s + %s", (["{}[{}] * {}".format(x[key].x, x[key].varName, self.store["a"][key[0]-1]) for key in x if key[1] == t]), ([str(s[key].varName) + "*" + str(self.store["st"][key[0]-1][key[1]-1]) for key in s if key[2] == t and s[key].x >= 0.001]))           

        self.model = model
Ejemplo n.º 16
0
def solvePerfectInformation(gp, I, K, W, l_init, q_init, c_init):
    GenAvg=0.0
    UpAvg=0.0
    SpAvg=0.0
    RefAvg=0.0
    FlrAvg=0.0
    L_min= 50
    L_max=1200
    ub=np.zeros(K)
    M=1000000   
    T_R_down=2
    T_F_down=4
# loop over all sample paths
    for k in range(K):
# Model
        perfectInfo = Model("GenAndUpg")

        Gen=[]
        for x_G in range(I):
            Gen.append(perfectInfo.addVar(lb=0 , vtype=GRB.CONTINUOUS, 
                                          obj=-W[x_G, k, 0]*gp[5]*np.power(gp[6], x_G),
                                          name="Gen[%d]" %x_G))
                       
        Up=[]    
        for x_U in range(I):
                Up.append(perfectInfo.addVar(lb=0, vtype=GRB.CONTINUOUS, 
                                             obj=gp[7]*np.power(gp[6], x_U),
                                             name="Up[%d]" %x_U))
    
        Sp=[]    
        for x_S in range(I):
            Sp.append(perfectInfo.addVar(lb=0, vtype=GRB.CONTINUOUS, 
                                         obj=0,
                                         name="Sp[%d]" %x_S))    

        Ref=[]    
        for x_R in range(I):
            Ref.append(perfectInfo.addVar(lb=0, vtype=GRB.BINARY, 
                                          obj=gp[8]*np.power(gp[6],x_R),
                                          name="Ref[%d]" %x_R))     
    
        Gen_b=[]
        for xi_G in range(I):
            Gen_b.append(perfectInfo.addVar(lb=0, vtype=GRB.BINARY, 
                                            obj=0,
                                            name="Gen_b[%d]" %xi_G))   

        Flr=[]
        for xi_F in range(I):
            Flr.append(perfectInfo.addVar(lb=0, vtype=GRB.BINARY, 
                                          obj=(100)* np.power(gp[6], xi_F),
                                          name="Flr[%d]" %xi_F))      

        Cap=[]
        for q in range(I):
            Cap.append(perfectInfo.addVar(lb=0 , vtype=GRB.CONTINUOUS, 
                                          obj=0,
                                          name="Cap[%d]" %q))    
        
        Res=[]
        for l in range(I):
            Res.append(perfectInfo.addVar(lb= L_min, ub=L_max, vtype=GRB.CONTINUOUS, 
                                          obj=0,
                                          name="Res[%d]" %l))  
        
        Con=[]
        for c in range(I):
            Con.append(perfectInfo.addVar(lb=0 , ub=1, vtype=GRB.CONTINUOUS, 
                                          obj=0,
                                          name="Con[%d]" %c))      
        #########################################################################
        #robust part
        
    
    
        perfectInfo.modelSense = GRB.MINIMIZE
    
     
        perfectInfo.addConstr(
                (Res[0]- l_init == 0), "initial reservior")
        
     
        perfectInfo.addConstr(
                (Cap[0]- q_init == 0), "initial capacity")
        
 
        perfectInfo.addConstr(
                (Con[0]- c_init == 0), "initial condition")    
    
        for i in range(I):  
            perfectInfo.addConstr(
                    (Gen[i]- Cap[i] <= 0), "Generation")


        for i in range(I):     
            perfectInfo.addConstr(
                    (Gen[i]- Res[i] <= 0))   

        for i in range(I):     
            perfectInfo.addConstr(
                    (Up[i]- gp[4] * Ref[i] <= 0))    
    

        for i in range(I):     
            perfectInfo.addConstr(
                    ( Gen_b[i] + Ref[i] <= 1)) 
            
        for i in range(I):     
            perfectInfo.addConstr(
                    ( Gen[i] - M* Gen_b[i] <= 0)) 

        for i in range(I):     
            perfectInfo.addConstr(
                    (Ref[i]- Flr[i] <= 0)) 

        for i in range(I):     
            perfectInfo.addConstr(
                    (quicksum(Gen[i+j] for j in range(min(T_R_down, I-i )))- M* (1-Ref[i]) <=0))
                               
        for i in range(I):     
            perfectInfo.addConstr(
                    (quicksum(Gen[i+j] for j in range(min(T_F_down, I-i )))- M* (1-Flr[i]) <=0))
    
        for i in range(I-1):
            perfectInfo.addConstr(
                    (Res[i+1]- Res[i]+ Gen[i] - W[i , k, 1] + Sp [i]==0 ))
        
        for i in range(I-1):
            perfectInfo.addConstr(
                    (Cap[i+1]- Cap[i] - Up[i] ==0 ))
          
        for i in range(I-1):
            perfectInfo.addConstr(
                    (Con[i+1]- Con[i] -  W[i, k, 2]* Gen_b[i] -(0- Con[i])* Ref[i] ==0 ))
        
        perfectInfo.write('GenAndUpg.lp') 
     
            
        perfectInfo.optimize()  
        print('Up[0]: {}, Sp[0]:{}, Ref[0]:{}, Flr[0]:{} \n'. format(
                         Up[0].x, Sp[0].x, Ref[0].x, Flr[0].x ))
        print('Power: {}, Inflow: {}, Detereoration: {}\n'. format(
                W[i, 0, 0], W[i, 0, 1],  W[i, 0, 2] ))  
        
        print('Sample path: {:.4f}'.format(
                k ))
        if perfectInfo.status == GRB.Status.OPTIMAL:
            print('Optimal objective: %g' % perfectInfo.objVal)
            ub[k]= -perfectInfo.objVal
#        else:
#            ub[k]= M
        elif perfectInfo.status == GRB.Status.INF_OR_UNBD:
            print('Model is infeasible or unbounded')
            exit(0)
        elif perfectInfo.status == GRB.Status.INFEASIBLE:
            print('Model is infeasible')
            exit(0)
        elif perfectInfo.status == GRB.Status.UNBOUNDED:
            print('Model is unbounded')
            exit(0)
        else:  
            print('Optimization ended with status %d' % perfectInfo.status)
        
        #refering to decisions at current period
       # pdb.set_trace()    
        GenAvg+= Gen[0].x
        print('Optimal generation: {:.4f}'. format( Gen[0].x))
        UpAvg+= Up[0].x
        SpAvg+= Sp[0].x
        RefAvg+= Ref[0].x 
        FlrAvg+= Flr[0].x
        
    # average of actions in the sample paths    
    GenAvg=GenAvg/K
    UpAvg=UpAvg/K
    SpAvg=SpAvg/K
    RefAvg= RefAvg/K
    FlrAvg=FlrAvg/K
    
    if RefAvg> 0.5:
        RefAvg=1
        UpAvg= UpAvg
        GenAvg= 0
    else:
        RefAvg=0
        UpAvg=0

       
    XAvg=[GenAvg, UpAvg, SpAvg, RefAvg, FlrAvg]
    
    return ub, XAvg  
Ejemplo n.º 17
0
from gurobipy import GRB, Model
from datetime import datetime
startTime = datetime.now()

model = Model('GAP per Wolsey')
model.modelSense = GRB.MAXIMIZE
model.setParam('OutputFlag', False)  # turns off solver chatter

b = [15, 15, 15]
c = [[6, 10, 1], [12, 12, 5], [15, 4, 3], [10, 3, 9], [8, 9, 5]]
a = [[5, 7, 2], [14, 8, 7], [10, 6, 12], [8, 4, 15], [6, 12, 5]]

# x[i][j] = 1 if i is assigned to j
x = []
for i in range(len(c)):
    x_i = []
    for j in c[i]:
        x_i.append(model.addVar(vtype=GRB.BINARY))
    x.append(x_i)

# We have to update the model so it knows about new variables
model.update()

# sum j: x_ij <= 1 for all i
for x_i in x:
    model.addConstr(sum(x_i) <= 1)

# sum i: a_ij * x_ij <= b[j] for all j
for j in range(len(b)):
    model.addConstr(sum(a[i][j] * x[i][j] for i in range(len(x))) <= b[j])
Ejemplo n.º 18
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
Ejemplo n.º 19
0
    def Mater_Problem(self):
        [R_turbine, routes, NumTechs] = self.Generating_Feasible_Routes()
        model = Model()

        # set parameters
        A = []
        for v in range(self.num_V):
            for t in range(self.period):
                for b in range(self.num_B):
                    for wf in range(self.num_WF):
                        if R_turbine[v][t][b][wf] == []:
                            # print (['(v,t,b,wf)[%d,%d,%d,%d]' % (v,t,b,wf)])
                            continue
                        for r in range(np.size(R_turbine[v][t][b][wf][0], 1)):
                            A.append((v, t, b, wf, r))
        x = model.addVars(A, vtype=GRB.BINARY)

        # add constraints
        for v in range(self.num_V):
            for t in range(self.period):
                tmp1 = 0
                for b in range(self.num_B):
                    for wf in range(self.num_WF):
                        if R_turbine[v][t][b][wf] == []:
                            continue
                        ntmp = np.size(R_turbine[v][t][b][wf][0], 1)
                        tmp1 += sum(x[v, t, b, wf, r] for r in range(ntmp))
                model.addConstr(tmp1 <= 1)

        # explore every turbines in the farm
        for b in range(self.num_B):
            for wf in range(self.num_WF):
                for j in range(len(self.WF_tech[wf])):
                    tmp = 0
                    for v in range(self.num_V):
                        for t in range(self.period):
                            if R_turbine[v][t][b][wf] == []:
                                continue
                            ntmp = np.size(R_turbine[v][t][b][wf][0], 1)
                            tmp += quicksum(x[v, t, b, wf, r] * R_turbine[v][t][b][wf][0][j, r] \
                                            for r in range(ntmp))
                    model.addConstr(tmp == 1)

        for b in range(self.num_B):
            for t in range(self.period):
                for p in self.types:
                    tmp = 0
                    for v in range(self.num_V):
                        for wf in range(self.num_WF):
                            if R_turbine[v][t][b][wf] == []:
                                continue
                            tmp += quicksum(x[v, t, b, wf, r] * NumTechs[v][t][b][wf][r][p] \
                                            for r in range(np.size(R_turbine[v][t][b][wf][0], 1)))
                    model.addConstr(tmp <= self.B_tech[b][p][t])

        ctmp = 0
        for v in range(self.num_V):
            for t in range(self.period):
                for b in range(self.num_B):
                    for wf in range(self.num_WF):
                        if R_turbine[v][t][b][wf] == []:
                            continue
                        ctmp += quicksum(R_turbine[v][t][b][wf][0][-1, r] * x[v, t, b, wf, r] \
                                         for r in range(np.size(R_turbine[v][t][b][wf][0], 1)))

        model.modelSense = GRB.MINIMIZE
        model.setParam('OutputFlag', 0)
        model.setObjective(ctmp)
        model.optimize()

        _routes = [[] for i in range(self.num_V)]
        if model.status == GRB.OPTIMAL:
            cost_opt = model.objVal
            # print('Master Problem: OPTIMAL\n', 'total cost: ', round(cost_opt, 2))
            # for v in range(self.num_V):
            #     for t in range(self.period):
            #         nums = 0
            #         for b in range(self.num_B):
            #             for wf in range(self.num_WF):
            #                 if R_turbine[v][t][b][wf] == []:
            #                         continue
            #                 for r in range(np.size(R_turbine[v][t][b][wf][0],1)):
            #                     if x[v,t,b,wf,r].x == 1:
            #                         nums += 1
            #         # print ('(v,t)[%d,%d]' % (v,t), 'nums: ', nums)

            for b in range(self.num_B):
                for wf in range(self.num_WF):
                    if R_turbine[v][t][b][wf] == []:
                        continue
                    turbines = []
                    for v in range(self.num_V):
                        for t in range(self.period):
                            # if R_turbine[v][t][b][wf] == []:
                            #     continue
                            if sum(x[v, t, b, wf, r].x for r in range(
                                    np.size(R_turbine[v][t][b][wf][0],
                                            1))) < 1:
                                _routes[v].append([])
                                continue
                            for r in range(
                                    np.size(R_turbine[v][t][b][wf][0], 1)):
                                if x[v, t, b, wf, r].x == 1:
                                    print('(b,wf,v,t)[%d,%d,%d,%d]' % (b, wf, v, t), \
                                          'routes: ', routes[v][t][b][wf][r])
                                    _routes[v].append(routes[v][t][b][wf][r])
            print('_routes: \n', _routes)
            return [cost_opt, _routes]
        else:
            print('Master Problem: Infeasible')
            return [None, None]
Ejemplo n.º 20
0
def solve(n, width, height, startNodes, targetNodes, startTimes, endTimes):
    model = Model("BoatSolver")

    def toGrid(val, y=0):
        if isinstance(val, list):
            return val[0] + val[1] * width
        return val + y * width

    T = max(endTimes)

    x = {}
    wait = {}
    for i, j, t in itertools.product(range(n), range(width * height), range(T)):
        x[i, j, t] = model.addVar(name="x_%d_%d_%d" % (i+1, j+1, t+1), vtype="b", obj=1)
        wait[i, j, t] = model.addVar(name="wait_%d_%d_%d" % (i+1, j+1, t+1), vtype="i", obj=-1)

    model.modelSense = GRB.MINIMIZE
    model.update()

    # Force startpositions
    for i, (sN, sT) in enumerate(zip(startNodes, startTimes)):
        for t in range(sT):
            for j in range(width * height):
                if j == toGrid(sN - 1) and t == sT - 1:
                    logging.debug("start: %s == 1", x[i, j, t].varName)
                    model.addConstr(x[i, j, t] == 1)
                else:
                    logging.debug("start: %s == 0", x[i, j, t].varName)
                    model.addConstr(x[i, j, t] == 0)

    # Force endpositions
    for i, (eN, eT) in enumerate(zip(targetNodes, endTimes)):
        j = toGrid(eN - 1)
        logging.debug("end: %s == 1", x[i, j, eT - 1].varName)
        model.addConstr(x[i, j, eT - 1] == 1)
        # Container vanishes after endTime
        for t in range(eT, T):
            logging.debug("end: %s == 0", x[i, j, t].varName)
            model.addConstr(x[i, j, t] == 0)

    # single container per node
    for j, t in itertools.product(range(width * height), range(T)):
        logging.debug("%s <= 1", [x[i, j, t].varName for i in range(n)])
        model.addConstr(quicksum(x[i, j, t] for i in range(n)) <= 1)

    # Force valid container movement
    for w, h in itertools.product(range(width), range(height)):
        vals = [toGrid(w, h)]
        if h >= 1:
            vals += [toGrid(w, h - 1)]
        if w >= 1:
            vals += [toGrid(w - 1, h)]
        if h+1 < height:
            vals += [toGrid(w, h + 1)]
        if w+1 < width:
            vals += [toGrid(w + 1, h)]

        for i, t in itertools.product(range(n), range(1, T)):
            if endTimes[i] > t and startTimes[i] <= t:
                logging.debug("sum(%s) >= %s", [x[i, j, t].varName for j in vals], x[i, toGrid(w, h), t - 1].varName)
                model.addConstr(quicksum(x[i, j, t] for j in vals) >= x[i, toGrid(w, h), t - 1])
            else:
                logging.debug("skipped(%s) >= %s", [x[i, j, t].varName for j in vals], x[i, toGrid(w, h), t - 1].varName)

        for i, t in itertools.product(range(n), range(1, T)):
            logging.debug("sum(%s) <= 1", [x[i, j, t].varName for j in vals])
            model.addConstr(quicksum(x[i, j, t] for j in vals) <= 1)

    # Force continous line through grid
    for i, t in itertools.product(range(n), range(0, T)):
        if endTimes[i] > t and startTimes[i] <= t + 1:
            logging.debug("sum(%s) == 1", [x[i, j, t].varName for j in range(width * height)])
            model.addConstr(quicksum(x[i, j, t] for j in range(width * height)) == 1)
        else:
            logging.debug("sum(%s) == 0", [x[i, j, t].varName for j in range(width * height)])
            model.addConstr(quicksum(x[i, j, t] for j in range(width * height)) == 0)

    # Prevent ships from passing over same link
    for t in range(1, T):
        for w, h in itertools.product(range(width - 1), range(height)):
            for i in range(n):
                for k in range(i+1, n):
                    model.addConstr(x[i, toGrid(w, h), t - 1] + x[i, toGrid(w + 1, h), t] + x[k, toGrid(w, h), t] + x[k, toGrid(w + 1, h), t - 1] <= 3)
                    model.addConstr(x[i, toGrid(w, h), t] + x[i, toGrid(w + 1, h), t - 1] + x[k, toGrid(w, h), t - 1] + x[k, toGrid(w + 1, h), t] <= 3)
        for w, h in itertools.product(range(width), range(height - 1)):
            for i in range(n):
                for k in range(i+1, n):
                    model.addConstr(x[i, toGrid(w, h), t - 1] + x[i, toGrid(w, h + 1), t] + x[k, toGrid(w, h), t] + x[k, toGrid(w, h + 1), t - 1] <= 3)
                    model.addConstr(x[i, toGrid(w, h), t] + x[i, toGrid(w, h + 1), t - 1] + x[k, toGrid(w, h), t - 1] + x[k, toGrid(w, h + 1), t] <= 3)

    # Allow free waiting
    for i, j, t in itertools.product(range(n), range(width * height), range(0, T)):
        if t < startTimes[i]:
            model.addConstr(x[i, j, t] == wait[i, j, t])
        else:
            model.addConstr(x[i, j, t - 1] + x[i, j, t] - 1 <= wait[i, j, t])
            model.addConstr(x[i, j, t - 1] >= wait[i, j, t])
            model.addConstr(x[i, j, t] >= wait[i, j, t])

    model.optimize()

    for y in model.getVars():
        if y.x:
            logging.warning("%s = %d", y.varName, y.x)

    return model
Ejemplo n.º 21
0
    def Solving_MILP(self, turbines, dist, travelTime, vessel, t, base, farm, \
                     R, routes, Techs, visited):

        for t_1 in range(1, t):
            for b_1 in range(self.num_B):
                if turbines not in visited[vessel][t_1][b_1][farm]:
                    continue
                index = visited[vessel][t_1][b_1][farm].index(turbines)
                if self.time_window[vessel][t][farm] == self.time_window[
                        vessel][t_1][farm]:
                    c_t = R[vessel][t_1][b_1][farm][0][-4, index]
                    c_p = R[vessel][t_1][b_1][farm][0][-3, index]
                    c_lr = sum(max(0, t - self.WF_deadline[farm][j]) \
                               * self.WF_penCost[farm][j] for j in turbines)
                    c_total = c_t + c_p + c_lr
                    path = routes[vessel][t_1][b_1][farm][index]
                    NumTechs = Techs[vessel][t_1][b_1][farm][index]
                    return [[c_t, c_p, c_lr, c_total], path, NumTechs]

        # total num of turbines in the wind farm
        n = len(self.WF_deadline[farm])
        # set of drop off nodes [1,...,n]
        dropoff = list(map(lambda qq: qq + 1, turbines))
        d1 = list(range(n + 1, 2 * n + 1))
        # set of pick up nodes [n+1, n+2,...,2n]
        pickup = [d1[i - 1] for i in dropoff]
        # set of nodes need vessels to be present
        waiting = [i + 1 for i in turbines if self.WF_present[farm][i] == 1]
        nodes = [0] + dropoff + pickup + [2 * n + 1]

        model = Model()
        T = model.addVars(nodes, lb=0.0, vtype=GRB.CONTINUOUS)
        A = [(i, j) for i in nodes for j in nodes if i != j]
        B = [(p, i) for p in self.types for i in nodes]
        y = model.addVars(A, vtype=GRB.BINARY)
        Q = model.addVars(B, lb=0, vtype=GRB.INTEGER)

        model.addConstr(y[2 * n + 1, 0] == 1)
        model.addConstrs(
            quicksum(y[i, j] for j in nodes if i != j) == 1
            for i in nodes)  # 9
        model.addConstr(quicksum(y[0, j] for j in dropoff) == 1)  # 10
        model.addConstr(quicksum(y[j, 2 * n + 1] for j in pickup) == 1)  # 11
        model.addConstrs(quicksum(y[i, j] for j in nodes if i != j) == \
                         quicksum(y[j, i] for j in nodes if i != j) for i in nodes)  # 12
        model.addConstrs(quicksum(y[i, j] for j in nodes if i != j) == \
                         quicksum(y[n + i, j] for j in nodes if n + i != j) for i in dropoff)  # 13
        model.addConstrs(y[i, n + i] == 1 for i in waiting)  # 14
        model.addConstrs(T[n + i] - T[i] >= self.WF_mainTime[farm][i - 1] \
                         + self.V_transTime[vessel] for i in dropoff)  # 15
        model.addConstr(
            T[2 * n + 1] <= self.time_window[vessel][t][farm])  # 16
        model.addConstr(T[0] == 0)  # 17
        model.addConstrs(y[0, j] == 0 for j in pickup)
        model.addConstrs(y[j, 2 * n + 1] == 0 for j in dropoff)
        model.addConstr(
            quicksum(Q[p, 0] for p in self.types) <= self.V_tech[vessel])  # 18
        model.addConstrs(Q[p, 0] <= self.B_tech[base][p][t]
                         for p in self.types)
        model.addConstrs(Q[p, 0] >= Q[p, i] for p in self.types for i in nodes)

        for i in nodes[1:-1]:
            for j in dropoff:
                if i == j:
                    continue
                model.addConstrs((y[i, j] == 1) >> \
                                 (Q[p, i] - Q[p, j] == self.WF_tech[farm][j - 1][p]) for p in self.types)
            for j in pickup:
                if i == j:
                    continue
                model.addConstrs((y[i, j] == 1) >> \
                                 (Q[p, j] - Q[p, i] == self.WF_tech[farm][j - n - 1][p]) for p in self.types)

        model.addConstrs((y[0, j] == 1) >> \
                         (T[0] + travelTime[0, j] <= T[j]) for j in dropoff)
        model.addConstrs((y[j, 2 * n + 1] == 1) >> (T[j] + self.V_transTime[vessel] \
                                                    + travelTime[j - n, 0] <= T[2 * n + 1]) for j in pickup)

        for i in nodes[1:-1]:
            for j in nodes[1:-1]:
                if j == i + n or i == j:
                    continue
                i1 = i if i <= n else i - n
                j1 = j if j <= n else j - n
                model.addConstr((y[i, j] == 1) >> \
                                (T[i] + self.V_transTime[vessel] + travelTime[i1, j1] <= T[j]))  # 19

        # cost for technicians
        c_qr = sum(Q[p, 0] * self.tech_cost[p] for p in self.types)
        # travel cost (fuel cost)
        c_tr = 0
        for i in nodes:
            for j in nodes:
                if i != j:
                    if i == 2 * n + 1:
                        i1 = 0
                    elif i <= n:
                        i1 = i
                    else:
                        i1 = i - n
                        i1 = i if i <= n else i - n
                    if j == 2 * n + 1:
                        j1 = 0
                    elif j <= n:
                        j1 = j
                    else:
                        j1 = j - n
                    c_tr += self.V_cost[vessel] * travelTime[i1, j1] * y[i, j]

        # penalty cost
        c_lr = sum(max(0, t + 1 - self.WF_deadline[farm][j]) \
                   * self.WF_penCost[farm][j] for j in turbines)
        # ojective function
        model.modelSense = GRB.MINIMIZE
        model.setObjective(c_qr + c_tr + c_lr)
        model.setParam('OutputFlag', 0)
        model.optimize()

        if model.status == GRB.OPTIMAL:
            print('optimal')
            c_total = model.objVal
            # cost for technicians
            c_q = sum(Q[p, 0].x * self.tech_cost[p] for p in self.types)
            # travel cost (fuel cost)
            c_t = 0
            for i in nodes:
                for j in nodes:
                    if i != j:
                        if i == 2 * n + 1:
                            i1 = 0
                        elif i <= n:
                            i1 = i
                        else:
                            i1 = i - n
                            i1 = i if i <= n else i - n
                        if j == 2 * n + 1:
                            j1 = 0
                        elif j <= n:
                            j1 = j
                        else:
                            j1 = j - n
                        c_t += self.V_cost[vessel] * travelTime[i1,
                                                                j1] * y[i, j].x

            path = []  # store the optimal route without base
            # path = [0]
            TT = [0]
            rr = 0
            ii = 0
            while rr < len(nodes) - 2:
                for k in nodes:
                    if ii != k and round(y[ii, k].x) == 1:
                        ii = k
                        path.append(k - 1 if k <= n else k - n - 1)
                        TT.append(round(T[k].x, 2))
                        # path.append(k)
                        break
                rr += 1
            TT.append(T[nodes[-1]].x)
            [c_t, c_q, c_lr,
             c_total] = [round(i, 2) for i in [c_t, c_q, c_lr, c_total]]
            num_techs = [Q[p, 0].x for p in self.types]
            # print('nodes: ', nodes)
            # print('path: ', ['vessel[%d]' % vessel] + ['period[%d]' % t] + \
            #      ['wf[%d]' % farm] + ['b[%d]' % base] + path)
            # print ('T: ', TT)
            # print ('###############\n \n')
            return [[c_t, c_q, c_lr, c_total], path, num_techs]
        else:
            print('infeasible')
            return [[None], None, None]
    def Solver(self):
        model = Model()
        n = len(self.WF_mainTime[0])
        dropoff = list(range(1, n+1))
        pickup = list(range(n+1, 2*n+1))
        nodes = list(range(2*n+2))
        B = list(range(self.num_B))
        WF = list(range(self.num_WF))
        D = list(range(self.period))
        V = list(range(self.num_V))
        P = list(range(len(self.B_tech[0])))
        waiting = [[i for i in dropoff if self.WF_present[wf][i-1] == 1] for wf in WF]
        
        # calculate distance
        dist = [[] for b in B]
        for b in B:
            for wf in WF:
                if self.lambda_bf[b][wf] == 1:
                    dist[b].append(self.createDistanceMatrix(self.WF_coordinate[wf], \
                    self.B_coordinate[b]))
                else: dist[b].append([])
        # print (dist)

        # calculate travel time
        travelTime = [[] for v in V]
        for v in V:
            for b in B:
                if self.B_vessel[b][v] == 1:
                    for wf in WF:
                        if self.lambda_bf[b][wf] == 1:
                            travelTime[v].append(dist[b][wf]/self.V_speed[v])
                        else: travelTime[v].append([])        
        # set decision variables
        AA = [(v,t,wf,i,j) for i in nodes for j in nodes for wf in WF \
            for t in D for v in V]
        BB = [(v,t,wf,i) for i in nodes for wf in WF for t in D for v in V]
        CC = [(v,t,wf,p,i) for i in nodes for p in P for wf in WF for t in D for v in V]
        DD = [(wf,i) for i in dropoff for wf in WF]
        y = model.addVars(AA, vtype = GRB.BINARY)
        T = model.addVars(BB, lb = 0, vtype = GRB.CONTINUOUS)
        Q = model.addVars(CC, lb = 0, vtype = GRB.INTEGER)
        x = model.addVars(DD, lb = 0, vtype = GRB.INTEGER)

################# Constraints ####################
        model.addConstrs(y[v,t,wf,i,i] == 0 for i in nodes for wf in WF \
            for t in D for v in V)
        model.addConstrs(quicksum(y[v,t,wf,0,j] for j in dropoff) <= 1  for wf in WF \
            for t in D for v in V)
        model.addConstrs(quicksum(y[v,t,wf,j,2*n+1] for j in pickup) <= 1 for wf in WF \
            for t in D for v in V)
        model.addConstrs(quicksum(y[v,t,wf,i,j] for i in nodes for t in D \
            for v in V) == 1 for j in pickup for wf in WF)
        model.addConstrs(quicksum(y[v,t,wf,i,j] for j in nodes) == \
            quicksum(y[v,t,wf,j,i] for j in nodes) for i in nodes for wf in WF \
            for t in D for v in V)
        model.addConstrs(quicksum(y[v,t,wf,i,j] for j in nodes) ==\
            quicksum(y[v,t,wf,n+i,j] for j in nodes) for i in dropoff for wf in WF \
            for t in D for v in V)
        model.addConstrs(quicksum(y[v,t,wf,i,n+i] for t in D for v in V) == 1 \
            for wf in WF for i in waiting[wf])
        
        model.addConstrs(T[v,t,wf,0] == 0 for wf in WF for t in D for v in V)
        model.addConstrs(T[v,t,wf,n+i] - T[v,t,wf,i] >= quicksum(y[v,t,wf,0,j] \
            for j in dropoff) * (self.WF_mainTime[wf][i-1] + self.V_transTime[v]) \
            for i in dropoff for v in V for t in D for wf in WF)
        model.addConstrs((y[v,t,wf,0,j]==1) >> (T[v,t,wf,j] >= travelTime[v][wf][0,j]) \
            for j in dropoff for wf in WF for t in D for v in V)
       
        model.addConstrs(quicksum(Q[v,t,wf,p,0] for p in P) <= self.V_tech[v] \
             for wf in WF for t in D for v in V)
        model.addConstrs(quicksum(Q[v,t,wf,p,0] * self.B_vessel[b][v] for v in V \
            for wf in WF) <= self.B_tech[b][p][t] for p in P for t in D for b in B)
        model.addConstrs(Q[v,t,wf,p,i] <= Q[v,t,wf,p,0] for p in P for i in nodes \
            for t in D for v in V for wf in WF)
        for i in nodes[1:-1]:
            for j in dropoff:
                model.addConstrs((y[v,t,wf,i,j] == 1) >> \
                    (Q[v,t,wf,p,i] - Q[v,t,wf,p,j] == self.WF_tech[wf][j-1][p]) \
                    for p in P for wf in WF for t in D for v in V)
            for j in pickup:
                model.addConstrs((y[v,t,wf,i,j] == 1) >> \
                    (Q[v,t,wf,p,j] - Q[v,t,wf,p,i] == self.WF_tech[wf][j-n-1][p]) \
                    for p in P for wf in WF for t in D for v in V)
            for j in nodes[1:]:
                if j == i+n:
                    continue    
                model.addConstrs((y[v,t,wf,i,j]==1) >> (T[v,t,wf,j] - T[v,t,wf,i] >=\
                    self.V_transTime[v] + travelTime[v][wf][i,j]) for wf in WF for t in D \
                    for v in V)

        model.addConstrs(quicksum(t * y[v,t,wf,i,j] - x[wf,j] for i in nodes for v in V \
            for t in D) <= self.WF_deadline[wf][j-1] for wf in WF for j in dropoff)


        model.addConstrs(y[v,t,wf,j,2*n+1] == 0 for j in dropoff for wf in WF \
            for t in D for v in V)
        model.addConstrs(y[v,t,wf,n+i,i] == 0 for i in dropoff for wf in WF \
            for t in D for v in V)
        model.addConstrs(y[v,t,wf,0,j] == 0 for j in pickup for wf in WF \
            for t in D for v in V)
        model.addConstrs(y[v,t,wf,i,j] <= self.lambda_bf[b][wf] for i in nodes \
            for j in nodes for t in D for v in V for wf in WF for b in B)
        model.addConstrs(y[v,t,wf,i,j] <= self.B_vessel[b][v] for i in nodes \
            for j in nodes for t in D for wf in WF for b in B for v in V)

        c_qr = quicksum(Q[v,t,wf,p,0] * self.tech_cost[p] for p in P \
            for wf in WF for t in D for v in V)
        c_tr = quicksum(self.V_cost[v] * travelTime[v][wf][i,j] * y[v,t,wf,i,j] \
            for i in nodes for j in nodes for wf in WF for t in D for v in V)
        c_lr = quicksum(x[wf,j] * self.WF_penCost[wf][j-1] for j in dropoff for wf in WF)
        
        model.modelSense = GRB.MINIMIZE
        model.setObjective(c_qr+c_tr+c_lr)
        model.optimize()
        if model.status == GRB.OPTIMAL:
            c_total = model.objVal
            print (c_total)
        else:
            print('infeasible')
        return