Gekko model with machine learning regression models for optimizing a compressor control value vector

41 Views Asked by At

I'm working on an optimization problem for a refrigeration system using the Gekko Python package, and I'm facing issues with integrating Gekko Linear Regression models (Gekko_LinearRegression_Modified) into my optimization model. Specifically, I encounter an error related to the definition of intermediate variables without equality expressions when I try to update costs based on predictions and set constraints based on the model's predictions. Below is a simplified version of my code:

from gekko import GEKKO
from gekko import ML
from gekko.ML import Gekko_GPR, Gekko_SVR, Gekko_LinearRegression
# Initialize Gekko model

m = GEKKO(remote=False)  # 'remote=False' for local execution

price_vec_list = [1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 1, 1, 1] # Price vector

# Create a Gekko array of parameters
price_vec_gekko = m.Array(m.Param, len(price_vec_list))
for i, val in enumerate(price_vec_list):
    price_vec_gekko[i].value = val

coolLoad = m.Const(3) # Cooling load
Q_Spc = m.Const(5) # Storage size
n = len(price_vec_gekko)  # Directly use the length of the price vector

T_brine_in = m.Array(m.Param, n) # Brine inlet temperature
for i in range(n):
    T_brine_in[i].VALUE = 25

ST_V = m.Array(m.MV, n) # Compressor control variable
for i in range(n):
    ST_V[i].VALUE = 0.5
    ST_V[i].LOWER = 0.43  # Correct property for lower limit
    ST_V[i].UPPER = 1  # Correct property for upper limit
    ST_V[i].status = 1  # Allow the solver to optimize this variable

coolLoad_sum_min = np.cumsum(np.full(n, coolLoad)) 
coolLoad_sum_max = coolLoad_sum_min + Q_Spc # Cold water storage cap

costs = m.Var(value=0)  # Initialize cost variable as a Gekko variable`

# Modify the Gekko_LinearRegression class initialization to handle scalar intercepts and coefficients
class Gekko_LinearRegression_Modified(Gekko_LinearRegression):
    def __init__(self, model, m):
        self.m = m
        # Check if coef_ is an array and handle accordingly
        if hasattr(model.coef_, "__len__"):
            self.coef = model.coef_[0] if len(model.coef_) > 1 else model.coef_
        else:
            self.coef = model.coef_
        # Check if intercept_ is a scalar and handle accordingly
        self.intercept = model.intercept_ if np.isscalar(model.intercept_) else model.intercept_[0]


    
# Using the modified class for predictions directly in equations
for i in range(n):
    # Directly use the prediction in the equation, avoid intermediate if not necessary
    costs_increment = Gekko_LinearRegression_Modified(MLA_LR_P, m).predict([ST_V[i], T_brine_in[i]]) / 1000 * price_vec_gekko[i]
    Qo_constraint = Gekko_LinearRegression_Modified(MLA_LR_Q, m).predict([ST_V[i], T_brine_in[i]]) / 1000

    # Update costs based on predictions and prices
    m.Equation(costs == costs + costs_increment)

    # Constraints based on Qo_Gekko_Model, ensure these are properly defined as equations
    m.Equation(Qo_constraint < coolLoad_sum_max[i])
    m.Equation(Qo_constraint > coolLoad_sum_min[i])        

   
m.Minimize(costs)  # Minimize
m.options.SOLVER = 1  # APOPT Solver
m.options.IMODE = 1
# Solve model
m.solve(disp=True)

The error message is:

APMonitor, Version 1.0.0
APMonitor Optimization Suite


 @error: Intermediate Definition
 Error: Intermediate variable with no equality (=) expression
   (((p25)*(2487.122166666668))-766.6071363636368)]
 STOPPING...

Exception                                 Traceback (most recent call last)
Cell In[14], line 81
     79 m.options.IMODE = 1
     80 # Solve model
---> 81 m.solve(disp=True)
     83 # Output results
     84 print(f'Optimized ST_V: {ST_V.VALUE[0]}')

