116int main(
int argc,
const char *argv[])
try {
118 SetConsoleOutputCP(CP_UTF8);
127 std::span args{argv,
static_cast<size_t>(argc)};
128 Options opts{argc - 2, argv + 2};
131 std::ostream &os = std::cout;
137 os <<
"Loading problem " << prob_path << std::endl;
138 auto problem =
load_problem(prob_type, prob_path.parent_path(),
139 prob_path.filename(), opts);
140 os <<
"Loaded problem " << problem.path.stem().string() <<
" from "
141 << problem.path <<
"\nnvar: " << problem.problem.get_n()
142 <<
"\nncon: " << problem.problem.get_m() <<
"\nProvided functions:\n";
147 auto has_opt = [&opts](std::string_view o) {
148 auto o_it = std::ranges::find(opts.options(), o);
149 if (o_it == opts.options().end())
151 auto index =
static_cast<size_t>(o_it - opts.options().begin());
152 ++opts.used()[index];
157 .hessians = !has_opt(
"--no-hessians"),
161 auto seed =
static_cast<unsigned int>(std::time(
nullptr));
166 auto used = opts.used();
167 auto unused_opt = std::ranges::find(used, 0);
168 auto unused_idx =
static_cast<size_t>(unused_opt - used.begin());
169 if (unused_opt != used.end())
170 throw std::invalid_argument(
"Unused option: " +
171 std::string(opts.options()[unused_idx]));
176}
catch (std::exception &e) {
178 << e.what() << std::endl;
200 const auto n = x.size();
201 std::vector<Eigen::Triplet<real_t, index_t>> coo;
202 vec h = vec::Zero(n);
204 const auto δ = 1e-2 * ε;
205 vec grad_x(n), grad_xh(n);
207 for (index_t i = 0; i < n; ++i) {
208 real_t hh = std::abs(x(i)) * ε > δ ? x(i) * ε : δ;
210 grad_L(x + h, grad_xh);
211 grad_xh = (grad_xh - grad_x) / hh;
212 for (index_t j = 0; j < n; ++j)
213 if (real_t v = grad_xh(j); v != 0)
214 coo.emplace_back(std::min(j, i), std::max(i, j),
215 v * (i == j ? 1 : 0.5));
218 Eigen::SparseMatrix<real_t, 0, index_t> hess(n, n);
219 hess.setFromTriplets(coo.begin(), coo.end());
243 auto &te_problem = lproblem.
problem;
248 auto n = te_problem.get_n(), m = te_problem.get_m();
250 std::srand(
static_cast<unsigned int>(std::time(
nullptr)));
251 vec Σ = 1.5 * vec::Random(m).array() + 2;
252 vec y = y0 + y0.norm() * vec::Random(m);
253 vec x = x0 + sc * vec::Random(n);
254 vec v = 5e-6 * sc * vec::Random(n);
258 auto print_compare = [&log, &opts](
const auto &fd,
const auto &ad) {
259 auto abs_err = (fd - ad).reshaped().template lpNorm<Eigen::Infinity>();
261 abs_err / fd.reshaped().template lpNorm<Eigen::Infinity>();
270 auto f = [&](crvec x) {
return te_problem.eval_f(x); };
271 log <<
"Gradient verification: ∇f(x)\n";
274 te_problem.eval_grad_f(x, grad_f);
275 print_compare(fd_grad_f, grad_f);
277 log <<
"Gradient verification: ∇L(x)\n";
278 auto L = [&](crvec x) {
279 te_problem.eval_g(x, gx);
280 return te_problem.eval_f(x) + gx.dot(y);
284 te_problem.eval_grad_L(x, y, grad_L, wn);
285 print_compare(fd_grad_L, grad_L);
287 log <<
"Gradient verification: ∇ψ(x)\n";
288 auto ψ = [&](crvec x) {
return te_problem.eval_ψ(x, y, Σ, wm); };
291 te_problem.eval_grad_ψ(x, y, Σ, grad_ψ, wn, wm);
292 print_compare(fd_grad_ψ, grad_ψ);
294 if (te_problem.provides_eval_hess_L_prod()) {
295 log <<
"Hessian product verification: ∇²L(x)\n";
298 te_problem.eval_grad_L(xv, y, grad_Lv, wn);
299 vec fd_hess_Lv = grad_Lv - grad_L;
301 te_problem.eval_hess_L_prod(x, y, 1, v, hess_Lv);
302 print_compare(fd_hess_Lv, hess_Lv);
305 if (te_problem.provides_eval_hess_ψ_prod()) {
306 log <<
"Hessian product verification: ∇²ψ(x)\n";
309 te_problem.eval_grad_ψ(xv, y, Σ, grad_ψv, wn, wm);
310 vec fd_hess_ψv = grad_ψv - grad_ψ;
312 te_problem.eval_hess_ψ_prod(x, y, Σ, 1, v, hess_ψv);
313 print_compare(fd_hess_ψv, hess_ψv);
316 if (opts.
hessians && te_problem.provides_eval_hess_L()) {
317 log <<
"Hessian verification: ∇²L(x)\n";
319 auto sparsity = te_problem.get_hess_L_sparsity();
320 sp::SparsityConverter<sp::Sparsity<config_t>, sp::Dense<config_t>> cvt{
323 auto eval_h = [&](rvec v) { te_problem.eval_hess_L(x, y, 1., v); };
324 cvt.convert_values(eval_h, hess_L.reshaped());
326 [&](crvec x, rvec g) { te_problem.eval_grad_L(x, y, g, wn); }, x);
327 print_compare(fd_hess_L, hess_L);
330 if (opts.
hessians && te_problem.provides_eval_hess_ψ()) {
331 log <<
"Hessian verification: ∇²ψ(x)\n";
333 auto sparsity = te_problem.get_hess_ψ_sparsity();
334 sp::SparsityConverter<sp::Sparsity<config_t>, sp::Dense<config_t>> cvt{
337 auto eval_h = [&](rvec v) { te_problem.eval_hess_ψ(x, y, Σ, 1., v); };
338 cvt.convert_values(eval_h, hess_ψ.reshaped());
340 [&](crvec x, rvec g) {
341 te_problem.eval_grad_ψ(x, y, Σ, g, wn, wm);
344 print_compare(fd_hess_ψ, hess_ψ);