8void alpaqa_setulb_c(
int n,
int m,
double *x,
const double *l,
const double *u,
9 const int *nbd,
double &f,
double *g,
double factr,
10 double pgtol,
double *wa,
int *iwa,
char *task,
int iprint,
11 char *csave,
bool *lsave,
int *isave,
double *dsave);
34 using std::chrono::nanoseconds;
35 using clock = std::chrono::steady_clock;
36 auto start_time = clock::now();
37 auto *os = opts.os ? opts.os : this->os;
38 auto max_time = params.max_time;
40 max_time = std::min(max_time, *opts.max_time);
43 if (!problem.provides_get_box_C())
44 throw std::invalid_argument(
"LBFGSBSolver requires box constraints");
46 throw std::invalid_argument(
"LBFGSBSolver only supports "
47 "PANOCStopCrit::ProjGradUnitNorm");
49 const auto n = problem.get_n();
50 const auto m_constr = problem.get_m();
51 const auto &C = problem.get_box_C();
52 const auto mem =
static_cast<length_t>(params.memory);
54 using intvec = Eigen::VectorX<int>;
56 vec work_n(n), work_m(m_constr);
59 vec wa(2 * mem * n + 5 * n + 11 * mem * mem + 8 * mem);
61 intvec iwa(3 * n), isave(44);
62 std::array<bool, 4> lsave{};
63 std::array<char, 60> task{}, csave{};
67 for (
index_t i = 0; i < n; ++i) {
68 static constexpr int nbd_legend[2][2] {{0, 3},
70 int lowerbounded = C.lowerbound(i) == -inf<config_t> ? 0 : 1;
71 int upperbounded = C.upperbound(i) == +inf<config_t> ? 0 : 1;
72 nbd(i) = nbd_legend[lowerbounded][upperbounded];
79 int print = params.print;
81 std::string_view task_sv{task.begin(), task.end()};
82 const int &num_iter = isave.coeffRef(29);
83 const int &lbfgs_skipped = isave.coeffRef(25);
84 const int &num_free_var = isave.coeffRef(37);
85 const real_t &τ_max = dsave.coeffRef(11);
86 const real_t &proj_grad_norm = dsave.coeffRef(12);
87 const real_t &τ_rel = dsave.coeffRef(13);
90 auto set_task = [&](std::string_view s) {
91 std::fill(std::copy(s.begin(), s.end(), task.begin()), task.end(),
' ');
94 std::array<char, 64> print_buf;
95 auto print_real = [
this, &print_buf](
real_t x) {
98 auto print_real3 = [&print_buf](
real_t x) {
103 *os <<
"┌─[LBFGSB]\n";
105 *os <<
"├─ " << std::setw(6) << k <<
" ──\n";
106 *os <<
"│ ψ = " << print_real(ψₖ)
107 <<
", ‖∇ψ‖ = " << print_real(grad_ψₖ.norm())
108 <<
", ε = " << print_real(εₖ) <<
'\n';
110 auto print_progress_2 = [&](
real_t τ_max,
real_t τ_rel,
int nJ) {
111 *os <<
"│ τ_max = " << print_real3(τ_max)
112 <<
", τ_rel = " << print_real3(τ_rel)
113 <<
", #J = " << std::setw(6) << nJ
117 *os <<
"└─ " << status <<
" ──"
120 bool do_print =
false;
121 bool did_print =
false;
129 x_solve.data(), C.lowerbound.data(),
130 C.upperbound.data(), nbd.data(), ψ, grad_ψ.data(),
131 factr, pgtol, wa.data(), iwa.data(), task.data(), print,
132 csave.data(), lsave.data(), isave.data(), dsave.data());
135 if (task_sv.starts_with(
"FG")) {
136 ψ = problem.eval_ψ_grad_ψ(x_solve, y, Σ, grad_ψ, work_n, work_m);
139 else if (task_sv.starts_with(
"NEW_X")) {
141 params.print_interval != 0 &&
142 static_cast<unsigned>(num_iter) % params.print_interval == 0;
144 if (std::exchange(did_print, do_print))
145 print_progress_2(τ_max, τ_rel, num_free_var);
147 if (proj_grad_norm <= opts.tolerance) {
149 set_task(
"STOP: projected gradient norm");
151 }
else if (clock::now() - start_time >= max_time) {
153 set_task(
"STOP: time");
155 }
else if (
static_cast<unsigned>(num_iter) >= params.max_iter) {
157 set_task(
"STOP: number iterations");
159 }
else if (stop_signal.stop_requested()) {
161 set_task(
"STOP: user request");
165 if (std::exchange(do_print,
false))
166 print_progress_1(num_iter - 1, ψ, grad_ψ, proj_grad_norm);
170 else if (task_sv.starts_with(
"CONVERGENCE: REL_REDUCTION_OF_F")) {
176 std::string_view task_trimmed = task_sv;
177 auto trim_pos = task_sv.find(
'\0');
178 trim_pos = task_sv.find_last_not_of(
' ', trim_pos);
179 if (trim_pos != task_trimmed.npos)
180 task_trimmed.remove_suffix(task_trimmed.size() - trim_pos);
181 *os <<
"[LBFGSB] Unexpected task: '" << task_trimmed <<
"'"
188 if (std::exchange(did_print,
false))
189 print_progress_2(τ_max, τ_rel, num_free_var);
190 else if (params.print_interval != 0)
191 print_progress_1(num_iter - 1, ψ, grad_ψ, proj_grad_norm);
192 if (params.print_interval != 0)
193 print_progress_n(s.
status);
195 auto time_elapsed = clock::now() - start_time;
196 s.
elapsed_time = duration_cast<nanoseconds>(time_elapsed);
198 s.
iterations =
static_cast<unsigned>(num_iter);
201 s.
ε = proj_grad_norm;
205 opts.always_overwrite_results) {
207 s.
final_ψ = problem.eval_ψ(x_solve, y, Σ, ŷ);
208 if (err_z.size() > 0)
209 err_z = Σ.asDiagonal().inverse() * (ŷ - y);
std::string get_name() const
Stats operator()(const Problem &problem, const SolveOptions &opts, rvec x, rvec y, crvec Σ, rvec err_z)
void alpaqa_setulb_c(int n, int m, double *x, const double *l, const double *u, const int *nbd, double &f, double *g, double factr, double pgtol, double *wa, int *iwa, char *task, int iprint, char *csave, bool *lsave, int *isave, double *dsave)
std::chrono::nanoseconds elapsed_time
@ ProjGradUnitNorm
∞-norm of the projected gradient with unit step size:
SolverStatus
Exit status of a numerical solver such as ALM or PANOC.
@ Interrupted
Solver was interrupted by the user.
@ MaxTime
Maximum allowed execution time exceeded.
@ Exception
An unexpected exception was thrown.
@ NoProgress
No progress was made in the last iteration.
@ MaxIter
Maximum number of iterations exceeded.
@ Converged
Converged and reached given tolerance.
typename Conf::real_t real_t
typename Conf::index_t index_t
typename Conf::length_t length_t
std::string_view float_to_str_vw(auto &buf, double value, int precision=std::numeric_limits< double >::max_digits10)
typename Conf::crvec crvec