Concurrent Solver
Nonlinear optimization problems are varied and complex and it is difficult to choose one set of tuning options that works well for all instances. Often there are changes to the default settings – either different algorithms or different tunings for the default algorithm – that may produce significantly improved peformance. For this reason, Knitro offers a concurrent solver feature that allows the user to run several Knitro solves in parallel using different algorithms or different tunings for a specific algorithm. Using the concurrent solver in Knitro can significantly improve the overall robustness of the solver, while also often solving faster, provided the problem is not too large or memory intensive.
Currently the concurrent solver in Knitro is only available for use with continuous optimization problems and is enabled by setting concurrent_solver = 1.
Note
Although not currently set as a default solver option, we highly recommend trying the concurrent solver in Knitro – particularly in cases where Knitro seems to struggle using the default settings and the problem is not too big.
Concurrent solver options
Below is a summary of the options currently available for the concurrent solver.
Option |
Meaning |
|---|---|
Specify multiple LP algorithms to run concurrently |
|
Maximum number of concurrent solves |
|
Specify multiple NLP algorithms to run concurrently |
|
Specify logging options for the concurrent solver |
|
Enable the concurrent solver |
|
Enforce concurrent solver to run deterministically |
The concurrent solver allows the user to specify running Knitro with different algorithms concurrently using the options concurrent_lpalg for linear programs and concurrent_nlpalg for nonlinear problems (as well as QPs and QCQPs). These options are bitset options, and have different values from the options nlp_algorithm and lp_algorithm used in single solve scenarios. This means each algorithm has a bit number (power of 2) and that multiple algorithms are specified by summing the bit numbers for each desired algorithm (i.e. using bitwise-and). For example, setting concurrent_nlpalg = 9 will cause Knitro to run the Interior/Direct and SQP algorithms concurrently since the values for these algorithms are 1 and 8 respectively in concurrent_nlpalg.
By default, or if just one algorithm is specified, then the Knitro concurrent solver will run just one algorithm with multiple tunings concurrently. Currently the different tunings in this case are chosen automatically by Knitro and are not customizable. In the future the concurrent solver may allow for more user customization.
By default, the Knitro concurrent solver will run non-deterministically and terminate at the first solve to find a solution. However, the concurrent solver can be forced to run in a deterministic mode by setting the user option deterministic = 1. Though guaranteed to produce the same solution every time (when run on the same machine) in deterministic mode, the solution process will be slower as it adds additional overhead. Use of the deterministic mode is primarily recommended only when running the same algorithm with multiple tunings concurrently as the overhead may be more significant when running different algorithms concurrently. In some cases, when running different algorithms concurrently, determinism is not allowed currently.
Note
The deterministic setting is not currently available when running different LP algorithms concurrently, or when running both the barrier/interior-point algorithms and the active-set/SQP algorithms concurrently when solving an NLP.
The option concurrent_maxsolves specifies an upper limit on the number of concurrent solves, while the concurrent_outlog option can be used to control the output/logging of the concurrent solver.
AMPL example
Let us consider again our AMPL example from Section Getting started with AMPL and run it with a different set of options:
1ampl: reset;
2ampl: option solver knitroampl;
3ampl: option knitro_options "concurrent_solver=1 concurrent_maxsolves=3 deterministic=1";
4ampl: model testproblem.mod;
5ampl: solve;
Since we did not specify any algorithms, Knitro runs the default barrier/interior-point algorithm with three different tunings concurrently. Since we specified deterministic = 1, Knitro will produce deterministic results in this case.
The Knitro log shows:
Knitro running 3 deterministic concurrent solves with 8 threads.
Solve 1 Solve 2 Solve 3
Barrier-Direct Barrier-Direct Barrier-Direct
Objective FeasErr Objective FeasErr Objective FeasErr Time
--------- ------- --------- ------- --------- ------- ----
9.7600e+02 1.3e+01 | 9.7600e+02 1.3e+01 | 9.7600e+02 1.3e+01
9.3600e+02 0.0e+00 | 9.3600e+02 0.0e+00 | 9.3600e+02 0.0e+00 0.01
optimal interrupted optimal
Solution returned for Solve 1
bar_murule 4
EXIT: Locally optimal solution found.
Final Statistics
----------------
Final objective value = 9.36000000030700e+02
Final feasibility error (abs / rel) = 0.00e+00 / 0.00e+00
Final optimality error (abs / rel) = 3.15e-09 / 1.97e-10
# of iterations = 6
# of CG iterations = 5
# of function evaluations = 0
# of gradient evaluations = 0
# of Hessian evaluations = 0
Total program time (secs) = 0.00687 ( 0.048 CPU time)
================================================================================
The output indicates that the final solution is returned from the first solve, which uses the tuning bar_murule = 4.
MATLAB example
In order to run the concurrent solver in MATLAB, we could pass the relevant settings using the options structure returned from a call to the knitro_options function:
options = knitro_options('concurrent_solver', 1, ...
'concurrent_maxsolves', 3, ...
'deterministic', 1);
Then let us run our MATLAB example from Section MATLAB example again, where the call to knitro_nlp has been replaced with:
knitro_nlp(@obj, x0, A, b, Aeq, beq, lb, ub, @nlcon, [], options);
The Knitro log looks similar to what we observed with AMPL. Alternatively, the options could be passed using a Knitro options file.
C example
The C example can also be easily modified to enable
the concurrent solver by adding the following lines before the
call to KN_solve():
// concurrent solver
if (KN_set_int_param_by_name (kc, "concurrent_solver", 1) != 0)
exit( -1 );
if (KN_set_int_param_by_name (kc, "concurrent_maxsolves", 3) != 0)
exit( -1 );
if (KN_set_int_param_by_name (kc, "deterministic", 1) != 0)
exit( -1 );
Again, running this example we get a Knitro log that looks similar to what we observed with AMPL.
Object-oriented example
The object-oriented example can be modified to enable
the concurrent solver by adding the following lines before the
call to solver.solve():
// multistart
solver.setParam("concurrent_solver", 1);
solver.setParam("concurrent_maxsolves", 3);
solver.setParam("deterministic", 1);
Again, running this example we get a Knitro log that looks similar to the trace obtained with AMPL.