Search code examples
pythonfor-loopconstraintslinear-programminggekko

How to make constriants in gekko by for loop?


By tips in a related question for using dictionaries as source input to gekko, I did as below;

import pandas as pd
from gekko import GEKKO
my_vars = ['x1','x2','x3']

# stored as dictionaries

Cost = {'x1':100,'x2':125,'x3':80}
Min = {'x1':0,'x2':0,'x3':0}
Max = {'x1':70,'x2':40,'x3':15}

LP = GEKKO(remote=False)
va = LP.Array(LP.Var, (len(my_vars)))  # array
vd = {}                                # dictionary
for i,xi in enumerate(my_vars):
    vd[xi] = va[i]
    vd[xi].lower = Min[xi]
    vd[xi].upper = Max[xi]

# Cost function
LP.Minimize(LP.sum([Cost[xi]*vd[xi] for xi in my_vars])) 

# This also works as a dictionary
LP.Equation(LP.sum([vd[xi] for xi in my_vars])==100)

LP.solve(disp=True)

for xi in my_vars:
    print(xi,vd[xi].value[0])
print ('Cost: ' + str(LP.options.OBJFCNVAL))

This was successful.

But suppose I have variables coefficients as LHS and the criteria data as RHS, in data frame format,

for example;

Coef = [['x1', 33, 8.8, 0.2, 0.1], ['x2', 24, 4.5, 2, 0.5], ['x3', 82, '', '', '']]
LHS = pd.DataFrame(Coef, columns=['Name', 'p1', 'p2', 'p3', 'p4'])
LHS.set_index('Name')
and
goals = [['p1', 30], ['p2', 5], ['p3', 0.7], ['p4', 0.2]]
RHS = pd.DataFrame(goals, columns=['property', 'goal'])

I want to construct constraints dynamically using LHS and RHS data in for loop. I did as below,

for i in range(len(RHS)):
    LP.Equation(LP.sum([LHS.iloc[list(my_vars).index(xi), i]*vd[xi] for xi in my_vars]) >= RHS.iloc[i,1])

but there were errors.


APMonitor, Version 0.9.2
APMonitor Optimization Suite


 --------- APM Model Size ------------  

Each time step contains
Objects : 6
Constants : 0
Variables : 28
Intermediates: 0
Connections : 24
Equations : 22
Residuals : 22
@error: Model Expression *** Error in syntax of function string: Invalid element: x1

Position: 7 v9-(((x1)*(v1))) ?

Traceback (most recent call last):

File "", line 1, in LP.solve(disp=True)

File "/opt/anaconda3/envs/py37/lib/python3.7/site-packages/gekko/gekko.py", line 2130, in solve raise Exception(apm_error)

Exception: @error: Model Expression *** Error in syntax of function string: Invalid element: x1

Position: 7 v9-(((x1)*(v1))) ?

What is wrong with my code?


Solution

  • There were a couple things that you needed to do to prepare your Pandas dataframe correctly. Here is a script that puts everything together and gives a successful solution.

    import pandas as pd
    from gekko import GEKKO
    my_vars = ['x1','x2','x3']
    
    # stored as dictionaries
    Cost = {'x1':100,'x2':125,'x3':80}
    Min = {'x1':0,'x2':0,'x3':0}
    Max = {'x1':70,'x2':40,'x3':15}
    
    Coef = [['x1', 33, 8.8, 0.2, 0.1],\
            ['x2', 24, 4.5, 2.0, 0.5],\
            ['x3', 82, 0.0, 0.0, 0.0]]
    LHS = pd.DataFrame(Coef,\
                       columns=['Name','p1','p2','p3','p4'])
    LHS = LHS.set_index('Name')
    print(LHS.head())
    
    goals = [['p1', 30], ['p2', 5], ['p3', 0.7], ['p4', 0.2]]
    RHS = pd.DataFrame(goals, columns=['property', 'goal'])
    RHS = RHS.set_index('property')
    print(RHS.head())
    
    LP = GEKKO(remote=False)
    va = LP.Array(LP.Var, (len(my_vars)))  # array
    vd = {}                                # dictionary
    for i,xi in enumerate(my_vars):
        vd[xi] = va[i]
        vd[xi].lower = Min[xi]
        vd[xi].upper = Max[xi]
    
    for yi in LHS.columns.values:
        LP.Equation(LP.sum([LHS[yi][xi]*vd[xi] for xi in my_vars]) \
                    >= RHS['goal'][yi])
    
    # Cost function
    LP.Minimize(LP.sum([Cost[xi]*vd[xi] for xi in my_vars])) 
    
    LP.solve(disp=False)
    
    print('\n---Solution---')
    for xi in my_vars:
        print(xi,vd[xi].value[0])
    print ('Total Cost: ' + str(LP.options.OBJFCNVAL))
    

    The Pandas dataframes show the constants.

          p1   p2   p3   p4
    Name                   
    x1    33  8.8  0.2  0.1
    x2    24  4.5  2.0  0.5
    x3    82  0.0  0.0  0.0
              goal
    property      
    p1        30.0
    p2         5.0
    p3         0.7
    p4         0.2
    

    The solution to the problem is below:

    ---Solution---
    x1 0.40506330168
    x2 0.31898731988
    x3 0.10947823632
    Total Cost: 89.138004059
    

    This is okay for small to moderate sized problems. However, if you have a large-scale Linear Programming (LP) problem then you may want to consider some of the more efficient methods in Gekko for solving LP problems. Instead of building the equations yourself:

    for yi in LHS.columns.values:
        LP.Equation(LP.sum([LHS[yi][xi]*vd[xi] for xi in my_vars]) \
                    >= RHS['goal'][yi])
    

    you can let Gekko do it for you with the axb function (see example linear programming problems).

    A = np.array(LHS.values).T
    b = np.array(RHS.values)
    LP.axb(A,b,x=va,etype='>=',sparse=False)
    

    Gekko can exploit sparsity in the A and b constant matrices to deliver an efficient solution for 100,000+ variables. Gekko uses nonlinear programming (NLP) solvers to find a solution to LP problems so that may also limit the speed of solution, especially if you have 1M+ variables.