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