6#include <guanaqo/dl-flags.hpp>
7#include <guanaqo/dl.hpp>
19using namespace std::string_literals;
32 std::cerr << s <<
" (" << code <<
")\n";
35auto checked(F &&func, std::string_view msg) {
36 return [msg, func{std::forward<F>(func)}]<
class... Args>(
37 Args &&...args)
mutable {
39 std::forward<F>(func)(&status, std::forward<Args>(args)...);
57 [func{std::forward<F>(func)}](
void *) { func(); }};
64 auto load() -> F::signature_t * {
68 template <
class F,
class... Args>
69 decltype(
auto)
call(Args &&...args) {
70 return load<F>()(std::forward<Args>(args)...);
74 std::filesystem::path p = outsdif_fname;
75 if (!std::filesystem::is_regular_file(p))
76 throw std::invalid_argument(
"CUTEstLoader: OUTSDIF path does not "
77 "exist or is not a regular file: \"" +
78 std::string(outsdif_fname) +
'"');
82 throw_if_error(
"Failed to open "s + outsdif_fname, status);
85 fptr_close(&
funit, &status);
86 log_if_error(
"Failed to close OUTSDIF.d file", status);
92 return cleanup([fptr_cterminate] {
94 fptr_cterminate(&status);
95 log_if_error(
"Failed to call cutest_cterminate", status);
101 DynamicLoadFlags dl_flags) {
102 namespace fs = std::filesystem;
103 auto path = fs::path(so_fname);
104 if (fs::is_directory(path))
105 path /=
"PROBLEM.so";
107 so_handle = guanaqo::load_lib(path.c_str(), dl_flags);
110 if (outsdif_fname && *outsdif_fname)
111 path = outsdif_fname;
113 path.replace_filename(
"OUTSDIF.d");
119 throw_if_error(
"Failed to call cutest_cdimen", status);
162 throw_if_error(
"Failed to call cutest_csetup", status);
197 throw_if_error(
"Failed to call CUTEST_probname", status);
198 if (
auto last = name.find_last_not_of(
' '); last != name.npos)
199 name.resize(last + 1);
207 throw_if_error(
"Failed to call CUTEST_creport", status);
210 throw_if_error(
"Failed to call CUTEST_ureport", status);
234 bool sparse, DynamicLoadFlags flags)
236 impl = std::make_unique<CUTEstLoader>(so_fname, outsdif_fname, flags);
237 resize(
static_cast<length_t>(impl->nvar),
239 x0.resize(num_variables);
240 y0.resize(num_constraints);
241 impl->setup_problem(x0, y0, variable_bounds, general_bounds);
242 name = impl->get_name();
254 impl->get_report(calls, time);
255 const bool constr =
impl->ncon > 0;
258 .objective =
static_cast<unsigned>(calls[0]),
259 .objective_grad =
static_cast<unsigned>(calls[1]),
260 .objective_hess =
static_cast<unsigned>(calls[2]),
261 .hessian_times_vector =
static_cast<unsigned>(calls[3]),
262 .constraints = constr ?
static_cast<unsigned>(calls[4]) : 0,
263 .constraints_grad = constr ?
static_cast<unsigned>(calls[5]) : 0,
264 .constraints_hess = constr ?
static_cast<unsigned>(calls[6]) : 0,
266 .time_setup = time[0],
275 checked(
impl->funcs.cofg,
"eval_objective: CUTEST_cofg")(
276 &
impl->nvar, x.data(), &f,
nullptr, &grad);
281 assert(grad_fx.size() ==
static_cast<length_t>(
impl->nvar));
284 checked(
impl->funcs.cofg,
"eval_objective_gradient: CUTEST_cofg")(
285 &
impl->nvar, x.data(), &f, grad_fx.data(), &grad);
294 checked(
impl->funcs.ccfg,
"eval_constraints: CUTEST_ccfg")(
295 &
impl->nvar, &
impl->ncon, x.data(), gx.data(), &jtrans, &zero, &zero,
299 rvec grad_gxy)
const {
300 if (
impl->ncon == 0) {
306 assert(grad_gxy.size() ==
static_cast<length_t>(
impl->nvar));
310 checked(
impl->funcs.cjprod,
311 "eval_constraints_gradient_product: CUTEST_cjprod")(
312 &
impl->nvar, &
impl->ncon, &gotj, &jtrans, x.data(), y.data(), &lvector,
313 grad_gxy.data(), &lresult);
329 checked(
impl->funcs.ccfsg,
"eval_constraints_jacobian: CUTEST_ccfsg")(
336 assert(J_values.size() ==
static_cast<length_t>(
impl->nvar) *
339 checked(
impl->funcs.ccfg,
"eval_constraints_jacobian: CUTEST_ccfg")(
340 &
impl->nvar, &
impl->ncon, x.data(),
impl->work.data(), &jtrans,
341 &
impl->ncon, &
impl->nvar, J_values.data(), &grad);
346 return sparsity::Dense{
349 .symmetry = sparsity::Symmetry::Unsymmetric,
352 checked(
impl->funcs.cdimsj,
353 "get_constraints_jacobian_sparsity: CUTEST_cdimsj")(&
nnz_J);
359 checked(
impl->funcs.csjp,
"eval_constraints_jacobian: CUTEST_csjp")(
362 using SparseCOO = sparsity::SparseCOO<int>;
366 .symmetry = sparsity::Symmetry::Unsymmetric,
369 .order = SparseCOO::Unsorted,
375 assert(grad_gi.size() ==
static_cast<length_t>(
impl->nvar));
376 if (
impl->ncon == 0) {
381 checked(
impl->funcs.cigr,
"eval_grad_gi: CUTEST_cigr")(
382 &
impl->nvar, &iprob, x.data(), grad_gi.data());
391 const auto *mult = y.data();
394 mult =
impl->work.data();
397 checked(
impl->funcs.chprod,
398 "eval_lagrangian_hessian_product: CUTEST_chprod")(
399 &
impl->nvar, &
impl->ncon, &goth, x.data(), mult,
400 const_cast<real_t *
>(v.data()), Hv.data());
411 auto &&ζ =
impl->work.topRows(
impl->ncon);
412 auto &&ŷ =
impl->work2.topRows(
impl->ncon);
415 ζ += y.cwiseQuotient(Σ);
419 ŷ.array() *= Σ.array();
425 ζ(i) = (ζ(i) <= D.lower(i)) || (D.upper(i) <= ζ(i)) ? Σ(i) :
real_t(0);
427 auto &&Jv =
impl->work2.topRows(
impl->ncon);
431 checked(
impl->funcs.cjprod,
432 "eval_augmented_lagrangian_hessian_product: CUTEST_cjprod-1")(
433 &
impl->nvar, &
impl->ncon, &gotj, &jtrans, x.data(), v.data(), &lvector,
434 Jv.data(), &lresult);
436 Jv.array() *= ζ.array();
438 std::swap(lvector, lresult);
440 auto &&JΣJv =
impl->work.topRows(
impl->nvar);
441 checked(
impl->funcs.cjprod,
442 "eval_augmented_lagrangian_hessian_product: CUTEST_cjprod-2")(
443 &
impl->nvar, &
impl->ncon, &gotj, &jtrans, x.data(), Jv.data(), &lvector,
444 JΣJv.data(), &lresult);
448 rvec H_values)
const {
452 const auto *mult = y.data();
455 mult =
impl->work.data();
464 checked(
impl->funcs.csh,
"eval_lagrangian_hessian: CUTEST_csh")(
471 assert(H_values.size() ==
static_cast<length_t>(
impl->nvar) *
473 checked(
impl->funcs.cdh,
"eval_lagrangian_hessian: CUTEST_cdh")(
482 return sparsity::Dense{
485 .symmetry = sparsity::Symmetry::Upper,
488 checked(
impl->funcs.cdimsh,
489 "get_lagrangian_hessian_sparsity: CUTEST_cdimsh")(&
nnz_H);
494 checked(
impl->funcs.cshp,
"eval_lagrangian_hessian: CUTEST_cshp")(
498 using SparseCOO = sparsity::SparseCOO<int>;
502 .symmetry = sparsity::Symmetry::Upper,
505 .order = SparseCOO::Unsorted,
512 assert(grad_fx.size() ==
static_cast<length_t>(
impl->nvar));
515 checked(
impl->funcs.cofg,
"eval_objective_and_gradient: CUTEST_cofg")(
516 &
impl->nvar, x.data(), &f, grad_fx.data(), &grad);
524 checked(
impl->funcs.cfn,
"eval_objective_and_constraints: CUTEST_cfn")(
525 &
impl->nvar, &
impl->ncon, x.data(), &f, g.data());
532 assert(grad_L.size() ==
static_cast<length_t>(
impl->nvar));
535 checked(
impl->funcs.clfg,
"eval_objective_and_constraints: CUTEST_clfg")(
536 &
impl->nvar, &
impl->ncon, x.data(), y.data(), &L, grad_L.data(), &grad);
541 os <<
"CUTEst problem: " <<
name <<
"\r\n\n"
544 <<
"Objective function evaluations: "
546 <<
"Objective function gradient evaluations: "
548 <<
"Objective function Hessian evaluations: "
550 <<
"Hessian times vector products: "
553 os <<
"Constraint function evaluations: "
555 <<
"Constraint function gradients evaluations: "
557 <<
"Constraint function Hessian evaluations: "
560 return os <<
"Setup time: " << r.
time_setup <<
"s\r\n"
561 <<
"Time since setup: " << r.
time <<
"s";
BoxConstrProblem(length_t num_variables, length_t num_constraints)
void eval_projecting_difference_constraints(crvec z, rvec p) const
cleanup_t cutest_terminate
Responsible for calling CUTEST_xterminate.
cutest::ccifg::signature_t * ccifg
cutest::cigr::signature_t * cigr
cutest::cfn::signature_t * cfn
integer ncon
Number of constraints.
cutest::ccfsg::signature_t * ccfsg
std::shared_ptr< void > cleanup_t
cutest::csjp::signature_t * csjp
cleanup_t cleanup_outsdif
Responsible for closing the OUTSDIF.d file.
cutest::cdimsh::signature_t * cdimsh
CUTEstLoader(const char *so_fname, const char *outsdif_fname, DynamicLoadFlags dl_flags)
integer iout
Fortran Unit Number for standard output.
cutest::cdimsj::signature_t * cdimsj
integer funit
Fortran Unit Number for OUTSDIF.d file.
decltype(auto) call(Args &&...args)
cutest::csh::signature_t * csh
cutest::clfg::signature_t * clfg
cleanup_t load_outsdif(const char *outsdif_fname)
cutest::cofg::signature_t * cofg
cleanup_t cleanup(F &&func)
integer nvar
Number of decision variabls.
std::shared_ptr< void > so_handle
dlopen handle to shared library
cutest::cjprod::signature_t * cjprod
alpaqa::Box< config_t > Box
cutest::cdh::signature_t * cdh
Eigen::VectorX< logical > logical_vec
Pointers to loaded problem functions.
cutest::chprod::signature_t * chprod
void setup_problem(rvec x0, rvec y0, Box &C, Box &D)
logical_vec equatn
whether the constraint is an equality
cutest::cshp::signature_t * cshp
auto load() -> F::signature_t *
void get_report(double *calls, double *time)
cutest::ccfg::signature_t * ccfg
logical_vec linear
whether the constraint is linear
integer io_buffer
Fortran Unit Number for internal IO.
Wrapper for CUTEst problems loaded from an external shared library.
void eval_constraints(crvec x, rvec gx) const
Sparsity get_lagrangian_hessian_sparsity() const
void eval_grad_gi(crvec x, index_t i, rvec grad_gi) const
void eval_lagrangian_hessian_product(crvec x, crvec y, real_t scale, crvec v, rvec Hv) const
Calls calls
Function call counters.
void eval_lagrangian_hessian(crvec x, crvec y, real_t scale, rvec H_values) const
unsigned constraints_grad
Number of calls to the constraint gradients.
real_t eval_objective_and_gradient(crvec x, rvec grad_fx) const
double time_setup
CPU time (in seconds) for CUTEST_csetup.
Report get_report() const
CUTEstProblem(const char *so_fname, const char *outsdif_fname=nullptr, bool sparse=false, DynamicLoadFlags dl_flags={})
Load a CUTEst problem from the given shared library and OUTSDIF.d file.
unsigned objective
Number of calls to the objective function.
struct alpaqa::CUTEstProblem::SparseStorage storage_hess_L
void eval_constraints_jacobian(crvec x, rvec J_values) const
real_t eval_objective(crvec x) const
void eval_augmented_lagrangian_hessian_product(crvec x, crvec y, crvec Σ, real_t scale, crvec v, rvec Hv) const
unsigned constraints
Number of calls to the constraint functions.
void eval_lagrangian_gradient(crvec x, crvec y, rvec grad_L, rvec work_n) const
std::string name
Problem name.
Sparsity get_constraints_jacobian_sparsity() const
real_t eval_objective_and_constraints(crvec x, rvec g) const
double time
CPU time (in seconds) since the end of CUTEST_csetup.
void eval_objective_gradient(crvec x, rvec grad_fx) const
unsigned objective_hess
Number of calls to the objective Hessian.
struct alpaqa::CUTEstProblem::SparseStorage storage_jac_g
std::ostream & format_report(std::ostream &os, const Report &r) const
void eval_constraints_gradient_product(crvec x, crvec y, rvec grad_gxy) const
guanaqo::copyable_unique_ptr< class CUTEstLoader > impl
unsigned constraints_hess
Number of calls to the constraint Hessians.
CUTEstProblem & operator=(const CUTEstProblem &)
unsigned objective_grad
Number of calls to the objective gradient.
The report generated by CUTEst.
#define USING_ALPAQA_CONFIG(Conf)
constexpr size_t fstring_len
auto as_span(Eigen::DenseBase< Derived > &v)
Convert an Eigen vector view to a std::span.
typename Conf::real_t real_t
typename Conf::index_t index_t
typename Conf::length_t length_t
typename Conf::crvec crvec
auto checked(F &&func, std::string_view msg)
void throw_error(std::string_view s, int code)
void throw_if_error(std::string_view s, int code)
void log_if_error(std::string_view s, int code)
void(integer *status, const integer *n, const integer *m, const doublereal *x, doublereal *f, doublereal *c) signature_t