alpaqa 1.0.0a18
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(show_funcs, "Print the provided problem functions"), //
134 PARAMS_MEMBER(problem, "Options to pass to the problem"), //
136
138
139} // namespace alpaqa::params
140
144
145void add_root_opts(std::vector<Result::Member> &v) {
146 MemberGetter s{};
147 auto r = get_members<alpaqa::params::RootOpts>(s);
148 for (auto &e : r.members)
149 v.push_back(e);
150}
151
152template <class S>
154 auto [key, remainder] = alpaqa::util::split(s.key, ".");
155 auto recurse = s;
156 recurse.key = remainder;
157
158 if (key == "alm")
159 return get_members<alpaqa::ALMParams<config_t>>(recurse);
160 if (key == "solver")
161 return get_members<typename S::Params>(recurse);
162 if (key == "dir")
163 return get_members<typename S::Direction::DirectionParams>(recurse);
164 if (key == "accel")
165 return get_members<typename S::Direction::AcceleratorParams>(recurse);
166 if (key.end() != s.key.end() || s.value) // no remainder && no '.'
167 return {.leaf = false, .prefix = "", .members = {}};
168 return {
169 .leaf = false,
170 .prefix = "",
171 .members = {{.name = "alm",
172 .doc = "Options for the augmented Lagrangian method",
173 .suffix = '.'},
174 {.name = "solver",
175 .doc = "Options for the inner solver",
176 .suffix = '.'},
177 {.name = "dir",
178 .doc = "Options for the direction provider",
179 .suffix = '.'},
180 {.name = "accel",
181 .doc = "Options for the accelerator",
182 .suffix = '.'}},
183 };
184}
185
186template <class S>
188 auto [key, remainder] = alpaqa::util::split(s.key, ".");
189 auto recurse = s;
190 recurse.key = remainder;
191
192 if (key == "alm")
193 return get_members<alpaqa::ALMParams<config_t>>(recurse);
194 if (key == "solver")
195 return get_members<typename S::Params>(recurse);
196 if (key.end() != s.key.end() || s.value)
197 return {.leaf = false, .prefix = "", .members = {}};
198 return {
199 .leaf = false,
200 .prefix = "",
201 .members = {{.name = "alm",
202 .doc = "Options for the augmented Lagrangian method",
203 .suffix = '.'},
204 {.name = "solver",
205 .doc = "Options for the inner solver",
206 .suffix = '.'}},
207 };
208}
209
210using func_t = Result(const MemberGetter &);
211struct Method {
212 // std::function<func_t> func;
214 std::string_view doc;
215};
216using dict_t = std::map<std::string_view, Method>;
217
219 // clang-format off
220 {"panoc", {get_results_panoc_like<alpaqa::PANOCSolver<alpaqa::LBFGSDirection<config_t>>>, "PANOC + LBFGS solver (default)"}},
221 {"panoc.lbfgs", {get_results_panoc_like<alpaqa::PANOCSolver<alpaqa::LBFGSDirection<config_t>>>, "PANOC + LBFGS solver"}},
222 {"panoc.struclbfgs", {get_results_panoc_like<alpaqa::PANOCSolver<alpaqa::StructuredLBFGSDirection<config_t>>>, "PANOC + Structured LBFGS solver"}},
223 {"panoc.anderson", {get_results_panoc_like<alpaqa::PANOCSolver<alpaqa::AndersonDirection<config_t>>>, "PANOC + Anderson acceleration solver"}},
224 {"panoc.convex-newton", {get_results_panoc_like<alpaqa::PANOCSolver<alpaqa::ConvexNewtonDirection<config_t>>>, "PANOC + Newton (for convex problems)"}},
225 {"zerofpr", {get_results_panoc_like<alpaqa::ZeroFPRSolver<alpaqa::LBFGSDirection<config_t>>>, "ZeroFPR + LBFGS solver"}},
226 {"zerofpr.lbfgs", {get_results_panoc_like<alpaqa::ZeroFPRSolver<alpaqa::LBFGSDirection<config_t>>>, "ZeroFPR + LBFGS solver"}},
227 {"zerofpr.struclbfgs", {get_results_panoc_like<alpaqa::ZeroFPRSolver<alpaqa::StructuredLBFGSDirection<config_t>>>, "ZeroFPR + Structured LBFGS solver"}},
228 {"zerofpr.anderson", {get_results_panoc_like<alpaqa::ZeroFPRSolver<alpaqa::AndersonDirection<config_t>>>, "ZeroFPR + Anderson acceleration solver"}},
229 {"zerofpr.convex-newton", {get_results_panoc_like<alpaqa::PANOCSolver<alpaqa::ConvexNewtonDirection<config_t>>>, "ZeroFPR + Newton (for convex problems)"}},
230 {"pantr", {get_results_panoc_like<alpaqa::PANTRSolver<alpaqa::NewtonTRDirection<config_t>>>, "PANTR solver"}},
231 {"fista", {get_results_fista_like<alpaqa::FISTASolver<config_t>>, "FISTA solver"}},
232 {"ipopt", {alpaqa::params::get_members<void>, "Ipopt solver"}},
233 {"qpalm", {alpaqa::params::get_members<void>, "QPALM solver"}},
234 // clang-format on
235};
236
237Result get_results(std::string_view method, const MemberGetter &s) {
238 if (s.key == "method") {
239 auto members = std::views::transform(methods, [](const auto &e) {
240 return Result::Member{
241 .name = e.first,
242 .doc = e.second.doc,
243 .suffix = std::nullopt,
244 };
245 });
246 return {
247 .leaf = true,
248 .prefix = "method",
249 .members = {members.begin(), members.end()},
250 };
251 }
252
253 if (method.empty())
254 method = "panoc";
255 try {
256 const auto &m = methods.at(method);
257 auto result = m.func(s);
258 if (result.members.empty())
259 result = get_members<alpaqa::params::RootOpts>(s);
260 else if (result.prefix.empty())
261 add_root_opts(result.members);
262 return result;
263 } catch (std::out_of_range &) {
264 return get_members<alpaqa::params::RootOpts>(s);
265 }
266}
267
268void print_completion(std::string_view method, std::string_view params) {
269 auto [key, value] = alpaqa::util::split(params, "=");
270 bool has_value = key.end() != params.end();
271 MemberGetter s{
272 .full_key = key,
273 .key = key,
274 .value = has_value ? std::make_optional(value) : std::nullopt,
275 };
276 auto result = get_results(method, s);
277 if (!result.members.empty()) {
278 std::cout << "_prefix:" << result.prefix;
279 if (!result.prefix.empty() && result.prefix.back() != '.')
280 std::cout << (result.leaf ? '=' : '.');
281 std::cout << "\n_suffix:";
282 if (result.leaf)
283 std::cout << ' ';
284 std::cout << '\n';
285 size_t max_len =
286 std::accumulate(result.members.begin(), result.members.end(),
287 size_t{0}, [](size_t acc, const auto &m) {
288 return std::max(acc, m.name.size());
289 });
290 for (const auto &member : result.members) {
291 auto name = member.name;
292 std::string padding(max_len - std::min(max_len, name.size()), ' ');
293 std::cout << name;
294 if (member.suffix)
295 std::cout << *member.suffix;
296 std::cout << ':' << name;
297 if (member.doc) {
298 auto doc = member.doc->empty() ? "(undocumented)" : *member.doc;
299 std::cout << padding << " -- " << doc << " ";
300 }
301 std::cout << '\n';
302 }
303 }
304}
#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