Впервые пользователь Pyomo здесь.
Я пытаюсь построить модель оптимизации, которая максимизирует количество отходов, собираемых в сети переработки отходов, состоящей из клиентов i и центров переработки j. (т. е. максимизировать количество отходов Qij, перетекающих из i в j). Вот математическая модель:
Я закодировал функцию в блокноте jupyter, которая считывает координаты широты и долготы клиента и центра переработки из двух отдельных файлов csv, используя функцию read_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-файлов для создания наборов и параметров для моей модели Pyomo с помощью AbstractModel(). Я не уверен, что этот метод или ConcreteModel() лучший способ сделать это.
Одно ограничение на задачу оптимизации определяет максимальное расстояние, которое клиент i преодолеет до центра переработки j, причем это максимальное расстояние установлено равным b = 5 км. Мне нужно, чтобы эти данные были прочитаны из CSV-файла или фрейма данных, но я не уверен, что это лучший метод, так как я мог бы также выполнить эту проверку при циклической передаче координат местоположения в функцию Distance_from.
Второе ограничение гарантирует, что общее количество отходов Qij, доставленных в аптеку j, не превысит пропускную способность j, которая также считывается из CSV-файла.
Бинарная переменная решения Xij=1, если клиент i доставляет отходы в центр переработки j, Xij=0 в противном случае
Вот код, который я попытался написать, который будет определять наборы для чтения из CSV-файла, определять целевую функцию и применять ограничения. Он появляется после кода выше. Я не уверен, насколько далеко этот код от того места, где мне нужно быть. Весь код был написан в 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
документация?
Несколько предложений:
Начните с ConcreteModel
и инициализируйте данные вручную. Я думаю, что это проще сделать, особенно. с возможностью python обрабатывать файлы .csv либо вручную (как показано ниже), либо с помощью pandas или csv_reader.
Выбросьте pandas
пока. Используйте его из отдельного файла, если необходимо, для Создайте файлов .csv, если вам это удобно, или просто напишите их вручную, или используйте csv_reader, но не смешивайте pandas
и pyomo
, пока не встанете на ноги. Тот же совет для numpy
.
Используйте формат «плоский файл» для ваших данных, а не табличный. Его легче проглотить. Так, например, создайте свою таблицу расстояний в формате csv, которая имеет 3 столбца, как у меня, и ее легче читать в словаре или, если вы идете в AbstractModel
, она находится в простом формате.
Используйте фрагмент небольшой ваших данных и pprint()
вашей модели, чтобы убедиться, что это имеет смысл и соответствует вашей математической модели.
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
Спасибо за ваш ответ. Да, я просматривал документацию Pyomo, но запутался в правильном способе формулировки проблемы при использовании «ConcreteModel» или «AbstractModel». Я попробую ваше предложение, так как оно кажется немного проще.