# 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | ```
#include <stdio.h>
#include <stdlib.h>
#include "knitro.h"
/* main */
int main (int argc, char *argv[]) {
int i, nStatus, error;
/** Declare variables. */
KN_context *kc;
int n, m;
double x[3];
double xLoBnds[3] = {0, 0, 0};
double xInitVals[3] = {2.0, 2.0, 2.0};
/** Used to define linear constraint. */
int lconIndexVars[3] = { 0, 1, 2};
double lconCoefs[3] = {8.0, 14.0, 7.0};
/** Used to specify quadratic constraint. */
int qconIndexVars1[3] = { 0, 1, 2};
int qconIndexVars2[3] = { 0, 1, 2};
double qconCoefs[3] = {1.0, 1.0, 1.0};
/** Used to specify quadratic objective terms. */
int qobjIndexVars1[5] = { 0, 1, 2, 0, 0};
int qobjIndexVars2[5] = { 0, 1, 2, 1, 2};
double qobjCoefs[5] = {-1.0, -2.0, -1.0, -1.0, -1.0};
/** Solution information */
double objSol;
double feasError, optError;
/** Create a new Knitro solver instance. */
error = KN_new(&kc);
if (error) exit(-1);
if (kc == NULL)
{
printf ("Failed to find a valid license.\n");
return( -1 );
}
/** Illustrate how to override default options by reading from
* the knitro.opt file. */
error = KN_load_param_file (kc, "knitro.opt");
if (error) exit(-1);
/** Initialize Knitro with the problem definition. */
/** Add the variables and set their bounds and initial values.
* Note: unset bounds assumed to be infinite. */
n = 3;
error = KN_add_vars(kc, n, NULL);
if (error) exit(-1);
error = KN_set_var_lobnds_all(kc, xLoBnds);
if (error) exit(-1);
error = KN_set_var_primal_init_values_all(kc, xInitVals);
if (error) exit(-1);
/** Add the constraints and set their bounds. */
m = 2;
error = KN_add_cons(kc, m, NULL);
if (error) exit(-1);
error = KN_set_con_eqbnd(kc, 0, 56.0);
if (error) exit(-1);
error = KN_set_con_lobnd(kc, 1, 25.0);
if (error) exit(-1);
/** Add coefficients for linear constraint. */
error = KN_add_con_linear_struct_one (kc, 3, 0, lconIndexVars,
lconCoefs);
if (error) exit(-1);
/** Add coefficients for quadratic constraint */
error = KN_add_con_quadratic_struct_one (kc, 3, 1, qconIndexVars1,
qconIndexVars2, qconCoefs);
if (error) exit(-1);
/** Set minimize or maximize (if not set, assumed minimize) */
error = KN_set_obj_goal(kc, KN_OBJGOAL_MINIMIZE);
if (error) exit(-1);
/** Add constant value to the objective. */
error= KN_add_obj_constant(kc, 1000.0);
if (error) exit(-1);
/** Set quadratic objective structure. */
error = KN_add_obj_quadratic_struct (kc, 5, qobjIndexVars1,
qobjIndexVars2, qobjCoefs);
if (error) exit(-1);
/** Solve the problem.
*
* Return status codes are defined in "knitro.h" and described
* in the Knitro manual. */
nStatus = KN_solve (kc);
printf ("\n\n");
printf ("Knitro converged with final status = %d\n",
nStatus);
/** An example of obtaining solution information. */
error = KN_get_solution(kc, &nStatus, &objSol, x, NULL);
if (!error) {
printf (" optimal objective value = %e\n", objSol);
printf (" optimal primal values x = (%e, %e, %e)\n", x[0], x[1], x[2]);
}
error = KN_get_abs_feas_error (kc, &feasError);
if (!error)
printf (" feasibility violation = %e\n", feasError);
error = KN_get_abs_opt_error (kc, &optError);
if (!error)
printf (" KKT optimality violation = %e\n", optError);
/** Delete the Knitro solver instance. */
KN_free (&kc);
return( 0 );
}
``` |

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 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | ```
=======================================
Commercial License
Artelys Knitro 12.2.0
=======================================
Knitro presolve eliminated 0 variables and 0 constraints.
The problem is identified as a QCQP.
Knitro changing algorithm from AUTO to 1.
Knitro changing bar_initpt from AUTO to 3.
Knitro changing bar_murule from AUTO to 4.
Knitro changing bar_penaltycons from AUTO to 1.
Knitro changing bar_penaltyrule from AUTO to 2.
Knitro changing bar_switchrule from AUTO to 2.
Knitro changing linesearch from AUTO to 1.
Knitro changing linsolver from AUTO to 2.
Problem Characteristics ( Presolved)
-----------------------
Objective goal: Minimize
Objective type: quadratic
Number of variables: 3 ( 3)
bounded below only: 3 ( 3)
bounded above only: 0 ( 0)
bounded below and above: 0 ( 0)
fixed: 0 ( 0)
free: 0 ( 0)
Number of constraints: 2 ( 2)
linear equalities: 1 ( 1)
quadratic equalities: 0 ( 0)
gen. nonlinear equalities: 0 ( 0)
linear one-sided inequalities: 0 ( 0)
quadratic one-sided inequalities: 1 ( 1)
gen. nonlinear one-sided inequalities: 0 ( 0)
linear two-sided inequalities: 0 ( 0)
quadratic two-sided inequalities: 0 ( 0)
gen. nonlinear two-sided inequalities: 0 ( 0)
Number of nonzeros in Jacobian: 6 ( 6)
Number of nonzeros in Hessian: 5 ( 5)
Iter Objective FeasError OptError ||Step|| CGits
-------- -------------- ---------- ---------- ---------- -------
0 9.760000e+02 1.300e+01
9 9.360000e+02 0.000e+00 1.515e-09 5.910e-05 0
EXIT: Locally optimal solution found.
Final Statistics
----------------
Final objective value = 9.36000000015579e+02
Final feasibility error (abs / rel) = 0.00e+00 / 0.00e+00
Final optimality error (abs / rel) = 1.51e-09 / 9.47e-11
# of iterations = 9
# of CG iterations = 2
# of function evaluations = 0
# of gradient evaluations = 0
# of Hessian evaluations = 0
Total program time (secs) = 0.00207 ( 0.001 CPU time)
Time spent in evaluations (secs) = 0.00000
===============================================================================
Knitro converged with final status = 0
optimal objective value = 9.360000e+02
optimal primal values x = (1.514577e-09, 1.484137e-14, 8.000000e+00)
feasibility violation = 0.000000e+00
KKT optimality violation = 1.514577e-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.