Skip to content

Commit

Permalink
new functions to return the final gradient information
Browse files Browse the repository at this point in the history
  • Loading branch information
yixuan committed May 20, 2022
1 parent 00f0f1b commit 7002030
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 10 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
## Unrealeased

### Added
- Added functions `final_grad()` and `final_grad_norm()` to `LBFGSSolver`
and `LBFGSBSolver` to retrieve the final gradient information
([#12](https://github.com/yixuan/LBFGSpp/issues/12))



## [0.2.0] - 2022-05-20

### Added
Expand Down
2 changes: 2 additions & 0 deletions examples/example-rosenbrock-box.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ int main()
std::cout << niter << " iterations" << std::endl;
std::cout << "x = \n" << x.transpose() << std::endl;
std::cout << "f(x) = " << fx << std::endl;
std::cout << "grad = " << solver.final_grad().transpose() << std::endl;
std::cout << "projected grad norm = " << solver.final_grad_norm() << std::endl;

return 0;
}
2 changes: 2 additions & 0 deletions examples/example-rosenbrock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ int main()
std::cout << niter << " iterations" << std::endl;
std::cout << "x = \n" << x.transpose() << std::endl;
std::cout << "f(x) = " << fx << std::endl;
std::cout << "grad = " << solver.final_grad().transpose() << std::endl;
std::cout << "||grad|| = " << solver.final_grad_norm() << std::endl;

return 0;
}
23 changes: 19 additions & 4 deletions include/LBFGS.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class LBFGSSolver
Vector m_fx; // History of the objective function values
Vector m_xp; // Old x
Vector m_grad; // New gradient
Scalar m_gnorm; // Norm of the gradient
Vector m_gradp; // Old gradient
Vector m_drt; // Moving direction

Expand Down Expand Up @@ -87,12 +88,12 @@ class LBFGSSolver

// Evaluate function and compute gradient
fx = f(x, m_grad);
Scalar gnorm = m_grad.norm();
m_gnorm = m_grad.norm();
if (fpast > 0)
m_fx[0] = fx;

// Early exit if the initial x is already a minimizer
if (gnorm <= m_param.epsilon || gnorm <= m_param.epsilon_rel * x.norm())
if (m_gnorm <= m_param.epsilon || m_gnorm <= m_param.epsilon_rel * x.norm())
{
return 1;
}
Expand All @@ -114,10 +115,10 @@ class LBFGSSolver
LineSearch<Scalar>::LineSearch(f, fx, x, m_grad, step, m_drt, m_xp, m_param);

// New gradient norm
gnorm = m_grad.norm();
m_gnorm = m_grad.norm();

// Convergence test -- gradient
if (gnorm <= m_param.epsilon || gnorm <= m_param.epsilon_rel * x.norm())
if (m_gnorm <= m_param.epsilon || m_gnorm <= m_param.epsilon_rel * x.norm())
{
return k;
}
Expand Down Expand Up @@ -151,6 +152,20 @@ class LBFGSSolver

return k;
}

///
/// Returning the gradient vector on the last iterate.
/// Typically used to debug and test convergence.
/// Should only be called after the `minimize()` function.
///
/// \return A const reference to the gradient vector.
///
const Vector& final_grad() const { return m_grad; }

///
/// Returning the Euclidean norm of the final gradient.
///
Scalar final_grad_norm() const { return m_gnorm; }
};

} // namespace LBFGSpp
Expand Down
30 changes: 24 additions & 6 deletions include/LBFGSB.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class LBFGSBSolver
Vector m_fx; // History of the objective function values
Vector m_xp; // Old x
Vector m_grad; // New gradient
Scalar m_projgnorm; // Projected gradient norm
Vector m_gradp; // Old gradient
Vector m_drt; // Moving direction

Expand Down Expand Up @@ -134,15 +135,15 @@ class LBFGSBSolver

// Evaluate function and compute gradient
fx = f(x, m_grad);
Scalar projgnorm = proj_grad_norm(x, m_grad, lb, ub);
m_projgnorm = proj_grad_norm(x, m_grad, lb, ub);
if (fpast > 0)
m_fx[0] = fx;

// std::cout << "x0 = " << x.transpose() << std::endl;
// std::cout << "f(x0) = " << fx << ", ||proj_grad|| = " << projgnorm << std::endl << std::endl;
// std::cout << "f(x0) = " << fx << ", ||proj_grad|| = " << m_projgnorm << std::endl << std::endl;

// Early exit if the initial x is already a minimizer
if (projgnorm <= m_param.epsilon || projgnorm <= m_param.epsilon_rel * x.norm())
if (m_projgnorm <= m_param.epsilon || m_projgnorm <= m_param.epsilon_rel * x.norm())
{
return 1;
}
Expand Down Expand Up @@ -181,14 +182,14 @@ class LBFGSBSolver
LineSearch<Scalar>::LineSearch(f, fx, x, m_grad, step, step_max, m_drt, m_xp, m_param);

// New projected gradient norm
projgnorm = proj_grad_norm(x, m_grad, lb, ub);
m_projgnorm = proj_grad_norm(x, m_grad, lb, ub);

/* std::cout << "** Iteration " << k << std::endl;
std::cout << " x = " << x.transpose() << std::endl;
std::cout << " f(x) = " << fx << ", ||proj_grad|| = " << projgnorm << std::endl << std::endl; */
std::cout << " f(x) = " << fx << ", ||proj_grad|| = " << m_projgnorm << std::endl << std::endl; */

// Convergence test -- gradient
if (projgnorm <= m_param.epsilon || projgnorm <= m_param.epsilon_rel * x.norm())
if (m_projgnorm <= m_param.epsilon || m_projgnorm <= m_param.epsilon_rel * x.norm())
{
return k;
}
Expand Down Expand Up @@ -238,6 +239,23 @@ class LBFGSBSolver

return k;
}

///
/// Returning the gradient vector on the last iterate.
/// Typically used to debug and test convergence.
/// Should only be called after the `minimize()` function.
///
/// \return A const reference to the gradient vector.
///
const Vector& final_grad() const { return m_grad; }

///
/// Returning the infinity norm of the final projected gradient.
/// The projected gradient is defined as \f$P(x-g,l,u)-x\f$, where \f$P(v,l,u)\f$ stands for
/// the projection of a vector \f$v\f$ onto the box specified by the lower bound vector \f$l\f$ and
/// upper bound vector \f$u\f$.
///
Scalar final_grad_norm() const { return m_projgnorm; }
};

} // namespace LBFGSpp
Expand Down

0 comments on commit 7002030

Please sign in to comment.