简体   繁体   中英

Pyomo (Transportation theory): including a constraint that limits to just one the number of sources/factories

I'm trying to solve the classical 'Transportation theory' to optimize the production and transportation of goods from 3 factories to 5 distribution centers.

There are:

  • 3 max capacities in each factory (items/week)
  • 3x5 transportation costs from each factory to each distribution center ($/item)
  • 5 weekly demand volume in each distribution center (items/week)

I'm able to solve it with Pyomo:

from pyomo.environ import *
import pyomo.environ as pyo

model = ConcreteModel()

model.i = Set(initialize=['Factory A','Factory B', 'Factory C'])
model.j = Set(initialize=['DC 1', 'DC 2', 'DC 3', 'DC 4', 'DC 5'])
model.a = Param(model.i, initialize={'Factory A':1000,'Factory B':4000, 'Factory C':2000}) #Weekly_capacities
model.b = Param(model.j, initialize={'DC 1':500,'DC 2':900,'DC 3':1800, 'DC 4':200, 'DC 5':700 }) #Weekly_demands

# Transportation costs
costs = {('Factory A', 'DC 1'): 2,('Factory A', 'DC 2'): 4, ('Factory A', 'DC 3'): 5, ('Factory A', 'DC 4'): 2, ('Factory A', 'DC 5'): 1, \
    ('Factory B', 'DC 1'): 3, ('Factory B', 'DC 2'): 1, ('Factory B', 'DC 3'): 3, ('Factory B', 'DC 4'): 2, ('Factory B', 'DC 5'): 3, \
    ('Factory C', 'DC 1'): 1, ('Factory C', 'DC 2'): 3, ('Factory C', 'DC 3'): 3, ('Factory C', 'DC 4'): 1, ('Factory C', 'DC 5'): 5}

model.d = Param(model.i, model.j, initialize=costs)

def f_costs(model, i, j):
    return model.d[i,j]
model.c = Param(model.i, model.j, initialize=f_costs)

model.x = Var(model.i, model.j, bounds=(0.0,None)) #Production

def f_supply(model, i):
    return sum(model.x[i,j] for j in model.j) <= model.a[i]
model.supply = Constraint(model.i, rule=f_supply)

def f_demand(model, j):
    return sum(model.x[i,j] for i in model.i) >= model.b[j]  
model.demand = Constraint(model.j, rule=f_demand)

def f_objetive(model):
    return sum(model.c[i,j]*model.x[i,j] for i in model.i for j in model.j)
model.objetive = Objective(rule=f_objetive, sense=minimize)

def pyomo_postprocess(options=None, instance=None, results=None):
    model.x.display()

opt = SolverFactory("glpk")
results = opt.solve(model)
pyomo_postprocess(None, None, results)

Solution:

x : Size=15, Index=x_index
    Key                   : Lower : Value  : Upper : Fixed : Stale : Domain
    ('Factory A', 'DC 1') :   0.0 :    0.0 :  None : False : False :  Reals
    ('Factory A', 'DC 2') :   0.0 :    0.0 :  None : False : False :  Reals
    ('Factory A', 'DC 3') :   0.0 :    0.0 :  None : False : False :  Reals
    ('Factory A', 'DC 4') :   0.0 :    0.0 :  None : False : False :  Reals
    ('Factory A', 'DC 5') :   0.0 :  700.0 :  None : False : False :  Reals
    ('Factory B', 'DC 1') :   0.0 :    0.0 :  None : False : False :  Reals
    ('Factory B', 'DC 2') :   0.0 :  900.0 :  None : False : False :  Reals
    ('Factory B', 'DC 3') :   0.0 :  500.0 :  None : False : False :  Reals
    ('Factory B', 'DC 4') :   0.0 :    0.0 :  None : False : False :  Reals
    ('Factory B', 'DC 5') :   0.0 :    0.0 :  None : False : False :  Reals
    ('Factory C', 'DC 1') :   0.0 :  500.0 :  None : False : False :  Reals
    ('Factory C', 'DC 2') :   0.0 :    0.0 :  None : False : False :  Reals
    ('Factory C', 'DC 3') :   0.0 : 1300.0 :  None : False : False :  Reals
    ('Factory C', 'DC 4') :   0.0 :  200.0 :  None : False : False :  Reals
    ('Factory C', 'DC 5') :   0.0 :    0.0 :  None : False : False :  Reals

However, due to my business and my logistics, I need that the supply of each one of the Distribution Centers comes exclusively from just one factory (and not from two or three). For instance, 'DC 3' is receiving the goods from 'Factory B' and 'Factory C' and I would like to force it to just 'Factory B' or just 'Factory C'.

Is there any way to include a Pyomo constraint to limit the number of sources for the Distribution Costs?

You need binary variables for this. I'll use math notation below as this is much less unwieldy than Pyomo code. The standard transportation model looks like:

 min sum((i,j), c[i,j]*x[i,j])
 sum(j, x[i,j]) <= a[i]   ∀i
 sum(i, x[i,j]) >= b[j]   ∀j
 x[i,j] >= 0

Now add binary variables y[i,j] and use:

 min sum((i,j), c[i,j]*x[i,j])
 sum(j, x[i,j]) <= a[i]   ∀i
 sum(i, x[i,j]) >= b[j]   ∀j
 x[i,j] <= M[i,j]*y[i,j]  ∀i,j
 sum(i,y[i,j]) = 1        ∀j
 x[i,j] >= 0
 y[i,j] ∈ {0,1}

here M[i,j] is an upper bound on x[i,j] . Eg

  M[i,j] = min(a[i],b[j])

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM