OptimizationProblemSecond.h 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /*
  2. * NICE-Core - efficient algebra and computer vision methods
  3. * - liboptimization - An optimization/template for new NICE libraries
  4. * See file License for license information.
  5. */
  6. /*****************************************************************************/
  7. #ifndef _OPTIMIZATIONPROBLEMSECOND_OPTIMIZATION_H
  8. #define _OPTIMIZATIONPROBLEMSECOND_OPTIMIZATION_H
  9. #include <iostream>
  10. #include <core/vector/MatrixT.h>
  11. #include <core/optimization/gradientBased/OptimizationProblemFirst.h>
  12. namespace NICE {
  13. /**
  14. * Base class for nonlinear minimization problems providing
  15. * 1st and 2nd order derivatives.
  16. *
  17. * The documentation of this class has three parts. The first part is of
  18. * general importance. The second part is for users of the library.
  19. * The third part describes details which are important
  20. * when implementing new optimization algorithms. These details can also
  21. * be important to users of the library.
  22. *
  23. * <b>1. General Information</b>
  24. *
  25. * The interface provides the value of the objective function, the gradient,
  26. * the Hessian and some further data.
  27. *
  28. * <b>2. Using the Library</b>
  29. *
  30. * If you want to use the library to solve an optimization problem,
  31. * you have to implement a subclass of \c OptimizationProblemSecond
  32. * or at least of \c OptimizationProblemFirst. The later is simpler,
  33. * as it does not require a function to compute the Hessian matrix.
  34. * However, it cannot be solved using the (generally) more efficient
  35. * second order optimization algorithms.
  36. *
  37. * Quite obviously, you need (at least) to implement all abstract
  38. * (i.e. pure virtual) methods:
  39. * - \c computeObjective() has to compute the value of the objective function
  40. * at the current position in parameter space.
  41. * - If you implement a subclass of \c OptimizationProblemFirst, you need
  42. * to implement \c computeGradient(), which has to compute the gradient
  43. * of the objective function at the current position in parameter space.
  44. * - If you implement a subclass of \c OptimizationProblemSecond, you need
  45. * to implement <b>either</b> \c computeGradientAndHessian() <b>or</b>
  46. * \c computeGradient() and \c computeHessian() (and a simple
  47. * \c computeGradientAndHessian() which calls the other two).
  48. *
  49. * You also need to take care of how the current position in parameter space
  50. * is represented. There are two possibilities:
  51. * - \c OptimizationProblemFirst provides the method \c position() which
  52. * gives public read access to the current position, and the protected method
  53. * \c parameters() which gives write access. You can simply store the
  54. * current position in parameter space in the vector returned by
  55. * \c parameters(). This is the suggested technique.
  56. * - If you want to have a different representation, you need to reimplement
  57. * \c computePosition(), \c doApplyStep() and \c doUnapplyStep().
  58. * Use this alternative technique only if there is a good reason
  59. * (e.g. if you already have existing code which uses its own
  60. * representation).
  61. *
  62. * Note: If you want to renormalize the position in parameter space
  63. * (e.g. to ensure that unit quaternions have unit length),
  64. * you can do so in \c doApplyStep(). Further information is provided
  65. * there.
  66. *
  67. * For an example, refer to the CppUnit test cases of the library.
  68. *
  69. * <b>3. Implementing Optimization Algorithms</b>
  70. *
  71. * There is an important difference in the way derivatives
  72. * and non-derivative information is handled. All non-derivate information is
  73. * automatically computed at the current position in parameter space
  74. * when the access method is called.
  75. * Derivatives are only computed by an explicit call to \c computeGradient()
  76. * (or \c computeGradientAndHessian() in the second order subclass)
  77. * and also by calling \c gradientCurrent(), \c gradientNormCurrent()
  78. * (or \c hessianCurrent() in the second order subclass).
  79. * This strategy allows keeping old derivatives without copying when applying
  80. * a test step. See \c FirstOrderTrustRegion for a quite simple example.
  81. *
  82. * \ingroup optimization_problems
  83. */
  84. class OptimizationProblemSecond : public OptimizationProblemFirst {
  85. public:
  86. //! Default constructor
  87. inline OptimizationProblemSecond(unsigned int dimension)
  88. : OptimizationProblemFirst(dimension), m_hessianCached(false) {}
  89. virtual ~OptimizationProblemSecond();
  90. inline void computeGradientAndHessian() {
  91. m_gradientNormCached = false;
  92. m_hessianCache.resize(dimension(), dimension());
  93. computeGradientAndHessian(m_gradientCache, m_hessianCache);
  94. m_gradientCached = true;
  95. m_hessianCached = true;
  96. }
  97. /**
  98. * Get the Hessian of the objective function
  99. * as computed by the last call to \c computeGradientAndHessian().
  100. */
  101. inline const Matrix& hessianCached() {
  102. return m_hessianCache;
  103. }
  104. /**
  105. * Get the Hessian of the objective function at the current position
  106. * in parameter space.
  107. * The Hessian will be computed if the Hessian cache is out of date.
  108. */
  109. inline const Matrix& hessianCurrent() {
  110. if (!m_hessianCached) {
  111. computeGradientAndHessian();
  112. }
  113. return m_hessianCache;
  114. }
  115. /**
  116. * See base class. Note: you probably don't want to override this
  117. * method in a subclass.
  118. */
  119. virtual void invalidateCaches() {
  120. OptimizationProblemFirst::invalidateCaches();
  121. m_hessianCached = false;
  122. }
  123. protected:
  124. /**
  125. * Compute the gradient and the Hessian of the objective function
  126. * at the current position.
  127. * @param newGradient Output parameter for the gradient of the objective
  128. * function. Be careful: \c newGradient is the <b>same</b> object
  129. * as \c gradientCached(). If you need to access (the old)
  130. * \c gradientCached()
  131. * during the computation, first make a copy.
  132. * @param newHessian Output parameter for the Hessian of the objective
  133. * function. Be careful: \c newHessian is the <b>same</b> object
  134. * as \c hessianCached(). If you need to access (the old)
  135. * \c hessianCached()
  136. * during the computation, first make a copy.
  137. */
  138. virtual void computeGradientAndHessian(Vector& newGradient,
  139. Matrix& newHessian) = 0;
  140. /**
  141. * See baseclass for documentation.
  142. * @note
  143. * There is a default implementation for this method, which uses
  144. * \c computeGradientAndHessian(). This works, but is not efficient for
  145. * 1st order optimization algorithms. To improve this, provide an efficient
  146. * implementation of \c computeGradient(). Depending on your situation,
  147. * it may or may not be a good idea to have a method computeHessian() and
  148. * call computeHessian() and computeGradient()
  149. * in computeGradientAndHessian().
  150. */
  151. virtual void computeGradient(Vector& newGradient);
  152. private:
  153. bool m_hessianCached;
  154. Matrix m_hessianCache;
  155. };
  156. }; // namespace NICE
  157. #endif /* _OPTIMIZATIONPROBLEMSECOND_OPTIMIZATION_H */