GEKKO optimization exceeds equation bounds (and for some reason creates variables)

17 views Asked by At

I am trying to optimize the price reduction for items bought at a local market using weights to determine the price. I have quantities bought by each user, and a certain self-consumption parameter:

cons = {'user1' :np.array([1,2,3,4]),
   'user2' : np.array([5,6,7,8]),
   'user3' : np.array([0.8,1,5,9]),
   'user4' : np.array([16,8,7,1])}
auto = {
    'user1': 0.7,
    'user2' : 0.6,
    'user3' : 0.32,
    'user4': 0.44
}

m=GEKKO(remote=False)
m.options.IMODE = 2
m.options.SOLVER = 1
m.options.CV_TYPE = 2
m.options.RTOL=1e-4
m.options.OTOL=1e-4

delta_user = {} # Price reduction for the margin of local-market shared energ
ml_bought={} # quantity bought in the local market
benefit_user = {} # quantity bought in the local market * price (delta)
self_cons = {} # weight factor - self consumption

fondos = m.Const(value =30)

delta_basic = 30/sum(cons['user1'] +cons['user2']+cons['user3']+cons['user4'])
delta_min = delta_basic*0.75
delta_max = delta_basic*1.25

for user in cons:
    # min, max and start values are calculated with the mean price to obtain that reduction
    delta_user[user] = m.Var(lb = delta_min, ub = delta_max, value= delta_basic)

    self_cons[user] = m.Param(auto[user])

    ml_bought[user] = m.Param(cons[user])

    benefit_user[user] = m.Intermediate(np.sum(ml_bought[user]*delta_user[user]))

# # Function: Sum of all reduced prices for the energy market cannot be greater than the maximum money available for the market. 
m.Equation(m.sum([benefit_user[user] for user in cons]) <= fondos)


m.Maximize(m.sum([benefit_user[user]*(self_cons[user]**2) for user in cons]))
m.solve()

The problem is solved, but the quantity obtained in this equation is not smaller than 30 as it should be, but 35.7:

m.Equation(m.sum([benefit_user[user] for user in cons]) <= fondos)

37.5 is the value i get if I use all the maximum values for delta, but there is not enough money for that

Also, my intention is to have 1 delta per user:

delta_use['user1'] = 0.3 #for example

Instead, if I run the following code I get an array

delta_use['user1'] = [0.3, 0.3, 0.3, 0.3] # For example

Clearly something is wrong, I just can't figure out what

1

There are 1 answers

1
John Hedengren On BEST ANSWER

In IMODE=2, use the m.vsum() function to get a summation across the data dimension.

s = m.Var()
m.Equation(s == m.sum([benefit_user[user] for user in cons]))
m.Equation(m.vsum(s) <= fondos)

This enforces the correct constraint:

sum(s) = 30.0 <fondos 30

To get a single value instead of an array of decision variables, use delta_user[user] = m.FV() with delta_user[user].STATUS=1 instead of m.Var(). This calculates a single decision variable across the data dimension. It displays the multiple values with print(delta_user[user].value), but they are constrained to be the same value in the optimization problem.

Here is a modified and complete script:

from gekko import GEKKO
import numpy as np

cons = {'user1' :np.array([1,2,3,4]),
   'user2' : np.array([5,6,7,8]),
   'user3' : np.array([0.8,1,5,9]),
   'user4' : np.array([16,8,7,1])}
auto = {
    'user1': 0.7,
    'user2' : 0.6,
    'user3' : 0.32,
    'user4': 0.44
}

m=GEKKO(remote=False)
m.options.IMODE = 2
m.options.SOLVER = 1
m.options.CV_TYPE = 2
m.options.RTOL=1e-4
m.options.OTOL=1e-4

delta_user = {} # Price reduction for the margin of local-market shared energ
ml_bought={} # quantity bought in the local market
benefit_user = {} # quantity bought in the local market * price (delta)
self_cons = {} # weight factor - self consumption

fondos = m.Const(value =30)

delta_basic = 30/sum(cons['user1'] +cons['user2']+cons['user3']+cons['user4'])
delta_min = delta_basic*0.75
delta_max = delta_basic*1.25

for user in cons:
    # min, max and start values are calculated with the mean price to obtain that reduction
    delta_user[user] = m.FV(lb = delta_min, ub = delta_max, value= delta_basic)
    delta_user[user].STATUS = 1

    self_cons[user] = m.Param(auto[user])
    ml_bought[user] = m.Param(cons[user])
    benefit_user[user] = m.Intermediate(np.sum(ml_bought[user]*delta_user[user]))

# # Function: Sum of all reduced prices
s = m.Var()
m.Equation(s == m.sum([benefit_user[user] for user in cons]))
m.Equation(m.vsum(s) <= fondos)


m.Maximize(m.sum([benefit_user[user]*(self_cons[user]**2) for user in cons]))
m.solve()

print(f'sum(s) = {sum(s.value)} < fondos {fondos.value}')
for user in cons:
    print('-'*30)
    print(f'user: {user}')
    print(f'delta_user: {delta_user[user].value[0]}')
    print(f'self_cons: {self_cons[user].value}')
    print(f'ml_bought: {ml_bought[user].value}')
    print(f'benefit_user: {benefit_user[user].value}')

Here is the solver output:

 Number of state variables:    53
 Number of total equations: -  49
 Number of slack variables: -  4
 ---------------------------------------
 Degrees of freedom       :    0
 
 ----------------------------------------------
 Model Parameter Estimation with APOPT Solver
 ----------------------------------------------
 
 Iter    Objective  Convergence
    0 -5.92655E+00  3.00000E+01
    1 -8.68352E+00  1.87498E-11
    2 -8.68352E+00  1.11022E-16
    3 -8.68352E+00  1.11022E-16
 Successful solution
 
 ---------------------------------------------------
 Solver         :  APOPT (v1.0)
 Solution time  :  0.019999999999999997 sec
 Objective      :  -8.683517899761338
 Successful solution
 ---------------------------------------------------

and the printed results:

sum(s) = 30.0 < fondos 30
------------------------------
user: user1
delta_user: 0.44749403341
self_cons: [0.7, 0.7, 0.7, 0.7]
ml_bought: [1.0, 2.0, 3.0, 4.0]
benefit_user: [0.44749403341, 0.89498806683, 1.3424821002, 1.7899761337]
------------------------------
user: user2
delta_user: 0.44749403341
self_cons: [0.6, 0.6, 0.6, 0.6]
ml_bought: [5.0, 6.0, 7.0, 8.0]
benefit_user: [2.2374701671, 2.6849642005, 3.1324582339, 3.5799522673]
------------------------------
user: user3
delta_user: 0.26849642005
self_cons: [0.32, 0.32, 0.32, 0.32]
ml_bought: [0.8, 1.0, 5.0, 9.0]
benefit_user: [0.21479713604, 0.26849642005, 1.3424821002, 2.4164677804]
------------------------------
user: user4
delta_user: 0.30149910501
self_cons: [0.44, 0.44, 0.44, 0.44]
ml_bought: [16.0, 8.0, 7.0, 1.0]
benefit_user: [4.8239856802, 2.4119928401, 2.1104937351, 0.30149910501]