51#define CUTEST_csjp FUNDERSCORE(cutest_csjp)
52void CUTEST_csjp(integer *status, integer *nnzj,
const integer *lj,
53 integer *J_var, integer *J_con);
57#define LOAD_DL_FUNC(f) dlfun<decltype(f)>(STR(f))
59using namespace std::string_literals;
62void throw_error(std::string s,
int code) {
63 throw std::runtime_error(s +
" (" + std::to_string(code) +
")");
65void throw_if_error(std::string s,
int code) {
69void log_if_error(std::string s,
int code) {
71 std::cerr << s <<
" (" << code <<
")\n";
74std::shared_ptr<void> load_lib(
const char *so_filename) {
77 void *h = ::dlopen(so_filename, RTLD_LOCAL | RTLD_NOW);
78 if (
auto *err = ::dlerror())
79 throw std::runtime_error(err);
80 return std::shared_ptr<void>{h, &::dlclose};
96 [func{std::forward<F>(func)}](
void *) { func(); }};
103 fptr_open(&
funit, outsdif_fname, &status);
104 throw_if_error(
"Failed to open "s + outsdif_fname, status);
107 fptr_close(&
funit, &status);
108 log_if_error(
"Failed to close OUTSDIF.d file", status);
114 return cleanup([fptr_cterminate] {
116 fptr_cterminate(&status);
117 log_if_error(
"Failed to call cutest_cterminate", status);
133 throw_if_error(
"Failed to call cutest_cdimen", status);
137 decltype(CUTEST_cfn) *
cfn;
147 decltype(CUTEST_cdh) *
cdh;
150 decltype(CUTEST_csh) *
csh;
172 &e_order, &l_order, &v_order);
173 throw_if_error(
"Failed to call cutest_csetup", status);
176 throw std::runtime_error(
177 "Unconstrained CUTEst problems are currently unsupported");
208 std::string name(FSTRING_LEN,
' ');
211 throw_if_error(
"Failed to call CUTEST_probname", status);
212 if (
auto last = name.find_last_not_of(
' '); last != name.npos)
213 name.resize(last + 1);
221 fptr_report(&status, calls, time);
228 auto res =
reinterpret_cast<T *
>(::dlsym(
so_handle.get(), name));
229 if (
const char *error = dlerror())
230 throw std::runtime_error(error);
256 impl = std::make_unique<CUTEstLoader>(so_fname, outsdif_fname);
257 resize(
static_cast<length_t>(impl->nvar),
261 impl->setup_problem(x0, y0, C, D);
262 name = impl->get_name();
268CUTEstProblem &CUTEstProblem::operator=(CUTEstProblem &&) noexcept = default;
269CUTEstProblem::~CUTEstProblem() = default;
275 using stat_t =
decltype(r.
status);
276 r.
status =
static_cast<stat_t
>(impl->get_report(calls, time));
277 r.
name = impl->get_name();
280 r.
calls.objective =
static_cast<unsigned>(calls[0]);
281 r.
calls.objective_grad =
static_cast<unsigned>(calls[1]);
282 r.
calls.objective_hess =
static_cast<unsigned>(calls[2]);
283 r.
calls.hessian_times_vector =
static_cast<unsigned>(calls[3]);
284 r.
calls.constraints = impl->
ncon > 0 ?
static_cast<unsigned>(calls[4]) : 0;
285 r.
calls.constraints_grad =
286 impl->
ncon > 0 ?
static_cast<unsigned>(calls[5]) : 0;
287 r.
calls.constraints_hess =
288 impl->
ncon > 0 ?
static_cast<unsigned>(calls[6]) : 0;
295 assert(x.size() ==
static_cast<length_t>(impl->nvar));
298 logical grad = FALSE_;
299 impl->funcs.cofg(&status, &impl->nvar, x.data(), &f,
nullptr, &grad);
300 throw_if_error(
"eval_f: CUTEST_cofg", status);
305 assert(grad_fx.size() ==
static_cast<length_t>(
impl->nvar));
308 logical grad = TRUE_;
309 impl->funcs.cofg(&status, &
impl->nvar, x.data(), &f, grad_fx.data(), &grad);
310 throw_if_error(
"eval_grad_f: CUTEST_cofg", status);
316 logical jtrans = TRUE_, grad = FALSE_;
318 impl->funcs.ccfg(&status, &
impl->nvar, &
impl->ncon, x.data(), gx.data(),
319 &jtrans, &zero, &zero,
nullptr, &grad);
320 throw_if_error(
"eval_g: CUTEST_ccfg", status);
325 assert(grad_gxy.size() ==
static_cast<length_t>(
impl->nvar));
327 auto lvector =
static_cast<integer
>(y.size()),
328 lresult =
static_cast<integer
>(grad_gxy.size());
329 logical gotj = FALSE_, jtrans = TRUE_;
330 impl->funcs.cjprod(&status, &
impl->nvar, &
impl->ncon, &gotj, &jtrans,
331 x.data(), y.data(), &lvector, grad_gxy.data(), &lresult);
332 throw_if_error(
"eval_grad_g_prod: CUTEST_cjprod", status);
337 rvec J_values)
const {
339 if (J_values.size() > 0) {
348 assert(outer_ptr.size() ==
static_cast<length_t>(
impl->nvar + 1));
349 const integer nnz =
nnz_J;
350 logical grad = TRUE_;
351 impl->funcs.ccfsg(&status, &
impl->nvar, &
impl->ncon, x.data(),
354 throw_if_error(
"eval_jac_g: CUTEST_ccfsg", status);
355 auto t0 = std::chrono::steady_clock::now();
357 auto t1 = std::chrono::steady_clock::now();
358 std::cout <<
"Permutation of J took: "
359 << std::chrono::duration<double>{t1 - t0}.count() * 1e6
364 assert(J_values.size() ==
static_cast<length_t>(
impl->nvar) *
367 logical jtrans = FALSE_, grad = TRUE_;
368 impl->funcs.ccfg(&status, &
impl->nvar, &
impl->ncon, x.data(),
369 impl->work.data(), &jtrans, &
impl->ncon,
370 &
impl->nvar, J_values.data(), &grad);
371 throw_if_error(
"eval_jac_g: CUTEST_ccfg", status);
378 assert(outer_ptr.size() ==
static_cast<length_t>(
impl->nvar + 1));
380 const integer nnz =
nnz_J;
382 throw_if_error(
"eval_jac_g: CUTEST_csjp", status);
385 util::convert_triplets_to_ccs<config_t>(
J_row,
J_col, inner_idx,
395 throw_if_error(
"get_jac_g_num_nonzeros: CUTEST_cdimsj", status);
407 assert(grad_gi.size() ==
static_cast<length_t>(
impl->nvar));
409 auto iprob =
static_cast<integer
>(i + 1);
410 impl->funcs.cigr(&status, &
impl->nvar, &iprob, x.data(), grad_gi.data());
411 throw_if_error(
"eval_grad_gi: CUTEST_cigr", status);
419 const auto *mult = y.data();
422 mult =
impl->work.data();
425 logical goth = FALSE_;
426 impl->funcs.chprod(&status, &
impl->nvar, &
impl->ncon, &goth, x.data(), mult,
427 const_cast<real_t *
>(v.data()), Hv.data());
428 throw_if_error(
"eval_hess_L_prod: CUTEST_chprod", status);
439 auto &&ζ =
impl->work.topRows(
impl->ncon);
440 auto &&ŷ =
impl->work2.topRows(
impl->ncon);
443 ζ += Σ.asDiagonal().inverse() * y;
447 ŷ.array() *= Σ.array();
456 auto &&Jv =
impl->work2.topRows(
impl->ncon);
458 auto lvector =
static_cast<integer
>(v.size()),
459 lresult =
static_cast<integer
>(Jv.size());
460 logical gotj = FALSE_, jtrans = FALSE_;
461 impl->funcs.cjprod(&status, &
impl->nvar, &
impl->ncon, &gotj, &jtrans,
462 x.data(), v.data(), &lvector, Jv.data(), &lresult);
463 throw_if_error(
"eval_hess_ψ_prod: CUTEST_cjprod-1", status);
465 Jv.array() *= ζ.array();
467 std::swap(lvector, lresult);
468 gotj = jtrans = TRUE_;
469 auto &&JΣJv =
impl->work.topRows(
impl->nvar);
470 impl->funcs.cjprod(&status, &
impl->nvar, &
impl->ncon, &gotj, &jtrans,
471 x.data(), Jv.data(), &lvector, JΣJv.data(), &lresult);
472 throw_if_error(
"eval_hess_ψ_prod: CUTEST_cjprod-2", status);
477 rvec H_values)
const {
479 if (H_values.size() > 0) {
482 const auto *mult = y.data();
485 mult =
impl->work.data();
494 assert(outer_ptr.size() ==
static_cast<length_t>(
impl->nvar + 1));
495 const integer nnz =
nnz_H;
496 impl->funcs.csh(&status, &
impl->nvar, &
impl->ncon, x.data(),
499 throw_if_error(
"eval_hess_L: CUTEST_csh", status);
500 auto t0 = std::chrono::steady_clock::now();
502 auto t1 = std::chrono::steady_clock::now();
503 std::cout <<
"Permutation of H took: "
504 << std::chrono::duration<double>{t1 - t0}.count() * 1e6
509 assert(H_values.size() ==
static_cast<length_t>(
impl->nvar) *
511 impl->funcs.cdh(&status, &
impl->nvar, &
impl->ncon, x.data(), mult,
512 &
impl->nvar, H_values.data());
513 throw_if_error(
"eval_hess_L: CUTEST_cdh", status);
522 assert(outer_ptr.size() ==
static_cast<length_t>(
impl->nvar + 1));
524 const integer nnz =
nnz_H;
527 throw_if_error(
"eval_hess_L: CUTEST_cshp", status);
530 util::convert_triplets_to_ccs<config_t>(
H_row,
H_col, inner_idx,
540 throw_if_error(
"get_hess_L_num_nonzeros: CUTEST_cdimsh", status);
550 assert(x.size() ==
static_cast<length_t>(impl->nvar));
551 assert(grad_fx.size() ==
static_cast<length_t>(impl->nvar));
554 logical grad = TRUE_;
555 impl->funcs.cofg(&status, &impl->nvar, x.data(), &f, grad_fx.data(), &grad);
556 throw_if_error(
"eval_f_grad_f: CUTEST_cofg", status);
560 assert(x.size() ==
static_cast<length_t>(impl->nvar));
561 assert(g.size() ==
static_cast<length_t>(impl->ncon));
564 impl->funcs.cfn(&status, &impl->nvar, &impl->ncon, x.data(), &f, g.data());
565 throw_if_error(
"eval_f_g: CUTEST_cfn", status);
571 assert(grad_L.size() ==
static_cast<length_t>(
impl->nvar));
574 logical grad = TRUE_;
575 impl->funcs.clfg(&status, &
impl->nvar, &
impl->ncon, x.data(), y.data(), &L,
576 grad_L.data(), &grad);
577 throw_if_error(
"eval_f_g: CUTEST_clfg", status);
583 case Status::Success:
return "Success";
584 case Status::AllocationError:
return "AllocationError";
585 case Status::ArrayBoundError:
return "ArrayBoundError";
586 case Status::EvaluationError:
return "EvaluationError";
589 throw std::out_of_range(
590 "invalid value for pa::CUTEstProblem::Report::Status");
598 os <<
"CUTEst problem: " << r.
name <<
"\r\n\n"
599 <<
"Number of variables: " << r.
nvar <<
"\r\n"
600 <<
"Number of constraints: " << r.
ncon <<
"\r\n\n"
601 <<
"Status: " << r.
status <<
" (" << +r.
status <<
")\r\n\n"
602 <<
"Objective function evaluations: " << r.
calls.objective
604 <<
"Objective function gradient evaluations: "
605 << r.
calls.objective_grad <<
"\r\n"
606 <<
"Objective function Hessian evaluations: "
607 << r.
calls.objective_hess <<
"\r\n"
608 <<
"Hessian times vector products: "
609 << r.
calls.objective_hess <<
"\r\n\n";
611 os <<
"Constraint function evaluations: "
612 << r.
calls.constraints <<
"\r\n"
613 <<
"Constraint function gradients evaluations: "
614 << r.
calls.constraints_grad <<
"\r\n"
615 <<
"Constraint function Hessian evaluations: "
616 << r.
calls.constraints_hess <<
"\r\n\n";
618 return os <<
"Setup time: " << r.
time_setup <<
"s\r\n"
619 <<
"Time since setup: " << r.
time <<
"s";
Implements common problem functions for minimization problems with box constraints.
void eval_proj_diff_g(crvec z, rvec p) const
Box D
Other constraints, .
cleanup_t cutest_terminate
Responsible for calling CUTEST_xterminate.
decltype(CUTEST_cigr) * cigr
decltype(CUTEST_ccfg) * ccfg
decltype(CUTEST_csh) * csh
integer ncon
Number of constraints.
decltype(CUTEST_cjprod) * cjprod
std::shared_ptr< void > cleanup_t
cleanup_t cleanup_outsdif
Responsible for closing the OUTSDIF.d file.
decltype(CUTEST_cofg) * cofg
decltype(CUTEST_chprod) * chprod
CUTEstLoader(const char *so_fname, const char *outsdif_fname)
decltype(CUTEST_ccifg) * ccifg
integer iout
Fortran Unit Number for standard output.
integer get_report(doublereal *calls, doublereal *time)
integer funit
Fortran Unit Number for OUTSDIF.d file.
decltype(CUTEST_clfg) * clfg
cleanup_t load_outsdif(const char *outsdif_fname)
decltype(CUTEST_cdimsj) * cdimsj
cleanup_t cleanup(F &&func)
integer nvar
Number of decision variabls.
T * dlfun(const char *name)
std::shared_ptr< void > so_handle
dlopen handle to shared library
decltype(CUTEST_cdimsh) * cdimsh
decltype(CUTEST_cdh) * cdh
Eigen::VectorX< logical > logical_vec
Pointers to loaded problem functions.
decltype(FUNDERSCORE(cutest_csjp)) * csjp
decltype(CUTEST_ccfsg) * ccfsg
void setup_problem(rvec x0, rvec y0, Box &C, Box &D)
logical_vec equatn
whether the constraint is an equality
decltype(CUTEST_cshp) * cshp
decltype(CUTEST_cfn) * cfn
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_grad_gi(crvec x, index_t i, rvec grad_gi) const
real_t eval_f_g(crvec x, rvec g) const
CUTEstProblem(const char *so_fname, const char *outsdif_fname, bool sparse=false)
Load a CUTEst problem from the given shared library and OUTSDIF.d file.
void eval_grad_L(crvec x, crvec y, rvec grad_L, rvec work_n) const
Eigen::VectorX< int > J_row
Eigen::VectorX< int > J_col
Eigen::VectorX< int > H_col
void eval_hess_L(crvec x, crvec y, real_t scale, rindexvec inner_idx, rindexvec outer_ptr, rvec H_values) const
util::copyable_unique_ptr< class CUTEstLoader > impl
real_t eval_f_grad_f(crvec x, rvec grad_fx) const
void eval_grad_g_prod(crvec x, crvec y, rvec grad_gxy) const
void eval_hess_L_prod(crvec x, crvec y, real_t scale, crvec v, rvec Hv) const
Eigen::VectorX< int > H_row
void eval_grad_f(crvec x, rvec grad_fx) const
real_t eval_f(crvec x) const
void eval_g(crvec x, rvec gx) const
length_t get_jac_g_num_nonzeros() const
CUTEstProblem & operator=(const CUTEstProblem &)
void eval_jac_g(crvec x, rindexvec inner_idx, rindexvec outer_ptr, rvec J_values) const
void eval_hess_ψ_prod(crvec x, crvec y, crvec Σ, real_t scale, crvec v, rvec Hv) const
length_t get_hess_L_num_nonzeros() const
#define USING_ALPAQA_CONFIG(Conf)
std::ostream & operator<<(std::ostream &os, PANOCStopCrit s)
typename Conf::real_t real_t
typename Conf::rindexvec rindexvec
typename Conf::index_t index_t
typename Conf::length_t length_t
typename Conf::crvec crvec
constexpr const char * enum_name(PANOCStopCrit s)
The report generated by CUTEst.
int ncon
Number of constraints.
double time_setup
CPU time (in seconds) for CUTEST_csetup.
enum alpaqa::CUTEstProblem::Report::Status status
Exit status.
int nvar
Number of independent variables.
Status
Status returned by CUTEst.
struct alpaqa::CUTEstProblem::Report::@0 calls
Function call counters.
std::string name
Name of the problem.
double time
CPU time (in seconds) since the end of CUTEST_csetup.