alpaqa 1.0.0a9
Nonconvex constrained optimization
Loading...
Searching...
No Matches
problem.cpp
Go to the documentation of this file.
6#if ALPAQA_HAVE_CASADI
8#endif
9#ifdef ALPAQA_HAVE_CUTEST
11#endif
12
13#include <filesystem>
14#include <fstream>
15#include <mutex>
16#include <optional>
17#include <span>
18#include <stdexcept>
19#include <string>
20
21#include "options.hpp"
22#include "problem.hpp"
23
24namespace fs = std::filesystem;
25
26namespace {
27
29
30std::string get_prefix_option(std::span<const std::string_view> prob_opts) {
31 std::string prefix = "alpaqa_problem";
32 std::string_view prefix_key = "prefix=";
33 auto prefix_it = std::find_if(
34 prob_opts.rbegin(), prob_opts.rend(),
35 [&](std::string_view opt) { return opt.starts_with(prefix_key); });
36 if (prefix_it != prob_opts.rend())
37 prefix = prefix_it->substr(prefix_key.size());
38 return prefix;
39}
40
41void load_initial_guess(Options &opts, LoadedProblem &problem) {
42 const auto n = problem.problem.get_n(), m = problem.problem.get_m();
43 alpaqa::params::vec_from_file<config_t> x0{n}, y0{m}, w0{2 * n};
44 set_params(x0, "x0", opts);
45 if (x0.value)
46 problem.initial_guess_x = std::move(*x0.value);
47 set_params(y0, "mul_g0", opts);
48 if (y0.value)
49 problem.initial_guess_y = std::move(*y0.value);
50 set_params(w0, "mul_x0", opts);
51 if (w0.value)
52 problem.initial_guess_w = std::move(*w0.value);
53}
54
55LoadedProblem load_dl_problem(const fs::path &full_path,
56 std::span<std::string_view> prob_opts,
57 Options &opts) {
59 using DLProblem = alpaqa::dl::DLProblem;
61 auto prefix = get_prefix_option(prob_opts);
62 std::any dl_opt = prob_opts;
63 LoadedProblem problem{
64 .problem = TEProblem::make<CntProblem>(std::in_place, full_path.c_str(),
65 prefix, &dl_opt),
66 .abs_path = fs::absolute(full_path),
67 .path = full_path,
68 };
69 auto &cnt_problem = problem.problem.as<CntProblem>();
70 try {
71 using sig_t = std::string(const DLProblem::instance_t *);
72 problem.name = cnt_problem.problem.call_extra_func<sig_t>("get_name");
73 } catch (std::out_of_range &) {
74 problem.name = problem.path.filename();
75 }
76 problem.evaluations = cnt_problem.evaluations;
77 load_initial_guess(opts, problem);
78 return problem;
79}
80
81#if ALPAQA_HAVE_CASADI
82template <bool = true>
83LoadedProblem load_cs_problem(const fs::path &full_path,
84 std::span<std::string_view> prob_opts,
85 Options &opts) {
86 static std::mutex mtx;
87 std::unique_lock lck{mtx};
89 using CsProblem = alpaqa::CasADiProblem<config_t>;
91 LoadedProblem problem{
92 .problem =
93 TEProblem::make<CntProblem>(std::in_place, full_path.c_str()),
94 .abs_path = fs::absolute(full_path),
95 .path = full_path,
96 };
97 lck.unlock();
98 auto &cnt_problem = problem.problem.as<CntProblem>();
99 auto &cs_problem = cnt_problem.problem;
100 problem.name = problem.path.filename();
101 problem.evaluations = cnt_problem.evaluations;
102 auto param_size = cs_problem.param.size();
103 alpaqa::params::set_params(cs_problem.param, "param", prob_opts);
104 if (cs_problem.param.size() != param_size)
106 "Incorrect problem parameter size: got " +
107 std::to_string(cs_problem.param.size()) + ", should be " +
108 std::to_string(param_size));
109 load_initial_guess(opts, problem);
110 return problem;
111}
112#endif
113
114#ifdef ALPAQA_HAVE_CUTEST
115template <bool = true>
116LoadedProblem load_cu_problem(const fs::path &full_path,
117 std::span<std::string_view> prob_opts,
118 Options &opts) {
119 std::string outsdif_path;
120 alpaqa::params::set_params(outsdif_path, "outsdif", prob_opts);
121 if (outsdif_path.empty())
122 outsdif_path = full_path.parent_path() / "OUTSDIF.d";
123 bool sparse = false;
124 alpaqa::params::set_params(sparse, "sparse", prob_opts);
125 static std::mutex mtx;
126 std::unique_lock lck{mtx};
127 using TEProblem = alpaqa::TypeErasedProblem<config_t>;
128 using CuProblem = alpaqa::CUTEstProblem;
130 LoadedProblem problem{
131 .problem = TEProblem::make<CntProblem>(std::in_place, full_path.c_str(),
132 outsdif_path.c_str(), sparse),
133 .abs_path = fs::absolute(full_path),
134 .path = full_path,
135 };
136 lck.unlock();
137 auto &cnt_problem = problem.problem.as<CntProblem>();
138 auto &cu_problem = cnt_problem.problem;
139 problem.name = cu_problem.name;
140 problem.evaluations = cnt_problem.evaluations;
141 problem.initial_guess_x = std::move(cu_problem.x0);
142 problem.initial_guess_y = std::move(cu_problem.y0);
143 load_initial_guess(opts, problem);
144 return problem;
145}
146#endif
147
148} // namespace
149
150LoadedProblem load_problem(std::string_view type, const fs::path &dir,
151 const fs::path &file, Options &opts) {
153 // Isolate problem-specific options
154 std::vector<std::string_view> prob_opts;
155 std::string_view prob_prefix = "problem.";
156 auto options = opts.options();
157 auto used = opts.used();
158 for (auto opt = options.begin(); opt != options.end(); ++opt) {
159 if (opt->starts_with(prob_prefix)) {
160 prob_opts.push_back(opt->substr(prob_prefix.size()));
161 ++used.begin()[opt - options.begin()];
162 }
163 }
164 // Load problem
165 auto full_path = dir / file;
166 if (type == "dl" || type.empty()) {
167 return load_dl_problem(full_path, prob_opts, opts);
168 } else if (type == "cs") {
169#if ALPAQA_HAVE_CASADI
170 if constexpr (std::is_same_v<config_t, alpaqa::EigenConfigd>)
171 return load_cs_problem(full_path, prob_opts, opts);
172 else
173 throw std::logic_error("CasADi only supports double precision.");
174#else
175 throw std::logic_error(
176 "This version of alpaqa was compiled without CasADi support");
177#endif
178 } else if (type == "cu") {
179#ifdef ALPAQA_HAVE_CUTEST
180 if constexpr (std::is_same_v<config_t, alpaqa::EigenConfigd>)
181 return load_cu_problem(full_path, prob_opts, opts);
182 else
183 throw std::logic_error("CUTEst only supports double precision.");
184#else
185 throw std::logic_error(
186 "This version of alpaqa was compiled without CUTEst support");
187#endif
188 }
189 throw std::invalid_argument("Unknown problem type '" + std::string(type) +
190 "'");
191}
std::span< unsigned > used()
Definition: options.hpp:23
std::span< const std::string_view > options() const
Definition: options.hpp:20
Wrapper for CUTEst problems loaded from an external shared library.
Problem definition for a CasADi problem, loaded from a DLL.
The main polymorphic minimization problem interface.
length_t get_n() const
[Required] Number of decision variables.
length_t get_m() const
[Required] Number of constraints.
Class that loads a problem using dlopen.
Definition: dl-problem.hpp:92
T & as() &
Convert the type-erased object to the given type.
#define USING_ALPAQA_CONFIG(Conf)
Definition: config.hpp:54
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
decltype(auto) set_params(T &t, std::string_view prefix, Options &opts)
Definition: options.hpp:27
LoadedProblem load_problem(std::string_view type, const fs::path &dir, const fs::path &file, Options &opts)
Definition: problem.cpp:150
vec initial_guess_y
Unknowns.
Definition: problem.hpp:21
vec initial_guess_x
Definition: problem.hpp:20
vec initial_guess_w
Multipliers g.
Definition: problem.hpp:22
alpaqa::TypeErasedProblem< config_t > problem
Definition: problem.hpp:15
std::string name
Definition: problem.hpp:18
fs::path path
Definition: problem.hpp:17
std::shared_ptr< alpaqa::EvalCounter > evaluations
Definition: problem.hpp:19
Double-precision double configuration.
Definition: config.hpp:127
Problem wrapper that keeps track of the number of evaluations and the run time of each function.
Custom parameter parsing exception.
Definition: params.hpp:26