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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
/**
* ripopt.h — C API for the ripopt nonlinear optimizer.
*
* Mirrors the Ipopt C interface so that existing Ipopt C code can be
* adapted with minimal changes.
*
* Usage:
* 1. Create a problem handle with ripopt_create().
* 2. Optionally tune options with ripopt_add_num/int/str_option().
* 3. Call ripopt_solve() with an initial point.
* 4. Free the handle with ripopt_free().
*
* Compile & link example (macOS):
* cargo build --release
* cc examples/c_api_test.c -I. -Ltarget/release -lripopt \
* -Wl,-rpath,target/release -o c_api_test
* ./c_api_test
*/
#ifndef RIPOPT_H
#define RIPOPT_H
/* Version information — keep in sync with Cargo.toml */
#define RIPOPT_VERSION_MAJOR 0
#define RIPOPT_VERSION_MINOR 2
#define RIPOPT_VERSION_PATCH 0
#define RIPOPT_VERSION "0.2.0"
#ifdef __cplusplus
extern "C" {
#endif
/* Opaque handle to a ripopt problem. */
typedef void* RipoptProblem;
/* -------------------------------------------------------------------------
* Callback signatures (identical to Ipopt C API)
* -------------------------------------------------------------------------
* All callbacks return 1 (true) on success, 0 on error.
* new_x / new_lambda: 1 if x/lambda changed since the last call, 0 otherwise.
* Ripopt currently passes 1 for every call (conservative / correct).
*
* Jacobian / Hessian callbacks are called in two modes:
* - values == NULL → fill iRow/jCol with the sparsity pattern (0-based)
* - values != NULL → fill values in the same element order as the pattern
* ------------------------------------------------------------------------- */
typedef int (*Eval_F_CB)(
int n, const double *x, int new_x,
double *obj_value,
void *user_data);
typedef int (*Eval_Grad_F_CB)(
int n, const double *x, int new_x,
double *grad_f,
void *user_data);
typedef int (*Eval_G_CB)(
int n, const double *x, int new_x,
int m, double *g,
void *user_data);
typedef int (*Eval_Jac_G_CB)(
int n, const double *x, int new_x,
int m, int nele_jac,
int *iRow, int *jCol,
double *values,
void *user_data);
typedef int (*Eval_H_CB)(
int n, const double *x, int new_x,
double obj_factor,
int m, const double *lambda, int new_lambda,
int nele_hess,
int *iRow, int *jCol,
double *values,
void *user_data);
/* -------------------------------------------------------------------------
* Return status codes
* ------------------------------------------------------------------------- */
typedef enum {
RIPOPT_SOLVE_SUCCEEDED = 0,
RIPOPT_ACCEPTABLE_LEVEL = 1,
RIPOPT_INFEASIBLE_PROBLEM = 2,
RIPOPT_MAXITER_EXCEEDED = 5,
RIPOPT_RESTORATION_FAILED = 6,
RIPOPT_ERROR_IN_STEP_COMPUTATION = 7,
RIPOPT_NOT_ENOUGH_DEGREES_OF_FREEDOM = 10,
RIPOPT_INVALID_PROBLEM_DEFINITION = 11,
RIPOPT_INTERNAL_ERROR = -1
} RipoptReturnStatus;
/* -------------------------------------------------------------------------
* Lifecycle
* -------------------------------------------------------------------------
* ripopt_create — allocate and return a new problem handle.
*
* n number of primal variables
* x_l/x_u variable lower/upper bounds (length n; use ±1e30 for ±∞)
* m number of constraints
* g_l/g_u constraint lower/upper bounds (length m)
* nele_jac number of nonzeros in the Jacobian
* nele_hess number of nonzeros in the lower-triangular Hessian
* eval_* callback function pointers (must remain valid until ripopt_free)
*
* Returns NULL on allocation failure.
* ------------------------------------------------------------------------- */
RipoptProblem ripopt_create(
int n, const double *x_l, const double *x_u,
int m, const double *g_l, const double *g_u,
int nele_jac, int nele_hess,
Eval_F_CB eval_f,
Eval_Grad_F_CB eval_grad_f,
Eval_G_CB eval_g,
Eval_Jac_G_CB eval_jac_g,
Eval_H_CB eval_h);
/** Free a problem handle obtained from ripopt_create(). */
void ripopt_free(RipoptProblem problem);
/* -------------------------------------------------------------------------
* Log callback
*
* When installed, all solver output (iteration table, warnings, diagnostics)
* is forwarded to the callback instead of being written to stderr.
* The callback receives a NUL-terminated message string and the user_data
* pointer provided at registration.
*
* The callback is thread-local and is cleared automatically after each
* ripopt_solve() call. Pass callback = NULL to revert to stderr output.
* ------------------------------------------------------------------------- */
typedef void (*RipoptLogCB)(const char *msg, void *user_data);
/** Register a log callback for solver output.
*
* Must be called before ripopt_solve(). The callback and user_data pointers
* must remain valid for the duration of the solve.
*/
void ripopt_set_log_callback(RipoptProblem problem,
RipoptLogCB callback,
void *user_data);
/* -------------------------------------------------------------------------
* Post-solve statistics (valid after ripopt_solve() returns)
* ------------------------------------------------------------------------- */
/** Number of IPM iterations in the most recent solve. */
int ripopt_get_iter_count(RipoptProblem problem);
/** Wall-clock solve time in seconds from the most recent solve. */
double ripopt_get_solve_time(RipoptProblem problem);
/** Final primal infeasibility from the most recent solve. */
double ripopt_get_primal_inf(RipoptProblem problem);
/** Final dual infeasibility from the most recent solve. */
double ripopt_get_dual_inf(RipoptProblem problem);
/** Final complementarity error from the most recent solve. */
double ripopt_get_compl_inf(RipoptProblem problem);
/* -------------------------------------------------------------------------
* Options (key/value, mirrors Ipopt option names)
* All functions return 1 on success, 0 if the keyword is unknown.
* ------------------------------------------------------------------------- */
/** Set a numeric (double) option, e.g. "tol" = 1e-8. */
int ripopt_add_num_option(RipoptProblem problem,
const char *keyword, double val);
/** Set an integer option, e.g. "max_iter" = 500. */
int ripopt_add_int_option(RipoptProblem problem,
const char *keyword, int val);
/** Set a string option, e.g. "mu_strategy" = "adaptive". */
int ripopt_add_str_option(RipoptProblem problem,
const char *keyword, const char *val);
/* -------------------------------------------------------------------------
* Solve
*
* problem handle from ripopt_create()
* x [in/out] initial point (length n) → primal solution
* g [out] constraint values g(x*) at solution, or NULL
* obj_val [out] objective f(x*) at solution, or NULL
* mult_g [out] constraint multipliers λ (length m), or NULL
* mult_x_L [out] lower bound multipliers z_L (length n), or NULL
* mult_x_U [out] upper bound multipliers z_U (length n), or NULL
* user_data arbitrary pointer forwarded to every callback
*
* Returns a RipoptReturnStatus code (cast to int).
* ------------------------------------------------------------------------- */
int ripopt_solve(
RipoptProblem problem,
double *x,
double *g,
double *obj_val,
double *mult_g,
double *mult_x_L,
double *mult_x_U,
void *user_data);
#ifdef __cplusplus
}
#endif
#endif /* RIPOPT_H */