117int main(
int argc, 
const char *argv[]) 
try {
 
  119    SetConsoleOutputCP(CP_UTF8);
 
  128    std::span args{argv, 
static_cast<size_t>(argc)};
 
  129    Options opts{argc - 2, argv + 2};
 
  132    std::ostream &os = std::cout;
 
  138    os << 
"Loading problem " << prob_path << std::endl;
 
  139    auto problem = 
load_problem(prob_type, prob_path.parent_path(),
 
  140                                prob_path.filename(), opts);
 
  141    os << 
"Loaded problem " << problem.path.stem().string() << 
" from " 
  142       << problem.path << 
"\nnvar: " << problem.problem.get_n()
 
  143       << 
"\nncon: " << problem.problem.get_m() << 
"\nProvided functions:\n";
 
  148    auto has_opt = [&opts](std::string_view o) {
 
  149        auto o_it = std::ranges::find(opts.options(), o);
 
  150        if (o_it == opts.options().end())
 
  152        auto index = 
static_cast<size_t>(o_it - opts.options().begin());
 
  153        ++opts.used()[index];
 
  158        .hessians            = !has_opt(
"--no-hessians"),
 
  159        .scale_perturbations = 1e-2,
 
  161    set_params(cg_opts.scale_perturbations, 
"--scale-perturbations", opts);
 
  164    auto seed = 
static_cast<unsigned int>(std::time(
nullptr));
 
  169    auto used       = opts.used();
 
  170    auto unused_opt = std::ranges::find(used, 0);
 
  171    auto unused_idx = 
static_cast<size_t>(unused_opt - used.begin());
 
  172    if (unused_opt != used.end())
 
  173        throw std::invalid_argument(
"Unused option: " +
 
  174                                    std::string(opts.options()[unused_idx]));
 
  179} 
catch (std::exception &e) {
 
  181              << e.what() << std::endl;
 
 
  231    const auto n = x.size();
 
  232    std::vector<Eigen::Triplet<real_t, index_t>> coo;
 
  233    vec h        = vec::Zero(n);
 
  235    const auto δ = 1e-2 * ε;
 
  236    vec grad_x(n), grad_xh(n);
 
  238    for (index_t i = 0; i < n; ++i) {
 
  239        real_t hh = std::abs(x(i)) * ε > δ ? x(i) * ε : δ;
 
  241        grad_L(x + h, grad_xh);
 
  242        grad_xh = (grad_xh - grad_x) / hh;
 
  243        for (index_t j = 0; j < n; ++j)
 
  244            if (real_t v = grad_xh(j); v != 0)
 
  245                coo.emplace_back(std::min(j, i), std::max(i, j),
 
  246                                 v * (i == j ? 1 : 0.5));
 
  249    Eigen::SparseMatrix<real_t, 0, index_t> hess(n, n);
 
  250    hess.setFromTriplets(coo.begin(), coo.end());
 
 
  274    auto &te_problem = lproblem.
problem;
 
  279    auto n = te_problem.get_n(), m = te_problem.get_m();
 
  281    std::srand(
static_cast<unsigned int>(std::time(
nullptr)));
 
  282    vec Σ = 1.5 * vec::Random(m).array() + 2;
 
  284    vec x = x0 + sc * vec::Random(n);
 
  285    vec v = 5e-6 * sc * vec::Random(n);
 
  289    auto print_compare = [&log, &opts](
const auto &other, 
const auto &ref) {
 
  291            (ref - other).reshaped().template lpNorm<Eigen::Infinity>();
 
  293            abs_err / ref.reshaped().template lpNorm<Eigen::Infinity>();
 
  301    auto print_compare_scal = [&log, &opts](
const auto &fd, 
const auto &ad) {
 
  302        auto abs_err = std::abs(fd - ad);
 
  303        auto rel_err = abs_err / std::abs(fd);
 
  312    auto f = [&](crvec x) { 
return te_problem.eval_f(x); };
 
  313    log << 
"Gradient verification: ∇f(x) (grad_f compared to finite " 
  314           "differences of f)\n";
 
  317    te_problem.eval_grad_f(x, grad_f);
 
  318    print_compare(grad_f, fd_grad_f);
 
  320    if (te_problem.provides_eval_f_grad_f()) {
 
  321        log << 
"Gradient verification: ∇f(x) (f_grad_f compared to grad_f)\n";
 
  323        auto f2 = te_problem.eval_f_grad_f(x, f_grad_f);
 
  324        print_compare(f_grad_f, grad_f);
 
  325        log << 
"Function verification: f(x) (f_grad_f compared to f)\n";
 
  326        print_compare_scal(f2, fx);
 
  329    log << 
"Gradient verification: ∇L(x) (grad_L compared to finite " 
  330           "differences of f + yᵀg)\n";
 
  331    auto L = [&](crvec x) {
 
  332        te_problem.eval_g(x, gx);
 
  333        return te_problem.eval_f(x) + gx.dot(y);
 
  337    te_problem.eval_grad_L(x, y, grad_L, wn);
 
  338    print_compare(grad_L, fd_grad_L);
 
  340    log << 
"Gradient verification: ∇ψ(x) (grad_ψ compared to finite " 
  341           "differences of ψ)\n";
 
  342    auto ψ = [&](crvec x) { 
return te_problem.eval_ψ(x, y, Σ, wm); };
 
  345    te_problem.eval_grad_ψ(x, y, Σ, grad_ψ, wn, wm);
 
  346    print_compare(grad_ψ, fd_grad_ψ);
 
  348    log << 
"Gradient verification: ∇ψ(x) (grad_ψ compared to reference " 
  349           "implementation based on g, ∇f, ∇g)\n";
 
  350    vec grad_ψ_default(n);
 
  353    print_compare(grad_ψ, grad_ψ_default);
 
  354    log << 
"Function verification: ψ(x) (ψ compared to reference " 
  355           "implementation based on f, g)\n";
 
  356    print_compare_scal(ψx, ψ_default);
 
  358    if (te_problem.provides_eval_ψ_grad_ψ()) {
 
  359        log << 
"Gradient verification: ∇ψ(x) (grad_ψ compared to ψ_grad_ψ)\n";
 
  361        real_t ψ2 = te_problem.eval_ψ_grad_ψ(x, y, Σ, ψ_grad_ψ, wn, wm);
 
  362        print_compare(grad_ψ, ψ_grad_ψ);
 
  363        log << 
"Function verification: ψ(x) (ψ compared to ψ_grad_ψ)\n";
 
  364        print_compare_scal(ψx, ψ2);
 
  367    if (te_problem.provides_eval_hess_L_prod()) {
 
  368        log << 
"Hessian product verification: ∇²L(x) (hess_L_prod compared to " 
  369               "finite differences of grad_L)\n";
 
  372        te_problem.eval_grad_L(xv, y, grad_Lv, wn);
 
  373        vec fd_hess_Lv = grad_Lv - grad_L;
 
  375        te_problem.eval_hess_L_prod(x, y, 1, v, hess_Lv);
 
  376        print_compare(hess_Lv, fd_hess_Lv);
 
  379    if (te_problem.provides_eval_hess_ψ_prod()) {
 
  380        log << 
"Hessian product verification: ∇²ψ(x) (hess_ψ_prod compared to " 
  381               "finite differences of grad_ψ)\n";
 
  384        te_problem.eval_grad_ψ(xv, y, Σ, grad_ψv, wn, wm);
 
  385        vec fd_hess_ψv = grad_ψv - grad_ψ;
 
  387        te_problem.eval_hess_ψ_prod(x, y, Σ, 1, v, hess_ψv);
 
  388        print_compare(hess_ψv, fd_hess_ψv);
 
  391    if (opts.
hessians && te_problem.provides_eval_hess_L()) {
 
  392        log << 
"Hessian verification: ∇²L(x) (hess_L compared to finite " 
  393               "differences of grad_L)\n";
 
  395        auto sparsity = te_problem.get_hess_L_sparsity();
 
  396        sp::SparsityConverter<sp::Sparsity<config_t>, sp::Dense<config_t>> cvt{
 
  399        auto eval_h = [&](rvec v) { te_problem.eval_hess_L(x, y, 1., v); };
 
  400        cvt.convert_values(eval_h, hess_L.reshaped());
 
  402            [&](crvec x, rvec g) { te_problem.eval_grad_L(x, y, g, wn); }, x);
 
  403        print_compare(hess_L, fd_hess_L);
 
  406    if (opts.
hessians && te_problem.provides_eval_hess_ψ()) {
 
  407        log << 
"Hessian verification: ∇²ψ(x) (hess_ψ compared to finite " 
  408               "differences of grad_ψ)\\n";
 
  410        auto sparsity = te_problem.get_hess_ψ_sparsity();
 
  411        sp::SparsityConverter<sp::Sparsity<config_t>, sp::Dense<config_t>> cvt{
 
  414        auto eval_h = [&](rvec v) { te_problem.eval_hess_ψ(x, y, Σ, 1., v); };
 
  415        cvt.convert_values(eval_h, hess_ψ.reshaped());
 
  417            [&](crvec x, rvec g) {
 
  418                te_problem.eval_grad_ψ(x, y, Σ, g, wn, wm);
 
  421        print_compare(hess_ψ, fd_hess_ψ);