Belle II Software  release-06-02-00
select_subset.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 #include <framework/datastore/SelectSubset.h>
9 #include <framework/datastore/StoreArray.h>
10 #include <framework/datastore/RelationsObject.h>
11 #include <framework/datastore/RelationArray.h>
12 
13 
14 #include <gtest/gtest.h>
15 
16 #include <string>
17 #include <vector>
18 #include <cstdlib>
19 #include <iostream>
20 #include <map>
21 #include <unordered_map>
22 #include <algorithm>
23 
24 using namespace std;
25 using namespace Belle2;
26 
27 
28 namespace {
30  class SelectSubsetTest : public ::testing::Test {
31 
32  public:
33 
34  using KeyElementType = UInt_t;
35  using StoredElement = RelationsObject;
36 
37 
38  static bool SelectionCriterium(const KeyElementType a)
39  {
40  // The elements whose UniqueID is prime are selected (well, if the UniqueID
41  // is equal or greather than 1369 the sieve is too coarse)
42  return (a % 2) != 0 && (a % 3) != 0 && (a % 5) != 0 && (a % 7) != 0 &&
43  (a % 11) != 0 && (a % 13) != 0 && (a % 17) != 0 && (a % 19) != 0 && (a % 23) != 0 &&
44  (a % 29) != 0 && (a % 31) != 0 ;
45  }
46 
47  static bool SelectionCriteriumOnElement(const StoredElement* a)
48  {
49  return SelectionCriterium(a->GetUniqueID());
50  }
51 
52  // The following map type is ment as a container of all the relations
53  // from m_fromElement to al other elements in all the store arrays.
54  // It maps the "To" KeyElement to the weight of Relation.
55  using FromTargetElementsToWeight = map< KeyElementType , double >;
56 
57 
58  class Relations {
59 
60  // This class is a container of all the
61  // relations from m_elementKey to all other elements
62  // in all the store arrays of the TestBench
63 
64  public:
65 
66  // the following map is ment to map the name of StoreArray to the
67  // map linking the target "to" element to the weight of the relation.
68  using FromStringToArrows = unordered_map< string, FromTargetElementsToWeight >;
69 
70  private:
71  KeyElementType m_fromElement;
72  FromStringToArrows m_allRelations;
73 
74  public:
75 
76  // constructor
77  explicit Relations(const KeyElementType& from):
78  m_fromElement(from)
79  {
80  }
81 
82  const FromStringToArrows&
83  getConstSetOfAllRelations() const
84  {
85  return m_allRelations;
86  }
87 
88  FromStringToArrows::const_iterator
89  getConstSetOfToRelations(const string& toSetName) const
90  {
91  return m_allRelations.find(toSetName) ;
92  }
93 
94 
95  FromStringToArrows::iterator
96  getSetOfToRelations(const string& toSetName)
97  {
98  return m_allRelations.find(toSetName) ;
99  }
100 
101  FromStringToArrows::const_iterator
102  getSetOfToRelations(const string& toSetName) const
103  {
104  return m_allRelations.find(toSetName) ;
105  }
106 
107 
108  void
109  print()
110  {
111  cout << "From KeyElement " << m_fromElement << "to:" << endl;
112  for (const auto& toSet : m_allRelations) {
113  for (auto pair : toSet.second)
114  cout << "Set name: "
115  << toSet.first << " "
116  << pair.first
117  << " ( " << pair.second << " ) " << endl;
118 
119  cout << "-----------------------------------------------------------------" << endl;
120  }
121  }
122 
123  bool
124  isPresentRelationTo(const string& toSetName, KeyElementType to) const
125  {
126  auto toRelations = getConstSetOfToRelations(toSetName);
127  if (toRelations == m_allRelations.end())
128  return false;
129  return toRelations->second.find(to) != toRelations->second.end();
130  }
131 
132  void
133  appendNewRelationTo(const string& toName, KeyElementType to,
134  double weight)
135  {
136  auto toRelations = getSetOfToRelations(toName);
137  if (toRelations == m_allRelations.end()) {
138  // add the new named set to the relation
139  m_allRelations.insert(pair <string, FromTargetElementsToWeight>
140  (toName,
141  FromTargetElementsToWeight({ {to, weight} })));
142  return;
143  }
144  pair< KeyElementType, double > relation(to, weight);
145  toRelations->second.insert(relation);
146 
147  }
148 
149  const FromTargetElementsToWeight&
150  getAllRelations(const string& toOtherSetName) const
151  {
152  static FromTargetElementsToWeight nothing;
153  auto toRelations = getSetOfToRelations(toOtherSetName);
154  if (toRelations == m_allRelations.end()) {
155  return nothing;
156  };
157  return toRelations->second;
158  }
159 
160  };
161 
162 //disable warnings about unused functions
163 #if defined(__INTEL_COMPILER)
164 #pragma warning disable 177
165 #endif
166 
167  class NamedSet {
168 
169  // The class NamedSet provides two representantions of the same entity.
170  // The entity has a name, a set, and some relations with other sets.
171  // The entity name is m_name.
172  // The set is stored both as a StoreArray named m_name and as an unordered_map
173  // The relations are stored both as relation and as unordered_map so that
174  // one can check the correctness of the SelectSubset utility.
175 
176  string m_name; // My name
177  map< KeyElementType, Relations > m_set; // What I am
178  StoreArray< StoredElement > m_storeArray; // How I am stored
179  RelationArray* to{nullptr}; // How my relation to the original set is stored
180  RelationArray* from{nullptr}; // How my relation from the original set is stored
181  RelationArray* self{nullptr}; // How the relation with myself is stored (yes, I am
182  // the original set)
183  public:
184 
185 
186  void print()
187  {
188  cout << "The NamedSet: " << m_name << " contains:" << endl ;
189  for (auto set : m_set) {
190  cout << set.first << endl;
191  set.second.print();
192  }
193  cout << "~~~~~~~~~~~~~~~~~~~~~~~" << endl;
194  }
195 
196  // constructor
197  explicit NamedSet(const string& name = "") :
198  m_name(name), m_storeArray(name) {}
199 
200  // order relation
201  bool operator()(const NamedSet& a, const NamedSet& b) const
202  {
203  return a.getName() < b.getName();
204  }
205 
206  // accessors
207  [[nodiscard]] const string getName() const
208  {
209  return m_name;
210  }
211 
212  StoreArray< StoredElement >& storedArray()
213  {
214  return m_storeArray;
215  }
216 
217 
218  void initializeDatastore()
219  {
220  // this method take care of the initialization of the
221  // StoreArray
222  DataStore::Instance().setInitializeActive(true);
223 
225  array.registerInDataStore();
226  array.registerRelationTo(array);
227 
228  DataStore::Instance().setInitializeActive(false);
229  }
230 
231  void initializeDatastore(const string& SetName)
232  {
233  // this method take care of the initialization of the
234  // store array and of the RelationArrays from and to
235  // the StoreArray named SetName
236 
237  DataStore::Instance().setInitializeActive(true);
238 
240  StoreArray< StoredElement > otherSet(SetName);
241  array.registerInDataStore();
242  array.registerRelationTo(otherSet);
243  otherSet.registerRelationTo(array);
244  //TODO one of these is wrong! -> getRelationsWith() would return both directions
245 
246  DataStore::Instance().setInitializeActive(false);
247  }
248 
249  void consolidate()
250  {
251  // this method consolidate the StoreArray and the RelationArrays
252  // to and from the set
253  if (self != nullptr)
254  self->consolidate();
255  if (from != nullptr)
256  from->consolidate();
257  if (to != nullptr)
258  to->consolidate();
259  }
260 
261 
262  void appendNewElement(KeyElementType element)
263  {
264  m_set.insert(pair< KeyElementType, Relations > (element, Relations(element)));
265  }
266 
267  void appendNewRelationTo(KeyElementType fromKey, const string& toName, KeyElementType toKey,
268  double weight)
269  {
270  auto fromElement = m_set.find(fromKey);
271  if (fromElement == m_set.end()) {
272  cout << "??" << endl;
273  return; // quietly skip
274  }
275  fromElement->second.appendNewRelationTo(toName, toKey, weight);
276  }
277 
278  [[nodiscard]] bool isPresentRelationFromTo(const KeyElementType& fromKey, const string& otherSetName ,
279  const KeyElementType& toKey) const
280  {
281  auto fromElement = m_set.find(fromKey);
282  if (fromElement != m_set.end()) {
283  return fromElement->second.isPresentRelationTo(otherSetName, toKey);
284  } else {
285  static int i(0);
286  if (i ++ < 999 || (i % 100) == 0) {
287  cout << "Error: from: " << getName() << " id " << fromKey <<
288  " -> " << otherSetName << " id " << toKey << endl;
289  for (const auto& element : m_set)
290  cout << element.first << "\t";
291  cout << endl;
292  for (const auto& element : m_storeArray)
293  cout << element.GetUniqueID() << "\t";
294  cout << endl;
295  } else if (i == 1000) {
296  cout << "Skipping 99% of the following errors" << endl;
297  }
298  return false;
299  }
300  }
301 
302  [[nodiscard]] const FromTargetElementsToWeight& getAllRelations(const KeyElementType& fromKey, const string& toOtherSetName) const
303  {
304  auto fromElement = m_set.find(fromKey);
305  return fromElement->second.getAllRelations(toOtherSetName);
306  }
307 
308  using StlRelationArray = map< KeyElementType , FromTargetElementsToWeight >;
309 
310  [[nodiscard]] StlRelationArray getRestrictedDomainRelationTo(const string& toOtherSetName)const
311  {
312  StlRelationArray theInducedRelation;
313  for (const auto& element : m_set) {
314  if (SelectionCriterium(element.first) &&
315  element.second.getAllRelations(toOtherSetName).size() != 0)
316  theInducedRelation.insert(pair< KeyElementType, FromTargetElementsToWeight>
317  (element.first, element.second.getAllRelations(toOtherSetName)));
318  }
319  return theInducedRelation;
320  }
321 
322  [[nodiscard]] StlRelationArray getRestrictedCodomainRelationTo(const string& setName)const
323  {
324  StlRelationArray theInducedRelation;
325  for (const auto& element : m_set) {
326  if (element.second.getConstSetOfToRelations(setName) ==
327  element.second.getConstSetOfAllRelations().end())
328  continue;
329  for (auto image : element.second.getConstSetOfToRelations(setName)->second) {
330  if (SelectionCriterium(image.first)) {
331  if (theInducedRelation.find(element.first) == theInducedRelation.end())
332  theInducedRelation.insert(pair< KeyElementType, FromTargetElementsToWeight>
333  (element.first, FromTargetElementsToWeight()));
334  theInducedRelation.find(element.first)->second.
335  insert(FromTargetElementsToWeight::value_type
336  (image.first, image.second));
337  }
338  }
339  }
340  return theInducedRelation;
341  }
342 
343  [[nodiscard]] StlRelationArray getRestrictedSelfRelation() const
344  {
345  StlRelationArray theInducedRelation;
346  for (const auto& element : m_set) {
347  if (! SelectionCriterium(element.first) ||
348  element.second.getAllRelations(m_name).size() == 0)
349  continue;
350  for (auto image : element.second.getConstSetOfToRelations(m_name)->second) {
351  if (SelectionCriterium(image.first)) {
352  if (theInducedRelation.find(element.first) == theInducedRelation.end())
353  theInducedRelation.insert(pair< KeyElementType, FromTargetElementsToWeight>
354  (element.first, FromTargetElementsToWeight()));
355  theInducedRelation.find(element.first)->second.
356  insert(FromTargetElementsToWeight::value_type
357  (image.first, image.second));
358  }
359  }
360  }
361  return theInducedRelation;
362 
363  }
364  };
365 
366  class CollectionOfSets {
367 
368  // This is the actual test bench. It contains the set to be subsetted
369  // together with the subset and the other sets in relation with the subset
370  private:
371  string m_setName; // We start from this set
372  string m_subsetName; // we will select this subset
373  NamedSet m_set;
374  NamedSet m_subset;
375 
376  vector< string > m_otherSetsNames; // other sets in the universe
377  unordered_map< string, NamedSet > m_otherSets;
378 
379  public:
380  // constructor
381  CollectionOfSets(): m_set("theSet"),
382  m_subset("theSubset"),
383  m_otherSetsNames {string("G"), string("F"), string("E"),
384  string("D"), string("C"), string("B"), string("A")
385  }
386  {
387  m_setName = m_set.getName();
388  m_subsetName = m_subset.getName();
389  for (const auto& aSetName : m_otherSetsNames)
390  m_otherSets.insert(pair<string, NamedSet> (aSetName, NamedSet(aSetName)));
391  };
392 
393  //accessors
394  const string&
395  getSetName() const
396  {
397  return m_setName ;
398  };
399 
401  getSet()
402  {
403  return m_set.storedArray();
404  };
405 
406  NamedSet&
407  getNamedSet()
408  {
409  return m_set;
410  };
411 
412 
413  const string&
414  getSubsetName() const
415  {
416  return m_subsetName ;
417  };
418 
420  getSubset()
421  {
422  return m_subset.storedArray();
423  };
424 
425  int
426  getNSets() const
427  {
428  return m_otherSets.size() ;
429  }
430 
431  const vector< string >&
432  getOtherSetsNames() const
433  {
434  return m_otherSetsNames ;
435  }
436 
437  const string&
438  getOtherSetsNames(int i) const
439  {
440  return m_otherSetsNames[i] ;
441  }
442 
444  getOtherSet(int i)
445  {
446  auto otherSet = m_otherSets.find(m_otherSetsNames[ i ]);
447  if (otherSet != m_otherSets.end())
448  return otherSet->second.storedArray();
449  else
450  cout << " ???????????? " << i << endl;
451  throw std::runtime_error("invalid set access");
452  }
453 
454  pair< const string, NamedSet>&
455  getOtherNamedSet(int i)
456  {
457  return * m_otherSets.find(m_otherSetsNames[ i ]);
458  }
459 
460  unordered_map< string, NamedSet >&
461  getOtherSets()
462  {
463  return m_otherSets;
464  }
465 
466  void
467  initializeDatastore()
468  {
469  // initialitation phase
470 
471  m_set.initializeDatastore();
472 
473  for (auto namedSet : m_otherSets)
474  namedSet.second.initializeDatastore(getSetName());
475 
476  }
477 
478  void
479  populateDatastore()
480  {
481  unsigned int nElements = 1368;
482  for (unsigned int i = 0; i < nElements ; i++)
483  appendNewElement(m_set);
484 
485  int n(0);
486 
487  for (auto& set : m_otherSets) {
488  unsigned int nOtherElements = nElements - n * 100;
489 
490  for (unsigned int i = 0; i < nOtherElements ; i++)
491  appendNewElement(set.second);
492 
493  }
494 
495  int j(2);
496  for (auto& set : m_otherSets) {
497 
498 
499  unsigned int nArrows = nElements * j;
500  j++;
501 
502  for (unsigned int arrow = 0; arrow < nArrows ; arrow ++) {
503  appendNewRelationToOther(set);
504  appendNewRelationFromOther(set);
505  }
506 
507  }
508 
509 
510  for (unsigned int arrow = 0; arrow < 5 * nElements; arrow ++)
511  appendNewSelfRelation();
512 
513 #ifdef DEBUG
514  m_set.print();
515 #endif
516 
517  }
518 
519 
520  double
521  getWeight()
522  {
523  static double counter(0.0);
524  return counter += 1.;
525  };
526 
527  unsigned int
528  flat_random(unsigned int max)
529  {
530  /* This algorithm is mentioned in the ISO C standard, here extended for 32 bits.
531  the initial seed is arbitrary set to 11036
532  the seed is 11036 and is fixed i.e. it is strictly reproducible and does
533  not interact with other random generators*/
534  static unsigned int next = 11036;
535  int result;
536 
537  next *= 1103515245;
538  next += 12345;
539  result = (unsigned int)(next / 65536) % 2048;
540 
541  next *= 1103515245;
542  next += 12345;
543  result <<= 10;
544  result ^= (unsigned int)(next / 65536) % 1024;
545 
546  next *= 1103515245;
547  next += 12345;
548  result <<= 10;
549  result ^= (unsigned int)(next / 65536) % 1024;
550 
551  return result % max;
552 
553  }
554 
555  void
556  appendNewElement(NamedSet& namedSet)
557  {
558  StoreArray< StoredElement >& set = namedSet.storedArray();
559  int i = set.getEntries() ;
560  static int uniqueId(0);
561 
562  namedSet.appendNewElement(uniqueId);
563  set.appendNew();
564  set[ i ]->SetUniqueID(uniqueId);
565  uniqueId++;
566  }
567 
568 
569  void
570  appendNewRelationToOther(pair< const string, NamedSet>& set)
571  {
572 
573  int from_index = flat_random(getSet().getEntries());
574  KeyElementType from_key = getSet()[from_index]->GetUniqueID();
575  int to_index = flat_random(set.second.storedArray().getEntries());
576  KeyElementType to_key = set.second.storedArray()[to_index]->GetUniqueID();
577 
578 
579  if (getNamedSet().isPresentRelationFromTo(from_key, set.first , to_key))
580  return; // Arrow already drawn
581 
582 
583  double weight = getWeight();
584 
585  getNamedSet().appendNewRelationTo(from_key, set.first, to_key , weight);
586 
587  RelationArray setToOtherSet(getSet(), set.second.storedArray());
588  setToOtherSet.add(from_index, to_index, weight);
589 
590  }
591 
592 
593  void
594  appendNewRelationFromOther(pair< const string, NamedSet>& otherSet)
595  {
596 
597  //cout << otherSet.first << "\t";
598  unsigned int from_index = flat_random(otherSet.second.storedArray().getEntries());
599  //cout << from_index << "\t";
600  KeyElementType from_key = otherSet.second.storedArray()[from_index]->GetUniqueID();
601  //cout << from_key << endl;
602  unsigned int to_index = flat_random(getSet().getEntries());
603  KeyElementType to_key = getSet()[to_index]->GetUniqueID();
604 
605  if (otherSet.second.isPresentRelationFromTo(from_key, getSetName(), to_key))
606 
607  return; // Arrow already drawn
608 
609  double weight = getWeight();
610 
611  otherSet.second.appendNewRelationTo(from_key, getSetName(), to_key , weight);
612 
613  //otherSet.second.storedArray()[ from_index ]->SetBinContent( 0 , to_index , weight);
614 
615  RelationArray otherSetToSet(otherSet.second.storedArray(), getSet());
616  otherSetToSet.add(from_index, to_index, weight);
617 
618  }
619 
620  void
621  appendNewSelfRelation()
622  {
623  unsigned int from_index = flat_random(getSet().getEntries());
624  KeyElementType from_key = getSet()[from_index]->GetUniqueID();
625  unsigned int to_index = flat_random(getSet().getEntries());
626  KeyElementType to_key = getSet()[to_index]->GetUniqueID();
627 
628 
629  if (getNamedSet().isPresentRelationFromTo(from_key, getSetName() , to_key))
630  return; // Arrow already drawn
631 
632  double weight = getWeight();
633 
634  getNamedSet().appendNewRelationTo(from_key, getSetName(), to_key , weight);
635 
636  RelationArray setToSet(getSet(), getSet());
637 
638  setToSet.add(from_index, to_index, weight);
639 
640 
641  }
642 
643 
644  };
645 
646 
647  protected:
648 
649  CollectionOfSets m_TestBench;
650 
651  void SetUp() override
652  {
653  }
654 
656  void TearDown() override
657  {
658  DataStore::Instance().reset();
659  }
660 
661 
662  bool
663  testRelationToOther(pair< const string, NamedSet>& otherSet)
664  {
665 
666  StoreArray< StoredElement > theSet(m_TestBench.getSetName());
667  StoreArray< StoredElement > subset(m_TestBench.getSubsetName());
668  RelationArray subsetToOtherSet(subset,
669  otherSet.second.storedArray());
670 
671 
672  NamedSet::StlRelationArray theInducedRelation;
673 
674  for (int relation = 0 ; relation < subsetToOtherSet.getEntries() ; relation++) {
675  size_t relationSize = subsetToOtherSet[ relation ].getSize();
676 
677  RelationElement::index_type from = subsetToOtherSet[ relation ].getFromIndex();
678  KeyElementType fromElementKey = subset[from]->GetUniqueID();
679  if (theInducedRelation.find(fromElementKey) == theInducedRelation.end())
680  theInducedRelation.insert(pair< KeyElementType, FromTargetElementsToWeight>
681  (fromElementKey, FromTargetElementsToWeight()));
682 
683  for (unsigned int to_index = 0 ; to_index < relationSize ; to_index++) {
684  RelationElement::index_type to = subsetToOtherSet[ relation ].getToIndex(to_index);
685  double weight = subsetToOtherSet[ relation ].getWeight(to_index);
686  KeyElementType toElementKey = otherSet.second.storedArray()[to]->GetUniqueID();
687 
688  theInducedRelation.find(fromElementKey)->second.insert(pair< KeyElementType, double> (toElementKey , weight));
689 
690  }
691  }
692 
693 
694  NamedSet::StlRelationArray theExpectedRelation = m_TestBench.getNamedSet().
695  getRestrictedDomainRelationTo(otherSet.first) ;
696 
697  bool OKorKO = equal(theExpectedRelation.begin(), theExpectedRelation.end(), theInducedRelation.begin(),
698  [](const NamedSet::StlRelationArray::value_type & a,
699  const NamedSet::StlRelationArray::value_type & b) {
700 #ifdef DEBUG
701  cout << a.first << " vs " << b.first << endl;
702 #endif
703  return a.first == b.first &&
704  equal(a.second.begin(), a.second.end(), b.second.begin(),
705  [](const FromTargetElementsToWeight::value_type & x,
706  const FromTargetElementsToWeight::value_type & y) {
707 #ifdef DEBUG
708  cout
709  << x.first << "," << x.second
710  << " <-> "
711  << y.first << "," << y.second << "\t";
712  cout << (x.first == y.first) << " , " << (x.second == y.second) << endl;
713 #endif
714  return x.first == y.first && x.second == y.second;
715  }
716  ) ;
717  });
718 
719 #ifdef DEBUG
720  for (auto relation : theExpectedRelation)
721  for (auto to : relation.second)
722  cout << relation.first << " -> " << to.first << " ( " << to.second << " )" << endl;
723 
724  for (auto relation : theInducedRelation)
725  for (auto to : relation.second)
726  cout << relation.first << " --> " << to.first << " ( " << to.second << " )" << endl;
727 #endif
728 
729 
730  return OKorKO;
731  }
732 
733  bool
734  testRelationFromOther(pair< const string, NamedSet>& otherNamedSet)
735  {
736 
737  StoreArray< StoredElement > subset(m_TestBench.getSubsetName());
738  StoreArray< StoredElement > other = otherNamedSet.second.storedArray();
739 
740 
741  RelationArray subsetFromOtherSet(otherNamedSet.second.storedArray(), subset);
742 
743 
744  NamedSet::StlRelationArray theInducedRelation;
745 
746  for (int relation = 0 ; relation < subsetFromOtherSet.getEntries() ; relation++) {
747  size_t relationSize = subsetFromOtherSet[ relation ].getSize();
748  RelationElement::index_type from = subsetFromOtherSet[ relation ].getFromIndex();
749  KeyElementType fromElementKey = other[from]->GetUniqueID();
750  if (theInducedRelation.find(fromElementKey) == theInducedRelation.end()) {
751  theInducedRelation.insert(pair< KeyElementType, FromTargetElementsToWeight>
752  (fromElementKey, FromTargetElementsToWeight()));
753  }
754 
755  for (unsigned int to_index = 0 ; to_index < relationSize ; to_index++) {
757  subsetFromOtherSet[ relation ].getToIndex(to_index);
758  double weight = subsetFromOtherSet[ relation ].getWeight(to_index);
759  KeyElementType toElementKey = subset[to]->GetUniqueID();
760 
761  theInducedRelation.find(fromElementKey)->second.insert(pair< KeyElementType, double> (toElementKey , weight));
762 
763  }
764  }
765 
766 
767  NamedSet::StlRelationArray theExpectedRelation
768  = otherNamedSet.second.getRestrictedCodomainRelationTo(m_TestBench.getSetName());
769  bool OKorKO = equal(theExpectedRelation.begin(), theExpectedRelation.end(), theInducedRelation.begin(),
770  [](const NamedSet::StlRelationArray::value_type & a,
771  const NamedSet::StlRelationArray::value_type & b) {
772 #ifdef DEBUG
773  cout << a.first << " vs " << b.first << endl;
774 #endif
775  return a.first == b.first &&
776  equal(a.second.begin(), a.second.end(), b.second.begin(),
777  [](const FromTargetElementsToWeight::value_type & x,
778  const FromTargetElementsToWeight::value_type & y) {
779 #ifdef DEBUG
780  cout
781  << x.first << "," << x.second
782  << " <-> "
783  << y.first << "," << y.second << "\t";
784  cout << (x.first == y.first) << " , " << (x.second == y.second) << endl;
785 #endif
786  return x.first == y.first && x.second == y.second;
787  }
788  ) ;
789  });
790 
791 #ifdef DEBUG
792  for (auto relation : theExpectedRelation)
793  for (auto to : relation.second)
794  cout << relation.first << " -> " << to.first << " ( " << to.second << " )" << endl;
795 
796  for (auto relation : theInducedRelation)
797  for (auto to : relation.second)
798  cout << relation.first << " --> " << to.first << " ( " << to.second << " )" << endl;
799 #endif
800 
801 
802  return OKorKO;
803  }
804 
805 
806  bool
807  testSelfRelation()
808  {
809 
810  StoreArray< StoredElement > subset(m_TestBench.getSubsetName());
811  RelationArray selfRelation(subset, subset);
812 
813 
814  NamedSet::StlRelationArray theInducedRelation;
815 
816  for (int relation = 0 ; relation < selfRelation.getEntries() ; relation++) {
817  size_t relationSize = selfRelation[ relation ].getSize();
818  RelationElement::index_type from = selfRelation[ relation ].getFromIndex();
819  KeyElementType fromElementKey = subset[from]->GetUniqueID();
820  if (theInducedRelation.find(fromElementKey) == theInducedRelation.end()) {
821  theInducedRelation.insert(pair< KeyElementType, FromTargetElementsToWeight>
822  (fromElementKey, FromTargetElementsToWeight()));
823  }
824 
825  for (unsigned int to_index = 0 ; to_index < relationSize ; to_index++) {
827  selfRelation[ relation ].getToIndex(to_index);
828  double weight = selfRelation[ relation ].getWeight(to_index);
829  KeyElementType toElementKey = subset[to]->GetUniqueID();
830 
831  theInducedRelation.find(fromElementKey)->second.insert(pair< KeyElementType, double> (toElementKey , weight));
832 
833  }
834  }
835 
836 
837  NamedSet::StlRelationArray theExpectedRelation = m_TestBench.getNamedSet().
838  getRestrictedSelfRelation();
839 
840  bool OKorKO = equal(theExpectedRelation.begin(), theExpectedRelation.end(), theInducedRelation.begin(),
841  [](const NamedSet::StlRelationArray::value_type & a,
842  const NamedSet::StlRelationArray::value_type & b) {
843 
844 #ifdef DEBUG
845  cout << a.first << " vs " << b.first << endl;
846 #endif
847  return (true || a.first == b.first) &&
848  equal(a.second.begin(), a.second.end(), b.second.begin(),
849  [](const FromTargetElementsToWeight::value_type & x,
850  const FromTargetElementsToWeight::value_type & y) {
851 #ifdef DEBUG
852  cout
853  << x.first << "," << x.second
854  << " <-> "
855  << y.first << "," << y.second << "\t";
856  cout << (x.first == y.first) << " , " << (x.second == y.second) << endl;
857 #endif
858  return x.first == y.first && x.second == y.second;
859  }
860  ) ;
861  });
862 
863 #ifdef DEBUG
864 
865  cout << "We do expect the following set of relations" << endl;
866  for (auto relation : theExpectedRelation)
867  for (auto to : relation.second)
868  cout << relation.first << " -> " << to.first << " ( " << to.second << " )" << endl;
869 
870  cout << "We found the following ones" << endl;
871  for (auto relation : theInducedRelation)
872  for (auto to : relation.second)
873  cout << relation.first << " --> " << to.first << " ( " << to.second << " )" << endl;
874  cout << "~~~~";
875 #endif
876 
877 
878  return OKorKO;
879  }
880  };
881 
882 
883 
884 
885 
886  TEST_F(SelectSubsetTest, ExtensiveTest)
887  {
888  m_TestBench.initializeDatastore();
889  m_TestBench.populateDatastore();
890 
892  StoreArray< StoredElement > set(m_TestBench.getSetName());
893 
894  DataStore::Instance().setInitializeActive(true);
895 
896  selector.registerSubset(set, m_TestBench.getSubsetName());
897 
898  for (auto other : m_TestBench.getOtherSets()) {
899  selector.inheritRelationsTo(other.second.storedArray());
900  selector.inheritRelationsFrom(other.second.storedArray());
901  }
902 
903  //inherit set <-> set relations
904  selector.inheritRelationsFrom(set);
905 
906  DataStore::Instance().setInitializeActive(false);
907 
908  selector.select(SelectionCriteriumOnElement);
909 
910  StoreArray< StoredElement > subset(m_TestBench.getSubsetName());
911 
912  bool allSubsetElementsAreGood(true);
913 
914 
915  // First of all let us check that all the elements in the subset
916  // do satisfy the SelectionCriterium and that
917  for (const auto& element : subset) {
918  if (! SelectionCriteriumOnElement(& element))
919  allSubsetElementsAreGood = false;
920 
921 
922  }
923 
924  EXPECT_TRUE(allSubsetElementsAreGood);
925 
926 
927  // Then we check that the size of the subset equals the number
928  // of elements in the set satisfiing the SelectionCriterium
929  int NSelected(0);
930  for (const auto& element : set)
931  NSelected += SelectionCriteriumOnElement(&element) ? 1 : 0;
932 
933  EXPECT_TRUE(NSelected == subset.getEntries());
934 
935 
936  // Then we test that all the relations are correct
937  EXPECT_TRUE(testSelfRelation());
938 
939  for (int i = 0 ; i < m_TestBench.getNSets(); i++) {
940 
941  auto otherSet = m_TestBench.getOtherNamedSet(i);
942  EXPECT_TRUE(testRelationToOther(otherSet));
943  EXPECT_TRUE(testRelationFromOther(otherSet));
944 
945  }
946  }
947 
948  bool hasOddIndex(const RelationsObject* a)
949  {
950  return (a->getArrayIndex() % 2) == 1;
951  }
952 
953  TEST_F(SelectSubsetTest, TestWithManyRelations)
954  {
955  //array 'main' with relations: a -> main -> b
956  //create subset: a -> subsetOfMain -> b
957 
958  DataStore::Instance().setInitializeActive(true);
959  StoreArray< RelationsObject > arrayMain("main");
960  StoreArray< RelationsObject > arrayA("a");
961  StoreArray< RelationsObject > arrayB("b");
962  arrayMain.registerInDataStore();
963  arrayA.registerInDataStore();
964  arrayB.registerInDataStore();
965  arrayA.registerRelationTo(arrayMain);
966  arrayMain.registerRelationTo(arrayB);
967 
968  //create subset and relations
969  SelectSubset< RelationsObject > selectorMain;
970  selectorMain.registerSubset(arrayMain, "subsetOfMain");
971 
972  selectorMain.inheritRelationsFrom(arrayA);
973  selectorMain.inheritRelationsTo(arrayB);
974 
975  DataStore::Instance().setInitializeActive(false);
976 
977  //fill some data
978  for (int i = 0; i < 10; i++) {
979  auto* mainObj = arrayMain.appendNew();
980  for (int j = 0; j < 2; j++) {
981  auto* aObj = arrayA.appendNew();
982  aObj->addRelationTo(mainObj);
983  }
984  for (int j = 0; j < 10; j++) {
985  auto* bObj = arrayB.appendNew();
986  mainObj->addRelationTo(bObj);
987  }
988  }
989 
990  //run selector
991  selectorMain.select(hasOddIndex);
992 
993 
994  //verify original contents
995  EXPECT_EQ(10, arrayMain.getEntries());
996  EXPECT_EQ(20, arrayA.getEntries());
997  EXPECT_EQ(100, arrayB.getEntries());
998 
999 
1000  StoreArray< RelationsObject > arraySubset("subsetOfMain");
1001 
1002  //verify subset
1003  EXPECT_EQ(5, arraySubset.getEntries());
1004  for (const RelationsObject& r : arraySubset) {
1005  EXPECT_EQ(2u, r.getRelationsFrom<RelationsObject>("a").size());
1006  EXPECT_EQ(0u, r.getRelationsFrom<RelationsObject>("b").size());
1007  EXPECT_EQ(10u, r.getRelationsTo<RelationsObject>("b").size());
1008  EXPECT_EQ(0u, r.getRelationsTo<RelationsObject>("a").size());
1009  EXPECT_TRUE(nullptr == r.getRelatedTo<RelationsObject>("main"));
1010 
1011  //go back to main set, check selection condidition holds
1012  EXPECT_EQ(1u, r.getRelationsWith<RelationsObject>("main").size());
1013  const RelationsObject* originalObject = r.getRelatedFrom<RelationsObject>("main");
1014  EXPECT_TRUE(hasOddIndex(originalObject));
1015  }
1016  }
1017 
1018  TEST_F(SelectSubsetTest, InheritAll)
1019  {
1020  //array 'main' with relations: a -> main -> b
1021  //create subset: a -> subsetOfMain -> b
1022 
1023  DataStore::Instance().setInitializeActive(true);
1024  StoreArray< RelationsObject > arrayMain("main");
1025  StoreArray< RelationsObject > arrayA("a");
1026  StoreArray< RelationsObject > arrayB("b");
1027  arrayMain.registerInDataStore();
1028  arrayA.registerInDataStore();
1029  arrayB.registerInDataStore();
1030  arrayA.registerRelationTo(arrayMain);
1031  arrayMain.registerRelationTo(arrayB);
1032 
1033  //create subset and relations
1034  SelectSubset< RelationsObject > selectorMain;
1035  selectorMain.registerSubset(arrayMain, "subsetOfMain");
1036 
1037  selectorMain.inheritAllRelations();
1038 
1039  DataStore::Instance().setInitializeActive(false);
1040 
1041  //check if the state matches what we expect
1042  EXPECT_FALSE(selectorMain.getInheritToSelf());
1043  EXPECT_EQ(std::vector<string>({"a"}), selectorMain.getInheritFromArrays());
1044  EXPECT_EQ(std::vector<string>({"b"}), selectorMain.getInheritToArrays());
1045  }
1046 
1047  TEST_F(SelectSubsetTest, TestExistingSetWithManyRelations)
1048  {
1049  //array 'main' with relations: a -> main -> b
1050  //then remove half of main.
1051 
1052  DataStore::Instance().setInitializeActive(true);
1053  StoreArray< RelationsObject > arrayMain("main");
1054  StoreArray< RelationsObject > arrayA("a");
1055  StoreArray< RelationsObject > arrayB("b");
1056  arrayMain.registerInDataStore();
1057  arrayA.registerInDataStore();
1058  arrayB.registerInDataStore();
1059  arrayA.registerRelationTo(arrayMain);
1060  arrayMain.registerRelationTo(arrayB);
1061 
1062  //create subset and relations
1063  SelectSubset< RelationsObject > selectorMain;
1064  selectorMain.registerSubset(arrayMain);
1065 
1066  DataStore::Instance().setInitializeActive(false);
1067 
1068  //fill some data
1069  for (int i = 0; i < 10; i++) {
1070  auto* mainObj = arrayMain.appendNew();
1071  for (int j = 0; j < 2; j++) {
1072  auto* aObj = arrayA.appendNew();
1073  aObj->addRelationTo(mainObj);
1074  }
1075  for (int j = 0; j < 10; j++) {
1076  auto* bObj = arrayB.appendNew();
1077  mainObj->addRelationTo(bObj);
1078  }
1079  }
1080 
1081  //verify original contents
1082  EXPECT_EQ(10, arrayMain.getEntries());
1083  EXPECT_EQ(20, arrayA.getEntries());
1084  EXPECT_EQ(100, arrayB.getEntries());
1085 
1086  //run selector
1087  selectorMain.select(hasOddIndex);
1088 
1089 
1090  //verify subset
1091  EXPECT_EQ(5, arrayMain.getEntries());
1092  for (const RelationsObject& r : arrayMain) {
1093  EXPECT_EQ(2u, r.getRelationsFrom<RelationsObject>("a").size());
1094  EXPECT_EQ(0u, r.getRelationsFrom<RelationsObject>("b").size());
1095  EXPECT_EQ(10u, r.getRelationsTo<RelationsObject>("b").size());
1096  EXPECT_EQ(0u, r.getRelationsTo<RelationsObject>("a").size());
1097  EXPECT_TRUE(nullptr == r.getRelatedTo<RelationsObject>("main"));
1098  }
1099  int i = 0;
1100  for (const RelationsObject& r : arrayA) {
1101  EXPECT_EQ((i / 2 % 2 == 1) ? 1u : 0u, r.getRelationsTo<RelationsObject>("main").size());
1102  i++;
1103  }
1104  }
1105 
1106  TEST_F(SelectSubsetTest, TestEmptyArray)
1107  {
1108  //array 'main' with relations: a -> main -> b
1109  //then remove half of main.
1110 
1111  DataStore::Instance().setInitializeActive(true);
1112  StoreArray< RelationsObject > arrayMain("main");
1113  StoreArray< RelationsObject > arrayA("a");
1114  StoreArray< RelationsObject > arrayB("b");
1115  arrayMain.registerInDataStore();
1116  arrayA.registerInDataStore();
1117  arrayB.registerInDataStore();
1118  arrayA.registerRelationTo(arrayMain);
1119  arrayMain.registerRelationTo(arrayB);
1120 
1121  //create subset and relations
1122  SelectSubset< RelationsObject > selectorMain;
1123  selectorMain.registerSubset(arrayMain);
1124 
1125  DataStore::Instance().setInitializeActive(false);
1126 
1127  //test with empty inputs
1128  EXPECT_EQ(0, arrayMain.getEntries());
1129  selectorMain.select(hasOddIndex);
1130  EXPECT_EQ(0, arrayMain.getEntries());
1131 
1132  //fill some data
1133  for (int i = 0; i < 10; i++) {
1134  auto* mainObj = arrayMain.appendNew();
1135  for (int j = 0; j < 2; j++) {
1136  auto* aObj = arrayA.appendNew();
1137  aObj->addRelationTo(mainObj);
1138  }
1139  for (int j = 0; j < 10; j++) {
1140  auto* bObj = arrayB.appendNew();
1141  mainObj->addRelationTo(bObj);
1142  }
1143  }
1144 
1145  //verify original contents
1146  EXPECT_EQ(10, arrayMain.getEntries());
1147  EXPECT_EQ(20, arrayA.getEntries());
1148  EXPECT_EQ(100, arrayB.getEntries());
1149 
1150  //delete all contents
1151  auto never = [](const RelationsObject*) -> bool { return false; };
1152  selectorMain.select(never);
1153 
1154 
1155  //verify subset
1156  EXPECT_EQ(0, arrayMain.getEntries());
1157  for (const RelationsObject& r : arrayA) {
1158  EXPECT_EQ(0u, r.getRelationsTo<RelationsObject>("main").size());
1159  }
1160  }
1161 
1162 } // namespace
Low-level class to create/modify relations between StoreArrays.
Definition: RelationArray.h:62
unsigned int index_type
type used for indices.
Defines interface for accessing relations of objects in StoreArray.
std::vector< std::string > getInheritToArrays() const
Get list of arrays we inherit relations to.
Definition: SelectSubset.h:34
std::vector< std::string > getInheritFromArrays() const
Get list of arrays we inherit relations from.
Definition: SelectSubset.h:32
bool getInheritToSelf() const
Do we inherit relations from original set to itself?
Definition: SelectSubset.h:36
Class to create a subset of a given StoreArray together with the relations with other StoreArrays.
Definition: SelectSubset.h:193
void inheritRelationsTo(const StoreArray< T > &array, MoreArguments... moreArgs)
Inherit relations pointing from objects selected into this subset to Other.
Definition: SelectSubset.h:275
void inheritRelationsFrom(const StoreArray< T > &array, MoreArguments... moreArgs)
Inherit relations pointing from Other to objects selected into this subset.
Definition: SelectSubset.h:250
void inheritAllRelations()
Automatically inherit all relations to or from the original set (if registered when calling this func...
Definition: SelectSubset.h:301
void registerSubset(const StoreArray< StoredClass > &set, DataStore::EStoreFlags storeFlags=DataStore::c_ErrorIfAlreadyRegistered)
Remove all non-selected objects from set.
Definition: SelectSubset.h:215
Accessor to arrays stored in the data store.
Definition: StoreArray.h:113
T * appendNew()
Construct a new T object at the end of the array.
Definition: StoreArray.h:246
int getEntries() const
Get the number of objects in the array.
Definition: StoreArray.h:216
TEST_F(GlobalLabelTest, LargeNumberOfTimeDependentParameters)
Test large number of time-dep params for registration and retrieval.
Definition: globalLabel.cc:72
void select(const std::function< bool(const StoredClass *)> &f)
This method is the actual worker.
Definition: SelectSubset.h:413
RelationsInterface< TObject > RelationsObject
Provides interface for getting/adding relations to objects in StoreArrays.
TString getName(const TObject *obj)
human-readable name (e.g.
Definition: ObjectInfo.cc:45
Abstract base class for different kinds of events.
std::bitset< max - min+1 > subset(std::bitset< nbits > set)
extract a subset of bitstring, like substring.
Definition: Cosim.h:120
def equal(a, b)
Definition: bitstring.py:292