Skip to main content

How to add constraints for a 14 day cycle of production and delivery

Answered

Comments

6 comments

  • Official comment
    Simranjit Kaur
    • Gurobi Staff
    This post is more than three years old. Some information may not be up to date. For current information, please check the Gurobi Documentation or Knowledge Base. If you need more help, please create a new post in the community forum. Or why not try our AI Gurobot?.
  • Jaromił Najman
    • Gurobi Staff

    Hi Nelly,

    Could you provide a minimal working example showing the issue?

    When starting off with a new model, it is often best to write down the formulation on a piece of paper (or anything similar) before coding it. This way, you can implement the variables and constraints one by one and additionally you can easily explain to others which constraints are causing you trouble.

    Best regards,
    Jaromił

    0
  • Nelly V
    • Gurobi-versary
    • First Comment
    • First Question

    Hello Jaromił Najman, thank you for your response. 

     

    Here is my problem:

    \[\begin{align} \ v = rate(in)t - rate(out)t + \textrm{what's generated} \end{align}\]

    \[\begin{align} \ V_{excess} = N_{t}r_{t_{0}}t - (N_{s}r_{s} + N_{t_{i}}r_{t})t + N_{r}r_{r}t \\ \end{align}\]

    \[\begin{align} \ Sum(V_{excess}) = Sum(N_{t}r_{t_{0}})t - Sum(N_{s}r_{s} + N_{t_{i}}r_{t})t + Sum(N_{r}r_{r}t) \\ \end{align}\]

    What the problem is trying to do is minimize excess, meaning the difference between what was produced in a factory and allocated to each county minus what was used by the county during a course of 14 days period. 

    what's in = the rate of transportation in a site (shipped)

    if the number of trucks coming in within a period t is N_{t} and each truck works at the rate of r then N r t is the volume per site 

    for all sites, we need to sum it up

    what's out = dispensing by staff + transportation out

    if each staff works at the rate pf r, in time t, N staffs will dispense N r t and if transportation out is N r at the same time t, then N in time t

    N r t is again for all sites

    what's produced is basically reactor rate r x number of reactors N in time t

    N r t needs to be summed for all sites

    Excess can't be less than zero but could be zero.

    This is to solve vaccine delivery solution where a factory needs to make enough doses for each vaccination center keeping in mind what's left behind in each tier. 

    I have added my variables in the previous post... does this help? 

     

    0
  • Jaromił Najman
    • Gurobi Staff

    Hi Nelly,

    Yes, this certainly helps. Now, could you post the code snippet of the constraints which produces the error you mentioned in your first post? Moreover, one would need the definition of \(\texttt{cartesian_prod_fct}\) to reproduce the problem.

    Best regards,
    Jaromił

    0
  • Nelly V
    • Gurobi-versary
    • First Comment
    • First Question

    Here is what I have written so far Jaromił Najman, please do let me know if there is any issues with the formatting of what I am intending to do. Thank you so much!

    import itertools
    from itertools import product
    from math import sqrt
    import pandas as pd
    import gurobipy as gp
    from gurobipy import GRB
    from gurobipy import quicksum


    m = gp.Model('VCStrategy')

    #minimum amount of dose made by one reactor per day (one minute run per day)
    minDosePerR = 600

    #max number of hours every reactor can run for (8 hours a day)
    maxRunTime = 8*60

    #county population
    CountyPopulation = 7000

    centers = [(0,0), (0,1), (0,2), (1,0), (1,1), (1,2), (2,0), (2,1), (2,2)] #this needs to reflect the db
    facilities = [(0,0), (0,1), (0,2)] #this needs to reflect the db

    # Indices for the facilities
    facilitiesIndex = [*range(1,3)] #this needs to reflect the count from db

    # Indices for the counties / later to be post codes/ as in GPs
    countiesIndex = [*range(1,9)] #this needs to reflect count the db

    #time period - 14 days
    period = [*range(0,13)]

    #nurse number of admissions per day
    nurse_ratePerDay = 28

    #max number of nurses in each clinic to administrate vaccines
    nurse_max = 8

    #cost to set up one reactor + storage staff and the rest for 14 days
    costPerFacilitySetup = [10000,10000,10000] #this needs to reflect the db for count of hospitals provided 10,000

    #cost of travel per mile by vehicle
    costPerMile = 10

    #cost per day per nurse
    costPerNurse = 105

    capacityTOStorePerGP = 399
    capacityTOStorePerHospital = 2000

    storageCostPerDoseGP = 0.90
    storageCostPerDoseHospital = 0.79


    budget = 200000

    # Cartesian product of counties and facilities
    fc = []
    for f in facilitiesIndex:
    for c in countiesIndex:
    tp = f,c
    fc.append(tp)

    # Cartesian product of facilites and centers and time period
    fct = []
    for f in facilitiesIndex:
    for c in countiesIndex:
    for t in period:
    tp = f,c,t
    fct.append(tp)

    # Cartesian product of facilities and time
    ft = []
    for f in facilitiesIndex:
    for t in period:
    tp = f,t
    ft.append(ft)

    # Cartesian product of centers and time
    ct = []

    for c in countiesIndex:
    for t in period:
    tp = c,f
    ct.append(tp)


    # This function determines the Euclidean distance between a facility and customer sites.
    def compute_distance(loc1, loc2):
    dx = loc1[0] - loc2[0]
    dy = loc1[1] - loc2[1]
    return sqrt(dx*dx + dy*dy)

    # Compute key parameters of MIP model formulation

    num_facilities = len(facilities)
    num_customers = len(centers)
    cartesian_prod_fc = list(product(range(num_facilities), range(num_customers)))
    cartesian_prod_fct = list(product(range(num_facilities), range(num_customers), (period)))
    cartesian_prod_ct = list(product(range(num_customers), (period)))
    cartesian_prod_ft = list(product(range(num_facilities), (period)))


    select = m.addVars(num_facilities, vtype=GRB.BINARY, name='Select')

    # Compute shipping costs

    shipping_cost = {(f,c): costPerMile*compute_distance(facilities[f], centers[c]) for f, c in cartesian_prod_fc}

    #number of reactors at facility f at period t
    rn = m.addVars(cartesian_prod_ft, vtype=GRB.CONTINUOUS, lb = 0, name="reactor_{}".format((f,t) for f,t in cartesian_prod_ft))

    #number of doses at facility f at period t
    d = m.addVars(cartesian_prod_ft, vtype=GRB.CONTINUOUS, lb = 0, name="doses_{}".format((f,t) for f,t in cartesian_prod_ft))

    #DurationOfRunPerReacorInTimePeriod - #minimum running time is 1 minute lower bound
    rnt = m.addVars(cartesian_prod_ft, vtype = GRB.CONTINUOUS, lb = 1, name = "reactorRunTime_{}".format((f,t) for f,t in cartesian_prod_ft))

    #rn*rnt*600 = total doses per day

    #number of reactors * duration of run * 600

    #number of allocated doses from facility f for center c at period t
    alloc = m.addVars(cartesian_prod_fct, vtype=GRB.CONTINUOUS, name="allocated_{}".format((f,c,t) for f,c,t in cartesian_prod_fct))

    #shipped doses
    s = m.addVars(cartesian_prod_fct, vtype=GRB.CONTINUOUS, name="Shipped_{}".format((f,c,t) for f,c,t in cartesian_prod_fct))

    #administrated doses
    adm = m.addVars(cartesian_prod_ct, vtype=GRB.CONTINUOUS, name="administrated_{}".format((c,t) for c,t in cartesian_prod_ct))

    #doses stored at facility f in period
    fstored = m.addVars(cartesian_prod_ft, vtype=GRB.CONTINUOUS, name="fstored{}".format((f,t) for f,t in cartesian_prod_ft))

    #doses stored at center c in period
    cstored = m.addVars(cartesian_prod_ct, vtype=GRB.CONTINUOUS, name="cstored_{}".format((c,t) for c,t in cartesian_prod_ct))

    #number of nurses at location c
    nc = m.addVars(cartesian_prod_ct, vtype = GRB.CONTINUOUS, lb = 0, name = "numberofNurses_{}".format((c,t) for c,t in cartesian_prod_ct))

    #number of deliveries from factory to center in period
    nd = m.addVars(cartesian_prod_fct, vtype = GRB.CONTINUOUS, lb = 0, name = "deliveries_{}".format((f,c,t) for f,c,t in cartesian_prod_fct))




    #List of Contraints

    #total of doses made in 14 days need to equal demand in county
    # m.addConstr(quicksum(d[f, t]) for f,t in cartesian_prod_ft == CountyPopulation)

    m.addConstrs((d[f, t] == CountyPopulation for f,t in cartesian_prod_ft
    if f != t), name='demandConstraints')

    #max hour of operation per reactor per day is 480 minutes
    m.addConstrs((rnt[f, t] <= maxRunTime for f,t in cartesian_prod_ft
    if f != t), name='maxRunTimeConstraints')

    #max number of nurses shouldn't be more than 8
    m.addConstrs((nc[c, t] <= maxRunTime for c,t in cartesian_prod_ct
    if c != t), name='maxNurseConstraints')


    #minimum produceddosesin each period is 600 doses if the factory is selected - as in the hospital is the point of production

    #if t=0, none of the centers have any excess doses
    #total allocated doses from facility f to center c in time period t shouldn't be greater than center's capacity for the day which is 399

    #if t!=0, centers have some remaining doses
    #total allocated doses from facility f to center c in time period t shouldn't be greater than center's capacity - remaining doses


    #total cost of setting the factories, shipping doses to all locations, administrating it and storing them in both factory and center shouldn't be greater than our budget for the total of 14 days

    #calculate the total for setting up the factories, shipping the doses and administrating it
    #total cost involves number of reactors time their fixed fee + numberofdeliveries * shippingcost + numberofstaff*theirdaily rate
    #this needs to reflect all 14 period




    #min excess = Total of produced in all periods - (total of all allocated per clinic - total of all dispenced)
    # integrate variables and constraints
    m.update()

    # Objective function
    totalPro = (gp.quicksum(d[f,t] for f,t in ft))
    totalAllocated = (gp.quicksum(alloc[f,c,t] for f,c,t in fct))
    totalAdm = (gp.quicksum(adm[c,t] for c,t in ct))


    obj = (totalPro - (totalAllocated - totalAdm))
    m.setObjective(obj,GRB.MINIMIZE)

    # start optimization
    m.optimize()

    And for the most part here is the error I keep getting. I am not sure what I am doing wrong..

    # Objective function
    --> 185 totalPro =  (gp.quicksum(d[f,t] for f,t in ft))
        186 totalAllocated = (gp.quicksum(alloc[f,c,t]  for f,c,t in fct))
        187 totalAdm = (gp.quicksum(adm[c,t] for c,t in ct))
    
    ValueError: too many values to unpack (expected 2)

    I think the quick sum over all products produced, allocated and administrated is right, both in constraints and in objective function

    0
  • Jaromił Najman
    • Gurobi Staff

    Hi Nelly,

    The error occurs because the \(\texttt{ft}\) list is not constructed properly. In line 77 it should read

    ft.append(tp)

    instead of

    ft.append(ft)

    The resulting model is found to be infeasible or unbounded. You could use the write() function to generate an LP file which you can analyze by hand. The InfUnbdInfo parameter provides additional information to determine whether the model is actually infeasible or unbounded. In the case of an infeasible model you might want to have a look at the Knowledge Base article How do I determine why my model is infeasible?

    Best regards,
    Jaromił

    0

Post is closed for comments.