OptimizationProblemFirst.h 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  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 _OPTIMIZATIONPROBLEMFIRST_OPTIMIZATION_H
  8. #define _OPTIMIZATIONPROBLEMFIRST_OPTIMIZATION_H
  9. #include <iostream>
  10. #include <core/basics/NonCopyable.h>
  11. #include <core/vector/VectorT.h>
  12. namespace NICE {
  13. /**
  14. * \defgroup optimization_problems Optimization Problems (Objective Functions)
  15. *
  16. * This module contains the base classes for user defined
  17. * nonlinear minimization problems:
  18. * objective functions together with their derivatives.
  19. * You will probably have to implement a subclass of one of these base classes.
  20. */
  21. /**
  22. * Base class for nonlinear minimization problems providing
  23. * 1st order derivatives.
  24. * Also read the documentation of \c OptimizationProblemSecond.
  25. *
  26. * \ingroup optimization_problems
  27. */
  28. class OptimizationProblemFirst : private NonCopyable {
  29. public:
  30. //! Default constructor
  31. inline OptimizationProblemFirst(unsigned int dimension)
  32. : m_gradientCache(dimension, 0), m_positionCache(dimension,0) {
  33. init();
  34. }
  35. virtual ~OptimizationProblemFirst();
  36. /**
  37. * Initialize the optimization problem (reset caches etc.)
  38. */
  39. inline void init() {
  40. m_objectiveCached = false;
  41. m_positionCached = false;
  42. m_gradientCached = false;
  43. m_gradientNormCached = false;
  44. }
  45. /**
  46. * The dimension of the optimization problem
  47. * (the dimension of the parameter space).
  48. */
  49. inline unsigned int dimension() const {
  50. return m_gradientCache.size();
  51. }
  52. /**
  53. * Get the value of the objective function at the current position.
  54. * The objective function will be evaluated only if the position has changed
  55. * via \c applyStep().
  56. */
  57. inline double objective() {
  58. if (!m_objectiveCached) {
  59. m_objectiveCache = computeObjective();
  60. m_objectiveCached = true;
  61. }
  62. return m_objectiveCache;
  63. }
  64. /**
  65. * Get the current position.
  66. */
  67. inline const Vector& position() {
  68. if (!m_positionCached) {
  69. m_positionCache.resize(dimension());
  70. computePosition(m_positionCache);
  71. m_positionCached = true;
  72. }
  73. return m_positionCache;
  74. }
  75. /**
  76. * Compute the gradient of the objective function at the current position.
  77. * @note If you are using \c OptimizationProblemSecond, don't call
  78. * \c computeGradient(), unless you don't need the Hessian.
  79. */
  80. inline void computeGradient() {
  81. m_gradientNormCached = false;
  82. computeGradient(m_gradientCache);
  83. m_gradientCached = true;
  84. }
  85. /**
  86. * Get the gradient of the objective function as computed by the last call
  87. * to \c computeGradient().
  88. */
  89. inline const Vector& gradientCached() {
  90. return m_gradientCache;
  91. }
  92. /**
  93. * Get the gradient of the objective function at the current position
  94. * in parameter space.
  95. * The gradient will be computed if the gradient cache is out of date.
  96. */
  97. inline const Vector& gradientCurrent() {
  98. if (!m_gradientCached) {
  99. computeGradient();
  100. }
  101. return m_gradientCache;
  102. }
  103. /**
  104. * Get the Euclidean norm of the gradient of the objective function
  105. * as computed by the last call to \c computeGradient().
  106. */
  107. inline double gradientNormCached() {
  108. if (!m_gradientNormCached) {
  109. m_gradientNormCache = gradientCached().normL2();
  110. m_gradientNormCached = true;
  111. }
  112. return m_gradientNormCache;
  113. }
  114. /**
  115. * Get the Euclidean norm of the gradient of the objective function.
  116. * The gradient will be computed if the gradient cache is out of date.
  117. */
  118. inline double gradientNormCurrent() {
  119. if (!m_gradientNormCached || !m_gradientCached) {
  120. m_gradientNormCache = gradientCurrent().normL2();
  121. m_gradientNormCached = true;
  122. }
  123. return m_gradientNormCache;
  124. }
  125. /**
  126. * Apply a step to the current position in parameter space.
  127. * @param step The change to be applied to the current position
  128. */
  129. inline void applyStep(const Vector& step) {
  130. invalidateCaches();
  131. doApplyStep(step);
  132. }
  133. /**
  134. * Unapply a step to the current position in parameter space.
  135. * Is equivalent to \c apply(-step); .
  136. * @param step The change to be unapplied to the current position
  137. */
  138. inline void unapplyStep(const Vector& step) {
  139. invalidateCaches();
  140. doUnapplyStep(step);
  141. }
  142. /**
  143. * Invalidate all caches. Call this method after changing the position
  144. * in parameter space outside of doApplyStep() and doUnapplyStep().
  145. */
  146. virtual void invalidateCaches() {
  147. m_objectiveCached = false;
  148. m_positionCached = false;
  149. m_gradientCached = false;
  150. }
  151. protected:
  152. /**
  153. * The current position in parameter space to be used by subclasses
  154. * which do NOT have their own representation for this data.
  155. * Using \c parameters() is recommended.
  156. */
  157. inline Vector& parameters() {
  158. m_positionCache.resize(dimension());
  159. return m_positionCache;
  160. }
  161. /**
  162. * The current position in parameter space to be used by subclasses
  163. * which do NOT have their own representation for this data.
  164. * Using \c parameters() / \c parametersConst() is recommended.
  165. */
  166. inline const Vector& parametersConst() const {
  167. if (m_positionCache.size() != dimension()) {
  168. fthrow(Exception,
  169. "parametersConst(): data not initialized. Call nonconst version of parameters() first");
  170. }
  171. return m_positionCache;
  172. }
  173. /**
  174. * Compute the value of the objective function at the current position.
  175. * @return value of the objective function
  176. */
  177. virtual double computeObjective() = 0;
  178. /**
  179. * Compute the gradient of the objective function at the current position.
  180. * @param newGradient Output parameter for the gradient of the objective
  181. * function. Be careful: \c newGradient is the <b>same</b> object
  182. * as \c gradient(). If you need to access (the old) \c gradient()
  183. * during the computation, first make a copy.
  184. */
  185. virtual void computeGradient(Vector& newGradient) = 0;
  186. /**
  187. * Compute the current position in parameter space.
  188. * Only needs to be implemented in subclasses if \c parameters() is not used
  189. * in the subclass to store the position in parameter space.
  190. * @param pos Output parameter for the position in parameter space.
  191. * Be careful: \c pos is the <b>same</b> object
  192. * as \c position(). If you need to access \c position()
  193. * during the computation, first make a copy.
  194. */
  195. virtual void computePosition(Vector& pos);
  196. /**
  197. * Apply a step to the current position in parameter space.
  198. * Only needs to be implemented in subclasses if \c parameters() is not used
  199. * in the subclass to store the position in parameter space.
  200. * @note If you want to renormalize the position vector after applying
  201. * the step, this method is the right place. If you use \c parameters()
  202. * to store the position, you should first call
  203. * \c OptimizationProblemFirst::doApplyStep(step);
  204. * and renormalize after that.
  205. * In this situation, you do not have to worry about \c doUnapplyStep().
  206. * The default implementation is just fine, as the position will be reset
  207. * to a backup copy of the previous position. So there are no normalization
  208. * issues involved in \c doUnapplyStep().
  209. * @param step The change to be applied to the current position
  210. */
  211. virtual void doApplyStep(const Vector& step);
  212. /**
  213. * Unapply a step to the current position in parameter space.
  214. * Only needs to be implemented in subclasses if \c parameters() is not used
  215. * in the subclass to store the position in parameter space.
  216. * @param step The change to be applied to the current position
  217. */
  218. virtual void doUnapplyStep(const Vector& step);
  219. private:
  220. bool m_positionCached;
  221. bool m_objectiveCached;
  222. bool m_gradientCached;
  223. bool m_gradientNormCached;
  224. double m_objectiveCache;
  225. Vector m_positionCache;
  226. Vector m_previousPosition;
  227. Vector m_gradientCache;
  228. double m_gradientNormCache;
  229. friend class OptimizationProblemSecond;
  230. };
  231. }; // namespace NICE
  232. #endif /* _OPTIMIZATIONPROBLEMFIRST_OPTIMIZATION_H */