IMP logo
Optimizer.h
Go to the documentation of this file.
1 /**
2  * \file Optimizer.h \brief Base class for all optimizers.
3  *
4  * Copyright 2007-2012 IMP Inventors. All rights reserved.
5  *
6  */
7 
8 #ifndef IMPKERNEL_OPTIMIZER_H
9 #define IMPKERNEL_OPTIMIZER_H
10 
11 #include "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"
21 #include <limits>
22 #include <cmath>
23 
24 IMP_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 IMPEXPORT Optimizer: public IMP::base::Object
47 {
48  public:
49  Optimizer();
50  Optimizer(Model *m, std::string name="Optimizer %1%");
51 
52  /** Optimize the model
53 
54  \param[in] max_steps The maximum number of iterations of the
55  optimizer to perform. Increasing this number will generally make
56  the optimizer spend more time searching for a solution, but
57  beyond that, the details of what changes will vary.
58 
59  \return The final score.
60  */
61  double optimize(unsigned int max_steps);
62 
63 #ifndef IMP_DOXYGEN
64  /** \name Score threshold
65  Optimizers can be set to stop if they achieve a score below
66  a score threshold. This is useful so that they don't spend time
67  improving already very good solutions.
68  @{
69  */
70  void set_score_threshold(double s) {min_score_=s;}
71  double get_score_threshold() const {return min_score_;}
72  /** @} */
73 #endif
74 
75  /** Optimization can be stopped if all the thresholds in the Model are
76  satisfied. */
77  void set_stop_on_good_score(bool tf) {
78  stop_on_good_score_=tf;
79  }
80  bool get_stop_on_good_score() const {
81  return stop_on_good_score_;
82  }
83  //! Return the score found in the last evaluate
84  double get_last_score() const {
85  return cache_->get_last_score();
86  }
87 
88  //! Return the scoring function that is being used
89  ScoringFunction *get_scoring_function() const {
90  return cache_;
91  }
92 
93  //! Get the model being optimized
94  Model *get_model() const {
95  return model_.get();
96  }
97 
98  //! Set the model being optimized
99  /**
100  \note The model is not owned by the optimizer and so is not
101  deleted when the optimizer is deleted. Further, the Optimizer
102  does not prevent the model from being deleted when all Python
103  references go away.
104  */
105  void set_model(Model *m);
106 
107  //! Print info about the optimizer state
108  /** It should end in a newline */
109  virtual void show(std::ostream &out= std::cout) const {
110  out << "Some optimizer" << std::endl;
111  }
112 
113  /** @name States
114 
115  The stored OptimizerState objects are updated each time the
116  Optimizer decides to accept a new configuration of the Model.
117  To manipulate the list of optimizer states use the methods below.
118  */
119  /**@{*/
120  IMP_LIST_ACTION(public, OptimizerState, OptimizerStates,
121  optimizer_state, optimizer_states, OptimizerState*,
122  OptimizerStates,
123  {
124  Optimizer::set_optimizer_state_optimizer(obj, this);
125  obj->set_was_used(true);
126  },{},
127  {Optimizer::set_optimizer_state_optimizer(obj, nullptr);});
128  /**@}*/
129 
130  /** By default, the Optimizer uses the scoring function provided by
131  the model, but you can use another scoring function instead.
132  */
133  virtual void set_scoring_function(ScoringFunctionInput sf);
134 
135 #ifndef IMP_DOXYGEN
136  void set_restraints(const RestraintsTemp &rs);
137 #endif
138 
140 
141  protected:
142  //! override this function to do actual optimization
143  virtual double do_optimize(unsigned int ns) =0;
144  //! Update optimizer states, should be called at each successful step
145  void update_states() const ;
146 
147 
148  /** @name Methods for getting and setting optimized attributes
149  Optimizers don't have to go through the particles themselves
150  looking for values to optimize unless they care about special
151  properties of the optimized values. Instead they can iterate
152  through the list of optimized attributes, each of which is
153  identified by a FloatIndex. With these FloatIndex objects
154  they can get and set the values and derivatives as needed.
155  */
156  //!@{
157  typedef Model::FloatIndex FloatIndex;
158  typedef base::Vector<FloatIndex> FloatIndexes;
159  base::Vector<Model::FloatIndex> get_optimized_attributes() const {
160  return get_model()->get_optimized_attributes();
161  }
162  void set_value(Model::FloatIndex fi, double v) const {
163  get_model()->set_attribute(fi.k_, fi.p_, v);
164  }
165 
166  Float get_value(Model::FloatIndex fi) const {
167  return get_model()->get_attribute(fi.k_, fi.p_);
168  }
169 
170  Float get_derivative(Model::FloatIndex fi) const {
171  return get_model()->get_derivative(fi.k_, fi.p_);
172  }
173 
174  //!@}
175 
176  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  void set_scaled_value(Model::FloatIndex fi, Float v) const {
200  double wid = width(fi.k_);
201  set_value(fi, v*wid);
202  }
203 
204  double get_scaled_value(Model::FloatIndex fi) const {
205  double uv= get_value(fi);
206  double wid = width(fi.k_);
207  return uv/wid;
208  }
209 
210  double get_scaled_derivative(Model::FloatIndex fi) const {
211  double uv=get_derivative(fi);
212  double wid= width(fi.k_);
213  return uv*wid;
214  }
215 
216  //! Clear the cache of range information. Do this at the start of optimization
217  void clear_range_cache() {
218  widths_.clear();
219  }
220  //!@}
221 
222  //! Return the restraint sets used in evaluation.
223  /** Use IMP::get_restraints() to get the actual restraints used.
224  */
225  Restraints get_restraints() const;
226 
227  private:
228  void set_is_optimizing_states(bool tf) const;
229  static void set_optimizer_state_optimizer(OptimizerState *os, Optimizer *o);
230  mutable Floats widths_;
231  Pointer<Model> model_;
232  double min_score_;
233  bool stop_on_good_score_;
234  Pointer<ScoringFunction> cache_;
235 };
236 
237 
238 IMP_OBJECTS(Optimizer,Optimizers);
239 
240 IMP_END_NAMESPACE
241 
242 #endif /* IMPKERNEL_OPTIMIZER_H */

Generated on Tue May 22 2012 23:33:15 for IMP by doxygen 1.8.1