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
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
/**
* 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 7
#define RIPOPT_VERSION_PATCH 1
#define RIPOPT_VERSION "0.7.1"
#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
* ------------------------------------------------------------------------- */
/* Values match Ipopt's ApplicationReturnStatus for drop-in compatibility. */
typedef enum {
RIPOPT_SOLVE_SUCCEEDED = 0,
/* RIPOPT_ACCEPTABLE_LEVEL = 1, */ /* not currently returned */
RIPOPT_INFEASIBLE_PROBLEM = 2,
RIPOPT_SEARCH_DIRECTION_TOO_SMALL = 3,
RIPOPT_DIVERGING_ITERATES = 4,
RIPOPT_USER_REQUESTED_STOP = 5,
/* RIPOPT_FEASIBLE_POINT_FOUND = 6, */ /* not currently returned */
RIPOPT_MAXITER_EXCEEDED = -1,
RIPOPT_RESTORATION_FAILED = -2,
RIPOPT_ERROR_IN_STEP_COMPUTATION = -3,
/* RIPOPT_MAX_CPUTIME_EXCEEDED = -4, */ /* not currently returned */
RIPOPT_MAX_WALLTIME_EXCEEDED = -5,
RIPOPT_NOT_ENOUGH_DEGREES_OF_FREEDOM = -10,
RIPOPT_INVALID_PROBLEM_DEFINITION = -11,
RIPOPT_INVALID_NUMBER_DETECTED = -13,
RIPOPT_INTERNAL_ERROR = -199
} 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
* index_style 0 = C (0-based indices), 1 = Fortran (1-based indices)
* 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,
int index_style,
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);
/* -------------------------------------------------------------------------
* File logging
* ------------------------------------------------------------------------- */
/** Open a log file for solver output.
*
* All solver output is written to the specified file. Overrides any
* previously set log callback. Returns 1 on success, 0 if the file
* cannot be opened.
*/
int ripopt_open_output_file(RipoptProblem problem,
const char *filename,
int print_level);
/* -------------------------------------------------------------------------
* Intermediate callback
*
* Called once per IPM iteration with current solver state.
* Return 1 to continue, 0 to request early termination
* (solver returns RIPOPT_USER_REQUESTED_STOP).
* ------------------------------------------------------------------------- */
/* Signature matches Ipopt's Intermediate_CB. */
typedef int (*RipoptIntermediateCB)(
int alg_mod, /* 0 = regular, 1 = restoration */
int iter,
double obj_value,
double inf_pr,
double inf_du,
double mu,
double d_norm, /* infinity-norm of primal step */
double regularization_size, /* Hessian regularization delta */
double alpha_du,
double alpha_pr,
int ls_trials,
void *user_data);
/** Register an intermediate callback.
*
* Must be called before ripopt_solve(). The callback and user_data pointers
* must remain valid for the duration of the solve.
*/
void ripopt_set_intermediate_callback(RipoptProblem problem,
RipoptIntermediateCB callback,
void *user_data);
/* -------------------------------------------------------------------------
* Problem scaling
* ------------------------------------------------------------------------- */
/** Set user-provided problem scaling (matches Ipopt's SetIpoptProblemScaling).
*
* obj_scaling scales the objective. x_scaling (length n) scales each
* variable; pass NULL for no variable scaling. g_scaling (length m) scales
* each constraint; pass NULL for no constraint scaling.
*/
void ripopt_set_scaling(RipoptProblem problem,
double obj_scaling,
const double *x_scaling,
const double *g_scaling);
/* -------------------------------------------------------------------------
* Current iterate / violations (valid ONLY during intermediate callback)
*
* These match Ipopt's GetIpoptCurrentIterate and GetIpoptCurrentViolations.
* Returns 1 on success, 0 if called outside of an intermediate callback.
* Pass NULL for any output array you don't need.
* ------------------------------------------------------------------------- */
/** Retrieve the current iterate (primal and dual variables). */
int ripopt_get_current_iterate(RipoptProblem problem,
int n,
double *x, /* length n, or NULL */
double *z_L, /* length n, or NULL */
double *z_U, /* length n, or NULL */
int m,
double *g, /* length m, or NULL */
double *lambda); /* length m, or NULL */
/** Retrieve current constraint and optimality violations. */
int ripopt_get_current_violations(RipoptProblem problem,
int n,
double *x_L_violation, /* length n, or NULL */
double *x_U_violation, /* length n, or NULL */
double *compl_x_L, /* length n, or NULL */
double *compl_x_U, /* length n, or NULL */
double *grad_lag_x, /* length n, or NULL */
int m,
double *constraint_violation, /* length m, or NULL */
double *compl_g); /* length m, or NULL */
/* -------------------------------------------------------------------------
* 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);
/* -------------------------------------------------------------------------
* Version
* ------------------------------------------------------------------------- */
/** Get the ripopt version as major.minor.patch integers. */
void ripopt_get_version(int *major, int *minor, int *patch);
#ifdef __cplusplus
}
#endif
#endif /* RIPOPT_H */