19using namespace std::string_literals;
22void throw_error(std::string_view s,
int code) {
26void throw_if_error(std::string_view s,
int code) {
30void log_if_error(std::string_view s,
int code) {
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)...);
40 throw_if_error(msg, status);
44std::shared_ptr<void> load_lib(
const char *so_filename) {
47 void *h = ::dlopen(so_filename, RTLD_LOCAL | RTLD_NOW);
48 if (
auto *err = ::dlerror())
49 throw std::runtime_error(err);
50 return std::shared_ptr<void>{h, &::dlclose};
66 [func{std::forward<F>(func)}](
void *) { func(); }};
73 auto load() -> F::signature_t * {
77 template <
class F,
class... Args>
78 decltype(
auto)
call(Args &&...args) {
79 return load<F>()(std::forward<Args>(args)...);
84 auto fptr_close = load<cutest::fortran_close>();
85 call<cutest::fortran_open>(&
funit, outsdif_fname, &status);
86 throw_if_error(
"Failed to open "s + outsdif_fname, status);
89 fptr_close(&
funit, &status);
90 log_if_error(
"Failed to close OUTSDIF.d file", status);
95 auto fptr_cterminate = load<cutest::cterminate>();
96 return cleanup([fptr_cterminate] {
98 fptr_cterminate(&status);
99 log_if_error(
"Failed to call cutest_cterminate", status);
114 throw_if_error(
"Failed to call cutest_cdimen", status);
152 call<cutest::csetup>(
156 linear.data(), &e_order, &l_order, &v_order);
157 throw_if_error(
"Failed to call cutest_csetup", status);
162 throw std::runtime_error(
163 "Unconstrained CUTEst problems are currently unsupported");
175 .
cfn = load<cutest::cfn>(),
176 .cofg = load<cutest::cofg>(),
177 .ccfg = load<cutest::ccfg>(),
178 .clfg = load<cutest::clfg>(),
179 .cjprod = load<cutest::cjprod>(),
180 .ccifg = load<cutest::ccifg>(),
181 .cigr = load<cutest::cigr>(),
182 .cdimsj = load<cutest::cdimsj>(),
183 .csjp = load<cutest::csjp>(),
184 .ccfsg = load<cutest::ccfsg>(),
185 .cdh = load<cutest::cdh>(),
186 .cdimsh = load<cutest::cdimsh>(),
187 .cshp = load<cutest::cshp>(),
188 .csh = load<cutest::csh>(),
189 .chprod = load<cutest::chprod>(),
196 call<cutest::probname>(&status, name.data());
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);
206 call<cutest::creport>(&status, calls, time);
207 throw_if_error(
"Failed to call CUTEST_creport", status);
209 call<cutest::ureport>(&status, calls, time);
210 throw_if_error(
"Failed to call CUTEST_ureport", status);
217 auto res =
reinterpret_cast<T *
>(::dlsym(
so_handle.get(), name));
218 if (
const char *error = dlerror())
219 throw std::runtime_error(error);
245 impl = std::make_unique<CUTEstLoader>(so_fname, outsdif_fname);
246 resize(
static_cast<length_t>(impl->nvar),
250 impl->setup_problem(x0, y0, C, D);
251 name = impl->get_name();
257CUTEstProblem &CUTEstProblem::operator=(CUTEstProblem &&) noexcept = default;
258CUTEstProblem::~CUTEstProblem() = default;
263 impl->get_report(calls, time);
264 const bool constr = impl->ncon > 0;
267 .
objective =
static_cast<unsigned>(calls[0]),
268 .objective_grad =
static_cast<unsigned>(calls[1]),
269 .objective_hess =
static_cast<unsigned>(calls[2]),
270 .hessian_times_vector =
static_cast<unsigned>(calls[3]),
271 .constraints = constr ?
static_cast<unsigned>(calls[4]) : 0,
272 .constraints_grad = constr ?
static_cast<unsigned>(calls[5]) : 0,
273 .constraints_hess = constr ?
static_cast<unsigned>(calls[6]) : 0,
275 .time_setup = time[0],
281 assert(x.size() ==
static_cast<length_t>(impl->nvar));
284 checked(impl->funcs.cofg,
"eval_f: CUTEST_cofg")(&impl->nvar, x.data(), &f,
290 assert(grad_fx.size() ==
static_cast<length_t>(
impl->nvar));
293 checked(
impl->funcs.cofg,
"eval_grad_f: CUTEST_cofg")(
294 &
impl->nvar, x.data(), &f, grad_fx.data(), &grad);
301 checked(
impl->funcs.ccfg,
"eval_g: CUTEST_ccfg")(
302 &
impl->nvar, &
impl->ncon, x.data(), gx.data(), &jtrans, &zero, &zero,
308 assert(grad_gxy.size() ==
static_cast<length_t>(
impl->nvar));
312 checked(
impl->funcs.cjprod,
"eval_grad_g_prod: CUTEST_cjprod")(
313 &
impl->nvar, &
impl->ncon, &gotj, &jtrans, x.data(), y.data(), &lvector,
314 grad_gxy.data(), &lresult);
319 rvec J_values)
const {
321 if (J_values.size() > 0) {
329 assert(outer_ptr.size() ==
static_cast<length_t>(
impl->nvar + 1));
332 checked(
impl->funcs.ccfsg,
"eval_jac_g: CUTEST_ccfsg")(
335 auto t0 = std::chrono::steady_clock::now();
337 auto t1 = std::chrono::steady_clock::now();
338 std::cout <<
"Permutation of J took: "
339 << std::chrono::duration<double>{t1 - t0}.count() * 1e6
344 assert(J_values.size() ==
static_cast<length_t>(
impl->nvar) *
347 checked(
impl->funcs.ccfg,
"eval_jac_g: CUTEST_ccfg")(
348 &
impl->nvar, &
impl->ncon, x.data(),
impl->work.data(), &jtrans,
349 &
impl->ncon, &
impl->nvar, J_values.data(), &grad);
356 assert(outer_ptr.size() ==
static_cast<length_t>(
impl->nvar + 1));
358 checked(
impl->funcs.csjp,
"eval_jac_g: CUTEST_csjp")(
362 util::convert_triplets_to_ccs<config_t>(
J_row,
J_col, inner_idx,
370 checked(
impl->funcs.cdimsj,
371 "get_jac_g_num_nonzeros: CUTEST_cdimsj")(&
nnz_J);
383 assert(grad_gi.size() ==
static_cast<length_t>(
impl->nvar));
385 checked(
impl->funcs.cigr,
"eval_grad_gi: CUTEST_cigr")(
386 &
impl->nvar, &iprob, x.data(), grad_gi.data());
394 const auto *mult = y.data();
397 mult =
impl->work.data();
400 checked(
impl->funcs.chprod,
"eval_hess_L_prod: CUTEST_chprod")(
401 &
impl->nvar, &
impl->ncon, &goth, x.data(), mult,
402 const_cast<real_t *
>(v.data()), Hv.data());
413 auto &&ζ =
impl->work.topRows(
impl->ncon);
414 auto &&ŷ =
impl->work2.topRows(
impl->ncon);
417 ζ += Σ.asDiagonal().inverse() * y;
421 ŷ.array() *= Σ.array();
430 auto &&Jv =
impl->work2.topRows(
impl->ncon);
434 checked(
impl->funcs.cjprod,
"eval_hess_ψ_prod: CUTEST_cjprod-1")(
435 &
impl->nvar, &
impl->ncon, &gotj, &jtrans, x.data(), v.data(), &lvector,
436 Jv.data(), &lresult);
438 Jv.array() *= ζ.array();
440 std::swap(lvector, lresult);
442 auto &&JΣJv =
impl->work.topRows(
impl->nvar);
443 checked(
impl->funcs.cjprod,
"eval_hess_ψ_prod: CUTEST_cjprod-2")(
444 &
impl->nvar, &
impl->ncon, &gotj, &jtrans, x.data(), Jv.data(), &lvector,
445 JΣJv.data(), &lresult);
450 rvec H_values)
const {
452 if (H_values.size() > 0) {
455 const auto *mult = y.data();
458 mult =
impl->work.data();
466 assert(outer_ptr.size() ==
static_cast<length_t>(
impl->nvar + 1));
468 checked(
impl->funcs.csh,
"eval_hess_L: CUTEST_csh")(
471 auto t0 = std::chrono::steady_clock::now();
473 auto t1 = std::chrono::steady_clock::now();
474 std::cout <<
"Permutation of H took: "
475 << std::chrono::duration<double>{t1 - t0}.count() * 1e6
480 assert(H_values.size() ==
static_cast<length_t>(
impl->nvar) *
482 checked(
impl->funcs.cdh,
"eval_hess_L: CUTEST_cdh")(
493 assert(outer_ptr.size() ==
static_cast<length_t>(
impl->nvar + 1));
495 checked(
impl->funcs.cshp,
"eval_hess_L: CUTEST_cshp")(
499 util::convert_triplets_to_ccs<config_t>(
H_row,
H_col, inner_idx,
507 checked(
impl->funcs.cdimsh,
508 "get_hess_L_num_nonzeros: CUTEST_cdimsh")(&
nnz_H);
518 assert(x.size() ==
static_cast<length_t>(impl->nvar));
519 assert(grad_fx.size() ==
static_cast<length_t>(impl->nvar));
522 checked(impl->funcs.cofg,
"eval_f_grad_f: CUTEST_cofg")(
523 &impl->nvar, x.data(), &f, grad_fx.data(), &grad);
527 assert(x.size() ==
static_cast<length_t>(impl->nvar));
528 assert(g.size() ==
static_cast<length_t>(impl->ncon));
530 checked(impl->funcs.cfn,
"eval_f_g: CUTEST_cfn")(&impl->nvar, &impl->ncon,
531 x.data(), &f, g.data());
537 assert(grad_L.size() ==
static_cast<length_t>(
impl->nvar));
540 checked(
impl->funcs.clfg,
"eval_f_g: CUTEST_clfg")(
541 &
impl->nvar, &
impl->ncon, x.data(), y.data(), &L, grad_L.data(), &grad);
546 os <<
"CUTEst problem: " <<
name <<
"\r\n\n"
547 <<
"Number of variables: " <<
n <<
"\r\n"
548 <<
"Number of constraints: " <<
m <<
"\r\n\n"
549 <<
"Objective function evaluations: "
551 <<
"Objective function gradient evaluations: "
553 <<
"Objective function Hessian evaluations: "
555 <<
"Hessian times vector products: "
558 os <<
"Constraint function evaluations: "
560 <<
"Constraint function gradients evaluations: "
562 <<
"Constraint function Hessian evaluations: "
565 return os <<
"Setup time: " << r.
time_setup <<
"s\r\n"
566 <<
"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
length_t m
Number of constraints, dimension of g(x) and z.
length_t n
Number of decision variables, dimension of x.
Box D
Other constraints, .
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)
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.
T * dlfun(const char *name)
std::shared_ptr< void > so_handle
dlopen handle to shared library
cutest::cjprod::signature_t * cjprod
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_grad_gi(crvec x, index_t i, rvec grad_gi) const
Calls calls
Function call counters.
unsigned constraints_grad
Number of calls to the constraint gradients.
real_t eval_f_g(crvec x, rvec g) const
double time_setup
CPU time (in seconds) for CUTEST_csetup.
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.
unsigned objective
Number of calls to the objective function.
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
unsigned constraints
Number of calls to the constraint functions.
std::string name
Problem name.
util::copyable_unique_ptr< class CUTEstLoader > impl
real_t eval_f_grad_f(crvec x, rvec grad_fx) const
double time
CPU time (in seconds) since the end of CUTEST_csetup.
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
unsigned objective_hess
Number of calls to the objective Hessian.
length_t get_jac_g_num_nonzeros() const
std::ostream & format_report(std::ostream &os, const Report &r) const
unsigned constraints_hess
Number of calls to the constraint Hessians.
CUTEstProblem & operator=(const CUTEstProblem &)
void eval_jac_g(crvec x, rindexvec inner_idx, rindexvec outer_ptr, rvec J_values) const
unsigned objective_grad
Number of calls to the objective gradient.
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
The report generated by CUTEst.
#define USING_ALPAQA_CONFIG(Conf)
constexpr size_t fstring_len
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