alpaqa 1.1.0a1
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_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 ! Evaluate the gradient of the cost, ∇f(x)
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 ! Evaluate the constraints, g(x)
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 ! Evaluate the matrix-vector product of the gradient of the constraints and
39 ! the vector y, ∇g(x) y
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 ! 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_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// Problem specification by inheriting from alpaqa::Problem
23struct FortranProblem : alpaqa::BoxConstrProblem<config_t> {
24 using alpaqa::BoxConstrProblem<config_t>::BoxConstrProblem;
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
42int main() {
43 alpaqa::init_stdout();
44
45 // Instantiate a problem
46 FortranProblem problem{problem_get_num_vars(), problem_get_num_constr()};
47 // Wrap the problem to count the function evaluations
48 auto counted_problem = alpaqa::problem_with_counters_ref(problem);
49
50 // Specify the bounds
51 const auto inf = alpaqa::inf<config_t>;
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 // Define the solvers to use
61 using InnerSolver = alpaqa::PANOCSolver<Direction>;
62 using OuterSolver = alpaqa::ALMSolver<InnerSolver>;
63
64 // Settings for the outer augmented Lagrangian method
65 OuterSolver::Params almparam;
66 almparam.tolerance = 1e-8; // tolerance
67 almparam.dual_tolerance = 1e-8;
68 almparam.penalty_update_factor = 10; // penalty update factor
69 almparam.max_iter = 20;
70 almparam.print_interval = 1;
71
72 // Settings for the inner PANOC solver
73 InnerSolver::Params panocparam;
74 panocparam.max_iter = 500;
75 panocparam.print_interval = 10;
76 // Settings for the L-BFGS algorithm used by PANOC
77 Direction::AcceleratorParams lbfgsparam;
78 lbfgsparam.memory = 2;
79
80 // Create an ALM solver using PANOC as inner solver
81 OuterSolver solver{
82 almparam, // params for outer solver
83 {panocparam, lbfgsparam}, // inner solver
84 };
85
86 // Initial guess
87 vec x(2);
88 x << 2, 2; // decision variables
89 vec y(1);
90 y << 1; // Lagrange multipliers
91
92 // Solve the problem
93 auto stats = solver(counted_problem, x, y);
94 // y and x have been overwritten by the solution
95
96 // Print the results
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.
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