IMP  2.0.1
The Integrative Modeling Platform
kernel/Decorator.h
Go to the documentation of this file.
1 /**
2  * \file IMP/kernel/Decorator.h \brief The base class for decorators.
3  *
4  * Copyright 2007-2013 IMP Inventors. All rights reserved.
5  *
6  */
7 
8 #ifndef IMPKERNEL_DECORATOR_H
9 #define IMPKERNEL_DECORATOR_H
10 
11 #include <IMP/kernel/kernel_config.h>
12 #include "base_types.h"
13 #include "Object.h"
14 #include "Pointer.h"
15 #include "Model.h"
16 #include "utility.h"
17 #include "Constraint.h"
18 #include "internal/utility.h"
20 #include <IMP/base/Vector.h>
21 #include <IMP/base/Value.h>
22 
23 IMPKERNEL_BEGIN_NAMESPACE
24 
25 /**
26 Representation of the structure in \imp is via a collection of
27 Particle objects. However, since particles are general purpose, they
28 provide a basic set of tools for managing the data (e.g.
29 IMP::Particle::add_attribute(), IMP::Particle::get_value()
30 etc). Decorators wrap (or \quote{decorate}) particles to provide a much
31 richer interface. For example, most particles have Cartesian
32 coordinates. The class IMP::core::XYZ decorates such a particle to
33 provide functions to get and set the Cartesian coordinates as well as
34 compute distances between particles.
35 \code
36 d0= IMP.core.XYZ(p0)
37 d1= IMP.core.XYZ(p1)
38 print IMP.core.distance(d0,d1)
39 print d0.get_coordinates()
40 \endcode
41 
42 \par Decorator basics
43 
44 Dealing with decorators and particles has two main parts
45 -# setting up the particle to be used with that decorator
46 -# decorating the particle.
47 
48 To set up a particle to be used with the IMP::core::XYZ decorator we do
49 \code
50 d0= IMP.core.XYZ.setup_particle(p, IMP.algebra.Vector3D(0,2,3))
51 \endcode
52 The method calls also decorates the particle and returns the decorator
53 which can now be used to manipulate the particle. For example we can
54 access the coordinates \c (0,2,3) by doing
55 \code
56 print d0.get_coordinates()
57 \endcode
58 We now say the particle is an XYZ particle. If that particle is
59 encountered later when we do not have the existing decorator available,
60 we can decorate it again (since it is already set up) by doing
61 \code
62 d1= IMP.core.XYZ(p)
63 \endcode
64 
65 If you do not know if \c p has been set up for the XYZ decorator, you can
66 ask with
67 \code
68 if IMP.core.XYZ.particle_is_instance(p):
69 \endcode
70 
71 More abstractly, decorators can be used to
72 - maintain invariants: e.g. an IMP::atom::Bond particle always connects
73  two other particles, both of which are IMP::atom::Bonded particles.
74 - add functionality: e.g. you can get the coordinates as an
75  IMP::algebra::Vector3D
76 - provide uniform names for attributes: so you do not use \quote{x} some places
77 and \quote{X} other places
78 
79 To see a list of all available decorators and to see what functions
80 all decorators have, look at the list of classes which inherit from
81 IMP::Decorator, below.
82 
83 See the IMP::example::ExampleDecorator %example for how to implement a
84 simple decorator.
85 
86 \note Decorator objects are ordered based on the address of the wrapped
87 particle. Like pointers, they are logical values so can be in \c if
88 statements.
89 
90 \implementation{Decorator, IMP_DECORATOR, IMP::example::ExampleDecorator}
91 \n\n For efficiency reasons attribute keys should always be created
92 lazily (at the time of the first use), and not be created as static
93 variables. The reason for this is that initialized attribute keys result
94 in space being allocated in decorators, even before they are used.\n\n
95 Implementors should consult IMP::example::ExampleDecorator,
96 IMP_DECORATOR(), IMP_DECORATOR_WITH_TRAITS(), IMP_DECORATOR_GET().
97 
98 \advanceddoc Lists of decorators are reference counted even though the
99 individual decorators are not. For more efficiency
100 you can use the non-reference counted version, IMP::core::XYZs
101 instead. This should only
102 be done when it is known to be safe. If you can't figure out
103 that it is, don't do it.
104 
105 A decorator can be cast to a IMP::Particle* in C++. You have to
106 use the Decorator::get_particle() function in Python.
107 
108 \note It is undefined behavior to use a decorator constructed on
109 a particle that is no longer part of a model. Since constructing
110 decorators is very cheap, you probably should not store decorators,
111 and then would not have this problem.
112 
113 See example::ExampleDecorator to see what a minimal decorator looks like.
114 */
115 class Decorator: public base::Value
116 {
117 private:
118  WeakPointer<Model> model_;
119  ParticleIndex pi_;
120  int compare(base::Object *o) const {
121  if (o < get_particle()) return -1;
122  else if (o > get_particle()) return 1;
123  else return 0;
124  }
128 public:
129  ParticleIndex get_particle_index() const {
130  return pi_;
131  }
132 #ifdef _MSC_VER
133  typedef Particle* ParticleP;
134 #endif
135 #ifndef IMP_DOXYGEN
136  bool __eq__(base::Object* o) const {
137  return operator==(o);
138  }
139  bool __ne__(base::Object* o) const {
140  return operator!=(o);
141  }
142  bool __lt__(base::Object* o) const {
143  return operator<(o);
144  }
145  bool __gt__(base::Object* o) const {
146  return operator>(o);
147  }
148  bool __ge__(base::Object* o) const {
149  return operator>=(o);
150  }
151  bool __le__(base::Object* o) const {
152  return operator<=(o);
153  }
154 #ifndef SWIG
155  bool operator==(base::Object* o) const {
156  return (compare(o) == 0);
157  }
158  bool operator!=(base::Object* o) const {
159  return (compare(o) != 0);
160  }
161  bool operator<(base::Object* o) const {
162  return (compare(o) <0);
163  }
164  bool operator>(base::Object* o) const {
165  return (compare(o) > 0);
166  }
167  bool operator>=(base::Object* o) const {
168  return !(compare(o) < 0);
169  }
170  bool operator<=(base::Object* o) const {
171  return !(compare(o) > 0);
172  }
173 
174  bool operator==(Particle* o) const {
175  return (compare(o) == 0);
176  }
177  bool operator!=(Particle* o) const {
178  return (compare(o) != 0);
179  }
180  bool operator<(Particle* o) const {
181  return (compare(o) <0);
182  }
183  bool operator>(Particle* o) const {
184  return (compare(o) > 0);
185  }
186  bool operator>=(Particle* o) const {
187  return !(compare(o) < 0);
188  }
189  bool operator<=(Particle* o) const {
190  return !(compare(o) > 0);
191  }
192 #endif
193 #endif
194 
195  /** \name Methods provided by the Decorator class
196  The following methods are provided by the Decorator class.
197  @{
198  */
199 
200  /** Returns the particle decorated by this decorator.*/
201  /** Returns the particle decorated by this decorator.*/
203  if (!model_) return nullptr;
204  else {
205  IMP_USAGE_CHECK(model_->get_particle(pi_),
206  "Particle " << pi_ << " is no longer part of the model.");
207  return model_->get_particle(pi_);
208  }
209  }
210 
211 #if !defined(IMP_DOXYGEN) && !defined(SWIG)
212  operator Particle*() const {
213  return get_particle();
214  }
215  Particle* operator->() const {
216  return get_particle();
217  }
218 #endif
219 
220  /** \brief Returns the Model containing the particle. */
221  Model *get_model() const {
222  return model_;
223  }
224  // here just to make the docs symmetric
225 private:
226  IMP_ONLY_DOXYGEN(int blah_);
227  //! @}
228 public:
229  IMP_HASHABLE_INLINE(Decorator, return boost::hash_value(get_particle()););
230 #ifdef IMP_DOXYGEN
231 
232  /** \name Methods that all decorators must have
233  All decorators must have the following methods. Decorators
234  which are parameterized (for example IMP::core::XYZR)
235  take an (optional) extra parameter after the Particle in
236  setup_particle(), and particle_is_instance().
237  \note these are
238  not actually methods of the Decorator class itself.
239  @{
240  */
241  /** \brief Return true if the particle can be cast to the decorator.
242 
243  That is, if particle_is_instance() returns \c true, then it is
244  legal to construct an instance of the decorator with that particle.
245  If not, setup_particle() must be called first.
246  \code
247  IMP::Particle *p = new IMP::Particle(m);
248  // it is false
249  std::cout << IMP::core::XYZ::particle_is_instance(p) << std::endl;
250  // As a result this is an error
251  IMP::core::XYZ d(p);
252  // now set it up
253  IMP::core::XYZ(p);
254  // now it is true
255  std::cout << IMP::core::XYZ::particle_is_instance(p) << std::endl;
256  // and now this code is OK
257  IMP::core::XYZ d(p);
258  \endcode
259  */
260  static bool particle_is_instance(Particle *p);
261 
262  /** Create an instance of the Decorator from the particle that has
263  already been set up. The particle must have been set up already
264  (eg particle_is_instance(p) must be true), but this is not
265  necessarily checked.
266  */
267  Decorator(Particle *p);
268  /** The default constructor must be defined and create a nullptr decorator,
269  analogous to a \c nullptr pointer in C++ or a \c None object in Python.
270  */
271  Decorator();
272  //! @}
273 #endif
274 #if !defined(IMP_DOXYGEN) && !defined(SWIG)
275  typedef boost::false_type DecoratorHasTraits;
276 #endif
277 };
278 
279 #ifndef IMP_DOXYGEN
280 
281 
282 inline Decorator::Decorator(Model *m, ParticleIndex pi): model_(m),
283  pi_(pi) {};
284 inline Decorator::Decorator(Particle *p): model_(p->get_model()),
285  pi_(p->get_index()){}
286 inline Decorator::Decorator() : pi_(-1) {}
287 
288 #define IMP_CONSTRAINT_DECORATOR_DECL(Name) \
289  private: \
290  static ObjectKey get_constraint_key(); \
291  static void set_constraint(SingletonModifier* before, \
292  SingletonDerivativeModifier *after, \
293  Particle *p); \
294 public: \
295  Constraint *get_constraint() const { \
296  return dynamic_cast<Constraint*>(get_particle() \
297  ->get_value(get_constraint_key())); \
298  } \
299  IMP_REQUIRE_SEMICOLON_CLASS(constraint)
300 
301 
302 #define IMP_CONSTRAINT_DECORATOR_DEF(Name) \
303  ObjectKey Name::get_constraint_key() { \
304  static ObjectKey ret(#Name " score state"); \
305  return ret; \
306  } \
307  void Name::set_constraint(SingletonModifier* before, \
308  SingletonDerivativeModifier *after, \
309  Particle *p) { \
310  if (!after && !before ) { \
311  if (p->has_attribute(get_constraint_key())) { \
312  p->get_model()->remove_score_state(dynamic_cast<ScoreState*> \
313  (p->get_value(get_constraint_key()))); \
314  p->remove_attribute(get_constraint_key()); \
315  } \
316  } else { \
317  Constraint *ss= new SingletonConstraint(before, \
318  after, p, \
319  std::string(#Name "updater for ")+p->get_name()); \
320  p->add_attribute(get_constraint_key(), ss); \
321  p->get_model()->add_score_state(ss); \
322  } \
323  } \
324  IMP_REQUIRE_SEMICOLON_NAMESPACE
325 
326 #endif
327 
328 #ifndef SWIG
329 /** Register a function that can be used to check that the particle
330  is valid with respect to the decorator. The function should take
331  a Particle* as an argument and return a bool. It should throw
332  an exception if something is wrong.
333 
334  This macro should only be used in a .cpp file.
335 */
336 #define IMP_CHECK_DECORATOR(Name, function) \
337  IMP::kernel::internal::ParticleCheck \
338  Name##pc(Name::particle_is_instance, function);
339 #endif
340 
341 #ifndef IMP_DOXYGEN
342 /** Check that the particle satisfies invariants registered by decorators.
343  */
344 IMPKERNELEXPORT void check_particle(Particle*p);
345 #endif
346 
347 IMPKERNEL_END_NAMESPACE
348 
349 #if !defined(SWIG) && !defined IMP_DOXYGEN
350 IMPKERNEL_BEGIN_INTERNAL_NAMESPACE
351 inline void unref(Decorator d) {
352  return base::internal::unref(static_cast<Particle*>(d));
353 }
354 inline void release(Decorator d) {
355  return base::internal::release(static_cast<Particle*>(d));
356 }
357 inline void ref(Decorator d) {
358  return base::internal::ref(static_cast<Particle*>(d));
359 }
360 
361 IMPKERNEL_END_INTERNAL_NAMESPACE
362 
363 #endif
364 
365 #endif /* IMPKERNEL_DECORATOR_H */