alpaqa no-casadi-dep
Nonconvex constrained optimization
Loading...
Searching...
No Matches
param-complete.cpp
Go to the documentation of this file.
1#include "param-complete.hpp"
2
6
7// For parameters
20#include <alpaqa/outer/alm.hpp>
21#if ALPAQA_WITH_OCP
23#endif
24// end
25
26#include <cstdio>
27#include <iostream>
28#include <numeric>
29#include <optional>
30#include <stdexcept>
31#include <string_view>
32using namespace std::string_view_literals;
33
35
36namespace alpaqa::params {
37
38template <class T>
39bool is_leaf() {
40 return !requires { attribute_table<T, MemberGetter>::table; };
41}
42
43/// Catch-all
44template <class T>
46 auto pfx = std::string_view{s.full_key.begin(), s.key.begin()};
47 return {.leaf = true, .prefix = pfx, .members = {}}; // no suggestions
48}
49
50/// Struct types
51template <class T>
52 requires requires { attribute_table<T, MemberGetter>::table; }
55 auto [key, remainder] = alpaqa::util::split(s.key, ".");
56 auto it = m.find(key);
57 if (it == m.end()) {
58 auto pfx = std::string_view{s.full_key.begin(), s.key.begin()};
59 if (key.end() != s.key.end() || s.value)
60 return {.leaf = false, .prefix = pfx, .members = {}};
61 auto members = std::views::transform(m, [](const auto &e) {
62 return Result::Member{
63 .name = e.first,
64 .doc = e.second.doc,
65 .suffix = e.second.leaf ? '=' : '.',
66 };
67 });
68 return {
69 .leaf = false,
70 .prefix = pfx,
71 .members = {members.begin(), members.end()},
72 };
73 }
74 auto recurse = s;
76 return it->second.get(recurse);
77}
78
79/// Enum types
80template <class T>
81 requires requires { enum_table<T, MemberGetter>::table; }
84 auto pfx = std::string_view{s.full_key.begin(), s.key.begin()};
85 auto members = std::views::transform(m, [](const auto &e) {
86 return Result::Member{
87 .name = e.first,
88 .doc = e.second.doc,
89 .suffix = std::nullopt,
90 };
91 });
92 return {
93 .leaf = true,
94 .prefix = pfx,
95 .members = {members.begin(), members.end()},
96 };
97}
98
99/// True/false
100template <>
102 auto pfx = std::string_view{s.full_key.begin(), s.key.begin()};
103 return {
104 .leaf = true,
105 .prefix = pfx,
106 .members = {{.name = "true"}, {.name = "false"}},
107 };
108}
109
110struct Value {};
111struct Struct {};
112
118
120
122 RootOpts, //
123 PARAMS_MEMBER(method, "Solver to use"), //
124 PARAMS_MEMBER(out, "File to write output to"), //
125 PARAMS_MEMBER(sol, "Folder to write the solutions and statistics to"), //
126 PARAMS_MEMBER(x0, "Initial guess for the solution"), //
127 PARAMS_MEMBER(mul_g0,
128 "Initial guess for the general constraint multipliers"), //
129 PARAMS_MEMBER(mul_x0,
130 "Initial guess for the bound constraint multipliers"), //
131 PARAMS_MEMBER(num_exp, "Number of times to repeat the experiment"), //
132 PARAMS_MEMBER(extra_stats, "Log more per-iteration solver statistics"), //
133 PARAMS_MEMBER(problem, "Options to pass to the problem"), //
135
137
138} // namespace alpaqa::params
139
143
144void add_root_opts(std::vector<Result::Member> &v) {
145 MemberGetter s{};
146 auto r = get_members<alpaqa::params::RootOpts>(s);
147 for (auto &e : r.members)
148 v.push_back(e);
149}
150
151template <class S>
153 auto [key, remainder] = alpaqa::util::split(s.key, ".");
154 auto recurse = s;
155 recurse.key = remainder;
156
157 if (key == "alm")
158 return get_members<alpaqa::ALMParams<config_t>>(recurse);
159 if (key == "solver")
160 return get_members<typename S::Params>(recurse);
161 if (key == "dir")
162 return get_members<typename S::Direction::DirectionParams>(recurse);
163 if (key == "accel")
164 return get_members<typename S::Direction::AcceleratorParams>(recurse);
165 if (key.end() != s.key.end() || s.value) // no remainder && no '.'
166 return {.leaf = false, .prefix = "", .members = {}};
167 return {
168 .leaf = false,
169 .prefix = "",
170 .members = {{.name = "alm",
171 .doc = "Options for the augmented Lagrangian method",
172 .suffix = '.'},
173 {.name = "solver",
174 .doc = "Options for the inner solver",
175 .suffix = '.'},
176 {.name = "dir",
177 .doc = "Options for the direction provider",
178 .suffix = '.'},
179 {.name = "accel",
180 .doc = "Options for the accelerator",
181 .suffix = '.'}},
182 };
183}
184
185template <class S>
187 auto [key, remainder] = alpaqa::util::split(s.key, ".");
188 auto recurse = s;
189 recurse.key = remainder;
190
191 if (key == "alm")
192 return get_members<alpaqa::ALMParams<config_t>>(recurse);
193 if (key == "solver")
194 return get_members<typename S::Params>(recurse);
195 if (key.end() != s.key.end() || s.value)
196 return {.leaf = false, .prefix = "", .members = {}};
197 return {
198 .leaf = false,
199 .prefix = "",
200 .members = {{.name = "alm",
201 .doc = "Options for the augmented Lagrangian method",
202 .suffix = '.'},
203 {.name = "solver",
204 .doc = "Options for the inner solver",
205 .suffix = '.'}},
206 };
207}
208
209using func_t = Result(const MemberGetter &);
210struct Method {
211 // std::function<func_t> func;
213 std::string_view doc;
214};
215using dict_t = std::map<std::string_view, Method>;
216
218 // clang-format off
219 {"panoc", {get_results_panoc_like<alpaqa::PANOCSolver<alpaqa::LBFGSDirection<config_t>>>, "PANOC + LBFGS solver (default)"}},
220 {"panoc.lbfgs", {get_results_panoc_like<alpaqa::PANOCSolver<alpaqa::LBFGSDirection<config_t>>>, "PANOC + LBFGS solver"}},
221 {"panoc.struclbfgs", {get_results_panoc_like<alpaqa::PANOCSolver<alpaqa::StructuredLBFGSDirection<config_t>>>, "PANOC + Structured LBFGS solver"}},
222 {"panoc.anderson", {get_results_panoc_like<alpaqa::PANOCSolver<alpaqa::AndersonDirection<config_t>>>, "PANOC + Anderson acceleration solver"}},
223 {"panoc.convex-newton", {get_results_panoc_like<alpaqa::PANOCSolver<alpaqa::ConvexNewtonDirection<config_t>>>, "PANOC + Newton (for convex problems)"}},
224 {"zerofpr", {get_results_panoc_like<alpaqa::ZeroFPRSolver<alpaqa::LBFGSDirection<config_t>>>, "ZeroFPR + LBFGS solver"}},
225 {"zerofpr.lbfgs", {get_results_panoc_like<alpaqa::ZeroFPRSolver<alpaqa::LBFGSDirection<config_t>>>, "ZeroFPR + LBFGS solver"}},
226 {"zerofpr.struclbfgs", {get_results_panoc_like<alpaqa::ZeroFPRSolver<alpaqa::StructuredLBFGSDirection<config_t>>>, "ZeroFPR + Structured LBFGS solver"}},
227 {"zerofpr.anderson", {get_results_panoc_like<alpaqa::ZeroFPRSolver<alpaqa::AndersonDirection<config_t>>>, "ZeroFPR + Anderson acceleration solver"}},
228 {"zerofpr.convex-newton", {get_results_panoc_like<alpaqa::PANOCSolver<alpaqa::ConvexNewtonDirection<config_t>>>, "ZeroFPR + Newton (for convex problems)"}},
229 {"pantr", {get_results_panoc_like<alpaqa::PANTRSolver<alpaqa::NewtonTRDirection<config_t>>>, "PANTR solver"}},
230 {"fista", {get_results_fista_like<alpaqa::FISTASolver<config_t>>, "FISTA solver"}},
231 {"ipopt", {alpaqa::params::get_members<void>, "Ipopt solver"}},
232 {"qpalm", {alpaqa::params::get_members<void>, "QPALM solver"}},
233 // clang-format on
234};
235
236Result get_results(std::string_view method, const MemberGetter &s) {
237 if (s.key == "method") {
238 auto members = std::views::transform(methods, [](const auto &e) {
239 return Result::Member{
240 .name = e.first,
241 .doc = e.second.doc,
242 .suffix = std::nullopt,
243 };
244 });
245 return {
246 .leaf = true,
247 .prefix = "method",
248 .members = {members.begin(), members.end()},
249 };
250 }
251
252 if (method.empty())
253 method = "panoc";
254 try {
255 const auto &m = methods.at(method);
256 auto result = m.func(s);
257 if (result.members.empty())
258 result = get_members<alpaqa::params::RootOpts>(s);
259 else if (result.prefix.empty())
260 add_root_opts(result.members);
261 return result;
262 } catch (std::out_of_range &) {
263 return get_members<alpaqa::params::RootOpts>(s);
264 }
265}
266
267void print_completion(std::string_view method, std::string_view params) {
268 auto [key, value] = alpaqa::util::split(params, "=");
269 bool has_value = key.end() != params.end();
270 MemberGetter s{
271 .full_key = key,
272 .key = key,
273 .value = has_value ? std::make_optional(value) : std::nullopt,
274 };
275 auto result = get_results(method, s);
276 if (!result.members.empty()) {
277 std::cout << "_prefix:" << result.prefix;
278 if (!result.prefix.empty() && result.prefix.back() != '.')
279 std::cout << (result.leaf ? '=' : '.');
280 std::cout << "\n_suffix:";
281 if (result.leaf)
282 std::cout << ' ';
283 std::cout << '\n';
284 size_t max_len =
285 std::accumulate(result.members.begin(), result.members.end(),
286 size_t{0}, [](size_t acc, const auto &m) {
287 return std::max(acc, m.name.size());
288 });
289 for (const auto &member : result.members) {
290 auto name = member.name;
291 std::string padding(max_len - std::min(max_len, name.size()), ' ');
292 std::cout << name;
293 if (member.suffix)
294 std::cout << *member.suffix;
295 std::cout << ':' << name;
296 if (member.doc) {
297 auto doc = member.doc->empty() ? "(undocumented)" : *member.doc;
298 std::cout << padding << " -- " << doc << " ";
299 }
300 std::cout << '\n';
301 }
302 }
303}
#define USING_ALPAQA_CONFIG(Conf)
Definition config.hpp:77
Result get_members(const MemberGetter &s)
Catch-all.
std::string_view key
The subkey to resolve next.
std::string_view full_key
Full key string, used for diagnostics.
Result get_members< bool >(const MemberGetter &s)
True/false.
std::optional< std::string_view > value
The value of the parameter to store.
Specialize this type to define the attribute name to attribute setters dictionaries for a struct type...
Definition structs.hpp:50
Specialize this type to define the enumerator name to value dictionaries for an enum type T.
Definition structs.hpp:103
auto split(std::string_view full, std::string_view tok)
Split the string full on the first occurrence of tok.
constexpr const auto inf
Definition config.hpp:112
Result get_results(std::string_view method, const MemberGetter &s)
Result get_results_fista_like(const MemberGetter &s)
Result(const MemberGetter &) func_t
std::map< std::string_view, Method > dict_t
Result get_results_panoc_like(const MemberGetter &s)
std::string_view doc
const dict_t methods
func_t * func
void print_completion(std::string_view method, std::string_view params)
void add_root_opts(std::vector< Result::Member > &v)
Double-precision double configuration.
Definition config.hpp:174
#define PARAMS_MEMBER(name,...)
Helper macro to easily initialize a alpaqa::params::attribute_table_t.
Definition structs.hpp:62
#define PARAMS_TABLE(type_,...)
Helper macro to easily specialize alpaqa::params::attribute_table.
Definition structs.hpp:53