繁体   English   中英

纸浆:如何将决策变量输出加/减在一起

[英]Pulp: How to add/subtract decision variable outputs together

我正在研究将产品从生产工厂转移到存储设施以满足需求的铁路调度问题。

我是纸浆新手,所以很难理解为什么这不起作用,不幸的是,关于这个主题的文档很少。

问题

需要监控三个决策变量:

  1. 每个工厂的产品可用性/库存 - 请注意每个工厂可以生产不同的产品。

  2. 铁路 - 每个工厂的每种产品要移动多少。 每列火车可运载8400吨。

  3. 存储设施中每种产品的库存。

运行程序后,铁路决策变量正常工作,即 output 符合预期,但工厂和存储设施的库存未显示铁路移除和随后添加的数量。

数据和代码如下:

import pulp as pulp
import pandas as pd
import datetime

#rail capacity df from plant: no_trains_per_day max
rail_capacity_df_daily = {'ABC': {'capacity_per_day': 1, 'max': 19},
                          'DEF': {'capacity_per_day': 1, 'max': 50}}
rail_capacity_df = pd.DataFrame.from_dict(rail_capacity_df_daily ,orient='Index')

# facilities_df
facilities_inventory = {'BZL': {'current': 100000, 'max': 210000}, 
                        'AFM': {'current': 100000, 'max': 190000},
                        'PRE': {'current': 100000, 'max': 245000}}
facilities_df = pd.DataFrame.from_dict(facilities_inventory, orient='Index')


# plants_df
plant_df_inventory = {('ABC', 'PRE'): {'inventory': 196710, 'daily_production': 6000},
                      ('ABC', 'AFM'): {'inventory': 199910, 'daily_production': 5000},
                      ('DEF', 'BZL'): {'inventory': 127110, 'daily_production': 5000},
                      ('DEF', 'PRE'): {'inventory': 227100, 'daily_production': 6000}}  

plants_df = pd.DataFrame.from_dict(plant_df_inventory,orient='Index').rename_axis(['plant', 'product'])

# Sales demand

sales_demand = {'2020-04-24': {'AFM': 10000, 'PRE': 15000, 'BZL': 10000},
                '2020-04-25': {'AFM': 10000, 'PRE': 15000, 'BZL': 10000},
                '2020-04-26': {'AFM': 10000, 'PRE': 15000, 'BZL': 10000},
                '2020-04-27': {'AFM': 10000, 'PRE': 15000, 'BZL': 10000},
                '2020-04-28': {'AFM': 10000, 'PRE': 15000, 'BZL': 10000},
                '2020-04-29': {'AFM': 10000, 'PRE': 15000, 'BZL': 10000},}

sales_df = pd.DataFrame.from_dict(sales_demand, orient='Index').rename_axis(['date'])

# Demand: Current Sales Demand
sales_demand = sales_df.to_dict(orient='index')

# PLANNING HORIZON PARAMS  
_current_date = pd.to_datetime(datetime.datetime.today().strftime('%Y%m%d'))
planning_horizon_max = datetime.datetime.today() + datetime.timedelta(4)
planning_horizon_max = pd.to_datetime(planning_horizon_max.strftime('%Y%m%d'))

# COMBINATION VARS
dates = [d.strftime('%F') for d in pd.date_range(_current_date,planning_horizon_max)]
plant_combinations = [(plant, product) for plant, product in plants_df.index]
products = [p for p in facilities_df.index] 
plants = ['ABC', 'DEF']

# Sales Demand: Grade Combinations by Date
demand_requirements = [(d, p) for d in dates for p in products]

# INVENTORY 
# Initial Storage Inventory
storage_inv = dict(zip(facilities_df.index, facilities_df['current']))

storage_max = dict(zip(facilities_df.index, facilities_df['max']))

# Initial Plant Inventory
plant_current_inventory = dict(zip(plants_df.index, plants_df.inventory))
plant_daily_production = dict(zip(plants_df.index, plants_df.daily_production))


# DECISION VARIABLES
# Plant facility vars
plant_inventory_vars = pulp.LpVariable.dicts(
    'Plant Inventory',
    ((date, plant, product) for date in dates for (plant, product) in plant_combinations),
    cat='Continuous',
    lowBound=0) 

# Storage Facility Vars
storage_facility_vars = pulp.LpVariable.dicts(
    'Storage Inventory',
    ((d, p) for d in dates for p in products),
    cat='Integer',
    lowBound=0)

# Total train capacity per plant dict
train_load_limit_daily = dict(zip(rail_capacity_df.index, 
                                  rail_capacity_df.capacity_per_day))

# Decision Vars: date, plant, product
train_consignment_variables = pulp.LpVariable.dicts(
    'Rail Loadings From plant',
    ((date, plant, product) for date in dates for (plant, product) in plant_combinations),
    cat='Continuous',
    lowBound=0) 


# OPTIMISATION

# Instantiate 
model = pulp.LpProblem('Rail Optimisation', pulp.LpMinimize)

solver = pulp.PULP_CBC_CMD()
solver.tmpDir = 'Users\CPrice2'

# Objective Function
model += pulp.lpSum(storage_max[product] 
    - storage_facility_vars[(date, product)] for (date, product) in storage_facility_vars), 'Minimise stockpile shortfalls'

    # PLANT INVENTORY
