I'm solving an integer nonlinear programming problem with python gekko, where there're 1446 integer variable, 31 constraints of the linear combinations of there variables, and 1 nonlinear objective to maximize.
The program takes a long time and I'm wondering if it can speed up, as well as how to tune a better m.solver_options.
Here're the codes.(I only leave some comments about the variables because their computation relies on some outer data files.)
m = GEKKO()
m.options.SOLVER = 1 # APOPT is an MINLP solver
# optional solver settings with APOPT
m.solver_options = ['minlp_maximum_iterations 500',
'minlp_as_nlp 0',
'minlp_branch_method 1',
'minlp_integer_tol 0',
'nlp_maximum_iterations 50',
]
# Constraint: sum of all weights <= 1
# e.g. weights = [0.04 * int_v1, 0.05 * int_v2, ..., 0.03 * int_v1446]
m.Equation(m.sum(weights) <= 1)
# Constraint: sum of weights on each cluster has an upper bound
# e.g. weights_per_cluster = {'1': [int_v2, int_v5, int_v8], '2': [int_v1, int_v4, int_v6], ..., '30': [int_v9, int_v12]}
for cluster in clusters:
m.Equation(m.sum(weights_per_cluster[cluster]) <= 0.1)
mu_sig_raw = np.array(mu_sig_raw).transpose() # real value, shape (106, 1446)
mu = np.mean(mu_sig_raw, axis=0) # real value, shape (1446, 1)
sigma = np.cov(np.transpose(mu_sig_raw)) # real value, shape (1446, 1446)
k = len(mu)
# Objective: profit-rate mean-variance model
m.Maximize(
(m.sum([mu[i] * weights[i] for i in range(k)]) - 0.03)
/
m.sqrt(m.sum([
m.sum([sigma[i, j] * weights[i] * weights[j] for j in range(k)])
for i in range(k)
]))
)
m.solve(disp=True)
The APOPT solver can be slow with many degrees of freedom (# Variables >> # Equations) or many integer variables. One strategy is to initialize with the IPOPT solver and then switch to APOPT for an integer solution.
m.options.SOLVER=3 # IPOPT
m.solve()
m.options.SOLVER=1 # APOPT
m.solve()
Another thing that can help is to redefine the inequalities as variables and set an upper bound on that variable.
for cluster in clusters:
m.Equation(m.sum(weights_per_cluster[cluster]) <= 0.1)
Transform to:
v = []
for cluster in clusters:
v.append(m.Var(ub=0.1))
m.Equation(m.sum(weights_per_cluster[cluster]) == v[-1])
You may also want to further adjust the solver options. The APOPT solver has a number of options that are available for tuning the solver performance. Some of the available options and default values are listed below:
If an integer solution is found, the minlp_gap_tol may help improve the solution time if the integer solution has a small enough gap. Because the complete script is not posted, we can't test any proposed improvements. Please consider posting a complete script for future questions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With