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_objective_gradient(void *instance, const real_t *x,
real_t *grad_f) {
struct ProblemData *problem = instance;
length_t n = problem->functions.num_variables;
matmul(n, n, 1, problem->Q, x, grad_f);
}
static real_t eval_objective_and_gradient(
void *instance,
const real_t *x,
real_t *grad_f) {
struct ProblemData *problem = instance;
length_t n = problem->functions.num_variables;
eval_objective_gradient(instance, x, grad_f);
matmul(1, n, 1, x, grad_f, &result);
return (real_t)0.5 * result;
}
static real_t eval_objective(
void *instance,
const real_t *x) {
struct ProblemData *problem = instance;
return eval_objective_and_gradient(instance, x, problem->work);
}
static void eval_constraints(void *instance, const real_t *x, real_t *gx) {
struct ProblemData *problem = instance;
length_t n = problem->functions.num_variables;
length_t m = problem->functions.num_constraints;
matmul(m, n, 1, problem->A, x, gx);
}
static void eval_constraints_gradient_product(void *instance, const real_t *x,
const real_t *y,
real_t *grad_gxy) {
(void)x;
struct ProblemData *problem = instance;
length_t n = problem->functions.num_variables;
length_t m = problem->functions.num_constraints;
matvec_transp(m, n, problem->A, y, grad_gxy);
}
static void eval_constraints_jacobian(void *instance, const real_t *x,
real_t *J_values) {
(void)x;
struct ProblemData *problem = instance;
size_t n = (size_t)problem->functions.num_variables;
size_t m = (size_t)problem->functions.num_constraints;
memcpy(J_values, problem->A, sizeof(real_t) * m * n);
}
static void initialize_general_bounds(void *instance, real_t *lb, real_t *ub) {
(void)instance;
(void)lb;
ub[0] = -1;
}
(void)user_data;
struct ProblemData *problem = malloc(sizeof(*problem));
size_t n = 2, m = 1;
.num_constraints = (length_t)m,
.name = "example problem",
.eval_objective = &eval_objective,
.eval_objective_gradient = &eval_objective_gradient,
.eval_constraints = &eval_constraints,
.eval_constraints_gradient_product = &eval_constraints_gradient_product,
.eval_constraints_jacobian = &eval_constraints_jacobian,
.eval_objective_and_gradient = &eval_objective_and_gradient,
.initialize_general_bounds = &initialize_general_bounds,
};
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);
}
struct ProblemData *problem = create_problem(user_data);
return result;
}
}
#define ALPAQA_DL_ABI_VERSION
void(* cleanup)(void *)
Pointer to the function to clean up instance.
ptrdiff_t alpaqa_length_t
alpaqa_length_t alpaqa_index_t
uint64_t alpaqa_dl_abi_version_t
#define ALPAQA_PROBLEM_REGISTER_INIT(self)
Initialize an instance of alpaqa_problem_register_t or alpaqa_control_problem_register_t.
void * instance
Owning pointer.
alpaqa_problem_functions_t * functions
Non-owning pointer, lifetime at least as long as instance.
C API providing function pointers to problem functions.
User-provided argument that is passed to the problem registration functions.
typename Conf::real_t real_t
typename Conf::length_t length_t
2#include <alpaqa/example-util.hpp>
5
6#include <filesystem>
7#include <iostream>
8
9namespace fs = std::filesystem;
10
11
13
14int main(
int argc,
char *argv[]) {
15 alpaqa::init_stdout();
16
17
18 fs::path so_name = DLPROBLEM_DLL;
19 if (argc > 1)
20 so_name = fs::path(argv[1]);
21 else if (argc > 0)
22 so_name = fs::canonical(fs::path(argv[0])).parent_path() / so_name;
23 std::cout << "Loading " << so_name << std::endl;
24
25
27
29
30
33 vec b = vec::Constant(m, -1);
39
40
44
45
46 OuterSolver::Params almparam;
47 almparam.tolerance = 1e-8;
48 almparam.dual_tolerance = 1e-8;
49 almparam.penalty_update_factor = 10;
50 almparam.max_iter = 20;
51 almparam.print_interval = 1;
52
53
54 InnerSolver::Params panocparam;
55 panocparam.max_iter = 500;
56 panocparam.print_interval = 10;
57
58 Direction::AcceleratorParams lbfgsparam;
59 lbfgsparam.memory = 2;
60
61
62 OuterSolver solver{
63 almparam,
64 {panocparam, lbfgsparam},
65 };
66
67
69 x << 2, 2;
71 y << 1;
72
73
74 auto stats = solver(counted_problem, x, y);
75
76
77
78 std::cout << '\n' << *counted_problem.evaluations << '\n';
79 std::cout
80 << "status: " << stats.status << '\n'
81 << "solver: " << solver.get_name() << '\n'
83 << "inner iterations: " << stats.inner.iterations << '\n'
84 << "outer iterations: " << stats.outer_iterations << '\n'
85 << "ε = " << stats.ε << '\n'
86 << "δ = " << stats.δ << '\n'
87 << "elapsed time: "
88 << std::chrono::duration<double>{stats.elapsed_time}.count() << " s"
89 << '\n'
90 << "x = " << x.transpose() << '\n'
91 << "y = " << y.transpose() << '\n'
92 << "avg τ = " << (stats.inner.sum_τ / stats.inner.count_τ) << '\n'
93 << "L-BFGS rejected = " << stats.inner.direction_update_rejected << '\n'
94 << "L-BFGS failures = " << stats.inner.direction_failures << '\n'
95 << "Line search failures = " << stats.inner.linesearch_failures << '\n'
96 << std::endl;
97}
int main(int argc, const char *argv[])
Augmented Lagrangian Method solver.
Box general_bounds
Other constraints, .
Box variable_bounds
Constraints of the decision variables, .
length_t get_num_constraints() const
Number of constraints , num_constraints.
length_t get_num_variables() const
Number of decision variables , num_variables.
Class that loads a problem using dlopen.
real_t eval_objective(crvec x) const
#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...
EigenConfigd DefaultConfig