alpaqa pi-pico
Nonconvex constrained optimization
Loading...
Searching...
No Matches
C++/FortranProblem/main.cpp

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 ! Evaluate the cost, f(x)
16 pure real(c_double) function problem_eval_f(x) bind(C)
17 real(c_double), intent(in) :: x(n)
18
19 problem_eval_f = 0.5_c_double * dot_product(x, matmul(q, x))
20 end function
21
22 ! Evaluate the gradient of the cost, ∇f(x)
23 pure subroutine problem_eval_grad_f(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 ! Evaluate the constraints, g(x)
31 pure subroutine problem_eval_g(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 ! Evaluate the matrix-vector product of the gradient of the constraints and
39 ! the vector y, ∇g(x) y
40 pure subroutine problem_eval_grad_g_prod(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 ! Get the number of variables of the problem
49 pure integer(c_ptrdiff_t) function problem_get_num_vars() bind(C)
50 problem_get_num_vars = n
51 end function
52
53 ! Get the number of constraints of the problem
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// Double precision, same as in Fortran
10
11// External Fortran routines
12extern "C" {
13ptrdiff_t problem_get_num_vars(void);
14ptrdiff_t problem_get_num_constr(void);
15double problem_eval_f(const double *);
16void problem_eval_grad_f(const double *, double *);
17void problem_eval_g(const double *, double *);
18void problem_eval_grad_g_prod(const double *, const double *, double *);
19}
20
21// Problem specification by inheriting from alpaqa::Problem
22struct FortranProblem : alpaqa::BoxConstrProblem<config_t> {
23 using alpaqa::BoxConstrProblem<config_t>::BoxConstrProblem;
24
25 real_t eval_f(crvec x) const { return problem_eval_f(x.data()); }
26 void eval_grad_f(crvec x, rvec fx) const {
27 problem_eval_grad_f(x.data(), fx.data());
28 }
29 void eval_g(crvec x, rvec gx) const { problem_eval_g(x.data(), gx.data()); }
30 void eval_grad_g_prod(crvec x, crvec y, rvec grad_gxy) const {
31 problem_eval_grad_g_prod(x.data(), y.data(), grad_gxy.data());
32 }
33};
34
35int main() {
37
38 // Instantiate a problem
39 FortranProblem problem{problem_get_num_vars(), problem_get_num_constr()};
40 // Wrap the problem to count the function evaluations
41 auto counted_problem = alpaqa::problem_with_counters_ref(problem);
42
43 // Specify the bounds
44 vec b = vec::Constant(problem.m, -1);
45 problem.C.lowerbound = vec::Constant(problem.n, -alpaqa::inf<config_t>);
46 problem.C.upperbound = vec::Constant(problem.n, +alpaqa::inf<config_t>);
47 problem.D.lowerbound = vec::Constant(problem.m, -alpaqa::inf<config_t>);
48 problem.D.upperbound = b;
49
50 // Define the solvers to use
52 using InnerSolver = alpaqa::PANOCSolver<Direction>;
53 using OuterSolver = alpaqa::ALMSolver<InnerSolver>;
54
55 // Settings for the outer augmented Lagrangian method
56 OuterSolver::Params almparam;
57 almparam.tolerance = 1e-8; // tolerance
58 almparam.dual_tolerance = 1e-8;
59 almparam.penalty_update_factor = 10; // penalty update factor
60 almparam.max_iter = 20;
61 almparam.print_interval = 1;
62
63 // Settings for the inner PANOC solver
64 InnerSolver::Params panocparam;
65 panocparam.max_iter = 500;
66 panocparam.print_interval = 10;
67 // Settings for the L-BFGS algorithm used by PANOC
68 Direction::AcceleratorParams lbfgsparam;
69 lbfgsparam.memory = 2;
70
71 // Create an ALM solver using PANOC as inner solver
72 OuterSolver solver{
73 almparam, // params for outer solver
74 {panocparam, lbfgsparam}, // inner solver
75 };
76
77 // Initial guess
78 vec x(2);
79 x << 2, 2; // decision variables
80 vec y(1);
81 y << 1; // Lagrange multipliers
82
83 // Solve the problem
84 auto stats = solver(counted_problem, x, y);
85 // y and x have been overwritten by the solution
86
87 // Print the results
88 std::cout << '\n' << *counted_problem.evaluations << '\n';
89 std::cout << "status: " << stats.status << '\n'
90 << "solver: " << solver.get_name() << '\n'
91 << "f = " << problem.eval_f(x) << '\n'
92 << "inner iterations: " << stats.inner.iterations << '\n'
93 << "outer iterations: " << stats.outer_iterations << '\n'
94 << "ε = " << stats.ε << '\n'
95 << "δ = " << stats.δ << '\n'
96 << "elapsed time: "
97 << std::chrono::duration<double>{stats.elapsed_time}.count()
98 << " s" << '\n'
99 << "x = " << x.transpose() << '\n'
100 << "y = " << y.transpose() << '\n'
101 << "avg τ = " << (stats.inner.sum_τ / stats.inner.count_τ) << '\n'
102 << "L-BFGS rejected = " << stats.inner.lbfgs_rejected << '\n'
103 << "L-BFGS failures = " << stats.inner.lbfgs_failures << '\n'
104 << "Line search failures = " << stats.inner.linesearch_failures
105 << '\n'
106 << std::endl;
107}
int main(int argc, const char *argv[])
Augmented Lagrangian Method solver.
Definition alm.hpp:69
Implements common problem functions for minimization problems with box constraints.
PANOC solver for ALM.
Definition panoc.hpp:142
#define USING_ALPAQA_CONFIG(Conf)
Definition config.hpp:77
auto problem_with_counters_ref(Problem &p)
Wraps the given problem into a ProblemWithCounters and keeps track of how many times each function is...
constexpr const auto inf
Definition config.hpp:112
typename Conf::vec vec
Definition config.hpp:88
Double-precision double configuration.
Definition config.hpp:176