Getting started with the callable library¶
Knitro is written in C and C++, with a well-documented application
programming interface (API) defined in the file knitro.h
provided in the installation under the include directory.
The Knitro callable library is used to build a model in pieces while providing special structures to Knitro (e.g. linear structures, quadratic structures), while providing callbacks to handle general, nonlinear structures. A typical sequence of function calls looks as follows:
KN_new(): create a new Knitro solver context pointer, allocating resources.KN_add_vars()/KN_add_cons()/KN_set_*bnds(): add basic problem information to Knitro.KN_add_*_linear_struct()/KN_add_*_quadratic_struct(): add special problem structures.KN_add_eval_callback(): add callback for nonlinear evaluations if needed.KN_set_cb_*(): set properties for nonlinear evaluation callbacks.KN_set_*_param(): set user options/parameters.KN_solve(): solve the problem.KN_free(): delete the Knitro context pointer, releasing allocated resources.
The example below shows how to use these function calls.
First example¶
Again, let us consider the toy example that we already solved
twice, using AMPL and MATLAB. The C callable library equivalent is the
following (see exampleQCQP.c provided with the distribution
in examples/C/).
1#include <stdio.h>
2#include <stdlib.h>
3#include "knitro.h"
4
5/* main */
6int main (int argc, char *argv[]) {
7 int i, nStatus, error;
8
9 /** Declare variables. */
10 KN_context *kc;
11 int n, m;
12 double x[3];
13 double xLoBnds[3] = {0, 0, 0};
14 double xInitVals[3] = {2.0, 2.0, 2.0};
15 /** Used to define linear constraint. */
16 int lconIndexVars[3] = { 0, 1, 2};
17 double lconCoefs[3] = {8.0, 14.0, 7.0};
18 /** Used to specify quadratic constraint. */
19 int qconIndexVars1[3] = { 0, 1, 2};
20 int qconIndexVars2[3] = { 0, 1, 2};
21 double qconCoefs[3] = {1.0, 1.0, 1.0};
22 /** Used to specify quadratic objective terms. */
23 int qobjIndexVars1[5] = { 0, 1, 2, 0, 0};
24 int qobjIndexVars2[5] = { 0, 1, 2, 1, 2};
25 double qobjCoefs[5] = {-1.0, -2.0, -1.0, -1.0, -1.0};
26 /** Solution information */
27 double objSol;
28 double feasError, optError;
29
30 /** Create a new Knitro solver instance. */
31 error = KN_new(&kc);
32 if (error) exit(-1);
33 if (kc == NULL)
34 {
35 printf ("Failed to find a valid license.\n");
36 return( -1 );
37 }
38
39 /** Illustrate how to override default options by reading from
40 * the knitro.opt file. */
41 error = KN_load_param_file (kc, "knitro.opt");
42 if (error) exit(-1);
43
44 /** Initialize Knitro with the problem definition. */
45
46 /** Add the variables and set their bounds and initial values.
47 * Note: unset bounds assumed to be infinite. */
48 n = 3;
49 error = KN_add_vars(kc, n, NULL);
50 if (error) exit(-1);
51 error = KN_set_var_lobnds_all(kc, xLoBnds);
52 if (error) exit(-1);
53 error = KN_set_var_primal_init_values_all(kc, xInitVals);
54 if (error) exit(-1);
55
56 /** Add the constraints and set their bounds. */
57 m = 2;
58 error = KN_add_cons(kc, m, NULL);
59 if (error) exit(-1);
60 error = KN_set_con_eqbnd(kc, 0, 56.0);
61 if (error) exit(-1);
62 error = KN_set_con_lobnd(kc, 1, 25.0);
63 if (error) exit(-1);
64
65 /** Add coefficients for linear constraint. */
66 error = KN_add_con_linear_struct_one (kc, 3, 0, lconIndexVars,
67 lconCoefs);
68 if (error) exit(-1);
69
70 /** Add coefficients for quadratic constraint */
71 error = KN_add_con_quadratic_struct_one (kc, 3, 1, qconIndexVars1,
72 qconIndexVars2, qconCoefs);
73 if (error) exit(-1);
74
75 /** Set minimize or maximize (if not set, assumed minimize) */
76 error = KN_set_obj_goal(kc, KN_OBJGOAL_MINIMIZE);
77 if (error) exit(-1);
78
79 /** Add constant value to the objective. */
80 error= KN_add_obj_constant(kc, 1000.0);
81 if (error) exit(-1);
82
83 /** Set quadratic objective structure. */
84 error = KN_add_obj_quadratic_struct (kc, 5, qobjIndexVars1,
85 qobjIndexVars2, qobjCoefs);
86 if (error) exit(-1);
87
88 /** Solve the problem.
89 *
90 * Return status codes are defined in "knitro.h" and described
91 * in the Knitro manual. */
92 nStatus = KN_solve (kc);
93
94 printf ("\n\n");
95 printf ("Knitro converged with final status = %d\n",
96 nStatus);
97
98 /** An example of obtaining solution information. */
99 error = KN_get_solution(kc, &nStatus, &objSol, x, NULL);
100 if (!error) {
101 printf (" optimal objective value = %e\n", objSol);
102 printf (" optimal primal values x = (%e, %e, %e)\n", x[0], x[1], x[2]);
103 }
104 error = KN_get_abs_feas_error (kc, &feasError);
105 if (!error)
106 printf (" feasibility violation = %e\n", feasError);
107 error = KN_get_abs_opt_error (kc, &optError);
108 if (!error)
109 printf (" KKT optimality violation = %e\n", optError);
110
111 /** Delete the Knitro solver instance. */
112 KN_free (&kc);
113
114 return( 0 );
115}
Note that the AMPL equivalent is much shorter and simpler (only a few lines of code). In both the AMPL example and this example, the quadratic structure is passed directly to Knitro, so no callback evaluations are needed. However, when there is more general nonlinear structure AMPL will often be more efficient since it is able to provide Knitro the exact derivatives of all nonlinear functions automatically as needed. To achieve the same efficiency in C, we would have to compute the derivatives manually, code them in C and input them to Knitro using a callback. We will show how to do this in the chapter on Derivatives. However the callable library has the advantage of greater control (for instance, on memory usage) and allows one to embed Knitro in a native application seamlessly.
The above example can be compiled and linked against the Knitro callable library with a standard C compiler. Its output is the following.
1=======================================
2 Commercial License
3 Artelys Knitro 15.1.0
4=======================================
5
6Knitro presolve eliminated 0 variables and 0 constraints.
7
8feastol 1e-06
9feastol_abs 0.001
10opttol 1e-06
11opttol_abs 0.001
12
13Problem Characteristics | Presolved
14-----------------------
15Problem type: QCQP
16Objective: minimize / quadratic
17Number of variables: 3 | 3
18 bounds: lower upper range | lower upper range
19 3 0 0 | 3 0 0
20 free fixed | free fixed
21 0 0 | 0 0
22Number of constraints: 2 | 2
23 eq. ineq. range | eq. ineq. range
24 linear: 1 0 0 | 1 0 0
25 quadratic: 0 1 0 | 0 1 0
26Number of nonzeros:
27 objective Jacobian Hessian | objective Jacobian Hessian
28 linear: 0 3 | 0 3
29 quadratic: 3 3 5 | 3 3 5
30 total: 3 6 5 | 3 6 5
31Coefficient range:
32 linear objective: [0e+00, 0e+00] | [0e+00, 0e+00]
33 linear constraints: [7e+00, 1e+01] | [7e+00, 1e+01]
34 quadratic objective: [1e+00, 2e+00] | [1e+00, 2e+00]
35 quadratic constraints: [1e+00, 1e+00] | [1e+00, 1e+00]
36 variable bounds: [0e+00, 0e+00] | [0e+00, 0e+00]
37 constraint bounds: [2e+01, 6e+01] | [2e+01, 6e+01]
38
39Knitro using the Interior-Point/Barrier Direct algorithm.
40
41 Iter Objective FeasError OptError ||Step|| Time
42-------- -------------- --------- --------- --------- --------
43 0 9.760000e+02 1.30e+01
44 6 9.360000e+02 0.00e+00 3.15e-09 7.58e-05 0.00
45
46EXIT: Locally optimal solution found.
47
48Final Statistics
49----------------
50Final objective value = 9.36000000030700e+02
51Final feasibility error (abs / rel) = 0.00e+00 / 0.00e+00
52Final optimality error (abs / rel) = 3.15e-09 / 1.97e-10
53# of iterations = 6
54# of CG iterations = 5
55# of function evaluations = 0
56# of gradient evaluations = 0
57# of Hessian evaluations = 0
58Total program time (secs) = 0.00207 ( 0.001 CPU time)
59Time spent in evaluations (secs) = 0.00000
60
61===============================================================================
62
63
64Knitro converged with final status = 0
65 optimal objective value = 9.360000e+02
66 optimal primal values x = (1.840277e-09, 3.678426e-10, 8.000000e+00)
67 feasibility violation = 0.000000e+00
68 KKT optimality violation = 3.153268e-09
Again, the solution value is the same (about 936.0), and the details of the log are similar (we used a different algorithm in the AMPL example).
Further information¶
Another chapter of this documentation will be dedicated to the callable library (Callbacks), more specifically to the communication mode between the solver and the user-supplied optimization problem.
The reference manual (Callable library API reference) also contains a comprehensive documentation of the Knitro callable library API.
Finally, the file knitro.h contains many useful comments
and can be used as an ultimate reference.
Additional examples¶
More C/C++ examples using the callable library are provided in
the examples/C and examples/C++ directories of the Knitro
distribution.