alpaqa no-casadi-dep
Nonconvex constrained optimization
Loading...
Searching...
No Matches
C++/CustomControlCppProblem/main.cpp

Bare-bones example demonstrating how to define optimal control problems for alpaqa::PANOCOCPSolver.

Bare-bones example demonstrating how to define optimal control problems for alpaqa::PANOCOCPSolver.

2#include <alpaqa/example-util.hpp>
6
7#include <iomanip>
8#include <iostream>
9
10struct Problem {
12 using Box = alpaqa::Box<config_t>;
13
14 length_t N = 32, // Horizon length
15 nu = 1, // Number of inputs
16 nx = 2, // Number of states
17 nh = nu + nx, // Number of stage outputs
18 nh_N = nx, // Number of terminal outputs
19 nc = 0, // Number of stage constraints
20 nc_N = 0; // Number of terminal constraints
21
22 mat A, B;
23
24 Problem() : A(nx, nx), B(nx, nu) {
25 A.setIdentity();
26 B.setIdentity();
27 }
28
29 // Horizon length
30 [[nodiscard]] length_t get_N() const { return N; }
31 // Number of inputs
32 [[nodiscard]] length_t get_nu() const { return nu; }
33 // Number of states
34 [[nodiscard]] length_t get_nx() const { return nx; }
35 // Number of stage outputs
36 [[nodiscard]] length_t get_nh() const { return nh; }
37 // Number of terminal outputs
38 [[nodiscard]] length_t get_nh_N() const { return nh_N; }
39 // Number of stage constraints
40 [[nodiscard]] length_t get_nc() const { return nc; }
41 // Number of terminal constraints
42 [[nodiscard]] length_t get_nc_N() const { return nc_N; }
43
44 // Bound constraints on the inputs u.
45 void get_U(Box &U) const {
46 U.lowerbound.setConstant(-1);
47 U.upperbound.setConstant(+1);
48 }
49 // Bound constraints on function of the states
50 void get_D([[maybe_unused]] Box &D) const {}
51 // Bound constraints on function of the terminal state
52 void get_D_N([[maybe_unused]] Box &D) const {}
53
54 // Get the initial state
55 void get_x_init(rvec x_init) const { x_init.setConstant(10.); }
56
57 // Discrete-time dynamics x⁺ = f(x, u)
58 void eval_f([[maybe_unused]] index_t timestep, crvec x, crvec u,
59 rvec fxu) const {
60 fxu.noalias() = A * x + B * u;
61 }
62 // Jacobian of dynamics
63 void eval_jac_f([[maybe_unused]] index_t timestep, [[maybe_unused]] crvec x,
64 [[maybe_unused]] crvec u, rmat J_fxu) const {
65 J_fxu.leftCols(nx).noalias() = A;
66 J_fxu.rightCols(nu).noalias() = B;
67 }
68 // Gradient-vector product of dynamics
69 void eval_grad_f_prod([[maybe_unused]] index_t timestep,
70 [[maybe_unused]] crvec x, [[maybe_unused]] crvec u,
71 crvec p, rvec grad_fxu_p) const {
72 grad_fxu_p.topRows(nx).noalias() = A.transpose() * p;
73 grad_fxu_p.bottomRows(nu).noalias() = B.transpose() * p;
74 }
75 // Output mapping
76 void eval_h([[maybe_unused]] index_t timestep, crvec x, crvec u,
77 rvec h) const {
78 h.topRows(nx) = x;
79 h.bottomRows(nu) = u;
80 }
81 // Terminal output mapping
82 void eval_h_N(crvec x, rvec h) const { h = x; }
83 // Stage cost
84 [[nodiscard]] real_t eval_l([[maybe_unused]] index_t timestep,
85 crvec h) const {
86 return 0.5 * h.squaredNorm();
87 }
88 // Terminal cost
89 [[nodiscard]] real_t eval_l_N(crvec h) const {
90 return 5.0 * h.squaredNorm();
91 }
92 // Gradient of the cost l(h(x, u))
93 void eval_qr([[maybe_unused]] index_t timestep, [[maybe_unused]] crvec xu,
94 crvec h, rvec qr) const {
95 auto Jh_xu = mat::Identity(nx + nu, nx + nu);
96 auto &&grad_l = h;
97 qr = Jh_xu.transpose() * grad_l;
98 }
99 // Gradient of the terminal cost l_N(h_N(x))
100 void eval_q_N([[maybe_unused]] crvec x, crvec h, rvec q) const {
101 auto Jh_x = mat::Identity(nx, nx);
102 auto &&grad_l = 10 * h;
103 q = Jh_x.transpose() * grad_l;
104 }
105 // Hessian of stage cost w.r.t. x
106 void eval_add_Q([[maybe_unused]] index_t timestep,
107 [[maybe_unused]] crvec xu, [[maybe_unused]] crvec h,
108 rmat Q) const {
109 Q += mat::Identity(nx, nx);
110 }
111 // Hessian of terminal cost
112 void eval_add_Q_N([[maybe_unused]] crvec x, [[maybe_unused]] crvec h,
113 rmat Q) const {
114 Q += 10 * mat::Identity(nx, nx);
115 }
116 // Hessian of stage cost w.r.t. u
117 void eval_add_R_masked([[maybe_unused]] index_t timestep,
118 [[maybe_unused]] crvec xu, [[maybe_unused]] crvec h,
119 crindexvec mask, rmat R,
120 [[maybe_unused]] rvec work) const {
121 auto R_full = mat::Identity(nu, nu);
122 R.noalias() += R_full(mask, mask);
123 }
124 // Hessian of stage cost w.r.t. x and u
125 void eval_add_S_masked([[maybe_unused]] index_t timestep,
126 [[maybe_unused]] crvec xu, [[maybe_unused]] crvec h,
127 crindexvec mask, rmat S,
128 [[maybe_unused]] rvec work) const {
129 // Mixed derivatives are zero, so the following has no effect
130 using Eigen::indexing::all;
131 auto S_full = mat::Zero(nu, nx);
132 S += S_full(mask, all);
133 }
134 // Hessian-vector product of stage cost w.r.t. u
135 void eval_add_R_prod_masked([[maybe_unused]] index_t timestep,
136 [[maybe_unused]] crvec xu,
137 [[maybe_unused]] crvec h, crindexvec mask_J,
138 crindexvec mask_K, crvec v, rvec out,
139 [[maybe_unused]] rvec work) const {
140 // R is diagonal, and J ∩ K = ∅, so the following has no effect
141 auto R_full = mat::Identity(nu, nu);
142 out.noalias() += R_full(mask_J, mask_K) * v(mask_K);
143 }
144 // Hessian-vector product of stage cost w.r.t. u and x
145 void eval_add_S_prod_masked([[maybe_unused]] index_t timestep,
146 [[maybe_unused]] crvec xu,
147 [[maybe_unused]] crvec h,
148 [[maybe_unused]] crindexvec mask_K,
149 [[maybe_unused]] crvec v,
150 [[maybe_unused]] rvec out,
151 [[maybe_unused]] rvec work) const {
152 // Mixed derivatives are zero, so the following has no effect
153 using Eigen::indexing::all;
154 auto Sᵀ = mat::Zero(nx, nu);
155 out.noalias() += Sᵀ(all, mask_K) * v(mask_K);
156 }
157 [[nodiscard]] length_t get_R_work_size() const {
158 // No workspace needed to share data between eval_add_R_masked and
159 // eval_add_R_prod_masked
160 return 0;
161 }
162 [[nodiscard]] length_t get_S_work_size() const {
163 // No workspace needed to share data between eval_add_S_masked and
164 // eval_add_S_prod_masked
165 return 0;
166 }
167
168 // Project the Lagrange multipliers for ALM
169 void eval_proj_multipliers([[maybe_unused]] rvec y,
170 [[maybe_unused]] real_t M) const {
171 // Empty for unconstrained problems
172 }
173
174 // Get the distance to the feasible set
175 void eval_proj_diff_g([[maybe_unused]] crvec z,
176 [[maybe_unused]] rvec e) const {
177 // Empty for unconstrained problems
178 }
179
180 void check() const {
181 // You could do some sanity checks here
182 }
183};
184
185int main() {
188
189 // Problem
191
192 // Problem dimensions
193 const auto n = problem.get_N() * problem.get_nu(),
194 m = problem.get_N() * problem.get_nc() + problem.get_nc_N();
195
196 // Initial guess and other solver inputs
197 vec u = vec::Zero(n); // Inputs (single shooting)
198 vec y = vec::Zero(m); // Lagrange multipliers
199 vec μ = vec::Ones(m); // Penalty factors
200 vec e(m); // Constraint violation
201
202 // Solver
205 params.gn_interval = 1;
206 params.print_interval = 1;
208
209 // Solve
210 auto stats = solver(problem, {.tolerance = 1e-8}, u, y, μ, e);
211
212 // Print statistics
213 auto δ = e.lpNorm<Eigen::Infinity>();
214 auto time_s = std::chrono::duration<double>(stats.elapsed_time).count();
215 std::cout << '\n'
216 << *problem.evaluations << '\n'
217 << "solver: " << solver.get_name() << '\n'
218 << "status: " << stats.status << '\n'
219 << "ψ = " << alpaqa::float_to_str(stats.final_ψ) << '\n'
220 << "ε = " << alpaqa::float_to_str(stats.ε) << '\n'
221 << "δ = " << alpaqa::float_to_str(δ) << '\n'
222 << "time: " << alpaqa::float_to_str(time_s, 3) << " s\n"
223 << "iter: " << std::setw(6) << stats.iterations << '\n'
224 << "line search backtrack: " << std::setw(6)
225 << stats.linesearch_backtracks << '\n'
226 << "step size backtrack: " << std::setw(6)
227 << stats.stepsize_backtracks << '\n'
228 << "solution: ";
229 alpaqa::print_python(std::cout, u) << std::endl;
230}
int main(int argc, const char *argv[])
#define USING_ALPAQA_CONFIG(Conf)
Definition config.hpp:77
unsigned print_interval
When to print progress.
Definition panoc-ocp.hpp:59
unsigned gn_interval
How often to use a Gauss-Newton step. Zero to disable GN entirely.
Definition panoc-ocp.hpp:44
PANOCStopCrit stop_crit
What stopping criterion to use.
Definition panoc-ocp.hpp:40
Tuning parameters for the PANOC algorithm.
Definition panoc-ocp.hpp:17
@ ProjGradUnitNorm
∞-norm of the projected gradient with unit step size:
constexpr const auto inf
Definition config.hpp:112
std::ostream & print_python(std::ostream &os, const Eigen::DenseBase< Derived > &M, Args &&...args)
Definition print.hpp:69
std::string float_to_str(F value, int precision)
Definition print.tpp:67
std::shared_ptr< OCPEvalCounter > evaluations
Double-precision double configuration.
Definition config.hpp:174