Descriptor Howto
Introduction
As the name suggests descriptors describe certain elements within the world and can be used for retrieval. For the example we will use AtomDescriptors, but all the examples can also be used on any other kind of descriptor.
Using Descriptors with the World
Descriptors can be passed around, stored and calculated. With a descriptor you can tell a function which atoms you mean, independently from the state of the world (e.g. you can say "All hydrogen atoms" instead of a specific data Structure carrying atoms). This means when you add a hydrogen atom to the world, the descriptor will automatically include this atom, even when it was created before this change. Descriptors can be used in several ways with the world:
- Accessing all objects that meet a criteria as a vector:
- This can be done using the
World::getAllAtoms(AtomDescriptor)
method.
- This can be done using the
- Calculating some value on all objects that meet a criteria:
- This can be done using the
World::calcOnAtoms(boost::function<T(atom*)>,std::string,AtomDescriptor)
method. This method takes a function that calculates some value from a single atom and a descriptor. It wraps this function inside a calculation object that performs the function of the single Atom on all Atoms that meet the criteria. This object is not executed at this time, but can also be stored and be passed around. Use the function operator on the object to do the calculation and retrieve the results in a vector.
- This can be done using the
- Manipulating all the Objects that meet a criteria:
- This can be done using the
manipulateAtoms(boost::function<void(atom*)>,std::string,AtomDescriptor)
method. Similar to the calculation method this method only creates a deferred calculation, but does not yet perform any manipulations. You can simplycall()
the resulting process when you want the actual changes to happen.
- This can be done using the
Retrieving objects from the world usually takes O(N) where N is the number of this kind of objects in the world. In some cases it is possible to speed up retrieval and the speed is improved for single descriptors. The
AtomById()
Descriptor for example will find the atom in O(log(N)) instead of O(N).
Calculations with descriptors
Descriptors can be used in calculations. These calculations then correspond to simple set operations, i.e. set-intersection, union and inversion. To calculate a new descriptor from existing ones you can use the operators
&&
for set intersection||
for set union!
for the inversion of a set
The calculated descriptors still need O(N) to search the world. Descriptors that use speed up mechanism can be used in calculations, but the speed-up will be lost, i.e. the descriptor resulting from the calculation
AtomById(1) || AtomById(2)
will take O(N) to find those two atoms.
You can also assign a new descriptor to a previously used descriptor.
Creating descriptors
Unlike other C++ objects descriptors are created by simple functions instead of constructors. This has to do with some internal mechanism that have to be handled upon creation. If you are simply interested in using descriptors you can just think of these methods as constructors giving you a descriptor of the specified type (although you might note, that the return type is always the same).