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.