I have a class that evaluates a result for a given input list of parameters. I would like to know the best set of parameters that minimises the result given by the class. Since the input must remain integer, I read that Pulp might be a solution compared to Scipy.minimize().
I tried to implement it, but the line prob += ... doesn't work. Here is a simplified version of the code that reproduces the problem I have. It seems that I don't understand something important about Pulp.
import pandas as pd
import pulp as pl
class ComplexClass():
def __init__(self, path_data:str):
# self.data = pd.read_csv(path_data)
d = {'col1': [i for i in range(100)], 'col2': [i**2 for i in range(100)]}
self.df = pd.DataFrame(data=d)
def eval_value(self, param: list):
self.p1 = param[0]
self.p2 = param[1]
# [...] Complexe stuff manipulating pandas DataFrame
self.df['col3'] = self.df['col1'].rolling(window=self.p1).mean()
self.df['col4'] = self.df['col2'].rolling(window=self.p2).mean()
self.df['col5'] = self.df['col3']+self.df['col4']
self.best_value = self.df['col5'].iloc[-1]
def func_to_minimize(input_parm:list, initialized_class):
initialized_class.eval_value(input_parm)
return initialized_class.best_value
path = './path2data/data.csv'
my_class = ComplexClass(path_data=path)
# ===== INIT TEST =====
my_param = [2, 10]
print(f'For input {my_param}\n => Value to minimize = {func_to_minimize(input_parm=my_param, initialized_class=my_class)}')
# ====== OPTIMIZATION WITH PULP =====
# Create the 'prob' variable to contain the problem data
prob = pl.LpProblem("Best_Param", pl.LpMinimize)
# The 2 variables Beef and Chicken are created with a lower limit of zero
x1 = pl.LpVariable("param1", lowBound=2, upBound=10, cat=pl.LpInteger)
x2 = pl.LpVariable("param2", lowBound=2, upBound=20, cat=pl.LpInteger)
# The objective function is added to 'prob' first
prob += func_to_minimize([x1, x2], my_class) # <= doesn't work
# The problem data is written to an .lp file
prob.writeLP("Best_Param.lp")
# The problem is solved using PuLP's choice of Solver
prob.solve()
The error message is when evaluating self.df['col3'] = self.df['col1'].rolling(window=self.p1).mean() and is: ValueError: window must be an integer 0 or greater. Indeed, the self.p1 used in window is a LpVariable and not an integer.
How to minimize a problem using Pulp when the result to be minimised must be evaluated by a function and not by a line?
Thank you.