This example shows how to load optimization problems from an external library using dlopen
.
This example shows how to load optimization problems from an external library using dlopen
.
\[ \begin{aligned}
& \underset{x}{\text{minimize}} && \tfrac12 \tp x Q x \\
& \text{subject to} && Ax \le b \\
\end{aligned} \]
#include <problem-c-export.h>
#include <stdlib.h>
#include <string.h>
#include "matmul.h"
struct ProblemData {
real_t *Q;
real_t *A;
real_t *work;
};
static void eval_grad_f(void *instance, const real_t *x, real_t *grad_f) {
struct ProblemData *problem = instance;
length_t n = problem->functions.n;
matmul(n, n, 1, problem->Q, x, grad_f);
}
static real_t eval_f_grad_f(
void *instance,
const real_t *x, real_t *grad_f) {
struct ProblemData *problem = instance;
eval_grad_f(instance, x, grad_f);
matmul(1, n, 1, x, grad_f, &result);
return (real_t)0.5 * result;
}
static real_t eval_f(
void *instance,
const real_t *x) {
struct ProblemData *problem = instance;
return eval_f_grad_f(instance, x, problem->work);
}
static void eval_g(void *instance, const real_t *x, real_t *gx) {
struct ProblemData *problem = instance;
matmul(m, n, 1, problem->A, x, gx);
}
static void eval_grad_g_prod(void *instance, const real_t *x, const real_t *y,
real_t *grad_gxy) {
(void)x;
struct ProblemData *problem = instance;
matvec_transp(m, n, problem->A, y, grad_gxy);
}
static void eval_jac_g(void *instance, const real_t *x, real_t *J_values) {
(void)x;
struct ProblemData *problem = instance;
size_t n = (size_t)problem->functions.n;
size_t m = (size_t)problem->functions.m;
memcpy(J_values, problem->A, sizeof(real_t) * m * n);
}
static void initialize_box_D(void *instance, real_t *lb, real_t *ub) {
(void)instance;
(void)lb;
ub[0] = -1;
}
static struct ProblemData *create_problem(void *user_data) {
(void)user_data;
struct ProblemData *problem = malloc(sizeof(*problem));
size_t n = 2, m = 1;
.m = (length_t)m,
.eval_f = &eval_f,
.eval_grad_f = &eval_grad_f,
.eval_g = &eval_g,
.eval_grad_g_prod = &eval_grad_g_prod,
.eval_jac_g = &eval_jac_g,
.eval_f_grad_f = &eval_f_grad_f,
.initialize_box_D = &initialize_box_D,
};
problem->Q = malloc(sizeof(real_t) * n * n);
problem->A = malloc(sizeof(real_t) * m * n);
problem->work = malloc(sizeof(real_t) * n);
problem->Q[0] = 3;
problem->Q[1] = -1;
problem->Q[2] = -1;
problem->Q[3] = 3;
problem->A[0] = 2;
problem->A[1] = 1;
return problem;
}
static void cleanup_problem(void *instance) {
struct ProblemData *problem = instance;
free(problem->Q);
free(problem->A);
free(problem->work);
free(problem);
}
alpaqa_problem_register(void *user_data) {
struct ProblemData *problem = create_problem(user_data);
return result;
}
ptrdiff_t alpaqa_length_t
alpaqa_length_t alpaqa_index_t
#define ALPAQA_PROBLEM_REGISTER_INIT(self)
Initialize an instance of alpaqa_problem_register_t or alpaqa_control_problem_register_t.
typename Conf::real_t real_t
typename Conf::length_t length_t
C API providing function pointers to problem functions.
void(* cleanup)(void *)
Pointer to the function to clean up instance.
void * instance
Owning pointer.
alpaqa_problem_functions_t * functions
Non-owning pointer, lifetime at least as long as instance.
8namespace fs = std::filesystem;
13int main(
int argc,
char *argv[]) {
15 fs::path so_name = DLPROBLEM_DLL;
17 so_name = fs::path(argv[1]);
19 so_name = fs::canonical(fs::path(argv[0])).parent_path() / so_name;
20 std::cout <<
"Loading " << so_name << std::endl;
28 length_t n = problem.get_n();
29 length_t m = problem.get_m();
30 vec b = vec::Constant(m, -1);
34 problem.D.upperbound = b;
42 OuterSolver::Params almparam;
43 almparam.tolerance = 1e-8;
44 almparam.dual_tolerance = 1e-8;
45 almparam.penalty_update_factor = 10;
46 almparam.max_iter = 20;
47 almparam.print_interval = 1;
50 InnerSolver::Params panocparam;
51 panocparam.max_iter = 500;
52 panocparam.print_interval = 10;
54 Direction::AcceleratorParams lbfgsparam;
55 lbfgsparam.memory = 2;
60 {panocparam, lbfgsparam},
70 auto stats = solver(counted_problem, x, y);
74 std::cout <<
'\n' << *counted_problem.evaluations <<
'\n';
75 std::cout <<
"status: " << stats.status <<
'\n'
76 <<
"solver: " << solver.get_name() <<
'\n'
77 <<
"f = " << problem.eval_f(x) <<
'\n'
78 <<
"inner iterations: " << stats.inner.iterations <<
'\n'
79 <<
"outer iterations: " << stats.outer_iterations <<
'\n'
80 <<
"ε = " << stats.ε <<
'\n'
81 <<
"δ = " << stats.δ <<
'\n'
83 << std::chrono::duration<double>{stats.elapsed_time}.count()
85 <<
"x = " << x.transpose() <<
'\n'
86 <<
"y = " << y.transpose() <<
'\n'
87 <<
"avg τ = " << (stats.inner.sum_τ / stats.inner.count_τ) <<
'\n'
88 <<
"L-BFGS rejected = " << stats.inner.lbfgs_rejected <<
'\n'
89 <<
"L-BFGS failures = " << stats.inner.lbfgs_failures <<
'\n'
90 <<
"Line search failures = " << stats.inner.linesearch_failures
int main(int argc, const char *argv[])
Augmented Lagrangian Method solver.
Class that loads a problem using dlopen.
#define USING_ALPAQA_CONFIG(Conf)
auto problem_with_counters_ref(Problem &p)
Wraps the given problem into a ProblemWithCounters and keeps track of how many times each function is...
Double-precision double configuration.