LocalOptimizer.h
1 /*
2  * Medical Image Registration ToolKit (MIRTK)
3  *
4  * Copyright 2013-2015 Imperial College London
5  * Copyright 2013-2015 Andreas Schuh
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 #ifndef MIRTK_LocalOptimizer_H
21 #define MIRTK_LocalOptimizer_H
22 
23 #include "mirtk/Observable.h"
24 
25 #include "mirtk/Math.h"
26 #include "mirtk/Array.h"
27 #include "mirtk/Queue.h"
28 #include "mirtk/OptimizationMethod.h"
29 #include "mirtk/ObjectiveFunction.h"
30 #include "mirtk/ObjectFactory.h"
31 
32 
33 namespace mirtk {
34 
35 
36 // Forward declaration of cyclic dependency
37 class StoppingCriterion;
38 
39 
40 /**
41  * Minimizes objective function without guarantee of global solution
42  */
43 class LocalOptimizer : public Observable
44 {
45  mirtkAbstractMacro(LocalOptimizer);
46 
47  // ---------------------------------------------------------------------------
48  // Attributes
49 
50  /// Objective function
51  mirtkPublicAggregateMacro(ObjectiveFunction, Function);
52 
53  /// Maximum number of iterative steps
54  mirtkPublicAttributeMacro(int, NumberOfSteps);
55 
56  /// First convergence criterium: Required minimum change of objective function
57  mirtkPublicAttributeMacro(double, Epsilon);
58 
59  /// Second convergence criterium: Required maximum change of DoFs
60  mirtkPublicAttributeMacro(double, Delta);
61 
62  /// Last n objective function values
63  mirtkReadOnlyAttributeMacro(Deque<double>, LastValues);
64 
65  /// Current slope of curve fit to last n function values
66  mirtkReadOnlyAttributeMacro(double, LastValuesSlope);
67 
68  /// Number of last objective function values to store
69  mirtkPublicAttributeMacro(int, NumberOfLastValues);
70 
71  /// Whether optimization converged within maximum number of steps
72  mirtkReadOnlyAttributeMacro(bool, Converged);
73 
74  /// List of stopping criteria
75  Array<class StoppingCriterion *> _StoppingCriteria;
76 
77  /// Copy attributes of this class from another instance
78  void CopyAttributes(const LocalOptimizer &);
79 
80  // ---------------------------------------------------------------------------
81  // Construction/Destruction
82 protected:
83 
84  /// Constructor
86 
87  /// Copy constructor
89 
90  /// Assignment operator
92 
93 public:
94 
95  /// Type of optimizer factory
97 
98  /// Get global optimizer factory instance
99  static FactoryType &Factory();
100 
101  /// Construct optimizer
102  static LocalOptimizer *New(enum OptimizationMethod, ObjectiveFunction * = NULL);
103 
104  /// Optimization method implemented by this optimizer
105  virtual enum OptimizationMethod OptimizationMethod() const = 0;
106 
107  /// Destructor
108  virtual ~LocalOptimizer();
109 
110  // ---------------------------------------------------------------------------
111  // Parameters
112 
113  // Import other overloads
114  using Observable::Parameter;
115 
116  /// Set parameter value from string
117  virtual bool Set(const char *, const char *);
118 
119  /// Get parameters as key/value as string map
120  virtual ParameterList Parameter() const;
121 
122  // ---------------------------------------------------------------------------
123  // Stopping criteria
124 
125  /// Get number of stopping criteria
126  int NumberOfStoppingCriteria() const;
127 
128  /// Add stopping criterion and take over ownership of the object
130 
131  /// Remove stopping criterion and revoke ownership of the object
133 
134  /// Get the n-th stopping criterion
136 
137  /// Get the n-th stopping criterion
138  const class StoppingCriterion *StoppingCriterion(int) const;
139 
140  /// Delete all stopping criteria
141  void ClearStoppingCriteria();
142 
143 protected:
144 
145  /// Test whether a given function value is better than another
146  ///
147  /// \param[in] prev Objective function value at previous iteration.
148  /// \param[in] value Objective function value at current iteration.
149  bool IsImprovement(double prev, double value) const;
150 
151  /// Test stopping criteria
152  ///
153  /// The objective function must be up-to-date when this function is called.
154  /// This is usually the case anyway because the current objective function
155  /// value after a change of the parameters must be evaluated before this
156  /// function is called to be able to provide this value as argument.
157  ///
158  /// \note The objective function value may be infinite in case of a non-parametric
159  /// deformable surface model. In this case, stopping criteria are based
160  /// only on the current surface geometry or last node displacements.
161  /// Stopping criteria based on the objective function value should
162  /// never be fulfilled in this case and always return \c false.
163  ///
164  /// \param[in] iter Current number of iterations.
165  /// \param[in] value Objective function value at current iteration.
166  /// \param[in] delta Last change of objective function parameters.
167  ///
168  /// \returns True when at least one stopping criterion is fulfilled.
169  virtual bool Converged(int iter, double value, const double *delta);
170 
171  // ---------------------------------------------------------------------------
172  // Optimization
173 public:
174 
175  /// Initialize optimization
176  virtual void Initialize();
177 
178  /// Run optimization
179  /// \returns Value of local minimum (maximum) of objective function
180  virtual double Run() = 0;
181 
182 };
183 
184 ////////////////////////////////////////////////////////////////////////////////
185 // Auxiliary macros for optimizer implementation
186 ////////////////////////////////////////////////////////////////////////////////
187 
188 // -----------------------------------------------------------------------------
189 #define mirtkOptimizerMacro(name, method) \
190  mirtkObjectMacro(name); \
191 public: \
192  /** Optimization method implemented by this optimizer */ \
193  static enum OptimizationMethod ID() { return method; } \
194  /** Optimization method implemented by this optimizer */ \
195  virtual enum OptimizationMethod OptimizationMethod() const { return method; }\
196 private:
197 
198 // -----------------------------------------------------------------------------
199 /// Register object type with factory singleton
200 #define mirtkRegisterOptimizerMacro(type) \
201  mirtk::LocalOptimizer::Factory() \
202  .Register(type::ID(), type::NameOfType(), \
203  mirtk::New<mirtk::LocalOptimizer, type>)
204 
205 // -----------------------------------------------------------------------------
206 #define mirtkAutoRegisterOptimizerMacro(type) \
207  mirtkAutoRegisterObjectTypeMacro(mirtk::LocalOptimizer::Factory(), \
208  mirtk::OptimizationMethod, type::ID(), \
209  mirtk::LocalOptimizer, type)
210 
211 ////////////////////////////////////////////////////////////////////////////////
212 // Inline definitions
213 ////////////////////////////////////////////////////////////////////////////////
214 
215 // -----------------------------------------------------------------------------
216 inline bool LocalOptimizer::IsImprovement(double prev, double value) const
217 {
218  if (IsInf(prev)) return !IsNaN(value);
219  if (IsInf(value)) return false;
220  return prev - value > _Epsilon;
221 }
222 
223 
224 } // namespace mirtk
225 
226 #endif // MIRTK_LocalOptimizer_H
LocalOptimizer(ObjectiveFunction *=NULL)
Constructor.
static FactoryType & Factory()
Get global optimizer factory instance.
void ClearStoppingCriteria()
Delete all stopping criteria.
class StoppingCriterion * StoppingCriterion(int)
Get the n-th stopping criterion.
void RemoveStoppingCriterion(StoppingCriterion *)
Remove stopping criterion and revoke ownership of the object.
ObjectFactory< enum OptimizationMethod, LocalOptimizer > FactoryType
Type of optimizer factory.
virtual bool Converged(int iter, double value, const double *delta)
MIRTKCU_API bool IsNaN(double x)
Check if floating point value is not a number (NaN)
Definition: Math.h:91
Array< Pair< string, string > > ParameterList
Ordered list of parameter name/value pairs.
Definition: Object.h:38
virtual ParameterList Parameter() const
Get parameters as key/value as string map.
static LocalOptimizer * New(enum OptimizationMethod, ObjectiveFunction *=NULL)
Construct optimizer.
int NumberOfStoppingCriteria() const
Get number of stopping criteria.
Definition: IOConfig.h:41
virtual bool Set(const char *, const char *)
Set parameter value from string.
MIRTKCU_API bool IsInf(double x)
Check if floating point value represents infinity.
Definition: Math.h:103
virtual double Run()=0
virtual ~LocalOptimizer()
Destructor.
void AddStoppingCriterion(StoppingCriterion *)
Add stopping criterion and take over ownership of the object.
virtual enum OptimizationMethod OptimizationMethod() const =0
Optimization method implemented by this optimizer.
virtual ParameterList Parameter() const
Get parameter name/value pairs.
Definition: Object.h:139
bool IsImprovement(double prev, double value) const
OptimizationMethod
Enumeration of available optimization methods.
virtual void Initialize()
Initialize optimization.
LocalOptimizer & operator=(const LocalOptimizer &)
Assignment operator.