This example shows how to define optimization problems using Fortran routines.
This example shows how to define optimization problems using Fortran routines.
It solves a simple quadratic program of the form:
\[ \begin{aligned}
& \underset{x}{\text{minimize}} && \tfrac12 \tp x Q x \\
& \text{subject to} && Ax \le b \\
\end{aligned} \]
Problem definition in Fortran
1module problem
2
3 use, intrinsic::iso_c_binding, only: c_double, c_ptrdiff_t
4 implicit none (type,external)
5
6 integer(c_ptrdiff_t), parameter :: n = 2
7 integer(c_ptrdiff_t), parameter :: m = 1
8 real(c_double) :: Q(n, n)
9 data q /3, -1, -1, 3/
10 real(c_double) :: A(m, n)
11 data a /2, 1/
12
13contains
14
15
16 pure real(c_double) function problem_eval_objective(x) bind(C)
17 real(c_double), intent(in) :: x(n)
18
19 problem_eval_objective = 0.5_c_double * dot_product(x, matmul(q, x))
20 end function
21
22
23 pure subroutine problem_eval_objective_gradient(x, grad_fx) bind(C)
24 real(c_double), intent(in) :: x(n)
25 real(c_double), intent(out) :: grad_fx(n)
26
27 grad_fx = matmul(q, x)
28 end subroutine
29
30
31 pure subroutine problem_eval_constraints(x, gx) bind(C)
32 real(c_double), intent(in) :: x(n)
33 real(c_double), intent(out) :: gx(m)
34
35 gx = matmul(a, x)
36 end subroutine
37
38
39
40 pure subroutine problem_eval_constraints_gradient_product(x, y, grad_gxy) bind(C)
41 real(c_double), intent(in) :: x(n)
42 real(c_double), intent(in) :: y(m)
43 real(c_double), intent(out) :: grad_gxy(n)
44
45 grad_gxy = matmul(transpose(a), y)
46 end subroutine
47
48
49 pure integer(c_ptrdiff_t) function problem_get_num_vars() bind(C)
50 problem_get_num_vars = n
51 end function
52
53
54 pure integer(c_ptrdiff_t) function problem_get_num_constr() bind(C)
55 problem_get_num_constr = m
56 end function
57
58end module
Problem solution using alpaqa
1#include <alpaqa/example-util.hpp>
5
6#include <iostream>
7
8
10
11
12extern "C" {
13ptrdiff_t problem_get_num_vars(void);
14ptrdiff_t problem_get_num_constr(void);
15double problem_eval_objective(const double *);
16void problem_eval_objective_gradient(const double *, double *);
17void problem_eval_constraints(const double *, double *);
18void problem_eval_constraints_gradient_product(const double *, const double *,
19 double *);
20}
21
22
25
26 real_t eval_objective(crvec x) const {
27 return problem_eval_objective(x.data());
28 }
29 void eval_objective_gradient(crvec x, rvec fx) const {
30 problem_eval_objective_gradient(x.data(), fx.data());
31 }
32 void eval_constraints(crvec x, rvec gx) const {
33 problem_eval_constraints(x.data(), gx.data());
34 }
35 void eval_constraints_gradient_product(crvec x, crvec y,
36 rvec grad_gxy) const {
37 problem_eval_constraints_gradient_product(x.data(), y.data(),
38 grad_gxy.data());
39 }
40};
41
43 alpaqa::init_stdout();
44
45
46 FortranProblem problem{problem_get_num_vars(), problem_get_num_constr()};
47
49
50
52 const auto n = problem.num_variables, m = problem.num_constraints;
53 vec b = vec::Constant(m, -1);
54 problem.variable_bounds.lower = vec::Constant(n, -inf);
55 problem.variable_bounds.upper = vec::Constant(n, +inf);
56 problem.general_bounds.lower = vec::Constant(m, -inf);
57 problem.general_bounds.upper = b;
58
59
63
64
65 OuterSolver::Params almparam;
66 almparam.tolerance = 1e-8;
67 almparam.dual_tolerance = 1e-8;
68 almparam.penalty_update_factor = 10;
69 almparam.max_iter = 20;
70 almparam.print_interval = 1;
71
72
73 InnerSolver::Params panocparam;
74 panocparam.max_iter = 500;
75 panocparam.print_interval = 10;
76
77 Direction::AcceleratorParams lbfgsparam;
78 lbfgsparam.memory = 2;
79
80
81 OuterSolver solver{
82 almparam,
83 {panocparam, lbfgsparam},
84 };
85
86
88 x << 2, 2;
90 y << 1;
91
92
93 auto stats = solver(counted_problem, x, y);
94
95
96
97 std::cout << '\n' << *counted_problem.evaluations << '\n';
98 std::cout
99 << "status: " << stats.status << '\n'
100 << "solver: " << solver.get_name() << '\n'
101 << "f = " << problem.eval_objective(x) << '\n'
102 << "inner iterations: " << stats.inner.iterations << '\n'
103 << "outer iterations: " << stats.outer_iterations << '\n'
104 << "ε = " << stats.ε << '\n'
105 << "δ = " << stats.δ << '\n'
106 << "elapsed time: "
107 << std::chrono::duration<double>{stats.elapsed_time}.count() << " s"
108 << '\n'
109 << "x = " << x.transpose() << '\n'
110 << "y = " << y.transpose() << '\n'
111 << "avg τ = " << (stats.inner.sum_τ / stats.inner.count_τ) << '\n'
112 << "L-BFGS rejected = " << stats.inner.direction_update_rejected << '\n'
113 << "L-BFGS failures = " << stats.inner.direction_failures << '\n'
114 << "Line search failures = " << stats.inner.linesearch_failures << '\n'
115 << std::endl;
116}
int main(int argc, const char *argv[])
Augmented Lagrangian Method solver.
Implements common problem functions for minimization problems with box constraints.
#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.