Search code examples
pythonoptimizationgekko

Obtaining NAN value for successfully solved optimization problem using GEKKO on Python


I am trying to solve an optimization problem using the GEKKO solver on Python, but keep obtaining an NAN objective value, even though the problem is successfully solved. There seems to be something I am missing, but I have not been able to identify what it is. I tried to make sure that nothing is being divided by zero, but as far as I can tell, that is not the case. The code I have is:

class FoodItem(): 
    def__init__(self,name,wastefactor,lossfactor,prioritylevel):
            self.name = name 
            self.wastefactor = wastefactor
            self.lossfactor = lossfactor 
            self.prioritylevel = prioritylevel 

wheatflour = FoodItem(name='WheatFlour',wastefactor= 0.15, lossfactor= 0.15, prioritylevel=1)

tomatoes = FoodItem(name='Tomatoes', wastefactor=0.15, lossfactor=0.15, prioritylevel=2)

oranges = FoodItem(name='Oranges', wastefactor=0.15, lossfactor=0.15, prioritylevel=2)

beans = FoodItem(name='Beans', wastefactor=0.15, lossfactor=0.15, prioritylevel=2)

beef = FoodItem(name='Beef',wastefactor=0.15, lossfactor=0.15, prioritylevel=1)

milk = FoodItem(name='Milk',wastefactor=0.15,lossfactor=0.15, prioritylevel=1)

fooditems = [wheatflour, tomatoes, oranges, beans, beef, milk]

m = GEKKO(remote=False)

foodvars = m.Array(m.Var,(len(fooditems),5))
fooditems_params = m.Array(m.Param,(len(fooditems),4))

def fillparametersFood(i,j):
    fooditems_params[j][0] = i.name
    fooditems_params[j][1] = i.wastefactor
    fooditems_params[j][2] = i.lossfactor
    fooditems_params[j][3] = i.prioritylevel
    return

j=0
for i in fooditems:
    fillparametersFood(i,j)
    j +=1

pop=1000
for i in range(len(foodvars)):    
    m.Equation(foodvars[i][0]+foodvars[i][1]-foodvars[i][2]==foodvars[i][3])
   
    m.Equation(foodvars[i][3]==(foodvars[i][4]*pop*365.25)/(10**6*(1-fooditems_params[i][1])*(1-fooditems_params[i][2])))


ssr_priority=0 

for i in range(len(foodvars)):
    ssr_priority += (foodvars[i][0]/(foodvars[i][0]+foodvars[i][1]-foodvars[i][2]))/fooditems_params[i][3]
    
m.Maximize(ssr_priority)

m.solve()

Any help to identify the problem would be highly appreciated. Many thanks.


Solution

  • The optimizer tries to maximize the objective function by making (foodvars[i][0]+foodvars[i][1]-foodvars[i][2]) approach zero. This gives an infinity objective function that results in the NaN result. Two suggestions:

    • Multiply both sides of equation 2 by (10**6*(1-fooditems_params[i][1])*(1-fooditems_params[i][2])) to remove the potential divide-by-zero.
    • Set bounds on foodvars to prevent divide-by-zero in the objective.
    from gekko import GEKKO
    m = GEKKO(remote=False)
    
    class FoodItem(): 
        def __init__(self,name,wastefactor,lossfactor,prioritylevel):
                self.name = name 
                self.wastefactor = wastefactor
                self.lossfactor = lossfactor 
                self.prioritylevel = prioritylevel 
    
    wheatflour = FoodItem(name='WheatFlour',wastefactor= 0.15, lossfactor= 0.15, prioritylevel=1)
    
    tomatoes = FoodItem(name='Tomatoes', wastefactor=0.15, lossfactor=0.15, prioritylevel=2)
    
    oranges = FoodItem(name='Oranges', wastefactor=0.15, lossfactor=0.15, prioritylevel=2)
    
    beans = FoodItem(name='Beans', wastefactor=0.15, lossfactor=0.15, prioritylevel=2)
    
    beef = FoodItem(name='Beef',wastefactor=0.15, lossfactor=0.15, prioritylevel=1)
    
    milk = FoodItem(name='Milk',wastefactor=0.15,lossfactor=0.15, prioritylevel=1)
    
    fooditems = [wheatflour, tomatoes, oranges, beans, beef, milk]
    
    m = GEKKO(remote=False)
    
    foodvars = m.Array(m.Var,(len(fooditems),5),lb=1,ub=100)
    fooditems_params = m.Array(m.Param,(len(fooditems),4))
    
    def fillparametersFood(i,j):
        fooditems_params[j][0] = i.name
        fooditems_params[j][1] = i.wastefactor
        fooditems_params[j][2] = i.lossfactor
        fooditems_params[j][3] = i.prioritylevel
        return
    
    j=0
    for i in fooditems:
        fillparametersFood(i,j)
        j +=1
    
    pop=1000
    for i in range(len(foodvars)):    
        m.Equation(foodvars[i][0]+foodvars[i][1]-foodvars[i][2]\
        ==foodvars[i][3])
       
        m.Equation((10**6*(1-fooditems_params[i][1])*(1-fooditems_params[i][2]))*foodvars[i][3]==(foodvars[i][4]*pop*365.25))
    
    
    ssr_priority=0 
    
    for i in range(len(foodvars)):
        ssr_priority += (foodvars[i][0]/(foodvars[i][0]+foodvars[i][1]-foodvars[i][2]))/fooditems_params[i][3]
        
    m.Maximize(ssr_priority)
    
    m.solve()
    

    This gives a successful solution with an objective of 450. Gekko converts a maximization problem to a minimization by multiplying by -1 so the objective looks like it is negative.

     ----------------------------------------------
     Steady State Optimization with APOPT Solver
     ----------------------------------------------
     
     Iter    Objective  Convergence
        0 -6.37500E+00  6.81400E-01
        1 -1.31250E+01  1.37806E-10
        2 -3.19432E+01  0.00000E+00
        3 -2.20125E+02  0.00000E+00
        4 -3.49596E+02  0.00000E+00
        5 -3.50465E+02  0.00000E+00
        6 -3.59156E+02  0.00000E+00
        7 -4.46063E+02  0.00000E+00
        8 -4.50000E+02  0.00000E+00
     
     Iter    Objective  Convergence
       10 -4.50000E+02  0.00000E+00
     Successful solution
     
     ---------------------------------------------------
     Solver         :  IPOPT (v3.12)
     Solution time  :   9.600000019418076E-003 sec
     Objective      :   -450.000000000000     
     Successful solution
     ---------------------------------------------------