Belle II Software development
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
24using namespace std;
25using namespace Belle2;
26
27
28namespace {
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
219
221 array.registerInDataStore();
222 array.registerRelationTo(array);
223
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
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
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 {
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
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
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
950 StoreArray< RelationsObject > arrayMain("main");
953 arrayMain.registerInDataStore();
954 arrayA.registerInDataStore();
955 arrayB.registerInDataStore();
956 arrayA.registerRelationTo(arrayMain);
957 arrayMain.registerRelationTo(arrayB);
958
959 //create subset and relations
961 selectorMain.registerSubset(arrayMain, "subsetOfMain");
962
963 selectorMain.inheritRelationsFrom(arrayA);
964 selectorMain.inheritRelationsTo(arrayB);
965
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
1015 StoreArray< RelationsObject > arrayMain("main");
1018 arrayMain.registerInDataStore();
1019 arrayA.registerInDataStore();
1020 arrayB.registerInDataStore();
1021 arrayA.registerRelationTo(arrayMain);
1022 arrayMain.registerRelationTo(arrayB);
1023
1024 //create subset and relations
1026 selectorMain.registerSubset(arrayMain, "subsetOfMain");
1027
1028 selectorMain.inheritAllRelations();
1029
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
1044 StoreArray< RelationsObject > arrayMain("main");
1047 arrayMain.registerInDataStore();
1048 arrayA.registerInDataStore();
1049 arrayB.registerInDataStore();
1050 arrayA.registerRelationTo(arrayMain);
1051 arrayMain.registerRelationTo(arrayB);
1052
1053 //create subset and relations
1055 selectorMain.registerSubset(arrayMain);
1056
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
1103 StoreArray< RelationsObject > arrayMain("main");
1106 arrayMain.registerInDataStore();
1107 arrayA.registerInDataStore();
1108 arrayB.registerInDataStore();
1109 arrayA.registerRelationTo(arrayMain);
1110 arrayMain.registerRelationTo(arrayB);
1111
1112 //create subset and relations
1114 selectorMain.registerSubset(arrayMain);
1115
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
static DataStore & Instance()
Instance of singleton Store.
Definition: DataStore.cc:54
void setInitializeActive(bool active)
Setter for m_initializeActive.
Definition: DataStore.cc:94
void reset(EDurability durability)
Frees memory occupied by data store items and removes all objects from the map.
Definition: DataStore.cc:86
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
bool getInheritToSelf() const
Do we inherit relations from original set to itself?
Definition: SelectSubset.h:36
std::vector< std::string > getInheritFromArrays() const
Get list of arrays we inherit relations from.
Definition: SelectSubset.h:32
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
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
STL namespace.