Reputation: 23
I have a problem where it is wanted to maximize an objective function which is a ratio.
Obj: sum(Ax)/Bx
For matrices A
and B
(of random zeros and ones) that have the same dimension. The problem is unconstrained. So basically I want to find an x
of zeros and ones that maximizes the given ratio.
Here is a minimum reproducible example of my problem (item 2 below):
import numpy as np
import pandas as pd
from gekko import GEKKO
# Number of columns and rows for the given matrices
C = 43
R = 20
# Name columns since I will need to work with dataframes
names = ['n'+str(i) for i in range(C)]
names2 = ['d'+str(i) for i in range(C)]
# Toy example of random distribution of zeros and ones
num = np.random.randint(2, size=(R, C))
den = np.random.randint(2, size=(R, C))
df_num = pd.DataFrame(columns=names, data=num)
df_den = pd.DataFrame(columns=names2, data=den)
# Start Gekko model
m = GEKKO(remote=False)
x = m.Array(m.Var,(df_num.shape[1]),lb=0,ub=1,integer=True)
for i in x:
i.value = np.random.randint(2, size=1)[0]
m.solver_options = ['minlp_as_nlp 1']
ival1 = m.Intermediate(df_num.mul(x).sum(1).sum())
ival2 = m.Intermediate(df_den.mul(x).sum(1).sum())
m.Obj(-np.divide(ival1, ival2))
m.options.SOLVER = 1 # APOPT solver
m.solve(disp=True)
I tried following the instructions given here and here and some other places, so I used the minlp_as_nlp 1
option to relax the integer restriction and also used intermediate variables to see if it helps, however, I cannot get the model to work.
Basically, the following 2 issues happen:
1. No solution is found (x is all zeros)
That's when I have a very small problem (like the one above, but with 42 columns or less, however, my actual problem ranges from 10k x 5e2 to 7e6 x 5e2). I would expect x
to have the final values found, but it is all zeros. This is what APM prints out:
----------------------------------------------------------------
APMonitor, Version 0.9.2
APMonitor Optimization Suite
----------------------------------------------------------------
--------- APM Model Size ------------
Each time step contains
Objects : 0
Constants : 0
Variables : 42
Intermediates: 2
Connections : 0
Equations : 3
Residuals : 1
Number of state variables: 42
Number of total equations: - 0
Number of slack variables: - 0
---------------------------------------
Degrees of freedom : 42
----------------------------------------------
Steady State Optimization with APOPT Solver
----------------------------------------------
Iter: 1 I: 0 Tm: 0.04 NLPi: 18 Dpth: 0 Lvs: 0 Obj: -2.17E+00 Gap: 0.00E+00
Successful solution
---------------------------------------------------
Solver : APOPT (v1.0)
Solution time : 4.780000000027940E-002 sec
Objective : -2.16666666666667
Successful solution
---------------------------------------------------
2. Runtime error
When I increase the number of columns to 43 (as above or more), I get the following error (edited to fit space):
----------------------------------------------------------------
APMonitor, Version 0.9.2
APMonitor Optimization Suite
----------------------------------------------------------------
@error: Max Equation Length
Error with line number: 48
i28=(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((0)*(int_v1))
+((0)*(int_v2)))+((0)*(int_v3)))+((1)*(int_v4)))+((1)*(int_v5)))+((1)*(int_v6))
)+((0)*(int_v7)))+((1)*(int_v8)))+((0)*(int_v9)))+((1)*(int_v10)))+((0)*(int_v1
.
.
.
_v31)))+((0)*(int_v32)))+((0)*(int_v33)))+((1)*(int_v34)))+((1)*(int_v35)))+((1
)*(int_v36)))+((1)*(int_v37)))+((0)*(int_v38)))+((0)*(int_v39)))+((0)*(int_v40)
))+((0)*(int_v41)))+((0)*(int_v42)))+((1)*(int_v43))))
APM model error: string > 15000 characters
Consider breaking up the line into multiple equations
The may also be due to only using newline character CR
instead of CR LF (for Windows) or LF (for MacOS/Linux)
To fix this problem, save APM file with appropriate newline characters
STOPPING...
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
<ipython-input-50-5885f6e9b4ca> in <module>
6 m.Obj(-np.divide(ival1, ival2))
7 m.options.SOLVER = 1
----> 8 m.solve(disp=True)
/anaconda_env/personal/rafaeldasilv/py3/lib/python3.7/site-packages/gekko/gekko.py in solve(self, disp, debug, GUI, **kwargs)
2128 print("Error:", errs)
2129 if (debug >= 1) and record_error:
-> 2130 raise Exception(apm_error)
2131
2132 else: #solve on APM server
Exception: @error: Max Equation Length
Error with line number: 48
i28=(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((0)*(int_v1))
+((0)*(int_v2)))+((0)*(int_v3)))+((1)*(int_v4)))+((1)*(int_v5)))+((1)*(int_v6))
)+((0)*(int_v7)))+((1)*(int_v8)))+((0)*(int_v9)))+((1)*(int_v10)))+((0)*(int_v1
1)))+((1)*(int_v12)))+((1)*(int_v13)))+((0)*(int_v14)))+((1)*(int_v15)))+((1)*(
.
.
.
)+((1)*(int_v27)))+((0)*(int_v28)))+((1)*(int_v29)))+((0)*(int_v30)))+((0)*(int
_v31)))+((0)*(int_v32)))+((0)*(int_v33)))+((1)*(int_v34)))+((1)*(int_v35)))+((1
)*(int_v36)))+((1)*(int_v37)))+((0)*(int_v38)))+((0)*(int_v39)))+((0)*(int_v40)
))+((0)*(int_v41)))+((0)*(int_v42)))+((1)*(int_v43))))
APM model error: string > `15000` characters
Consider breaking up the line into multiple equations
The may also be due to only using newline character CR
instead of CR LF (for Windows) or LF (for MacOS/Linux)
To fix this problem, save APM file with appropriate newline characters
STOPPING...
Would anyone have any guess of what I could be missing here or even if this is the right approach? Thank you!
EDIT: Solution after running suggested code change (R=400, C=76):
----------------------------------------------------------------
APMonitor, Version 0.9.2
APMonitor Optimization Suite
----------------------------------------------------------------
--------- APM Model Size ------------
Each time step contains
Objects : 802
Constants : 0
Variables : 61678
Intermediates: 0
Connections : 62402
Equations : 60801
Residuals : 60801
Number of state variables: 61678
Number of total equations: - 61602
Number of slack variables: - 0
---------------------------------------
Degrees of freedom : 76
----------------------------------------------
Steady State Optimization with APOPT Solver
----------------------------------------------
Iter: 1 I: 0 Tm: 1.60 NLPi: 3 Dpth: 0 Lvs: 3 Obj: -1.00E+00 Gap: NaN
--Integer Solution: 0.00E+00 Lowest Leaf: -1.00E+00 Gap: 1.00E+00
Iter: 2 I: 0 Tm: 0.44 NLPi: 2 Dpth: 1 Lvs: 2 Obj: 0.00E+00 Gap: 1.00E+00
Iter: 3 I: 0 Tm: 1.37 NLPi: 2 Dpth: 1 Lvs: 4 Obj: -1.00E+00 Gap: 1.00E+00
--Integer Solution: -1.00E+00 Lowest Leaf: -1.00E+00 Gap: 2.82E-06
Iter: 4 I: 0 Tm: 0.45 NLPi: 2 Dpth: 2 Lvs: 4 Obj: -1.00E+00 Gap: 2.82E-06
Successful solution
---------------------------------------------------
Solver : APOPT (v1.0)
Solution time : 4.02930000000015 sec
Objective : -0.999995215333898
Successful solution
---------------------------------------------------
Runtime: 1568.80s
Upvotes: 2
Views: 367
Reputation: 14376
Try using the Gekko summation to avoid a long symbolic expression.
m.Maximize(m.sum(Ax)/m.sum(Bx))
No solution is found because the denominator goes to zero, creating an objective of infinity. This can be avoided by adding a small constant to the denominator such as:
m.Maximize(m.sum(Ax)/(m.sum(Bx)+1e-3))
The current version without m.sum()
produces an objective function expression that is over 15,000 characters long.
I also switched to A@x
and B@x
to simplify the matrix multiplication expressions but your original Pandas expressions also work.
import numpy as np
import pandas as pd
from gekko import GEKKO
# Number of columns and rows for the given matrices
C = 43
R = 20
# Name columns since I will need to work with dataframes
names = ['n'+str(i) for i in range(C)]
names2 = ['d'+str(i) for i in range(C)]
# Toy example of random distribution of zeros and ones
A = np.random.randint(2, size=(R, C))
B = np.random.randint(2, size=(R, C))
# Start Gekko model
m = GEKKO(remote=False)
x = m.Array(m.Var,C,lb=0,ub=1,integer=True)
for i in x:
i.value = np.random.randint(2, size=1)[0]
m.solver_options = ['minlp_as_nlp 1']
# Calculate Ax and Bx
Ax = A@x
Bx = B@x
# Maximize ratio
m.Maximize(m.sum(Ax)/(m.sum(Bx)+1e-3))
# Solve
m.options.SOLVER = 1 # APOPT solver
m.solve(disp=True)
Solution:
Iter Objective Convergence
30 -2.19956E+00 1.30104E-18
31 -2.19956E+00 6.93889E-18
32 -2.19956E+00 6.93889E-18
Successful solution
---------------------------------------------------
Solver : APOPT (v1.0)
Solution time : 0.13 sec
Objective : -2.1995600879824035
Successful solution
---------------------------------------------------
Edit: Alternative Matrix Multiplication
Use Gekko summations for the matrix multiplication if there are much larger matrices.
# Calculate Ax and Bx
#Ax = A@x
#Bx = B@x
Ax = [m.sum([A[i,j]*x[j] for j in range(C)]) for i in range(R)]
Bx = [m.sum([A[i,j]*x[j] for j in range(C)]) for i in range(R)]
This solves successfully with C=43
and R=20
but would also be applicable to much larger matrices.
Upvotes: 0