从 csv 文件中定义集和参数以用于 pyomo 优化最大数量废物收集问题

Define sets and parameters from csv file to be used in pyomo optimization max quantity waste collected problem

这里是 Pyomo 的第一次用户。

我正在尝试建立一个优化模型,以最大化由客户 i 和回收中心 j 组成的废物回收网络中收集的废物数量。 (即最大化从 i 流向 j 的废物量 Qij)。数学模型如下:

Mathematical model

我在 jupyter notebook 中编写了一个函数,该函数使用 read_csv 函数从两个单独的 csv 文件中读取客户和回收中心的纬度和经度坐标。名为 distance_from 的函数计算坐标之间的正弦距离并运行一个循环,该循环将逐一解析客户位置到 distance_from 函数。这会生成 80x16 RowsxColumns 的数据框。这是这个位的代码:

#create data file of customers i and recycling centres j
df_cent = pd.read_csv("recycling centres.csv",index_col=[0], header=0)
df_cust = pd.read_csv("customers.csv",index_col=[0], header=0)

# concatenating lat and long to create a consolidated location as accepted by haversine function
df_cent['coordinates'] = list(zip(df_cent.Latitude, df_cent.Longitude))
df_cust['coordinates'] = list(zip(df_cust.Latitude, df_cust.Longitude))

# defining a  function to calculate distance between two locations 
# loc1= location of an existing recycling centre
# loc2= location of customer

def distance_from(loc1,loc2): 
    dist=hs.haversine(loc1,loc2)
    return round(dist,2)

# running a loop which will parse customers location one by one to distance from function 
for _,row in df_cent.iterrows():
    df_cust[row.Name]=df_cust['coordinates'].apply(lambda d:
                                                 distance_from(row.coordinates,d))

我的问题是我没有对这个函数进行任何优化。我想使用 csv 文件中的数据使用 AbstractModel() 为我的 Pyomo 模型创建集合和参数。我不确定此方法或 ConcreteModel() 是否是执行此操作的最佳方法。

优化问题的一个约束决定了客户 i 将前往回收中心 j 的最大距离,该最大距离设置为 b=5km。我需要从 csv 文件或数据框中读取这些数据,但我不确定这是否是最好的方法,因为我也可以在将位置坐标循环到 distance_from 函数时执行此检查。

第二个约束确保运送到药房 j 的废物总量 Qij 不超过 j 的容量,这也是从 csv 文件中读取的。

二元决策变量 Xij=1 如果客户 i 将废物送到回收中心 j,否则 Xij=0

这是我尝试编写的代码,它将定义要从 csv 文件中读取的集合,定义 objective 函数并应用约束。它出现在上面的代码之后。我不确定这段代码离我需要去的地方有多远。所有代码都是在 Jupyter Notebook 中编写的,但我不认为我可以在此处访问该文件,或者与此相关的 csv 数据文件。

from pyomo.environ import *
import pandas as pd
import haversine as hs

solver = SolverFactory('glpk') #GNU Linear Programming Kit

model = AbstractModel()

#set of customers
model.I = pd.read_csv("customers.csv", index_col="Number")
#set of recycling centres
model.J = pd.read_csv("recycling centres.csv", index_col="Name")
#waste generation quantity unit=kg/month
model.Q = pd.read_csv("customers.csv", index_col="Waste Generation (kg/month)")
#Capacity at recycling centre j unit=kg/month
model.Cj = pd.read_csv("recycling centres.csv", index_col="Capacity (kg/month)")

#Binary decision Variable X=1 if customer i served by recycling centre j, X=0 otherwise
model.X = Var(model.I, model.J, domain=Binary)
#Maximum distance customer i will travel to recycling facility j unit=km
model.b = 5 

# Objective is to maximise waste collected within network
def waste_(model):
    return sum(model.Q[i,j]*model.X[i,j] for i in model.I for j in model.J)
model.waste = Objective(rule=waste_, sense=maximize)

# Distance from i to j constraint
def distance_(model, i, j):
    return sum(model.d[i,j]*model.X[i,j] for i in model.I for j in model.J) <= model.b
model.distance = Constraint(rule=distance_)

#Capacity constraint
def capacity_(model, i, j):
    return sum(model.d[i,j]*model.X[i,j] for i in model.I for j in model.J) <= model.Cj
model.capacity = Constraint(rule=capacity_)


提前致谢!

欢迎来到本站。

您的开局“不错”。您的模型中有很多错误....您是否看过 pyomo documentation 中的示例?

几点建议:

  1. ConcreteModel开始,手动初始化数据。我认为这更容易做到,尤其是。 python 能够手动(如下所示)或使用 pandas 或 csv_reader.

    处理 .csv 文件
  2. 暂时放弃 pandas。如果需要 创建 .csv 文件(如果您对此感到满意),或者只是手动编写它们,或者使用 csv_reader,则可以从单独的文件中使用它, 但在您脚踏实地之前,不要混合使用 pandaspyomonumpy.

    同样的建议
  3. 为您的数据使用“平面文件”格式,而不是表格格式。它更容易摄取。因此,例如,像我一样在具有 3 列的 csv 中创建你的距离 table,这样更容易读入字典,或者,如果你转到 AbstractModel,它的格式很简单.

  4. 使用 small 数据切片和 pprint() 模型以确保它有意义并符合您的数学模型。

distances.csv(其他数据文件可从输出推断)

Bob,Main St.,2.1
Cindy,Main St.,3.4
Bob,3rd Ave.,4.9
Cindy,3rd Ave.,0.5 

代码

# pyomo model for customers and distances
import pyomo.environ as pyo

customers = []
centers = []
distances = {}
with open('customers.csv', 'r') as src:
    for line in src:
        customers.append(line.strip())
with open('centers.csv', 'r') as src:
    for line in src:
        centers.append(line.strip())
with open('distances.csv', 'r') as src:
    for line in src:
        cust, center, dist = line.strip().split(',')
        distances[cust, center] = float(dist)

print(customers)
print(centers)
print(distances)

model = pyo.ConcreteModel()

# SETS
model.customers = pyo.Set(initialize=customers)
model.centers = pyo.Set(initialize=centers)

# PARAMETERS
model.distances = pyo.Param(model.customers, model.centers, initialize=distances)

# check it...
model.pprint()

输出

['Bob', 'Cindy']
['Main St.', '3rd Ave.']
{('Bob', 'Main St.'): 2.1, ('Cindy', 'Main St.'): 3.4, ('Bob', '3rd Ave.'): 4.9, ('Cindy', '3rd Ave.'): 0.5}
3 Set Declarations
    centers : Size=1, Index=None, Ordered=Insertion
        Key  : Dimen : Domain : Size : Members
        None :     1 :    Any :    2 : {'Main St.', '3rd Ave.'}
    customers : Size=1, Index=None, Ordered=Insertion
        Key  : Dimen : Domain : Size : Members
        None :     1 :    Any :    2 : {'Bob', 'Cindy'}
    distances_index : Size=1, Index=None, Ordered=True
        Key  : Dimen : Domain            : Size : Members
        None :     2 : customers*centers :    4 : {('Bob', 'Main St.'), ('Bob', '3rd Ave.'), ('Cindy', 'Main St.'), ('Cindy', '3rd Ave.')}

1 Param Declarations
    distances : Size=4, Index=distances_index, Domain=Any, Default=None, Mutable=False
        Key                   : Value
          ('Bob', '3rd Ave.') :   4.9
          ('Bob', 'Main St.') :   2.1
        ('Cindy', '3rd Ave.') :   0.5
        ('Cindy', 'Main St.') :   3.4

4 Declarations: customers centers distances_index distances