Belle II Software  release-08-01-10
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 
163  class NamedSet {
164 
165  // The class NamedSet provides two representantions of the same entity.
166  // The entity has a name, a set, and some relations with other sets.
167  // The entity name is m_name.
168  // The set is stored both as a StoreArray named m_name and as an unordered_map
169  // The relations are stored both as relation and as unordered_map so that
170  // one can check the correctness of the SelectSubset utility.
171 
172  string m_name; // My name
173  map< KeyElementType, Relations > m_set; // What I am
174  StoreArray< StoredElement > m_storeArray; // How I am stored
175  RelationArray* to{nullptr}; // How my relation to the original set is stored
176  RelationArray* from{nullptr}; // How my relation from the original set is stored
177  RelationArray* self{nullptr}; // How the relation with myself is stored (yes, I am
178  // the original set)
179  public:
180 
181 
182  void print()
183  {
184  cout << "The NamedSet: " << m_name << " contains:" << endl ;
185  for (auto set : m_set) {
186  cout << set.first << endl;
187  set.second.print();
188  }
189  cout << "~~~~~~~~~~~~~~~~~~~~~~~" << endl;
190  }
191 
192  // constructor
193  explicit NamedSet(const string& name = "") :
194  m_name(name), m_storeArray(name) {}
195 
196  // order relation
197  bool operator()(const NamedSet& a, const NamedSet& b) const
198  {
199  return a.getName() < b.getName();
200  }
201 
202  // accessors
203  [[nodiscard]] const string getName() const
204  {
205  return m_name;
206  }
207 
208  StoreArray< StoredElement >& storedArray()
209  {
210  return m_storeArray;
211  }
212 
213 
214  void initializeDatastore()
215  {
216  // this method take care of the initialization of the
217  // StoreArray
218  DataStore::Instance().setInitializeActive(true);
219 
221  array.registerInDataStore();
222  array.registerRelationTo(array);
223 
224  DataStore::Instance().setInitializeActive(false);
225  }
226 
227  void initializeDatastore(const string& SetName)
228  {
229  // this method take care of the initialization of the
230  // store array and of the RelationArrays from and to
231  // the StoreArray named SetName
232 
233  DataStore::Instance().setInitializeActive(true);
234 
236  StoreArray< StoredElement > otherSet(SetName);
237  array.registerInDataStore();
238  array.registerRelationTo(otherSet);
239  otherSet.registerRelationTo(array);
240  //TODO one of these is wrong! -> getRelationsWith() would return both directions
241 
242  DataStore::Instance().setInitializeActive(false);
243  }
244 
245  void consolidate()
246  {
247  // this method consolidate the StoreArray and the RelationArrays
248  // to and from the set
249  if (self != nullptr)
250  self->consolidate();
251  if (from != nullptr)
252  from->consolidate();
253  if (to != nullptr)
254  to->consolidate();
255  }
256 
257 
258  void appendNewElement(KeyElementType element)
259  {
260  m_set.insert(pair< KeyElementType, Relations > (element, Relations(element)));
261  }
262 
263  void appendNewRelationTo(KeyElementType fromKey, const string& toName, KeyElementType toKey,
264  double weight)
265  {
266  auto fromElement = m_set.find(fromKey);
267  if (fromElement == m_set.end()) {
268  cout << "??" << endl;
269  return; // quietly skip
270  }
271  fromElement->second.appendNewRelationTo(toName, toKey, weight);
272  }
273 
274  [[nodiscard]] bool isPresentRelationFromTo(const KeyElementType& fromKey, const string& otherSetName,
275  const KeyElementType& toKey) const
276  {
277  auto fromElement = m_set.find(fromKey);
278  if (fromElement != m_set.end()) {
279  return fromElement->second.isPresentRelationTo(otherSetName, toKey);
280  } else {
281  cout << "Error: from: " << getName() << " id " << fromKey <<
282  " -> " << otherSetName << " id " << toKey << endl;
283  for (const auto& element : m_set)
284  cout << element.first << "\t";
285  cout << endl;
286  for (const auto& element : m_storeArray)
287  cout << element.GetUniqueID() << "\t";
288  cout << endl;
289  return false;
290  }
291  }
292 
293  [[nodiscard]] const FromTargetElementsToWeight& getAllRelations(const KeyElementType& fromKey, const string& toOtherSetName) const
294  {
295  auto fromElement = m_set.find(fromKey);
296  return fromElement->second.getAllRelations(toOtherSetName);
297  }
298 
299  using StlRelationArray = map< KeyElementType, FromTargetElementsToWeight >;
300 
301  [[nodiscard]] StlRelationArray getRestrictedDomainRelationTo(const string& toOtherSetName)const
302  {
303  StlRelationArray theInducedRelation;
304  for (const auto& element : m_set) {
305  if (SelectionCriterium(element.first) &&
306  element.second.getAllRelations(toOtherSetName).size() != 0)
307  theInducedRelation.insert(pair< KeyElementType, FromTargetElementsToWeight>
308  (element.first, element.second.getAllRelations(toOtherSetName)));
309  }
310  return theInducedRelation;
311  }
312 
313  [[nodiscard]] StlRelationArray getRestrictedCodomainRelationTo(const string& setName)const
314  {
315  StlRelationArray theInducedRelation;
316  for (const auto& element : m_set) {
317  if (element.second.getConstSetOfToRelations(setName) ==
318  element.second.getConstSetOfAllRelations().end())
319  continue;
320  for (auto image : element.second.getConstSetOfToRelations(setName)->second) {
321  if (SelectionCriterium(image.first)) {
322  if (theInducedRelation.find(element.first) == theInducedRelation.end())
323  theInducedRelation.insert(pair< KeyElementType, FromTargetElementsToWeight>
324  (element.first, FromTargetElementsToWeight()));
325  theInducedRelation.find(element.first)->second.
326  insert(FromTargetElementsToWeight::value_type
327  (image.first, image.second));
328  }
329  }
330  }
331  return theInducedRelation;
332  }
333 
334  [[nodiscard]] StlRelationArray getRestrictedSelfRelation() const
335  {
336  StlRelationArray theInducedRelation;
337  for (const auto& element : m_set) {
338  if (! SelectionCriterium(element.first) ||
339  element.second.getAllRelations(m_name).size() == 0)
340  continue;
341  for (auto image : element.second.getConstSetOfToRelations(m_name)->second) {
342  if (SelectionCriterium(image.first)) {
343  if (theInducedRelation.find(element.first) == theInducedRelation.end())
344  theInducedRelation.insert(pair< KeyElementType, FromTargetElementsToWeight>
345  (element.first, FromTargetElementsToWeight()));
346  theInducedRelation.find(element.first)->second.
347  insert(FromTargetElementsToWeight::value_type
348  (image.first, image.second));
349  }
350  }
351  }
352  return theInducedRelation;
353 
354  }
355  };
356 
357  class CollectionOfSets {
358 
359  // This is the actual test bench. It contains the set to be subsetted
360  // together with the subset and the other sets in relation with the subset
361  private:
362  string m_setName; // We start from this set
363  string m_subsetName; // we will select this subset
364  NamedSet m_set;
365  NamedSet m_subset;
366 
367  vector< string > m_otherSetsNames; // other sets in the universe
368  unordered_map< string, NamedSet > m_otherSets;
369 
370  public:
371  // constructor
372  CollectionOfSets(): m_set("theSet"),
373  m_subset("theSubset"),
374  m_otherSetsNames {string("G"), string("F"), string("E"),
375  string("D"), string("C"), string("B"), string("A")
376  }
377  {
378  m_setName = m_set.getName();
379  m_subsetName = m_subset.getName();
380  for (const auto& aSetName : m_otherSetsNames)
381  m_otherSets.insert(pair<string, NamedSet> (aSetName, NamedSet(aSetName)));
382  };
383 
384  //accessors
385  const string&
386  getSetName() const
387  {
388  return m_setName ;
389  };
390 
392  getSet()
393  {
394  return m_set.storedArray();
395  };
396 
397  NamedSet&
398  getNamedSet()
399  {
400  return m_set;
401  };
402 
403 
404  const string&
405  getSubsetName() const
406  {
407  return m_subsetName ;
408  };
409 
411  getSubset()
412  {
413  return m_subset.storedArray();
414  };
415 
416  int
417  getNSets() const
418  {
419  return m_otherSets.size() ;
420  }
421 
422  const vector< string >&
423  getOtherSetsNames() const
424  {
425  return m_otherSetsNames ;
426  }
427 
428  const string&
429  getOtherSetsNames(int i) const
430  {
431  return m_otherSetsNames[i] ;
432  }
433 
435  getOtherSet(int i)
436  {
437  auto otherSet = m_otherSets.find(m_otherSetsNames[ i ]);
438  if (otherSet != m_otherSets.end())
439  return otherSet->second.storedArray();
440  else
441  cout << " ???????????? " << i << endl;
442  throw std::runtime_error("invalid set access");
443  }
444 
445  pair< const string, NamedSet>&
446  getOtherNamedSet(int i)
447  {
448  return * m_otherSets.find(m_otherSetsNames[ i ]);
449  }
450 
451  unordered_map< string, NamedSet >&
452  getOtherSets()
453  {
454  return m_otherSets;
455  }
456 
457  void
458  initializeDatastore()
459  {
460  // initialitation phase
461 
462  m_set.initializeDatastore();
463 
464  for (auto namedSet : m_otherSets)
465  namedSet.second.initializeDatastore(getSetName());
466 
467  }
468 
469  void
470  populateDatastore()
471  {
472  unsigned int nElements = 1368;
473  for (unsigned int i = 0; i < nElements ; i++)
474  appendNewElement(m_set);
475 
476  int n(0);
477 
478  for (auto& set : m_otherSets) {
479  unsigned int nOtherElements = nElements - n * 100;
480 
481  for (unsigned int i = 0; i < nOtherElements ; i++)
482  appendNewElement(set.second);
483 
484  }
485 
486  int j(2);
487  for (auto& set : m_otherSets) {
488 
489 
490  unsigned int nArrows = nElements * j;
491  j++;
492 
493  for (unsigned int arrow = 0; arrow < nArrows ; arrow ++) {
494  appendNewRelationToOther(set);
495  appendNewRelationFromOther(set);
496  }
497 
498  }
499 
500 
501  for (unsigned int arrow = 0; arrow < 5 * nElements; arrow ++)
502  appendNewSelfRelation();
503 
504 #ifdef DEBUG
505  m_set.print();
506 #endif
507 
508  }
509 
510 
511  double
512  getWeight()
513  {
514  static double counter(0.0);
515  return counter += 1.;
516  };
517 
518  unsigned int
519  flat_random(unsigned int max)
520  {
521  /* This algorithm is mentioned in the ISO C standard, here extended for 32 bits.
522  the initial seed is arbitrary set to 11036
523  the seed is 11036 and is fixed i.e. it is strictly reproducible and does
524  not interact with other random generators*/
525  static unsigned int next = 11036;
526  int result;
527 
528  next *= 1103515245;
529  next += 12345;
530  result = (unsigned int)(next / 65536) % 2048;
531 
532  next *= 1103515245;
533  next += 12345;
534  result <<= 10;
535  result ^= (unsigned int)(next / 65536) % 1024;
536 
537  next *= 1103515245;
538  next += 12345;
539  result <<= 10;
540  result ^= (unsigned int)(next / 65536) % 1024;
541 
542  return result % max;
543 
544  }
545 
546  void
547  appendNewElement(NamedSet& namedSet)
548  {
549  StoreArray< StoredElement >& set = namedSet.storedArray();
550  int i = set.getEntries() ;
551  static int uniqueId(0);
552 
553  namedSet.appendNewElement(uniqueId);
554  set.appendNew();
555  set[ i ]->SetUniqueID(uniqueId);
556  uniqueId++;
557  }
558 
559 
560  void
561  appendNewRelationToOther(pair< const string, NamedSet>& set)
562  {
563 
564  int from_index = flat_random(getSet().getEntries());
565  KeyElementType from_key = getSet()[from_index]->GetUniqueID();
566  int to_index = flat_random(set.second.storedArray().getEntries());
567  KeyElementType to_key = set.second.storedArray()[to_index]->GetUniqueID();
568 
569 
570  if (getNamedSet().isPresentRelationFromTo(from_key, set.first, to_key))
571  return; // Arrow already drawn
572 
573 
574  double weight = getWeight();
575 
576  getNamedSet().appendNewRelationTo(from_key, set.first, to_key, weight);
577 
578  RelationArray setToOtherSet(getSet(), set.second.storedArray());
579  setToOtherSet.add(from_index, to_index, weight);
580 
581  }
582 
583 
584  void
585  appendNewRelationFromOther(pair< const string, NamedSet>& otherSet)
586  {
587 
588  //cout << otherSet.first << "\t";
589  unsigned int from_index = flat_random(otherSet.second.storedArray().getEntries());
590  //cout << from_index << "\t";
591  KeyElementType from_key = otherSet.second.storedArray()[from_index]->GetUniqueID();
592  //cout << from_key << endl;
593  unsigned int to_index = flat_random(getSet().getEntries());
594  KeyElementType to_key = getSet()[to_index]->GetUniqueID();
595 
596  if (otherSet.second.isPresentRelationFromTo(from_key, getSetName(), to_key))
597 
598  return; // Arrow already drawn
599 
600  double weight = getWeight();
601 
602  otherSet.second.appendNewRelationTo(from_key, getSetName(), to_key, weight);
603 
604  //otherSet.second.storedArray()[ from_index ]->SetBinContent( 0 , to_index , weight);
605 
606  RelationArray otherSetToSet(otherSet.second.storedArray(), getSet());
607  otherSetToSet.add(from_index, to_index, weight);
608 
609  }
610 
611  void
612  appendNewSelfRelation()
613  {
614  unsigned int from_index = flat_random(getSet().getEntries());
615  KeyElementType from_key = getSet()[from_index]->GetUniqueID();
616  unsigned int to_index = flat_random(getSet().getEntries());
617  KeyElementType to_key = getSet()[to_index]->GetUniqueID();
618 
619 
620  if (getNamedSet().isPresentRelationFromTo(from_key, getSetName(), to_key))
621  return; // Arrow already drawn
622 
623  double weight = getWeight();
624 
625  getNamedSet().appendNewRelationTo(from_key, getSetName(), to_key, weight);
626 
627  RelationArray setToSet(getSet(), getSet());
628 
629  setToSet.add(from_index, to_index, weight);
630 
631 
632  }
633 
634 
635  };
636 
637 
638  protected:
639 
640  CollectionOfSets m_TestBench;
641 
642  void SetUp() override
643  {
644  }
645 
647  void TearDown() override
648  {
649  DataStore::Instance().reset();
650  }
651 
652 
653  bool
654  testRelationToOther(pair< const string, NamedSet>& otherSet)
655  {
656 
657  StoreArray< StoredElement > theSet(m_TestBench.getSetName());
658  StoreArray< StoredElement > subset(m_TestBench.getSubsetName());
659  RelationArray subsetToOtherSet(subset,
660  otherSet.second.storedArray());
661 
662 
663  NamedSet::StlRelationArray theInducedRelation;
664 
665  for (int relation = 0 ; relation < subsetToOtherSet.getEntries() ; relation++) {
666  size_t relationSize = subsetToOtherSet[ relation ].getSize();
667 
668  RelationElement::index_type from = subsetToOtherSet[ relation ].getFromIndex();
669  KeyElementType fromElementKey = subset[from]->GetUniqueID();
670  if (theInducedRelation.find(fromElementKey) == theInducedRelation.end())
671  theInducedRelation.insert(pair< KeyElementType, FromTargetElementsToWeight>
672  (fromElementKey, FromTargetElementsToWeight()));
673 
674  for (unsigned int to_index = 0 ; to_index < relationSize ; to_index++) {
675  RelationElement::index_type to = subsetToOtherSet[ relation ].getToIndex(to_index);
676  double weight = subsetToOtherSet[ relation ].getWeight(to_index);
677  KeyElementType toElementKey = otherSet.second.storedArray()[to]->GetUniqueID();
678 
679  theInducedRelation.find(fromElementKey)->second.insert(pair< KeyElementType, double> (toElementKey, weight));
680 
681  }
682  }
683 
684 
685  NamedSet::StlRelationArray theExpectedRelation = m_TestBench.getNamedSet().
686  getRestrictedDomainRelationTo(otherSet.first) ;
687 
688  bool OKorKO = equal(theExpectedRelation.begin(), theExpectedRelation.end(), theInducedRelation.begin(),
689  [](const NamedSet::StlRelationArray::value_type & a,
690  const NamedSet::StlRelationArray::value_type & b) {
691 #ifdef DEBUG
692  cout << a.first << " vs " << b.first << endl;
693 #endif
694  return a.first == b.first &&
695  equal(a.second.begin(), a.second.end(), b.second.begin(),
696  [](const FromTargetElementsToWeight::value_type & x,
697  const FromTargetElementsToWeight::value_type & y) {
698 #ifdef DEBUG
699  cout
700  << x.first << "," << x.second
701  << " <-> "
702  << y.first << "," << y.second << "\t";
703  cout << (x.first == y.first) << " , " << (x.second == y.second) << endl;
704 #endif
705  return x.first == y.first && x.second == y.second;
706  }
707  ) ;
708  });
709 
710 #ifdef DEBUG
711  for (auto relation : theExpectedRelation)
712  for (auto to : relation.second)
713  cout << relation.first << " -> " << to.first << " ( " << to.second << " )" << endl;
714 
715  for (auto relation : theInducedRelation)
716  for (auto to : relation.second)
717  cout << relation.first << " --> " << to.first << " ( " << to.second << " )" << endl;
718 #endif
719 
720 
721  return OKorKO;
722  }
723 
724  bool
725  testRelationFromOther(pair< const string, NamedSet>& otherNamedSet)
726  {
727 
728  StoreArray< StoredElement > subset(m_TestBench.getSubsetName());
729  StoreArray< StoredElement > other = otherNamedSet.second.storedArray();
730 
731 
732  RelationArray subsetFromOtherSet(otherNamedSet.second.storedArray(), subset);
733 
734 
735  NamedSet::StlRelationArray theInducedRelation;
736 
737  for (int relation = 0 ; relation < subsetFromOtherSet.getEntries() ; relation++) {
738  size_t relationSize = subsetFromOtherSet[ relation ].getSize();
739  RelationElement::index_type from = subsetFromOtherSet[ relation ].getFromIndex();
740  KeyElementType fromElementKey = other[from]->GetUniqueID();
741  if (theInducedRelation.find(fromElementKey) == theInducedRelation.end()) {
742  theInducedRelation.insert(pair< KeyElementType, FromTargetElementsToWeight>
743  (fromElementKey, FromTargetElementsToWeight()));
744  }
745 
746  for (unsigned int to_index = 0 ; to_index < relationSize ; to_index++) {
748  subsetFromOtherSet[ relation ].getToIndex(to_index);
749  double weight = subsetFromOtherSet[ relation ].getWeight(to_index);
750  KeyElementType toElementKey = subset[to]->GetUniqueID();
751 
752  theInducedRelation.find(fromElementKey)->second.insert(pair< KeyElementType, double> (toElementKey, weight));
753 
754  }
755  }
756 
757 
758  NamedSet::StlRelationArray theExpectedRelation
759  = otherNamedSet.second.getRestrictedCodomainRelationTo(m_TestBench.getSetName());
760  bool OKorKO = equal(theExpectedRelation.begin(), theExpectedRelation.end(), theInducedRelation.begin(),
761  [](const NamedSet::StlRelationArray::value_type & a,
762  const NamedSet::StlRelationArray::value_type & b) {
763 #ifdef DEBUG
764  cout << a.first << " vs " << b.first << endl;
765 #endif
766  return a.first == b.first &&
767  equal(a.second.begin(), a.second.end(), b.second.begin(),
768  [](const FromTargetElementsToWeight::value_type & x,
769  const FromTargetElementsToWeight::value_type & y) {
770 #ifdef DEBUG
771  cout
772  << x.first << "," << x.second
773  << " <-> "
774  << y.first << "," << y.second << "\t";
775  cout << (x.first == y.first) << " , " << (x.second == y.second) << endl;
776 #endif
777  return x.first == y.first && x.second == y.second;
778  }
779  ) ;
780  });
781 
782 #ifdef DEBUG
783  for (auto relation : theExpectedRelation)
784  for (auto to : relation.second)
785  cout << relation.first << " -> " << to.first << " ( " << to.second << " )" << endl;
786 
787  for (auto relation : theInducedRelation)
788  for (auto to : relation.second)
789  cout << relation.first << " --> " << to.first << " ( " << to.second << " )" << endl;
790 #endif
791 
792 
793  return OKorKO;
794  }
795 
796 
797  bool
798  testSelfRelation()
799  {
800 
801  StoreArray< StoredElement > subset(m_TestBench.getSubsetName());
802  RelationArray selfRelation(subset, subset);
803 
804 
805  NamedSet::StlRelationArray theInducedRelation;
806 
807  for (int relation = 0 ; relation < selfRelation.getEntries() ; relation++) {
808  size_t relationSize = selfRelation[ relation ].getSize();
809  RelationElement::index_type from = selfRelation[ relation ].getFromIndex();
810  KeyElementType fromElementKey = subset[from]->GetUniqueID();
811  if (theInducedRelation.find(fromElementKey) == theInducedRelation.end()) {
812  theInducedRelation.insert(pair< KeyElementType, FromTargetElementsToWeight>
813  (fromElementKey, FromTargetElementsToWeight()));
814  }
815 
816  for (unsigned int to_index = 0 ; to_index < relationSize ; to_index++) {
818  selfRelation[ relation ].getToIndex(to_index);
819  double weight = selfRelation[ relation ].getWeight(to_index);
820  KeyElementType toElementKey = subset[to]->GetUniqueID();
821 
822  theInducedRelation.find(fromElementKey)->second.insert(pair< KeyElementType, double> (toElementKey, weight));
823 
824  }
825  }
826 
827 
828  NamedSet::StlRelationArray theExpectedRelation = m_TestBench.getNamedSet().
829  getRestrictedSelfRelation();
830 
831  bool OKorKO = equal(theExpectedRelation.begin(), theExpectedRelation.end(), theInducedRelation.begin(),
832  [](const NamedSet::StlRelationArray::value_type & a,
833  const NamedSet::StlRelationArray::value_type & b) {
834 
835 #ifdef DEBUG
836  cout << a.first << " vs " << b.first << endl;
837 #endif
838  return (true || a.first == b.first) &&
839  equal(a.second.begin(), a.second.end(), b.second.begin(),
840  [](const FromTargetElementsToWeight::value_type & x,
841  const FromTargetElementsToWeight::value_type & y) {
842 #ifdef DEBUG
843  cout
844  << x.first << "," << x.second
845  << " <-> "
846  << y.first << "," << y.second << "\t";
847  cout << (x.first == y.first) << " , " << (x.second == y.second) << endl;
848 #endif
849  return x.first == y.first && x.second == y.second;
850  }
851  ) ;
852  });
853 
854 #ifdef DEBUG
855 
856  cout << "We do expect the following set of relations" << endl;
857  for (auto relation : theExpectedRelation)
858  for (auto to : relation.second)
859  cout << relation.first << " -> " << to.first << " ( " << to.second << " )" << endl;
860 
861  cout << "We found the following ones" << endl;
862  for (auto relation : theInducedRelation)
863  for (auto to : relation.second)
864  cout << relation.first << " --> " << to.first << " ( " << to.second << " )" << endl;
865  cout << "~~~~";
866 #endif
867 
868 
869  return OKorKO;
870  }
871  };
872 
873 
874 
875 
876 
877  TEST_F(SelectSubsetTest, ExtensiveTest)
878  {
879  m_TestBench.initializeDatastore();
880  m_TestBench.populateDatastore();
881 
883  StoreArray< StoredElement > set(m_TestBench.getSetName());
884 
885  DataStore::Instance().setInitializeActive(true);
886 
887  selector.registerSubset(set, m_TestBench.getSubsetName());
888 
889  for (auto other : m_TestBench.getOtherSets()) {
890  selector.inheritRelationsTo(other.second.storedArray());
891  selector.inheritRelationsFrom(other.second.storedArray());
892  }
893 
894  //inherit set <-> set relations
895  selector.inheritRelationsFrom(set);
896 
897  DataStore::Instance().setInitializeActive(false);
898 
899  selector.select(SelectionCriteriumOnElement);
900 
901  StoreArray< StoredElement > subset(m_TestBench.getSubsetName());
902 
903  bool allSubsetElementsAreGood(true);
904 
905 
906  // First of all let us check that all the elements in the subset
907  // do satisfy the SelectionCriterium and that
908  for (const auto& element : subset) {
909  if (! SelectionCriteriumOnElement(& element))
910  allSubsetElementsAreGood = false;
911 
912 
913  }
914 
915  EXPECT_TRUE(allSubsetElementsAreGood);
916 
917 
918  // Then we check that the size of the subset equals the number
919  // of elements in the set satisfiing the SelectionCriterium
920  int NSelected(0);
921  for (const auto& element : set)
922  NSelected += SelectionCriteriumOnElement(&element) ? 1 : 0;
923 
924  EXPECT_TRUE(NSelected == subset.getEntries());
925 
926 
927  // Then we test that all the relations are correct
928  EXPECT_TRUE(testSelfRelation());
929 
930  for (int i = 0 ; i < m_TestBench.getNSets(); i++) {
931 
932  auto otherSet = m_TestBench.getOtherNamedSet(i);
933  EXPECT_TRUE(testRelationToOther(otherSet));
934  EXPECT_TRUE(testRelationFromOther(otherSet));
935 
936  }
937  }
938 
939  bool hasOddIndex(const RelationsObject* a)
940  {
941  return (a->getArrayIndex() % 2) == 1;
942  }
943 
944  TEST_F(SelectSubsetTest, TestWithManyRelations)
945  {
946  //array 'main' with relations: a -> main -> b
947  //create subset: a -> subsetOfMain -> b
948 
949  DataStore::Instance().setInitializeActive(true);
950  StoreArray< RelationsObject > arrayMain("main");
951  StoreArray< RelationsObject > arrayA("a");
952  StoreArray< RelationsObject > arrayB("b");
953  arrayMain.registerInDataStore();
954  arrayA.registerInDataStore();
955  arrayB.registerInDataStore();
956  arrayA.registerRelationTo(arrayMain);
957  arrayMain.registerRelationTo(arrayB);
958 
959  //create subset and relations
960  SelectSubset< RelationsObject > selectorMain;
961  selectorMain.registerSubset(arrayMain, "subsetOfMain");
962 
963  selectorMain.inheritRelationsFrom(arrayA);
964  selectorMain.inheritRelationsTo(arrayB);
965 
966  DataStore::Instance().setInitializeActive(false);
967 
968  //fill some data
969  for (int i = 0; i < 10; i++) {
970  auto* mainObj = arrayMain.appendNew();
971  for (int j = 0; j < 2; j++) {
972  auto* aObj = arrayA.appendNew();
973  aObj->addRelationTo(mainObj);
974  }
975  for (int j = 0; j < 10; j++) {
976  auto* bObj = arrayB.appendNew();
977  mainObj->addRelationTo(bObj);
978  }
979  }
980 
981  //run selector
982  selectorMain.select(hasOddIndex);
983 
984 
985  //verify original contents
986  EXPECT_EQ(10, arrayMain.getEntries());
987  EXPECT_EQ(20, arrayA.getEntries());
988  EXPECT_EQ(100, arrayB.getEntries());
989 
990 
991  StoreArray< RelationsObject > arraySubset("subsetOfMain");
992 
993  //verify subset
994  EXPECT_EQ(5, arraySubset.getEntries());
995  for (const RelationsObject& r : arraySubset) {
996  EXPECT_EQ(2u, r.getRelationsFrom<RelationsObject>("a").size());
997  EXPECT_EQ(0u, r.getRelationsFrom<RelationsObject>("b").size());
998  EXPECT_EQ(10u, r.getRelationsTo<RelationsObject>("b").size());
999  EXPECT_EQ(0u, r.getRelationsTo<RelationsObject>("a").size());
1000  EXPECT_TRUE(nullptr == r.getRelatedTo<RelationsObject>("main"));
1001 
1002  //go back to main set, check selection condidition holds
1003  EXPECT_EQ(1u, r.getRelationsWith<RelationsObject>("main").size());
1004  const RelationsObject* originalObject = r.getRelatedFrom<RelationsObject>("main");
1005  EXPECT_TRUE(hasOddIndex(originalObject));
1006  }
1007  }
1008 
1009  TEST_F(SelectSubsetTest, InheritAll)
1010  {
1011  //array 'main' with relations: a -> main -> b
1012  //create subset: a -> subsetOfMain -> b
1013 
1014  DataStore::Instance().setInitializeActive(true);
1015  StoreArray< RelationsObject > arrayMain("main");
1016  StoreArray< RelationsObject > arrayA("a");
1017  StoreArray< RelationsObject > arrayB("b");
1018  arrayMain.registerInDataStore();
1019  arrayA.registerInDataStore();
1020  arrayB.registerInDataStore();
1021  arrayA.registerRelationTo(arrayMain);
1022  arrayMain.registerRelationTo(arrayB);
1023 
1024  //create subset and relations
1025  SelectSubset< RelationsObject > selectorMain;
1026  selectorMain.registerSubset(arrayMain, "subsetOfMain");
1027 
1028  selectorMain.inheritAllRelations();
1029 
1030  DataStore::Instance().setInitializeActive(false);
1031 
1032  //check if the state matches what we expect
1033  EXPECT_FALSE(selectorMain.getInheritToSelf());
1034  EXPECT_EQ(std::vector<string>({"a"}), selectorMain.getInheritFromArrays());
1035  EXPECT_EQ(std::vector<string>({"b"}), selectorMain.getInheritToArrays());
1036  }
1037 
1038  TEST_F(SelectSubsetTest, TestExistingSetWithManyRelations)
1039  {
1040  //array 'main' with relations: a -> main -> b
1041  //then remove half of main.
1042 
1043  DataStore::Instance().setInitializeActive(true);
1044  StoreArray< RelationsObject > arrayMain("main");
1045  StoreArray< RelationsObject > arrayA("a");
1046  StoreArray< RelationsObject > arrayB("b");
1047  arrayMain.registerInDataStore();
1048  arrayA.registerInDataStore();
1049  arrayB.registerInDataStore();
1050  arrayA.registerRelationTo(arrayMain);
1051  arrayMain.registerRelationTo(arrayB);
1052 
1053  //create subset and relations
1054  SelectSubset< RelationsObject > selectorMain;
1055  selectorMain.registerSubset(arrayMain);
1056 
1057  DataStore::Instance().setInitializeActive(false);
1058 
1059  //fill some data
1060  for (int i = 0; i < 10; i++) {
1061  auto* mainObj = arrayMain.appendNew();
1062  for (int j = 0; j < 2; j++) {
1063  auto* aObj = arrayA.appendNew();
1064  aObj->addRelationTo(mainObj);
1065  }
1066  for (int j = 0; j < 10; j++) {
1067  auto* bObj = arrayB.appendNew();
1068  mainObj->addRelationTo(bObj);
1069  }
1070  }
1071 
1072  //verify original contents
1073  EXPECT_EQ(10, arrayMain.getEntries());
1074  EXPECT_EQ(20, arrayA.getEntries());
1075  EXPECT_EQ(100, arrayB.getEntries());
1076 
1077  //run selector
1078  selectorMain.select(hasOddIndex);
1079 
1080 
1081  //verify subset
1082  EXPECT_EQ(5, arrayMain.getEntries());
1083  for (const RelationsObject& r : arrayMain) {
1084  EXPECT_EQ(2u, r.getRelationsFrom<RelationsObject>("a").size());
1085  EXPECT_EQ(0u, r.getRelationsFrom<RelationsObject>("b").size());
1086  EXPECT_EQ(10u, r.getRelationsTo<RelationsObject>("b").size());
1087  EXPECT_EQ(0u, r.getRelationsTo<RelationsObject>("a").size());
1088  EXPECT_TRUE(nullptr == r.getRelatedTo<RelationsObject>("main"));
1089  }
1090  int i = 0;
1091  for (const RelationsObject& r : arrayA) {
1092  EXPECT_EQ((i / 2 % 2 == 1) ? 1u : 0u, r.getRelationsTo<RelationsObject>("main").size());
1093  i++;
1094  }
1095  }
1096 
1097  TEST_F(SelectSubsetTest, TestEmptyArray)
1098  {
1099  //array 'main' with relations: a -> main -> b
1100  //then remove half of main.
1101 
1102  DataStore::Instance().setInitializeActive(true);
1103  StoreArray< RelationsObject > arrayMain("main");
1104  StoreArray< RelationsObject > arrayA("a");
1105  StoreArray< RelationsObject > arrayB("b");
1106  arrayMain.registerInDataStore();
1107  arrayA.registerInDataStore();
1108  arrayB.registerInDataStore();
1109  arrayA.registerRelationTo(arrayMain);
1110  arrayMain.registerRelationTo(arrayB);
1111 
1112  //create subset and relations
1113  SelectSubset< RelationsObject > selectorMain;
1114  selectorMain.registerSubset(arrayMain);
1115 
1116  DataStore::Instance().setInitializeActive(false);
1117 
1118  //test with empty inputs
1119  EXPECT_EQ(0, arrayMain.getEntries());
1120  selectorMain.select(hasOddIndex);
1121  EXPECT_EQ(0, arrayMain.getEntries());
1122 
1123  //fill some data
1124  for (int i = 0; i < 10; i++) {
1125  auto* mainObj = arrayMain.appendNew();
1126  for (int j = 0; j < 2; j++) {
1127  auto* aObj = arrayA.appendNew();
1128  aObj->addRelationTo(mainObj);
1129  }
1130  for (int j = 0; j < 10; j++) {
1131  auto* bObj = arrayB.appendNew();
1132  mainObj->addRelationTo(bObj);
1133  }
1134  }
1135 
1136  //verify original contents
1137  EXPECT_EQ(10, arrayMain.getEntries());
1138  EXPECT_EQ(20, arrayA.getEntries());
1139  EXPECT_EQ(100, arrayB.getEntries());
1140 
1141  //delete all contents
1142  auto never = [](const RelationsObject*) -> bool { return false; };
1143  selectorMain.select(never);
1144 
1145 
1146  //verify subset
1147  EXPECT_EQ(0, arrayMain.getEntries());
1148  for (const RelationsObject& r : arrayA) {
1149  EXPECT_EQ(0u, r.getRelationsTo<RelationsObject>("main").size());
1150  }
1151  }
1152 
1153 } // 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:414
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