python-3.xoptimizationgekko

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


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


Solution

  • 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]