File ~\anaconda3\lib\site-packages\gekko\gekko.py:2140, in GEKKO.solve(self, disp, debug, GUI, **kwargs)
   2138         print("Error:", errs)
   2139     if (debug >= 1) and record_error:
-> 2140         raise Exception(apm_error)
   2142 else: #solve on APM server
   2143     def send_if_exists(extension):

Exception: @error: Intermediate Definition
 Error: Intermediate variable with no equality (=) expression
   (((p25)*(2487.122166666668))-766.6071363636368)]
 STOPPING...

If I don't use the class Gekko_LinearRegression_Modified, then I get this error

IndexError                                Traceback (most recent call last)
Cell In[15], line 64
     35 # Assuming MLA_LR_P and MLA_LR_Q are already defined and trained linear regression models
     36 #for i in range(n):
     37  #   Pel_Gekko_Model = Gekko_LinearRegression(MLA_LR_P, m).predict([ST_V[i], T_brine_in[i]])
   (...)
     60         
     61 # Using the modified class for predictions directly in equations
     62 for i in range(n):
     63     # Directly use the prediction in the equation, avoid intermediate if not necessary
---> 64     costs_increment = Gekko_LinearRegression(MLA_LR_P, m).predict([ST_V[i], T_brine_in[i]]) /     1000 * price_vec_gekko[i]
     65     Qo_constraint = Gekko_LinearRegression(MLA_LR_Q, m).predict([ST_V[i], T_brine_in[i]]) / 1000
     67     # Update costs based on predictions and prices

File ~\anaconda3\lib\site-packages\gekko\ML.py:838, in Gekko_LinearRegression.__init__(self, model, m)
    836 self.m = m
    837 self.coef = model.coef_[0]
--> 838 self.intercept = model.intercept_[0]

IndexError: invalid index to scalar variable.
1

There are 1 best solutions below

0
LaGrande Gunnell On

Sorry to hear that you are having trouble with the LinearRegression model. The original code was not robust enough, and will be updated soon. I have created a slim down and modified version of your code that runs (with a placeholder model) the model prediction. I fixed one line in your modified linear regression class; it was only saving one coefficient even if there were multiple.

from gekko import GEKKO
from gekko import ML
from gekko.ML import Gekko_GPR, Gekko_SVR, Gekko_LinearRegression
import numpy as np

class Gekko_LinearRegression_Modified(Gekko_LinearRegression):
    def __init__(self, model, m):
        self.m = m
        # Check if coef_ is an array and handle accordingly
        if hasattr(model.coef_, "__len__"):
            self.coef = model.coef_[0] if len(model.coef_) == 1 else model.coef_ ##changed to == 1 here
        else:
            self.coef = model.coef_
        # Check if intercept_ is a scalar and handle accordingly
        self.intercept = model.intercept_ if np.isscalar(model.intercept_) else model.intercept_[0]

#train a placeholder model
from sklearn.linear_model import LinearRegression

test_out = np.random.random(10)

test_in = np.random.random((10,2))

MLA_LR_P = LinearRegression().fit(test_in,test_out)
print(MLA_LR_P.predict(np.array([0.5,25]).reshape(1,-1)))

m = GEKKO(remote=False)

price_vec_list = [1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 1, 1, 1] # Price vector

# Create a Gekko array of parameters
price_vec_gekko = m.Array(m.Param, len(price_vec_list))
for i, val in enumerate(price_vec_list):
    price_vec_gekko[i].value = val

ST_V = m.Array(m.MV, n) # Compressor control variable
for i in range(n):
    ST_V[i].VALUE = 0.5
    ST_V[i].LOWER = 0.43  # Correct property for lower limit
    ST_V[i].UPPER = 1  # Correct property for upper limit
    ST_V[i].status = 1  # Allow the solver to optimize this variable

T_brine_in = m.Array(m.Param, n) # Brine inlet temperature
for i in range(n):
    T_brine_in[i].VALUE = 25

#Example prediction
pred = Gekko_LinearRegression_Modified(MLA_LR_P,m).predict(np.array([ST_V[i],T_brine_in[i]]))

#solve
a = m.Var() #dummy variable
m.solve(disp=False)
print(pred.value[0])