[英]Pulp: How to add/subtract decision variable outputs together
我正在研究將產品從生產工廠轉移到存儲設施以滿足需求的鐵路調度問題。
我是紙漿新手,所以很難理解為什么這不起作用,不幸的是,關於這個主題的文檔很少。
問題
需要監控三個決策變量:
每個工廠的產品可用性/庫存 - 請注意每個工廠可以生產不同的產品。
鐵路 - 每個工廠的每種產品要移動多少。 每列火車可運載8400噸。
運行程序后,鐵路決策變量正常工作,即 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,我只是獲取字典值而不考慮鐵路添加/刪除的數量。
如果沒有可重現示例形式的代碼,我無法確定所有問題,但這里有一些:
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)
storage_facility_vars[(date, product)] = plant_current_inv[product]
線性規划的一般方法是聲明變量、要優化的目標以及存在的約束。 在 PULP 中,使用model +=
語法將目標和約束添加到問題中。 您在這里所做的是獲取您創建的線性變量並用plant_current_inv[product'
中的任何內容覆蓋它。 我認為您想要做的是設置一個等式約束並將其添加到問題中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.