alpaqa no-casadi-dep
Nonconvex constrained optimization
Loading...
Searching...
No Matches
options.hpp
Go to the documentation of this file.
1#pragma once
2
6
7#include <algorithm>
8#include <ranges>
9#include <span>
10#include <stdexcept>
11#include <string_view>
12#include <vector>
13
14#if ALPAQA_WITH_JSON
16#include <nlohmann/json.hpp>
17#include <fstream>
18#else
20#endif
21
22class Options {
23 private:
24 std::vector<std::string_view> opts_storage;
25 std::vector<unsigned> used_storage;
26 size_t num_json;
27#if ALPAQA_WITH_JSON
28 std::vector<nlohmann::json> json_storage;
29 nlohmann::json json_out;
30#endif
31
32 public:
33 Options(int argc, const char *const argv[])
34 : opts_storage{argv, argv + argc} {
35 // Arguments starting with an '@' sign refer to JSON files with options
36 auto with_at = [](std::string_view s) { return s.starts_with('@'); };
37 // JSON options are always applied before command-line options
38 auto non_json = std::ranges::stable_partition(opts_storage, with_at);
39 num_json = static_cast<size_t>(non_json.begin() - opts_storage.begin());
40#if ALPAQA_WITH_JSON
41 // Load the JSON data for each '@' option
42 auto load = [](std::string_view s) {
43 return load_json(std::string(s.substr(1)));
44 };
45 auto json_obj = std::views::transform(json_flags(), load);
46 json_storage = decltype(json_storage){json_obj.begin(), json_obj.end()};
47#else
48 if (num_json > 0)
49 throw std::logic_error(
50 "This version of alpaqa was compiled without JSON support: "
51 "cannot parse options " +
52 alpaqa::util::join_quote(json_flags(), {.sep = " "}));
53#endif
54 // Keep track of which options are used
55 used_storage.resize(opts_storage.size() - num_json);
56 }
57 [[nodiscard]] std::span<const std::string_view> json_flags() const {
58 return std::span{opts_storage}.first(num_json);
59 }
60 [[nodiscard]] std::span<const std::string_view> options() const {
61 return std::span{opts_storage}.subspan(num_json);
62 }
63 [[nodiscard]] std::span<unsigned> used() { return used_storage; }
64
65 template <class T>
66 void set_params(T &t, std::string_view prefix);
67
68#if ALPAQA_WITH_JSON
69 [[nodiscard]] std::span<const nlohmann::json> json_data() const {
70 return json_storage;
71 }
72
73 [[nodiscard]] const nlohmann::json &get_json_out() const {
74 return json_out;
75 }
76
77 private:
78 [[nodiscard]] static nlohmann::json load_json(const std::string &name) {
79 nlohmann::json j;
80 std::ifstream f{name};
81 if (!f)
82 throw std::runtime_error("Unable to open JSON file '" + name + "'");
83 try {
84 f >> j;
85 } catch (nlohmann::json::exception &e) {
86 throw std::runtime_error("Unable to parse JSON file '" + name +
87 "': " + e.what());
88 }
89 return j;
90 }
91#endif
92};
93
94template <class T>
95void Options::set_params(T &t, std::string_view prefix) {
96#if ALPAQA_WITH_JSON
97 auto json_data = this->json_data();
98 for (size_t i = 0; i < json_data.size(); ++i)
99 try {
100 if (auto j = json_data[i].find(prefix); j != json_data[i].end())
103 std::string fname{this->json_flags()[i].substr(1)};
104 throw std::invalid_argument(
105 "Error in JSON file '" + fname + "' at '" +
106 std::string(prefix) +
107 alpaqa::util::join_quote(std::views::reverse(e.backtrace),
108 {.sep = "",
109 .empty = "",
110 .quote_left = ".",
111 .quote_right = ""}) +
112 "': " + e.what());
113 } catch (nlohmann::json::exception &e) {
114 std::string fname{this->json_flags()[i].substr(1)};
115 throw std::invalid_argument("Error in JSON file '" + fname +
116 "': " + e.what());
117 }
118#endif
119 alpaqa::params::set_params(t, prefix, this->options(), this->used());
120#if ALPAQA_WITH_JSON
122 if constexpr (!std::is_same_v<T, vec_from_file>)
123 alpaqa::params::get_param(t, this->json_out[std::string{prefix}]);
124#endif
125}
126
127template <class T>
128void set_params(T &t, std::string_view prefix, Options &opts) {
129 opts.set_params(t, prefix);
130}
std::span< unsigned > used()
Definition options.hpp:63
std::span< const std::string_view > json_flags() const
Definition options.hpp:57
std::span< const std::string_view > options() const
Definition options.hpp:60
std::vector< unsigned > used_storage
Definition options.hpp:25
size_t num_json
Definition options.hpp:26
void set_params(T &t, std::string_view prefix)
Definition options.hpp:95
std::vector< std::string_view > opts_storage
Definition options.hpp:24
Options(int argc, const char *const argv[])
Definition options.hpp:33
void get_param(const T &, json &j)
Get the first argument as a JSON object j.
Definition json.cpp:252
void set_param(T &, const json &j)
Update/overwrite the first argument based on the JSON object j.
Definition json.cpp:248
void set_params(T &t, std::string_view prefix, std::span< const std::string_view > options, std::optional< std::span< unsigned > > used=std::nullopt)
Overwrites t based on the options that start with prefix.
Definition params.hpp:49
std::string join_quote(std::ranges::input_range auto strings, join_quote_opt opt={})
Join the list of strings into a single string, using the separator given by opt.
void set_params(T &t, std::string_view prefix, Options &opts)
Definition options.hpp:128
Custom parameter parsing exception.
Definition json.hpp:28
std::vector< std::string > backtrace
Definition json.hpp:30