'Scipy linprog constraints not satisfied
I’ve defined a linear programming model using scipy linprog however the equality constraints when I calculate them manually do not satisfy the constraint. I have an x by y table that represents different locations, where the row is the facility material is sent from and column is the receiving facility.
I want the decision variable coefficient to be -1 across a specific row (stored in the variable r) of a table which results in the sum of the decision variables being equal to a value pulled from an excel file. I reshape the list to be the same dimensions as the table to print into excel which gives the correct structure I need (-1 across row r for each constraint) when I look at the excel file, when printing the list of exportreq, this is also correctly loaded when compared to the excel file.
I’m struggling to understand why the solution doesn’t satisfy the constraints when solved, I’ve tried relaxing the constraints by artificially increasing the volume that a receiving facility can take however this still results in the constraints not being satisfied even though there is a large excess in capacity.
I have an inequality constraint that works on the same principle except it has the coefficient as 1 down a specific column (Column c), and that works as expected when loaded into the excel file as the constraint is satisfied when calculated manually.
See the code below that defines the objective function, constraints and also the call of linprog in the code:
Objective Function Definition and Excel sheet Reference
import openpyxl as pyxl
from scipy.optimize import linprog
import numpy as np
from datetime import datetime
import pandas as pd
import time
start_time = datetime.now()
# do your work here
wb = pyxl.load_workbook('Filepath/Filename.xlsx',data_only=True)
ws = wb.get_sheet_by_name("Sheet1")
ws2 = wb.get_sheet_by_name("Sheet2")
ws3 = wb.get_sheet_by_name("Sheet3")
obj = []
lhs_ineq=[]
rhs_ineq=[]
lhs_eq=[]
rhs_eq=[]
bnd = []
x0bounds = []
x1bounds = []
#Loop for objective function definition and import capacity constraints
totalrows = 563
totalcols = 26
for i in range(2,totalcols):
for j in range(4,totalrows):
c = ws2.cell(row = 2, column = i).value
y = ws.cell(row = j, column = i).value
y = (y/60/28)*44
z = y + c
x0bounds.append(0)
x1bounds.append("inf")
# add coefficient to objective function list
obj.append(z)
Constraints
For the importvar constraint, I loop through the x by y table for every column. Adding a 1 when the column numbers match.
#This Constraint works perfectly
for r in range(2,totalcols):
importvar=[]
for c in range(2,totalcols):
for r2 in range(4,totalrows):
if c == r:
importvar.append(1)
else:
importvar.append(0)
lhs_ineq.append(importvar)
rhs_ineq.append(ws2.cell(row=3,column=r).value)
For the exportvar constraint, I loop through the x by y table for every row. Adding a 1 when the row numbers match.This constraint should be a greater than or equal to constraint so I have used -1 as a coefficient and multiplied the rhs_ineq by -1. The code to reshape the dataframe is to check the structure of the constraints in excel, I did this with the previous constraint to check the structure was correct and have since removed that part of the code.
#This inequality isn't currently working properly!
for r in range(4,totalrows):
exportvar=[]
for c in range(2,totalcols):
for r2 in range(4,totalrows):
if r == r2:
exportvar.append(-1)
else:
exportvar.append(0)
splitx = np.reshape(exportvar,(totalrows-4,totalcols-2),order = 'F')
d[r] = pd.DataFrame(splitx)
d[r].columns = [ws.cell(row = 1, column = i).value for i in range(2,len(d[r].columns)+2)]
d[r].index = [ws.cell(row = i, column = 1).value for i in range(4,len(d[r].index)+4)]
lhs_ineq.append(exportvar)
exportreq = ws3.cell(row = r,column = 56).value
rhs_ineq.append(-exportreq)
Calling Linprog and writing decision variables to excel in x by y table
tols = {"tol":0.0001}
opt = linprog(obj, A_ub = lhs_ineq, b_ub = rhs_ineq, A_eq = lhs_eq, b_eq = rhs_eq, bounds=bnd,method="interior-point", options = tols)
splitx = np.reshape(opt.x,(totalrows-4,totalcols-2),order = 'F')
df = pd.DataFrame(splitx)
#use pandas to write the decision variables into excel and add in headers
df.columns = [ws.cell(row = 1, column = i).value for i in range(2,len(df.columns)+2)]
df.index = [ws.cell(row = i, column = 1).value for i in range(4,len(df.index)+4)]
df.to_excel('Filepath/Filename' + time.strftime("%d%m%Y") +'.xlsx',sheet_name = "SheetName",float_format="%.2f",startrow=0,startcol=0,header=True,index=True)
writer = pd.ExcelWriter('Filepath/Filename' +time.strftime("%d%m%Y") +'.xlsx', engine='xlsxwriter')
#
##write each DataFrame to a specific sheet
for c in range(4,25):
d[c].to_excel(writer, sheet_name='Dataset '+ str(c-1))
#close the Pandas Excel writer and output the Excel file
writer.save()
end_time1 = datetime.now()
print('Duration of Optimisation: {}'.format(end_time1 - end_time))
print("Status: " +str(opt.status) + " "+ str(opt.message) + " Iterations: "+ str(opt.nit))
When returning the status of the optimisation after solving, it is status 0 indicating the problem was solved successfully.
Why are the exportvar constraints not being satisfied?
Please let me know if there's any additional code you'd like to see, I've removed some for brevity.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|