Objectoriented interface reference
What is the objectoriented interface?
The objectoriented interface provides the functionality of the callable library with an easytouse set of classes. The interface is available in C++, C#, and Java. The problem definition is contained in a class definition and is simpler: variable and constraint properties can be defined more compactly; memory for the problem characteristics does not need to be allocated; and Knitro API functions are simplified with some of the arguments handled internally within the classes.
This guide focuses on the C++ version of the interface.
Simple examples of the objectoriented interface can be found in User guide. More complex examples can be found in the examples folder.
Getting started with the Java objectoriented interface
Java interfaces are distributed as a JAR with additional packages containing Javadoc, sources and dependencies.
Java interfaces require using Java 8 or higher and BridJ, a Java native interoperability library, which is also provided.
Import JAR files and dependencies within your project in order to enable using Knitro with Java interfaces.
Examples can be compiled and run from your favorite IDE or using the provided makefile.
Getting started with the C# objectoriented interface
C# interface requires .net 4.0 or higher.
A project is distributed as a Microsoft Visual Studio solution with all the sources and examples.
In order to run, the project only needs to have KNITRODIR
environment variable
set to the Knitro directory.
To modify the example run by Visual Studio, right click on “KNCS” project then select “Properties” and modify “Startup object” (in Application tab).
Getting started with the C++ objectoriented interface
The C++ object oriented interface is distributed as a library which is straightforward to include within your projects.
Examples are provided within a CMake project. Please refer to the README file
in examples/C++
directory for more details.
The following sections and subsequent references to objectoriented interfaces within the documentation, use C++ interface methods and classes.
Defining a problem
This section describes how to define a problem in the objectoriented interface by implementing
the KNProblem
class.
Sparse structures
The C++ interface uses the concept of sparse structures to provide Knitro information concerning only subparts of the problem. Sparse structures are used to affect values to a subset of indexes (variables or constraints). For example, to specify upper bounds for some variables:
setVarUpBnds({ {1, 5, 8}, {10.0, 7.5, 8.9} });
Variables x1, x5 and x8 will have respectively 10.0, 7.5 and 8.9 as upper bound. Other variables upper bounds would have default values set internally by Knitro.
This behaviour is ensured by the sparse structure KNSparseVector
.
/**
* A SparseVector is simply a mapping between a set of indexes and a set of values.
* The number of indexes shall never exceed the number of values.
*
* A sparse vector represent the mapping indexes[i] > values[i], where i is a coordinate of the vector.
* A SparseVector is empty if size(index) == size(values) == 0
* A SparseVector is plain if size(index) == 0 && size(values) > 0
* A SparseVector is sparse if size(index) == size(values) > 0
* Examples :
* T = ({0,1,3,5}, {1.2,36,3.9,4.8})
* T is a sparse vector and T[3] = 4.8, mapping the index 5 to 4.8
*
* T = ({}, {1.2,36,3.9,4.8})
* T is a plain vector and T[3] = 4.8, mapping the index 3 to 4.8
*
* T = ({}, {})
* T is an empty vector
*
* T = ({{0,1,3,5}}, {})
* T is an invalid vector
*/
template<class IndexType, class ValueType>
class KNSparseVector {
...
/**
* List of indexes.
*/
std::vector<IndexType> _indexes;
/**
* List of values.
*/
std::vector<ValueType> _values;
};
The same syntax can be used to represent linear expressions as a set of variable indexes and a set of constant coefficients.
/**
* A LinearStructure is a SparseVector with types :
* int for indexes
* double for values
*
* Typically, a LinearStructure is a matrix form of the linear part of a given function.
* Where indexes are the variables indexes of the problem which appear linearly in the function
* and values are the corresponding coefficients.
*
* Example:
*
* ({2,3,7}, {5.0, 5.8, 3.6})
* Represents the linear part:
* 5.0x2  5.8x3 + 3.6x7
*/
class KNLinearStructure : public KNSparseVector<int,double>
Or to provide coordinates in a matrix (Jacobian for instance).
/**
* A SparseMatrixStructure is a SparseVector with types :
* int for indexes
* int for values
*
* Typically, a SparseMatrixStructure represents a list of coordinates in a matrix.
* Example:
*
* ({2,3,7}, {6,8,9})
*
* Are the coordinates :
* [(2,6),(3,8),(7,9)]
*/
class KNSparseMatrixStructure : public KNSparseVector<int,int>
The concept is also extended to a tripet of sets representing quadratic expressions.
/**
* A QuadraticStructure works as a LinearStructure with types :
* int for first variable indexes
* int for second variable indexes
* double for coefficients
*
* Typically, a QuadraticStructure represents a pair of variable with an associated coefficient.
* Example:
*
* ({2,3,7}, {2,8,9}, {5.0, 5.8, 3.6})
*
* Is the quadratic expression :
* 5.0x2^2  5.8x3x8 + 3.6x7x9
*/
class KNQuadraticStructure : public KNLinearStructure {
...
/**
* List of indexes, indexes of second variable of a quadratic term in a quadratic part.
*/
std::vector<int> _varIndexes2;
};
Sparse structures In Java and C#
These structures are implemented as well in Java and C#. However, the methods that use these structures are overloaded by more userfriendly methods.
Here is an example with setVarUpBnds:
In Java:
/**
* To set variables upper bounds, variable indexes and upper bound values are given as arguments.
*/
setVarUpBnds(Arrays.asList(1, 5, 8), Arrays.asList(10.0, 7.5, 8.9));
/**
* This method overloads the setVarUpBnds methods with KNSparseVector.
*/
public void setVarUpBnds(final List<Integer> varIndexes, final List<Double> varUpBnds) throws KNException
{
setVarUpBnds(new KNSparseVector<>(varUpBndsIndexes, varUpBndsValues));
}
In C#:
/**
* To set variables upper bounds, variable indexes and upper bound values are given as arguments.
*/
SetVarUpBnds(new List<int> {1, 5, 8}, new List<double> {10.0, 7.5, 8.9});
/**
* This method overloads the setVarUpBnds methods with KNSparseVector.
*/
public void SetVarUpBnds(List<int> varIndexes, List<double> varUpBnds)
{
SetVarUpBnds(new KNSparseVector<int, double>(varIndexes, varUpBnds));
}
Minimal required implementation
In order to define an optimization problem, a problem class that inherits from
KNProblem
must be defined by the user. Such a class should at least:
pass the number of variables to the
KNProblem
constructor.pass the number of constraints to the
KNProblem
constructor.
The user can also :
set variable upper and lower bounds with
KNProblem::setVarLoBnds()
andKNProblem::setVarUpBnds()
set constraint upper and lower bounds with
KNProblem::setConLoBnds()
andKNProblem::setConUpBnds()
set constraint types with
KNProblem::setConTypes()
set the objective type with
KNProblem::setObjType()
set the objective goal with
KNProblem::setObjGoal()
set the initial primal variable values with
KNProblem::setXInitial()
set the initial dual variable values with
KNProblem::setLambdaInitial()
If these values are not set, Knitro will automatically determine initial values.
Implementing a MIP problem
If the problem has integer or binary variables, the following must also be used:
set variable types with
KNProblem::setVarTypes()
Implementing derivatives
Like the callable library, the objectoriented interface does not compute derivatives automatically.
To evaluate non linear parts of its problem, the user should define:
A callback to evaluate the non linear parts
If possible callbacks to evaluate first and second derivatives
Sparsity patterns for the Jacobian and Hessian matrices
Note
Exact derivative evaluation is a key element of the implementation. It will make Knitro more efficient and robust. If these callbacks are not available, Knitro will perform approximations.
Knitro uses the sparsity pattern to speed up linear algebra computations.
See parts Derivatives and Callbacks for more information.
The class KNNonLinearStructure
holds all the necessary information to pass a nonlinear function to Knitro.
/**
* NonLinearStructure represents the nonlinear part of a given function
* It stores all the information to be passed down to Knitro for its callback routines.
*
* NonLinearStructure holds an EvalCallback which stores 3 function pointers to evaluate :
* This function nonlinear part through a callback
* This function nonlinear part's jacobian (gradient) through a callback
* This function nonlinear part's hessian through a callback
*
* NonLinearStructure also holds derivatives structural informations :
* KNSparseMatrixStructure for the jacobian nonzero pattern
* KNSparseMatrixStructure for the hessian nonzero pattern
*/
class KNNonLinearStructure {...}
/**
* NonLinearBloc is a NonLinearStructure that is used for a set of constraints
* The same structure of callbacks and nonzero patterns is used to represent
* nonlinear parts of several constraints.
*/
class KNNonLinearBloc : public KNNonLinearStructure {
...
std::vector<int> _indexes;
}
Here is an example on how to use nonlinear bloc to register several nonlinear constraints and their derivatives.
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* This example demonstrates how to use Knitro to solve the following
* simple nonlinear optimization problem. This model is test problem
* HS40 from the Hock & Schittkowski collection.
*
* max x0*x1*x2*x3 (obj)
* s.t. x0^3 + x1^2 = 1 (c0)
* x0^2*x3  x2 = 0 (c1)
* x3^2  x1 = 0 (c2)
*
* This is the same as exampleNLP2.c, but it demonstrates using
* multiple callbacks for the nonlinear evaluations and computing
* some gradients using finitedifferencs, while others are provided
* in callback routines.
*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#include "KNSolver.h"
#include "KNProblem.h"
using namespace knitro;
class ProblemNLP2 : public knitro::KNProblem {
public:
/**/
/* FUNCTION EVALUATION CALLBACKS */
/**/
/** The signature of this function matches KN_eval_callback in knitro.h.
* Only "obj" is set in the KN_eval_result structure.
*/
static int callbackEvalObj (KN_context_ptr kc,
CB_context_ptr cb,
KN_eval_request_ptr const evalRequest,
KN_eval_result_ptr const evalResult,
void * const userParams)
{
const double *x;
double *obj;
if (evalRequest>type != KN_RC_EVALFC)
{
printf ("*** callbackEvalObj incorrectly called with eval type %d\n",
evalRequest>type);
return( 1 );
}
x = evalRequest>x;
obj = evalResult>obj;
/** Evaluate nonlinear term in objective */
*obj = x[0]*x[1]*x[2]*x[3];
return( 0 );
}
/** The signature of this function matches KN_eval_callback in knitro.h.
* Only "c0" is set in the KN_eval_result structure.
*/
static int callbackEvalC0 (KN_context_ptr kc,
CB_context_ptr cb,
KN_eval_request_ptr const evalRequest,
KN_eval_result_ptr const evalResult,
void * const userParams)
{
const double *x;
double *c;
if (evalRequest>type != KN_RC_EVALFC)
{
printf ("*** callbackEvalC0 incorrectly called with eval type %d\n",
evalRequest>type);
return( 1 );
}
x = evalRequest>x;
c = evalResult>c;
/** Evaluate nonlinear terms in constraint, c0 */
*c = x[0]*x[0]*x[0];
return( 0 );
}
/** The signature of this function matches KN_eval_callback in knitro.h.
* Only "c1" is set in the KN_eval_result structure.
*/
static int callbackEvalC1 (KN_context_ptr kc,
CB_context_ptr cb,
KN_eval_request_ptr const evalRequest,
KN_eval_result_ptr const evalResult,
void * const userParams)
{
const double *x;
double *c;
if (evalRequest>type != KN_RC_EVALFC)
{
printf ("*** callbackEvalC1 incorrectly called with eval type %d\n",
evalRequest>type);
return( 1 );
}
x = evalRequest>x;
c = evalResult>c;
/** Evaluate nonlinear terms in constraint, c1 */
*c = x[0]*x[0]*x[3];
return( 0 );
}
/**/
/* GRADIENT EVALUATION CALLBACKS */
/**/
/** The signature of this function matches KN_eval_callback in knitro.h.
* Only "objGrad" is set in the KN_eval_result structure.
*/
static int callbackEvalObjGrad (KN_context_ptr kc,
CB_context_ptr cb,
KN_eval_request_ptr const evalRequest,
KN_eval_result_ptr const evalResult,
void * const userParams)
{
const double *x;
double *objGrad;
if (evalRequest>type != KN_RC_EVALGA)
{
printf ("*** callbackEvalObjGrad incorrectly called with eval type %d\n",
evalRequest>type);
return( 1 );
}
x = evalRequest>x;
objGrad = evalResult>objGrad;
/** Evaluate nonlinear terms in objective gradient */
objGrad[0] = x[1]*x[2]*x[3];
objGrad[1] = x[0]*x[2]*x[3];
objGrad[2] = x[0]*x[1]*x[3];
objGrad[3] = x[0]*x[1]*x[2];
return( 0 );
}
/** The signature of this function matches KN_eval_callback in knitro.h.
* Only gradient of c0 is set in the KN_eval_result structure.
*/
static int callbackEvalC0Grad (KN_context_ptr kc,
CB_context_ptr cb,
KN_eval_request_ptr const evalRequest,
KN_eval_result_ptr const evalResult,
void * const userParams)
{
const double *x;
double *jac;
if (evalRequest>type != KN_RC_EVALGA)
{
printf ("*** callbackEvalC0Grad incorrectly called with eval type %d\n",
evalRequest>type);
return( 1 );
}
x = evalRequest>x;
jac = evalResult>jac;
/** Evaluate nonlinear terms in c0 constraint gradients */
jac[0] = 3.0*x[0]*x[0]; /* derivative of x0^3 term wrt x0 */
return( 0 );
}
ProblemNLP2() : KNProblem(4,3) {
// Initial primal values
this>setXInitial({ {0.8, 0.8, 0.8, 0.8} });
// Constraints rhs
this>setConEqBnds({ {1.0, 0.0, 0.0} });
/** Add linear structure and coefficients. */
this>setConstraintsLinearParts({ {1, 2}, // c1 and c2 have linear parts
{
{ {2}, {1.0} }, // linear pattern for c1 (x2)
{ {1}, {1.0} } // linear pattern for c2 (x1)
}
});
/** Add quadratic structure and coefficients. */
this>setConstraintsQuadraticParts({ {0, 2}, // c0 and c2 have quadratic parts
{
{ {1}, {1}, {1.0} }, // quadratic pattern for c0 (x1^2)
{ {3}, {3}, {1.0} } // quadratic pattern for c2 (x3^2)
}
});
this>setObjEvalCallback(&ProblemNLP2::callbackEvalObj);
this>setObjGradNnzPattern({ {0, 1, 2, 3} });
this>setGradEvalCallback(&ProblemNLP2::callbackEvalObjGrad);
/** Set minimize or maximize (if not set, assumed minimize) */
this>setObjGoal(KN_OBJGOAL_MAXIMIZE);
this>setNonLinearC0();
this>setNonLinearC1();
}
void setNonLinearC0() {
KNEvalCallback callback(&ProblemNLP2::callbackEvalC0, NULL, &ProblemNLP2::callbackEvalC0Grad, NULL);
KNSparseMatrixStructure jacNnzPattern = { {0}, {0} };
KNSparseMatrixStructure hessNnzPattern;
std::vector<int> cst_indexes = {0};
KNNonLinearBloc c0bloc(cst_indexes, callback, jacNnzPattern, hessNnzPattern);
this>getConstraintsNonLinearParts().push_back(c0bloc);
}
void setNonLinearC1() {
KNEvalCallback callback(&ProblemNLP2::callbackEvalC1, NULL, NULL, NULL);
KNSparseMatrixStructure jacNnzPattern = { {1,1}, {0,3} };
KNSparseMatrixStructure hessNnzPattern;
std::vector<int> cst_indexes = {1};
KNNonLinearBloc c1bloc(cst_indexes, callback, jacNnzPattern, hessNnzPattern);
this>getConstraintsNonLinearParts().push_back(c1bloc);
}
};
int main() {
// Create a problem instance.
ProblemNLP2 instance = ProblemNLP2();
// Create a solver
knitro::KNSolver solver(&instance);
/** Set option to print output after every iteration. */
solver.setParam("hessopt", KN_HESSOPT_BFGS);
solver.initProblem();
int solveStatus = solver.solve();
std::vector<double> x;
std::vector<double> lambda;
int nStatus = solver.getSolution(x, lambda);
printf ("Knitro converged with final status = %d\n", nStatus);
printf (" optimal objective value = %e\n", solver.getObjValue());
printf (" optimal primal values x = (%e, %e, %e, %e)\n", x[0], x[1], x[2], x[3]);
printf (" feasibility violation = %e\n", solver.getAbsFeasError());
printf (" KKT optimality violation = %e\n", solver.getAbsOptError());
return 0;
}
Non linear structures and function callbacks in Java and C#
KNNonLinearStructure
and KNNonLinearBloc
are available as well in Java and C#.
The example above is available in Java and C# (ExampleMultipleCB
) in the Knitro examples folder. Note that
function callbacks are defined differently in Java and C#. The function callbacks are abstract classes with an evaluate
function to override. Below are examples in Java and C# on how to define the objective callback callbackEvalObj from
the example above.
In Java:
private class callbackEvalObj extends KNEvalFCCallback
{
@Override
public void evaluateFC(final List<Double> x, final List<Double> obj, final List<Double> c)
{
obj.set(0, x.get(0)*x.get(1)*x.get(2)*x.get(3));
}
}
/**
* Then register the callback in the problem.
*/
ProbmlemNLP2() throws KNException
{
super(4, 3);
//...
setObjEvalCallback(new callbackEvalObj());
//...
}
In C#:
private class CallbackEvalObj : KNEvalFCCallback
{
public override void EvaluateFC(ReadOnlyCollection<double> x, IList<double> obj, IList<double> c)
{
obj[0] = x[0] * x[1] * x[2] * x[3];
}
}
/**
* Then register the callback in the problem.
*/
public ProblemNLP2() : base(4, 3)
{
//...
SetObjEvalCallback(new CallbackEvalObj());
//...
}
Complementarity Constraints
Complementarity constraints can be specified in the objectoriented interface by passing the lists of complementary variables to the function:
KNProblem::setCompConstraintsParts(const KNSparseMatrixStructure& compConsPart);
Example:
// x2 x3 and x4 complements respectively x5, x6 and x7
setCompConstraintsParts({{2, 3, 4}, {5, 6, 7}});
Using the KNSolver class to solve a problem
Once a problem is defined by inheriting from KNProblem
or KNProblemLSQ
, the KNSolver
class is used to call Knitro to solve the problem.
This class is also used to set most Knitro parameters, and access solution information after Knitro has completed solving the problem.
To use the KNSolver
class, one of four constructors can be used. Each of the constructors takes at least a pointer
to a KNBaseProblem
object (each KNSolver
object is associated with one problem definition. If different problems
are to be solved, multiple KNSolver
objects are needed).
KNSolver(KNBaseProblem * problem);
This constructor should be used when using exact gradient and Hessian evaluation.
KNSolver(KNBaseProblem * problem, int gradopt, int hessopt);
This constructor should be used when specifying a gradient and Hessian evaluation other than the default exact gradient and Hessian evaluations.
For both of these constructors, a pointer to a ALM
object can also be passed as an additional argument, when using a network license
of Knitro with the Artelys License Manager. Otherwise, a local Knitro license is used.
Once the solver object is created, Knitro options can be set with KNSolver::setParam()
, or by loading a parameters file
with KNSolver::loadParamFile()
. Finally, the function KNSolver::solve()
will call Knitro to solve the problem
and will return a solution status code.
KNSolver::solve()
can be called multiple times. Between each call to solve()
, two types of changes can be made:
KNSolver::setParam()
can be used to change problem parameters, except for the gradient and Hessian evaluation types.Variable bounds can be changed by calling
KNSolver::setVarLoBnds()
andKNSolver::setVarUpBnds()
in the problem object that the solver object points to.
Accessing callable library functions from the objectoriented interface
The objectoriented interface provides access to the Knitro callable library functions. The table below shows the correspondence between callable library functions and objectoriented interface functions.
The majority of the functions are accessed directly through KNSolver
methods. There
are a few major differences between the callable library functions and the objectoriented
interface methods:
The callable library methods take a
KN_context_ptr
argument (created from a call toKN_new()
), which holds problem information. The objectoriented interface methods do not take this argument, storing the necessary information in theKNSolver
object.The callable library methods return status codes, with a nonzero status code usually indicating an error. The objectoriented interface methods do not return status codes. If the methods encounter an error, usually related to an invalid Knitro license or invalid function arguments, a
KNException
is thrown.Several callable library methods, such as
KN_get_con_values()
, modify input parameters. Instead, the objectoriented interface methods return these values as output parameters (rather than returning status codes).Function arguments use
std::vector<>
(C++),IList<>
(Java), orList<>
(C#) instead of Cstyle (pointer) arrays. Instead of character arrays, functions usestd::string
(C++), orString
(Java and C#).
Callable Library Function 
ObjectOriented Interface Methods 


Not necessary  problem information stored in KNSolver object. 

Not necessary  problem information stored in KNSolver object. 











































Not necessary  




































































Callbacks in the objectoriented interface
The objectoriented interface supports all of the callbacks that are supported by the callable library: MIP node callbacks; multistart initial point callbacks; multistart process callbacks; new point callbacks, and Knitro output redirection callbacks.
Each of these callbacks can be used through the KNUserCallback
class,
and passing the callback object to a KNBaseProblem
object via the function
KNBaseProblem::set{Callbacktype}
(for some callback type):
KNUserCallback(KN_user_callback * fct_ptr, void * userParams)
The callback functionality is the same as described in the callable library reference section.
Below, we show an example of use of a NewPointCallback
. This type of callback is
called by Knitro during the problem iteration whenever Knitro
finds a new estimate of the solution point (i.e., after each major iteration).
This callback cannot modify any of its arguments, but can provide information about
the solve before it is completed. In this example, the callback prints the number of
objective function and constraint evaluations.
This callback should be passed to the KNProblem
object, before passing it
to the KNSolver
object. This is shown below. The problem solved is the same
example problem solved in previous sections (QCQP), but this callback is independent of the
problem solved.
int newPointCBFct(KN_context_ptr kcSub, const double * const x, const double * const lambda, void *userParams) {
/** The Knitro solver pointer was passed in */
KNSolver* solver = static_cast<KNSolver*>(userParams);
int n = solver>getNumVars();
std::cout << ' ' << ">> New point computed by Knitro: (";
for (int i = 0; i < n  1; i++) {
std::cout << x[i] << ", ";
}
std::cout << x[n  1] << ")" << std::endl;
std::cout << '\t' << "Number FC evals = " << solver>getNumberFCEvals() << std::endl;
std::cout << '\t' << "Current feasError = " << solver>getAbsFeasError() << std::endl;
return 0;
}
int main() {
// Create a problem instance.
ProblemQCQP1 instance = ProblemQCQP1();
// Create a solver
knitro::KNSolver solver(&instance, KN_GRADOPT_FORWARD, KN_HESSOPT_BFGS);
// Create a callback for new points
KNUserCallback newPointCB(&newPointCBFct, &solver);
instance.setNewPointCallback(newPointCB);
solver.initProblem();
int solveStatus = solver.solve();
std::vector<double> x;
std::vector<double> lambda;
int nStatus = solver.getSolution(x, lambda);
printf ("Knitro converged with final status = %d\n", nStatus);
printf (" optimal objective value = %e\n", solver.getObjValue());
printf (" optimal primal values x = (%e, %e, %e)\n", x[0], x[1], x[2]);
printf (" feasibility violation = %e\n", solver.getAbsFeasError());
printf (" KKT optimality violation = %e\n", solver.getAbsOptError());
return 0;
}
Calling this function gives the following output, showing additional information each time Knitro finds a new estimate of the solution value:
=======================================
Commercial License
Artelys Knitro 13.1.0
=======================================
Knitro presolve eliminated 0 variables and 0 constraints.
gradopt: 2
hessopt: 2
The problem is identified as a QCQP.
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 onesided inequalities: 0 ( 0)
quadratic onesided inequalities: 1 ( 1)
gen. nonlinear onesided inequalities: 0 ( 0)
linear twosided inequalities: 0 ( 0)
quadratic twosided inequalities: 0 ( 0)
gen. nonlinear twosided inequalities: 0 ( 0)
Number of nonzeros in Jacobian: 6 ( 6)
Number of nonzeros in Hessian: 0 ( 6)
Knitro using the InteriorPoint/Barrier Direct algorithm.
Iter Objective FeasError OptError Step CGits
     
0 9.760000e+02 1.300e+01
>> New point computed by Knitro: (3.8794, 0.01, 3.69211)
Number FC evals = 0
Current feasError = 1.01993
>> New point computed by Knitro: (3.86709, 5e05, 3.71871)
Number FC evals = 0
Current feasError = 0.968364
>> New point computed by Knitro: (3.21477, 2.5e07, 4.34564)
Number FC evals = 0
Current feasError = 0.137647
>> New point computed by Knitro: (0.0160738, 8.08315e08, 7.99343)
Number FC evals = 0
Current feasError = 0.0825911
>> New point computed by Knitro: (8.03692e05, 8.07197e08, 8.01171)
Number FC evals = 0
Current feasError = 0.0825814
>> New point computed by Knitro: (4.01846e07, 7.48165e08, 8.01117)
Number FC evals = 0
Current feasError = 0.0782078
>> New point computed by Knitro: (2.00923e09, 5.04472e10, 8.00003)
Number FC evals = 0
Current feasError = 0.000201966
>> New point computed by Knitro: (9.71394e10, 3.11246e10, 8)
Number FC evals = 0
Current feasError = 1.42109e14
>> New point computed by Knitro: (1.6533e11, 5.31416e12, 8)
Number FC evals = 0
Current feasError = 7.10543e15
9 9.360000e+02 7.105e15 3.591e09 1.976e09 0
EXIT: Locally optimal solution found.
HINT: Knitro spent 0.000620 seconds checking model convexity.
To skip the automatic convexity checker for QPs and QCQPs,
explicity set the user option convex=0 or convex=1.
Final Statistics

Final objective value = 9.36000000000340e+02
Final feasibility error (abs / rel) = 7.11e15 / 5.47e16
Final optimality error (abs / rel) = 3.59e09 / 2.24e10
# of iterations = 9
# of CG iterations = 0
# of function evaluations = 0
# of gradient evaluations = 0
Total program time (secs) = 0.00610 ( 0.005 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.653297e11, 5.314156e12, 8.000000e+00)
feasibility violation = 7.105427e15
KKT optimality violation = 3.590869e09
Callbacks in Java and C#
Java and C# handle these callbacks with different classes; MIP node callbacks, multistart
process callbacks and new point callbacks are handle by KNUserCallback
; multistart initial
point callbacks is handle by KNMSInitPtCallback
; Knitro output redirection callbacks is handle
by KNPutsCallback
. Some examples provided in the Knitro examples folder show how to use them.
MIP node callbacks :
ExampleMINLP1
Multistart process callbacks :
ExampleMultiStart
New point callbacks :
ExampleNewPointCallback
Multistart initial point callbacks :
ExampleMSInitPtCallback
Knitro output redirection callbacks :
ExamplePuts
Changing variable bounds in the objectoriented interface
In both the objectoriented interface and the callable library, a problem can be
solved multiple times. The objectoriented interface differs
from the callable library in how variable bounds are changed between two solves. In the objectoriented
interface, variable bounds are set in a KNProblem
object. When KNSolver::solve()
is called to solve the problem, the variable bounds in the KNProblem
object
are passed to the solver. the following example shows changing variable bounds between
calls to KNSolver::solve()
.
int main() {
// Create a problem instance.
ProblemQCQP1 instance = ProblemQCQP1();
// Create a solver
knitro::KNSolver solver(&instance);
solver.initProblem();
int solveStatus = solver.solve();
solver.setVarUpBnds({{0.7, 0.7, 0.7}}, 3);
solveStatus = solver.solve();
return 0;
}
In this example, the problem characteristics (including variable bounds) are
initialized in the constructor of ProblemQCQP1
. After the first call of
KNSolver::solve()
, the variable bounds are changed directly into the solver
with the KNSolver::setVarUpBnds()
function. This function sets all variable
bounds to 0.7. In addition to variable bounds,
Knitro parameters except for the gradient and Hessian evaluation type can be changed
between calls to solve
.
Equivalently, the user can change variable bounds through the KNProblem
, and call
KNSolver::setVarUpBnds()
to trigger the update of variable upper bounds and nothing else.
int main() {
// Create a problem instance.
ProblemQCQP1 instance = ProblemQCQP1();
// Create a solver
knitro::KNSolver solver(&instance);
solver.initProblem();
int solveStatus = solver.solve();
instance.setVarUpBnds({{0.7, 0.7, 0.7}});
solver.setVarUpBnds();
solveStatus = solver.solve();
return 0;
}
Using the Artelys License Manager with the objectoriented interface
The objectoriented interface can be used with either a standalone Knitro license or a network Knitro license using the Artelys License Manager (ALM) and a license server.
In order to use the ALM with the objectoriented interface, the license server needs to be installed and the user machine (from which Knitro is run) should be configured to find the license server. For information on installing and configuring the ALM, see the Artelys License Manager User’s Manual.
To use the ALM with the objectoriented interface, a ALM
object needs to be
created and passed to a KNSolver
object constructor. When the ALM object
is created, a network license will be checked out for use and unavailable
for other users until the ALM
object is destroyed.
An example usage is shown below. This example is identical to (and produces
the same output as) the other examples of the objectoriented interface,
except for the instantiation of the ALM
object and the KNSolver
constructor that takes a pointer to the ALM object.
int main() {
knitro::ALM alm;
// Create a problem instance.
ProblemQCQP instance = ProblemQCQP();
// Create a solver
KNSolver solver(&alm, &instance);
int solveStatus = solver.solve();
return 0;
}