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