for date in dates:
  current_date = datetime.date.today().strftime('%F')
  date_t_minus_one = datetime.datetime.strptime(date, '%Y-%m-%d') - datetime.timedelta(days=1)
  date_t_minus_one = date_t_minus_one.strftime('%F')
  for plant, product in plant_combinations:
    if date == current_date:
      # Set current inventory
      model += plant_current_inventory[(plant, product)] - \
          train_consignment_variables[(date, plant, product)] == \
          plant_inventory_vars[(date, plant, product)] + \
          plant_daily_production[(plant, product)]
    else:
      # Get inventory from t-1
      model += plant_inventory_vars[(f'{date_t_minus_one}', plant, product)] - \
          train_consignment_variables[(date, plant, product)] == \
          plant_inventory_vars[(date, plant, product)] + \
          plant_daily_production[(plant, product)]

# Trains: Daily Rail Out Constraint 
for date in dates:
  for plant in plants:
    plant_product_combination = [tup for tup in plant_combinations if tup[0] == plant]
    variable_list = []
    for (plant_, product_) in plant_product_combination:
      variable = train_consignment_variables[(date, plant_, product_)]
      variable_list.append(variable)
    model += pulp.lpSum(var for var in variable_list) == train_load_limit_daily[plant] * 8400

# STORAGE FACILITY 
for date in dates:
  current_date = datetime.date.today().strftime('%F')
  date_t_minus_one = datetime.datetime.strptime(date, '%Y-%m-%d') - datetime.timedelta(days=1)
  date_t_minus_one = date_t_minus_one.strftime('%F')
  for plant, product in plant_combinations:
    if date == current_date:
      # Current Inv == current inventory + train in
      model += storage_inv[product] + \
          train_consignment_variables[(date, plant, product)] == \
          storage_facility_vars[(date, product)] - sales_demand[date][product] 
    else:
      model += storage_facility_vars[(f'{date_t_minus_one}', product)] + \
          train_consignment_variables[(date, plant, product)] == \
          storage_facility_vars[(date, product)] - sales_demand[date][product]

# Run solver
model.solve(solver)
pulp.LpStatus[model.status]

# Storage Out
storage_facility_out = []

for (date, product) in storage_facility_vars:
  var_out = {
      'Date': date,
      'Product': product,
      'Out Inventory': storage_facility_vars[(date, product)].varValue
  }
  storage_facility_out.append(var_out)

storage_facility_out_df = pd.DataFrame.from_records(storage_facility_out).sort_values(['Date', 'Product'])
storage_facility_out_df.set_index(['Date', 'Product'], inplace=True)

# Rail Out
rail_optimisation_outputs = []

for date, plant, product in train_consignment_variables:
  var_output = {
      'Date': date,
      'Plant': plant,
      'Product': product,
      'Rail_Out': train_consignment_variables[(date, plant, product)].varValue
  }
  rail_optimisation_outputs.append(var_output)

output_df = pd.DataFrame.from_records(rail_optimisation_outputs).sort_values(['Date', 'Plant', 'Product'])
output_df.set_index(['Date', 'Plant', 'Product'], inplace=True)

# Production Plant Out
plant_stock_out = []

for date, plant, product in plant_inventory_vars:
  var_out = {
      'Date': date,
      'Plant': plant,
      'Product': product,
      'Out Inventory': plant_inventory_vars[(date, plant, product)].varValue
      }
  plant_stock_out.append(var_out)
plant_stock_out_df = pd.DataFrame.from_records(plant_stock_out).sort_values(['Date', 'Product'])
plant_stock_out_df.set_index(['Date', 'Plant', 'Product'], inplace=True)
plant_stock_out_df

当我访问每个决策变量的输出时:

train_consignment_vars.varValue = output ok.

对于工厂和存储设施,我得到以下信息:

storage_facility_vars.varValue = AttributeError: 'float' object 没有属性 'value'。 如果我不调用.varValue,我只是获取字典值而不考虑铁路添加/删除的数量。

如果没有可重现示例形式的代码,我无法确定所有问题,但这里有一些:

  1. 在您已经添加了目标函数之后,您似乎添加了更多不是约束形式的表达式,例如:

model += pulp.lpSum(plant_inventory_vars[(date, plant, product)]) - pulp.lpSum(train_consignment_variables[(date, plant, product)])

这不是一个约束。 model +=之后的东西需要采用“A == B”或“A <= B”或“A >= B”的形式。 你的表情没有。

这里还有一个:

model += pulp.lpSum(port_inventory_vars[(date, product)]) + pulp.lpSum(train_consignment_variables[(date, plant, product)] for plant, product in plant_combinations)

  1. 正如@pchtsp 所指出的,您正在覆盖一些纸浆变量:

storage_facility_vars[(date, product)] = plant_current_inv[product]

线性规划的一般方法是声明变量、要优化的目标以及存在的约束。 在 PULP 中,使用model +=语法将目标和约束添加到问题中。 您在这里所做的是获取您创建的线性变量并用plant_current_inv[product'中的任何内容覆盖它。 我认为您想要做的是设置一个等式约束并将其添加到问题中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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