IMP  2.0.1
The Integrative Modeling Platform
kernel/Optimizer.h
Go to the documentation of this file.
1 /**
2  * \file IMP/kernel/Optimizer.h \brief Base class for all optimizers.
3  *
4  * Copyright 2007-2013 IMP Inventors. All rights reserved.
5  *
6  */
7 
8 #ifndef IMPKERNEL_OPTIMIZER_H
9 #define IMPKERNEL_OPTIMIZER_H
10 
11 #include <IMP/kernel/kernel_config.h>
12 #include "base_types.h"
13 #include "VersionInfo.h"
14 #include "Object.h"
15 #include "utility.h"
16 #include "Model.h"
17 #include "Particle.h"
18 #include "Pointer.h"
19 #include "OptimizerState.h"
20 #include <IMP/base/Vector.h>
21 #include <limits>
22 #include <cmath>
23 
24 IMPKERNEL_BEGIN_NAMESPACE
25 
26 //! Base class for all optimizers.
27 /** An optimizer attempts to improve the current configuration of the
28  Model by moving particles around so as to lower the score.
29 
30  The Optimizer maintains a list of OptimizerStates which are
31  updated each time the conformation is changed.
32 
33  The optimizers have one key method Optimizer::optimize() which takes
34  the number of steps to perform. The optimizers can have other
35  stopping conditions as appropriate.
36 
37  A typical optimization loop proceeds by:
38  - the optimizer calls Model::evaluate() to compute the score
39  (and possibly the derivatives) of the
40  current conformation of the Model.
41  - the optimizer uses this information to update the optimizeable
42  parameters of the Particles contained in the Model.
43 
44  \implementationwithoutexample{Optimizer, IMP_OPTIMIZER}
45 */
46 class IMPKERNELEXPORT Optimizer: public IMP::base::Object
47 {
48  public:
49  Optimizer();
50  Optimizer(Model *m, std::string name="Optimizer %1%");
51 
52  //! Optimize the model for up to max_steps iterations
53  /** Optimize the model
54 
55  @param[in] max_steps The maximum number of iterations of the
56  optimizer to perform. Increasing this number will generally make
57  the optimizer spend more time searching for a solution, but
58  beyond that, the details of what changes will vary.
59 
60  @return The final score.
61  */
62  double optimize(unsigned int max_steps);
63 
64 #ifndef IMP_DOXYGEN
65  /** \name Score threshold
66  Optimizers can be set to stop if they achieve a score below
67  a score threshold. This is useful so that they don't spend time
68  improving already very good solutions.
69  @{
70  */
71  void set_score_threshold(double s) {min_score_=s;}
72  double get_score_threshold() const {return min_score_;}
73  /** @} */
74 #endif
75 
76  /** Optimization can be stopped if all the thresholds in the Model are
77  satisfied. */
78  void set_stop_on_good_score(bool tf) {
79  stop_on_good_score_=tf;
80  }
81  bool get_stop_on_good_score() const {
82  return stop_on_good_score_;
83  }
84  //! Return the score found in the last evaluate
85  double get_last_score() const {
86  return cache_->get_last_score();
87  }
88 
89  //! Return the scoring function that is being used
91  return cache_;
92  }
93 
94  //! Get the model being optimized
95  Model *get_model() const {
96  return model_.get();
97  }
98 
99  //! Set the model being optimized
100  /**
101  \note The model is not owned by the optimizer and so is not
102  deleted when the optimizer is deleted. Further, the Optimizer
103  does not prevent the model from being deleted when all Python
104  references go away.
105  */
106  void set_model(Model *m);
107 
108  //! Print info about the optimizer state
109  /** It should end in a newline */
110  virtual void show(std::ostream &out= std::cout) const {
111  out << "Some optimizer" << std::endl;
112  }
113 
114  /** @name States
115 
116  The stored OptimizerState objects are updated each time the
117  Optimizer decides to accept a new configuration of the Model.
118  To manipulate the list of optimizer states use the methods below.
119  */
120  /**@{*/
121  IMP_LIST_ACTION(public, OptimizerState, OptimizerStates,
122  optimizer_state, optimizer_states, OptimizerState*,
124  {
125  set_optimizer_state_optimizer(obj, this);
126  obj->set_was_used(true);
127  },{},
128  {Optimizer::set_optimizer_state_optimizer(obj, nullptr);});
129  /**@}*/
130 
131  /** By default, the Optimizer uses the scoring function provided by
132  the model, but you can use another scoring function instead.
133  */
134  virtual void set_scoring_function(ScoringFunctionAdaptor sf);
135 
136 #ifndef IMP_DOXYGEN
137  void set_restraints(const RestraintsTemp &rs);
138 #endif
139 
141 
142 protected:
143  //! override this function to do actual optimization
144  virtual double do_optimize(unsigned int ns) =0;
145  //! Update optimizer states, should be called at each successful step
146  /** Make sure the scoring function restraints are up to date before this is
147  called (eg by calling evaluate).*/
148  void update_states() const;
149 
150  /** @name Methods for getting and setting optimized attributes
151  Optimizers don't have to go through the particles themselves
152  looking for values to optimize unless they care about special
153  properties of the optimized values. Instead they can iterate
154  through the list of optimized attributes, each of which is
155  identified by a FloatIndex. With these FloatIndex objects
156  they can get and set the values and derivatives as needed.
157  */
158  //!@{
159  FloatIndexes get_optimized_attributes() const {
160  return get_model()->get_optimized_attributes();
161  }
162  IMP_PROTECTED_METHOD(void, set_value,(FloatIndex fi, double v), const, {
163  get_model()->set_attribute(fi.get_key(), fi.get_particle(), v);
164  });
165 
166  IMP_PROTECTED_METHOD(Float, get_value,(FloatIndex fi), const, {
167  return get_model()->get_attribute(fi.get_key(), fi.get_particle());
168  });
169 
170  IMP_PROTECTED_METHOD(Float, get_derivative,(FloatIndex fi), const, {
171  return get_model()->get_derivative(fi.get_key(), fi.get_particle());
172  });
173 
174  //!@}
175 
176  IMP_PROTECTED_METHOD(double, width,(FloatKey k), const, {
177  if (widths_.size() <=k.get_index() || widths_[k.get_index()]==0) {
178  FloatRange w= model_->get_range(k);
179  double wid=static_cast<double>(w.second)- w.first;
180  widths_.resize(std::max(widths_.size(), size_t(k.get_index()+1)), 0.0);
181  if (wid > .0001) {
182  //double nwid= std::pow(2, std::ceil(log2(wid)));
183  widths_[k.get_index()]= wid;
184  } else {
185  widths_[k.get_index()]= 1.0;
186  }
187  }
188  return widths_[k.get_index()];
189  //return 1.0;
190  });
191 
192  /** @name Methods to get and set scaled optimizable values
193  Certain optimizers benefit from having all the optimized values
194  scaled to vary over a similar range. These accessors use the
195  Model::get_range ranges to scale the values before returning
196  them and unscale them before setting them.
197  */
198  //{@
199  IMP_PROTECTED_METHOD(void, set_scaled_value,(FloatIndex fi, Float v),
200  const, {
201  double wid = width(fi.get_key());
202  set_value(fi, v*wid);
203  });
204 
205  IMP_PROTECTED_METHOD(double, get_scaled_value,(FloatIndex fi),
206  const, {
207  double uv= get_value(fi);
208  double wid = width(fi.get_key());
209  return uv/wid;
210  });
211 
212  IMP_PROTECTED_METHOD(double, get_scaled_derivative,(FloatIndex fi),
213  const, {
214  double uv=get_derivative(fi);
215  double wid= width(fi.get_key());
216  return uv*wid;
217  });
218 
219  //! Clear the cache of range information. Do this at the start of optimization
220  IMP_PROTECTED_METHOD(void, clear_range_cache,(),, {
221  widths_.clear();
222  });
223  //!@}
224 
225 #ifndef IMP_DOXYGEN
226  //! Return the restraint sets used in evaluation.
227  /** Use IMP::kernel::get_restraints() to get the actual restraints used.
228  */
230 #endif
231  private:
232  void set_is_optimizing_states(bool tf) const;
233  static void set_optimizer_state_optimizer(OptimizerState *os, Optimizer *o);
234  mutable Floats widths_;
235  Pointer<Model> model_;
236  double min_score_;
237  bool stop_on_good_score_;
238  Pointer<ScoringFunction> cache_;
239 };
240 
241 
243 
244 IMPKERNEL_END_NAMESPACE
245 
246 #endif /* IMPKERNEL_OPTIMIZER_H */