Belle II Software  release-05-02-19
RelationArray.h
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2010 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Martin Ritter *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 
11 #pragma once
12 
13 #include <framework/datastore/DataStore.h>
14 #include <framework/datastore/StoreAccessorBase.h>
15 #include <framework/utilities/ArrayIterator.h>
16 #include <framework/dataobjects/RelationElement.h>
17 #include <framework/dataobjects/RelationContainer.h>
18 #include <framework/logging/Logger.h>
19 
20 namespace Belle2 {
25  template <class T> class StoreArray;
26 
64  class RelationArray: public StoreAccessorBase {
65  public:
67  typedef ObjArrayIterator<const TClonesArray, const RelationElement> const_iterator;
68 
71 
74 
80  c_doNothing,
82  c_zeroWeight,
84  };
85 
90  typedef std::pair<index_type, bool> consolidation_type;
91 
96  struct Identity {
98  consolidation_type operator()(index_type old) const { return std::make_pair(old, false); }
99  };
100 
106  template < class MapType = std::map<index_type, consolidation_type> > class ReplaceMap {
107  public:
108 
110  explicit ReplaceMap(MapType& replace): m_replace(replace) {}
111 
114  {
115  typename MapType::const_iterator iter = m_replace.find(old);
116  if (iter != m_replace.end()) {
117  return iter->second;
118  }
119  return std::make_pair(old, false);
120  }
121 
122  private:
123 
125  MapType& m_replace;
126  };
127 
128 
134  template < class VecType = std::vector<consolidation_type> > class ReplaceVec {
135  public:
136 
138  explicit ReplaceVec(VecType& replace): m_replace(replace) {}
139 
141  consolidation_type operator()(index_type old) const { return m_replace[old]; }
142 
143  private:
144 
146  VecType& m_replace;
147  };
148 
149 
155  bool create(bool replace = false)
156  {
157  bool result = DataStore::Instance().createObject(0, replace, *this);
158  m_relations = reinterpret_cast<RelationContainer**>(DataStore::Instance().getObject(*this));
159  if (result) {
160  (*m_relations)->setFromName(m_accessorFrom.first);
161  (*m_relations)->setFromDurability(m_accessorFrom.second);
162  (*m_relations)->setToName(m_accessorTo.first);
163  (*m_relations)->setToDurability(m_accessorTo.second);
164  }
165  return result;
166  }
167 
180  template <class FROM, class TO> RelationArray(const StoreArray<FROM>& from, const StoreArray<TO>& to, const std::string& name = "",
182  StoreAccessorBase(name.empty() ? DataStore::relationName(from.getName(), to.getName()) : name, durability,
183  RelationContainer::Class(), false),
186  m_relations(0)
187  {
189  B2FATAL("Tried to create RelationArray '" << m_name << "' with a durability larger than the StoreArrays it relates");
190  }
191  }
192 
200  RelationArray(const AccessorParams& fromAccessor, const AccessorParams& toAccessor,
202  StoreAccessorBase(DataStore::relationName(fromAccessor.first, toAccessor.first), durability, RelationContainer::Class(), false),
203  m_accessorFrom(fromAccessor),
204  m_accessorTo(toAccessor),
205  m_relations(nullptr)
206  {
207  if (m_accessorFrom.second > m_durability || m_accessorTo.second > m_durability) {
208  B2FATAL("Tried to create RelationArray '" << m_name << "' with a durability larger than the StoreArrays it relates");
209  }
210  }
211 
220  explicit RelationArray(const std::string& name, DataStore::EDurability durability = DataStore::c_Event):
221  StoreAccessorBase(name, durability, RelationContainer::Class(), false),
222  m_relations(0)
223  {
224  if (name.empty()) {
225  B2FATAL("Cannot guess relation name, please supply correct name");
226  }
227  }
228 
230  ~RelationArray() {}
231 
236  inline bool isValid() const { ensureAttached(); return m_relations && *m_relations;}
238  inline operator bool() const { return isValid(); }
239 
241  const RelationElement& operator[](int i) const { assertValid(); return (*m_relations)->getElement(i);}
242 
244  int getEntries() const { return isValid() ? ((*m_relations)->getEntries()) : 0; }
245 
248  {
250  if (m_accessorFrom.first.empty())
251  B2FATAL("trying to get accessor params from non-existing relation (this is likely a framework bug)");
253  }
254 
256  const AccessorParams& getToAccessorParams() const
257  {
258  ensureAttached();
259  if (m_accessorTo.first.empty())
260  B2FATAL("trying to get accessor params from non-existing relation (this is likely a framework bug)");
261  return m_accessorTo;
262  }
263 
265  bool getModified() const { assertValid(); return (*m_relations)->getModified(); }
266 
268  void setModified(bool modified) { assertCreated(); (*m_relations)->setModified(modified); }
269 
271  void clear() override
272  {
273  setModified(true);
274  (*m_relations)->elements().Delete();
275  }
276 
283  void add(index_type from, index_type to, weight_type weight = 1.0)
284  {
285  setModified(true);
286  new(next()) RelationElement(from, to, weight);
287  }
288 
295  void add(index_type from, const std::vector<index_type>& to, weight_type weight = 1.0)
296  {
297  setModified(true);
298  std::vector<weight_type> weights(to.size(), weight);
299  new(next()) RelationElement(from, to, weights);
300  }
301 
308  void add(index_type from, const std::vector<index_type>& to, const std::vector<weight_type>& weights)
309  {
310  setModified(true);
311  new(next()) RelationElement(from, to, weights);
312  }
313 
322  template <class InputIterator> void add(index_type from, const InputIterator& begin, const InputIterator& end)
323  {
324  setModified(true);
325  new(next()) RelationElement(from, begin, end);
326  }
327 
333  void consolidate() { consolidate<Identity, Identity>(); }
334 
365  template<class FunctionFrom, class FunctionTo> void consolidate(const
366  FunctionFrom& replaceFrom = FunctionFrom(), const FunctionTo&
367  replaceTo = FunctionTo(), EConsolidationAction action =
368  c_doNothing);
369 
371  const_iterator begin() const { assertValid(); return const_iterator((*m_relations)->elements(), 0); }
373  const_iterator end() const { assertValid(); return const_iterator((*m_relations)->elements(), getEntries()); }
374 
375  private:
383  explicit RelationArray(const AccessorParams& params):
384  StoreAccessorBase(params.first, params.second, RelationContainer::Class(), false),
385  m_relations(0)
386  {
387  if (params.first.empty()) {
388  B2FATAL("Cannot guess relation name, please supply correct name");
389  }
390  }
391 
392 
395  {
396  int index = (*m_relations)->elements().GetLast() + 1;
397  return static_cast<RelationElement*>((*m_relations)->elements().AddrAt(index));
398  }
399 
401  void checkRelation(const std::string& direction, const AccessorParams& array, const AccessorParams& rel) const
402  {
403  if (array.second == 0 && array.first.empty())
404  return; //no information to check against...
405 
406  if (array != rel) {
407  B2FATAL("Relation '" << m_name << "' exists but points " << direction << " wrong array:"
408  << " requested " << array.first << "(" << array.second << ")"
409  << ", got " << rel.first << "(" << rel.second << ")"
410  );
411  }
412  }
413 
415  void ensureAttached() const
416  {
417  if (m_relations)
418  return;
419 
420  const_cast<RelationArray*>(this)->m_relations = reinterpret_cast<RelationContainer**>(DataStore::Instance().getObject(*this));
421  if (m_relations && *m_relations && !(*m_relations)->isDefaultConstructed()) {
422  AccessorParams fromAccessorRel((*m_relations)->getFromName(), (DataStore::EDurability)(*m_relations)->getFromDurability());
423  AccessorParams toAccessorRel((*m_relations)->getToName(), (DataStore::EDurability)(*m_relations)->getToDurability());
424  //set if unset
425  if (m_accessorFrom.first.empty())
426  const_cast<RelationArray*>(this)->m_accessorFrom = fromAccessorRel;
427  if (m_accessorTo.first.empty())
428  const_cast<RelationArray*>(this)->m_accessorTo = toAccessorRel;
429  checkRelation("from", m_accessorFrom, fromAccessorRel);
430  checkRelation("to", m_accessorTo, toAccessorRel);
431  } else {
432  //no relation found, mark as invalid
433  const_cast<RelationArray*>(this)->m_relations = nullptr;
434  }
435  }
436 
438  void assertValid() const { if (!isValid()) B2FATAL("RelationArray does not point to valid StoreObject"); }
439 
444  void assertCreated()
445  {
446  if (!isValid()) {
447  if (!create()) {
448  B2FATAL("Couldn't create relation " << m_name << "!");
449  }
450  }
451  }
452 
455 
458 
461 
462  template<class FROM, class TO> friend class RelationIndex;
463  template<class FROM, class TO> friend class RelationIndexContainer;
464 
465  };
466 
467  template<class FunctionFrom, class FunctionTo>
468  void RelationArray::consolidate(const FunctionFrom& replaceFrom, const FunctionTo& replaceTo, EConsolidationAction action)
469  {
470  if (!isValid()) {
471  B2ERROR("Cannot consolidate an invalid relation (" << m_name << ")");
472  return;
473  }
474  typedef std::map<index_type, weight_type> element_t;
475  typedef std::map<index_type, element_t > buffer_t;
476  buffer_t buffer;
477 
478  //Fill all existing elements in a nested map, adding the weights of
479  //duplicate elements
480  index_type lastFromIndex(0);
481  buffer_t::iterator lastFromIter = buffer.end();
482  unsigned int nElements = (*m_relations)->getEntries();
483  TClonesArray& elements = (*m_relations)->elements();
484  for (unsigned int i = 0; i < nElements; ++i) {
485  RelationElement& element = *static_cast<RelationElement*>(elements[i]);
486  //Replace from index
487  consolidation_type from = replaceFrom(element.getFromIndex());
488 
489  //Ignore whole element if original element got deleted
490  if (action == c_deleteElement && from.second) continue;
491 
492  //Check if the fromIndex is the same as the last one and reuse
493  //iterator if possible
494  if (from.first != lastFromIndex || lastFromIter == buffer.end()) {
495  lastFromIter = buffer.insert(make_pair(from.first, element_t())).first;
496  lastFromIndex = from.first;
497  }
498  //Loop over all elements of this relationelement and add them to the map
499  size_t size = element.getSize();
500  for (size_t j = 0; j < size; ++j) {
501  //Replace to Index
502  consolidation_type to = replaceTo(element.getToIndex(j));
503  //Ignore whole element if original element got deleted
504  if (action == c_deleteElement && to.second) continue;
505  double weight = element.getWeight(j);
506  //Original from or to element got deleted. Do whatever is specified by action
507  //Warning: if there is more than one element pointing to the same
508  //from->to element after transformation the negative weight option is
509  //not safe as we sum a positive and a negative weight when
510  //consolidating.
511  if (from.second || to.second) {
512  if (action == c_zeroWeight) {
513  weight = 0;
514  } else if (action == c_negativeWeight && weight > 0) {
515  weight = -weight;
516  }
517  }
518  //add the weight to the new from->to index pair
519  lastFromIter->second[to.first] += weight;
520  }
521  }
522  //Clear the existing relation
523  elements.Delete();
524  //Fill the map into the relation
525  for (buffer_t::iterator iter = buffer.begin(); iter != buffer.end(); ++iter) {
526  add(iter->first, iter->second.begin(), iter->second.end());
527  }
528  }
529 
531 } // end namespace Belle2
Belle2::RelationArray::clear
void clear() override
Clear all elements from the relation.
Definition: RelationArray.h:279
Belle2::RelationArray
Low-level class to create/modify relations between StoreArrays.
Definition: RelationArray.h:72
Belle2::RelationArray::setModified
void setModified(bool modified)
Set modified flag of underlying container.
Definition: RelationArray.h:276
Belle2::RelationContainer::isDefaultConstructed
bool isDefaultConstructed() const
Returns true if no information was set yet or Clear() was called.
Definition: RelationContainer.h:69
Belle2::RelationArray::c_negativeWeight
@ c_negativeWeight
Flip the sign of the weight to become negative if the original element got re-attributed.
Definition: RelationArray.h:89
Belle2::RelationArray::consolidate
void consolidate()
Consolidate Relation Elements.
Definition: RelationArray.h:341
Belle2::DataStore::Instance
static DataStore & Instance()
Instance of singleton Store.
Definition: DataStore.cc:54
Belle2::RelationArray::Identity
Struct for identity transformation on indices.
Definition: RelationArray.h:104
Belle2::RelationArray::ReplaceMap::m_replace
MapType & m_replace
Reference of the used replacement map.
Definition: RelationArray.h:133
Belle2::RelationArray::c_doNothing
@ c_doNothing
Do nothing, just treat it as reordering.
Definition: RelationArray.h:88
Belle2::RelationArray::ReplaceMap::operator()
consolidation_type operator()(index_type old) const
Take old index and return the new index.
Definition: RelationArray.h:121
Belle2::RelationContainer
Class to store relations between StoreArrays in the DataStore.
Definition: RelationContainer.h:35
Belle2::StoreAccessorBase::getAccessorParams
AccessorParams getAccessorParams() const
Return pair of name and durability under which stored object is saved.
Definition: StoreAccessorBase.h:136
Belle2::RelationIndex
Provides access to fast ( O(log n) ) bi-directional lookups on a specified relation.
Definition: RelationIndex.h:84
Belle2::RelationArray::consolidation_type
std::pair< index_type, bool > consolidation_type
Typedef declaring the return value of any consolidation mapping.
Definition: RelationArray.h:98
Belle2::RelationArray::getFromAccessorParams
const AccessorParams & getFromAccessorParams() const
Return the AccessorParams the attached relation points from.
Definition: RelationArray.h:255
Belle2::StoreAccessorBase::getName
const std::string & getName() const
Return name under which the object is saved in the DataStore.
Definition: StoreAccessorBase.h:130
Belle2::RelationArray::EConsolidationAction
EConsolidationAction
Modification actions for the consolidate member.
Definition: RelationArray.h:87
Belle2::RelationArray::end
const_iterator end() const
Return const_iterator to last entry +1.
Definition: RelationArray.h:381
Belle2::RelationArray::c_zeroWeight
@ c_zeroWeight
Set the weight of the relation to 0 if the original element got re-attributed.
Definition: RelationArray.h:90
Belle2::RelationArray::create
bool create(bool replace=false)
Create an empty relation array in the data store.
Definition: RelationArray.h:163
Belle2::DataStore::getObject
TObject ** getObject(const StoreAccessorBase &accessor)
Get a pointer to a pointer of an object in the DataStore.
Definition: DataStore.cc:306
Belle2::RelationArray::index_type
RelationElement::index_type index_type
Typedef to simplify use of correct index_type.
Definition: RelationArray.h:78
Belle2::RelationArray::ReplaceVec::m_replace
VecType & m_replace
Reference of the used replacement vector.
Definition: RelationArray.h:154
Belle2::RelationArray::Identity::operator()
consolidation_type operator()(index_type old) const
Take old index and return the new index.
Definition: RelationArray.h:106
Belle2::RelationArray::m_accessorTo
AccessorParams m_accessorTo
Accessor params for to array.
Definition: RelationArray.h:465
Belle2::RelationArray::next
RelationElement * next()
Return address where the next RelationElement should be created.
Definition: RelationArray.h:402
Belle2::StoreAccessorBase::m_name
std::string m_name
Store name under which this object/array is saved.
Definition: StoreAccessorBase.h:168
Belle2::RelationArray::m_relations
RelationContainer ** m_relations
Pointer that actually holds the relations.
Definition: RelationArray.h:468
Belle2::RelationElement
Class to store a single element of a relation.
Definition: RelationElement.h:33
Belle2::AccessorParams
std::pair< std::string, DataStore::EDurability > AccessorParams
Pair of parameters needed to find an object in the DataStore.
Definition: StoreAccessorBase.h:26
Belle2::RelationArray::weight_type
RelationElement::weight_type weight_type
Typedef to simplify use of correct weight_type.
Definition: RelationArray.h:81
Belle2::StoreAccessorBase::m_durability
DataStore::EDurability m_durability
Store durability under which the object/array is saved.
Definition: StoreAccessorBase.h:171
Belle2::RelationArray::const_iterator
ObjArrayIterator< const TClonesArray, const RelationElement > const_iterator
STL-like const_iterator over the T objects (not T* ).
Definition: RelationArray.h:75
Belle2::RelationArray::ReplaceVec::operator()
consolidation_type operator()(index_type old) const
Take old index and return the new index.
Definition: RelationArray.h:149
Belle2::RelationContainer::setFromName
void setFromName(const std::string &name)
Set name of the StoreArray we relate from.
Definition: RelationContainer.h:54
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::RelationArray::c_deleteElement
@ c_deleteElement
Delete the whole relation element if the original element got re-attributed.
Definition: RelationArray.h:91
Belle2::RelationArray::begin
const_iterator begin() const
Return const_iterator to first entry.
Definition: RelationArray.h:379
Belle2::RelationArray::isValid
bool isValid() const
Check whether the object was created.
Definition: RelationArray.h:244
Belle2::RelationArray::getToAccessorParams
const AccessorParams & getToAccessorParams() const
Return the AccessorParams the attached relation points to.
Definition: RelationArray.h:264
Belle2::RelationArray::ensureAttached
void ensureAttached() const
Attach to relation, if necessary.
Definition: RelationArray.h:423
Belle2::RelationArray::assertValid
void assertValid() const
check that pointer exits, otherwise bail out.
Definition: RelationArray.h:446
Belle2::RelationElement::index_type
unsigned int index_type
type used for indices.
Definition: RelationElement.h:37
Belle2::RelationArray::add
void add(index_type from, index_type to, weight_type weight=1.0)
Add a new element to the relation.
Definition: RelationArray.h:291
Belle2::RelationArray::getModified
bool getModified() const
Get modified flag of underlying container.
Definition: RelationArray.h:273
Belle2::RelationArray::ReplaceVec
Struct to replace indices based on a sequential container.
Definition: RelationArray.h:142
Belle2::RelationArray::checkRelation
void checkRelation(const std::string &direction, const AccessorParams &array, const AccessorParams &rel) const
Check that the AccessorParams stored in the relation and the one given to the constructor are the sam...
Definition: RelationArray.h:409
Belle2::RelationArray::ReplaceMap
Struct to replace indices based on a map-like container.
Definition: RelationArray.h:114
Belle2::RelationArray::RelationArray
RelationArray(const StoreArray< FROM > &from, const StoreArray< TO > &to, const std::string &name="", DataStore::EDurability durability=DataStore::c_Event)
Constructor which takes both store arrays and performs some sanity checks on the relation.
Definition: RelationArray.h:188
Belle2::RelationIndexContainer
Class to store a bidirectional index between two StoreArrays.
Definition: RelationIndexContainer.h:58
Belle2::RelationArray::getEntries
int getEntries() const
Get the number of elements.
Definition: RelationArray.h:252
Belle2::RelationArray::~RelationArray
~RelationArray()
Empty destructor.
Definition: RelationArray.h:238
Belle2::RelationArray::assertCreated
void assertCreated()
Create relation, if necessary.
Definition: RelationArray.h:452
Belle2::RelationArray::ReplaceMap::ReplaceMap
ReplaceMap(MapType &replace)
Set reference to used replacement map.
Definition: RelationArray.h:118
Belle2::RelationArray::m_accessorFrom
AccessorParams m_accessorFrom
Accessor params for from array.
Definition: RelationArray.h:462
Belle2::DataStore::createObject
bool createObject(TObject *object, bool replace, const StoreAccessorBase &accessor)
Create a new object/array in the DataStore or add an existing one.
Definition: DataStore.cc:316
Belle2::RelationElement::weight_type
float weight_type
type used for weights.
Definition: RelationElement.h:40
Belle2::DataStore::c_Event
@ c_Event
Different object in each event, all objects/arrays are invalidated after event() function has been ca...
Definition: DataStore.h:61
Belle2::StoreAccessorBase::StoreAccessorBase
StoreAccessorBase(const std::string &name, DataStore::EDurability durability, TClass *objClass, bool isArray)
Constructor to access an object or array in the DataStore.
Definition: StoreAccessorBase.h:39
Belle2::RelationArray::ReplaceVec::ReplaceVec
ReplaceVec(VecType &replace)
Set reference to used replacement vector.
Definition: RelationArray.h:146
Belle2::RelationArray::operator[]
const RelationElement & operator[](int i) const
Imitate array functionality.
Definition: RelationArray.h:249
Belle2::DataStore::EDurability
EDurability
Durability types.
Definition: DataStore.h:60