Uno's C interface allows you to solve an optimization model described by callback functions.
The file Uno_C_API.cpp is compiled as part of libuno (static or shared) via make, and the header Uno_C_API.h is installed via make install.
An example is available in the file example_hs015.c.
Start by including the Uno header:
#include "Uno_C_API.h"Building an optimization model is incremental and starts with the information about the variables:
void* model = uno_create_model(problem_type, number_variables,
variables_lower_bounds, variables_upper_bounds, base_indexing);or (for an unconstrained model):
void* model = uno_create_unconstrained_model(problem_type, number_variables, base_indexing);The following optional elements can be added or set to the model separately:
- lower bounds for the variables:
uno_set_variables_lower_bounds(model, variables_lower_bounds)- upper bounds for the variables:
uno_set_variables_upper_bounds(model, variables_upper_bounds)- a lower bound for a given variable:
uno_set_variable_lower_bound(model, variable_index, lower_bound)- an upper bound for a given variable:
uno_set_variable_upper_bound(model, variable_index, upper_bound)- the objective function (and its gradient). It is 0 otherwise;
uno_set_objective(model, optimization_sense, objective_function, objective_gradient);- constraint functions (and their Jacobian);
uno_set_constraints(model, number_constraints, constraint_functions,
constraints_lower_bounds, constraints_upper_bounds, number_jacobian_nonzeros,
jacobian_row_indices, jacobian_column_indices, jacobian);- lower bounds for the constraints:
uno_set_constraints_lower_bounds(model, constraints_lower_bounds)- upper bounds for the constraints:
uno_set_constraints_upper_bounds(model, constraints_upper_bounds)- a lower bound for a given constraint:
uno_set_constraint_lower_bound(model, constraint_index, lower_bound)- an upper bound for a given constraint:
uno_set_constraint_upper_bound(model, constraint_index, upper_bound)- the Lagrangian Hessian;
uno_set_lagrangian_hessian(model, number_hessian_nonzeros, hessian_triangular_part,
hessian_row_indices, hessian_column_indices, lagrangian_hessian);- a Jacobian operator (performs Jacobian-vector products);
uno_set_jacobian_operator(model, jacobian_operator);- a Jacobian-transposed operator (performs Jacobian-transposed-vector products);
uno_set_jacobian_transposed_operator(model, jacobian_transposed_operator);- a Hessian operator (performs Hessian-vector products);
uno_set_lagrangian_hessian_operator(model, lagrangian_hessian_operator);- a Lagrangian sign convention (default is
UNO_MULTIPLIER_NEGATIVE);
uno_set_lagrangian_sign_convention(model, lagrangian_sign_convention);- user data of an arbitrary type (
void*);
uno_set_user_data(model, user_data);- an initial primal point;
uno_set_initial_primal_iterate(model, initial_primal_iterate);- an initial dual point.
uno_set_initial_dual_iterate(model, initial_dual_iterate);Each of these functions returns an integer that is 0 upon success and positive upon failure.
The memory for the model is allocated by the C interface and must be freed by a call to the function:
uno_destroy_model(model);Create an instance of the Uno solver with a simple function call.
void* solver = uno_create_solver();The memory for the solver is allocated by the C interface and must be freed by a call to the function:
uno_destroy_solver(solver);Options can be passed to the Uno solver:
uno_set_solver_integer_option(solver, "max_iterations", 1000);
uno_set_solver_double_option(solver, "primal_tolerance", 1.0e-6);
uno_set_solver_bool_option(solver, "print_solution", true);
uno_set_solver_string_option(solver, "hessian_model", "exact");Loading options from a file (overwrites existing options):
uno_load_solver_option_file(solver, "uno.opt");Getting typed value of an option from the Uno solver:
uno_int uno_get_solver_integer_option(solver, "max_iterations");
size_t uno_get_solver_unsigned_integer_option(solver, "max_iterations");
double uno_set_solver_double_option(solver, "primal_tolerance");
bool uno_get_solver_bool_option(solver, "print_solution");
const char* uno_get_solver_string_option(solver, "hessian_model");Setting a preset has Uno mimic an existing solver:
uno_set_solver_preset(solver, "filtersqp");Setting the user callbacks to the Uno solver:
uno_set_solver_callbacks(solver, notify_acceptable_iterate_callback, user_termination_callback, user_data);Setting the logger stream callback:
uno_set_logger_stream_callback(logger_stream_callback, user_data);and reset the logger stream to the standard output:
uno_reset_logger_stream();The model can then be solved by Uno:
uno_optimize(solver, model);A set of functions allows you to inspect the result of the optimization:
- the optimization status (
UNO_SUCCESS,UNO_ITERATION_LIMIT,UNO_TIME_LIMIT,UNO_EVALUATION_ERROR,UNO_ALGORITHMIC_ERROR):
uno_get_optimization_status(solver);- the solution status (
UNO_NOT_OPTIMAL,UNO_FEASIBLE_KKT_POINT,UNO_FEASIBLE_FJ_POINT,UNO_INFEASIBLE_STATIONARY_POINT,UNO_FEASIBLE_SMALL_STEP,UNO_INFEASIBLE_SMALL_STEP,UNO_UNBOUNDED):
uno_int uno_get_solution_status(solver);- the objective value of the solution:
double uno_get_solution_objective(solver);- the primal solution:
void uno_get_primal_solution(solver, primal_solution);- the dual solution associated with the general constraints:
void uno_get_constraint_dual_solution(solver, constraint_dual_solution);- the dual solution associated with the lower bounds:
void uno_get_lower_bound_dual_solution(solver, lower_bound_dual_solution);- the dual solution associated with the upper bounds:
void uno_get_upper_bound_dual_solution(solver, upper_bound_dual_solution);- the primal feasibility measure at the solution:
double uno_get_solution_primal_feasibility(solver);- the stationarity measure at the solution:
double uno_get_solution_stationarity(solver);- the complementarity measure at the solution:
double uno_get_solution_complementarity(solver);