Belle II Software  release-08-01-10
filters.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 
9 #include <gtest/gtest.h>
10 
11 
12 #include <tracking/trackFindingVXD/filterMap/filterFramework/Shortcuts.h>
13 #include <tuple>
14 #include <iostream>
15 #include <math.h>
16 
17 using namespace std;
18 
19 using namespace Belle2;
20 
21 namespace VXDTFfilterTest {
22 
24  class spacePoint: public tuple<float, float, float> {
25  public:
27  spacePoint(float x, float y, float z): tuple<float, float, float>(x, y, z)
28  {};
29  private:
32  spacePoint(const spacePoint&) = delete;
33  };
34 
35 
37  class SquaredDistance3D : public SelectionVariable< spacePoint, 2, float > {
38  public:
40  static const std::string name(void) {return "SquaredDistance3D"; };
41 
43  static float value(const spacePoint& p1, const spacePoint& p2)
44  {
45  return
46  pow(get<0>(p1) - get<0>(p2), 2) +
47  pow(get<1>(p1) - get<1>(p2), 2) +
48  pow(get<2>(p1) - get<2>(p2), 2) ;
49  }
50  };
51 
52 
54  class SquaredDistance2Dxy : public SelectionVariable< spacePoint, 2, float > {
55  public:
57  static const std::string name(void) {return "SquaredDistance2Dxy"; };
58 
60  static float value(const spacePoint& p1, const spacePoint& p2)
61  {
62  return
63  pow(get<0>(p1) - get<0>(p2), 2) +
64  pow(get<1>(p1) - get<1>(p2), 2) ;
65  }
66  };
67 
68 
70  class SquaredDistance1Dx : public SelectionVariable< spacePoint, 2, float > {
71  public:
73  static const std::string name(void) {return "SquaredDistance1Dx"; };
74 
76  static float value(const spacePoint& p1, const spacePoint& p2)
77  {
78  return
79  pow(get<0>(p1) - get<0>(p2), 2);
80  }
81  };
82 
83 
85  class BooleanVariable : public SelectionVariable< spacePoint, 2, bool > {
86  public:
88  static const std::string name(void) {return "BooleanVariable"; };
89 
91  static float value(const spacePoint& p1, const spacePoint& p2)
92  {
93  return
94  get<0>(p1) - get<0>(p2) == 0.;
95  }
96  };
97 
98 
100  template < class T> class counter {
101  public:
102  static int N;
103  counter() {};
104  ~counter() {};
105  };
106 
107 
109  template<>
111 
112 
114  template<>
116 
117 
119  template<>
121 
122 
124  class Observer : public VoidObserver {
125  public:
127  template<class Var, typename ... otherTypes>
128  static void notify(const Var&,
129  const otherTypes& ...)
130  {
131  counter<Var>::N ++ ;
132  }
133  };
134 
135 
136 
138  class FilterTest : public ::testing::Test {
139  protected:
140  };
141 
142 
145  {
146 
147  Range<double, double> range(0., 1.);
148  EXPECT_TRUE(range.contains(0.5));
149  EXPECT_FALSE(range.contains(-1.));
150  EXPECT_FALSE(range.contains(0.));
151  EXPECT_FALSE(range.contains(1.));
152  EXPECT_FALSE(range.contains(2.));
153  EXPECT_EQ(0., range.getInf());
154  EXPECT_EQ(1., range.getSup());
155  }
156 
158  TEST_F(FilterTest, ClosedRange)
159  {
160 
161  ClosedRange<double, double> range(0., 1.);
162  EXPECT_TRUE(range.contains(0.5));
163  EXPECT_FALSE(range.contains(-1.));
164  EXPECT_TRUE(range.contains(0.));
165  EXPECT_TRUE(range.contains(1.));
166  EXPECT_FALSE(range.contains(2.));
167  EXPECT_EQ(0., range.getInf());
168  EXPECT_EQ(1., range.getSup());
169  }
170 
171 
173  TEST_F(FilterTest, UpperBoundedSet)
174  {
175 
176  UpperBoundedSet<double> upperBoundedSet(0.);
177  EXPECT_TRUE(upperBoundedSet.contains(-1.));
178  EXPECT_FALSE(upperBoundedSet.contains(0.));
179  EXPECT_FALSE(upperBoundedSet.contains(1.));
180  EXPECT_EQ(0., upperBoundedSet.getSup());
181  }
182 
184  TEST_F(FilterTest, ClosedUpperBoundedSet)
185  {
186 
187  ClosedUpperBoundedSet<double> upperBoundedSet(0.);
188  EXPECT_TRUE(upperBoundedSet.contains(-1.));
189  EXPECT_TRUE(upperBoundedSet.contains(0.));
190  EXPECT_FALSE(upperBoundedSet.contains(1.));
191  EXPECT_EQ(0., upperBoundedSet.getSup());
192  }
193 
194 
196  TEST_F(FilterTest, LowerBoundedSet)
197  {
198 
199  LowerBoundedSet<double> lowerBoundedSet(0.);
200  EXPECT_TRUE(lowerBoundedSet.contains(1.));
201  EXPECT_FALSE(lowerBoundedSet.contains(0.));
202  EXPECT_FALSE(lowerBoundedSet.contains(-1.));
203  EXPECT_EQ(0., lowerBoundedSet.getInf());
204  }
205 
207  TEST_F(FilterTest, ClosedLowerBoundedSet)
208  {
209 
210  ClosedLowerBoundedSet<double> lowerBoundedSet(0.);
211  EXPECT_TRUE(lowerBoundedSet.contains(1.));
212  EXPECT_TRUE(lowerBoundedSet.contains(0.));
213  EXPECT_FALSE(lowerBoundedSet.contains(-1.));
214  EXPECT_EQ(0., lowerBoundedSet.getInf());
215  }
216 
217 
219  TEST_F(FilterTest, SelectionVariableName)
220  {
221 
222  EXPECT_EQ("SquaredDistance3D", SquaredDistance3D().name());
223  }
224 
225 
227  TEST_F(FilterTest, BasicFilter)
228  {
229  // Very verbose declaration, see below for convenient shortcuts
231 
232  spacePoint x1(0.0f, 0.0f, 0.0f);
233  spacePoint x2(0.5f, 0.0f, 0.0f);
234  spacePoint x3(2.0f, 0.0f, 0.0f);
235 
236  EXPECT_TRUE(filter.accept(x1, x2));
237  EXPECT_FALSE(filter.accept(x1, x3));
238 
239  }
240 
241 
243  TEST_F(FilterTest, ObservedFilter)
244  {
245  // Very verbose declaration, see below for convenient shortcuts
247 
249  spacePoint x1(0.0f, 0.0f, 0.0f);
250  spacePoint x2(0.5f, 0.0f, 0.0f);
251  spacePoint x3(2.0f, 0.0f, 0.0f);
252  counter< SquaredDistance3D >::N = 0;
253 
254  EXPECT_TRUE(filter.accept(x1, x2));
255  EXPECT_FALSE(filter.accept(x1, x3));
256  EXPECT_EQ(2, counter< SquaredDistance3D >::N);
257  }
258 
260  TEST_F(FilterTest, SwitchingObservers)
261  {
262  //build an dummy filter which is unobserved (VoidObserver)
263  auto dummyFilter = ((-10. <= SquaredDistance3D() <= 10.) &&
264  ((-100. <= SquaredDistance2Dxy() <= -10.) || // put 2nd pair of parentheses to silence warning
265  (-10. <= SquaredDistance1Dx() <= 10.)) &&
266  // cppcheck-suppress duplicateExpression
267  !(-10. <= SquaredDistance1Dx() <= -10.));
268 
269  // values are chosen in that way that all sub-filters of dummyFilter have to be called (see comment below)
270  // and so that dummyFilter is always true
271  spacePoint x1(0.0f, 0.0f, 0.0f);
272  spacePoint x2(0.5f, 0.0f, 0.0f);
273  spacePoint x3(2.0f, 0.0f, 0.0f);
274 
275  counter< SquaredDistance3D >::N = 0;
276  counter< SquaredDistance1Dx >::N = 0;
277  counter< SquaredDistance2Dxy >::N = 0;
278 
279  dummyFilter.accept(x1, x2);
280  dummyFilter.accept(x1, x3);
281 
282  // useless test as it tests if realy unobserved
283  EXPECT_EQ(0, counter< SquaredDistance3D >::N);
284  EXPECT_EQ(0, counter< SquaredDistance2Dxy >::N);
285  EXPECT_EQ(0, counter< SquaredDistance1Dx >::N);
286 
287  // Now switch observer, this is done recursively for each of the underlying filters
288  // One cannot switch the observer of an existing filter (as it would mean to switch type) so one has to create a new one!
289  // Note that if one filter is evaluated as false the other filter are not evaluated anymore and thus not observed!
290  auto observedDummyFilter = dummyFilter.observe(Observer());
291  observedDummyFilter.accept(x1, x2);
292  observedDummyFilter.accept(x1, x3);
293 
294  EXPECT_EQ(2, counter< SquaredDistance3D >::N);
295  EXPECT_EQ(2, counter< SquaredDistance2Dxy >::N);
296  //Note SquaredDistance1D is used twice in the filter so it is evaluated twice!
297  EXPECT_EQ(4, counter< SquaredDistance1Dx >::N);
298  }
299 
300 
302  TEST_F(FilterTest, BypassableFilter)
303  {
304  bool bypassControl(false);
305  // Very verbose declaration, see below for convenient shortcuts
307  auto filter = nonBypassableFilter.bypass(bypassControl);
308  spacePoint x1(0.0f, 0.0f, 0.0f);
309  spacePoint x2(2.0f, 0.0f, 0.0f);
310  counter< SquaredDistance3D >::N = 0;
311 
312  EXPECT_FALSE(filter.accept(x1, x2));
313  EXPECT_EQ(1, counter< SquaredDistance3D >::N);
314 
315  // The clang static analyser doesn't understand that the `filter` has a pointer to
316  // `bypassControl` and thus doesn't know that the variable is in fact used after being changed to `true` here.
317  // According to https://clang-analyzer.llvm.org/faq.html#exclude_code, the only way to suppress these
318  // warnings as of May 2023 is the following
319 #ifndef __clang_analyzer__
320  bypassControl = true;
321 #endif
322  EXPECT_TRUE(filter.accept(x1, x2));
323  EXPECT_EQ(2, counter< SquaredDistance3D >::N);
324 
325  }
326 
327 
329  TEST_F(FilterTest, Shortcuts)
330  {
331 
332  spacePoint x1(0.0f, 0.0f, 0.0f);
333  spacePoint x2(0.5f, 0.0f, 0.0f);
334  spacePoint x3(2.0f, 0.0f, 0.0f);
335  spacePoint x4(1.0f, 0.0f, 0.0f);
336 
337  auto filterSup = (SquaredDistance3D() < 1.) ;
338  EXPECT_TRUE(filterSup.accept(x1, x2));
339  EXPECT_FALSE(filterSup.accept(x1, x4));
340  EXPECT_FALSE(filterSup.accept(x1, x3));
341 
342  auto filterMax = (SquaredDistance3D() <= 1.) ;
343  EXPECT_TRUE(filterMax.accept(x1, x2));
344  EXPECT_TRUE(filterMax.accept(x1, x4));
345  EXPECT_FALSE(filterMax.accept(x1, x3));
346 
347 
348  auto filterSup2 = (1 > SquaredDistance3D()) ;
349  EXPECT_TRUE(filterSup2.accept(x1, x2));
350  EXPECT_FALSE(filterSup2.accept(x1, x3));
351  EXPECT_FALSE(filterSup2.accept(x1, x4));
352 
353  auto filterMax2 = (1 >= SquaredDistance3D()) ;
354  EXPECT_TRUE(filterMax2.accept(x1, x2));
355  EXPECT_FALSE(filterMax2.accept(x1, x3));
356  EXPECT_TRUE(filterMax2.accept(x1, x4));
357 
358  auto filterInf = (SquaredDistance3D() > 1.) ;
359  EXPECT_TRUE(filterInf.accept(x1, x3));
360  EXPECT_FALSE(filterInf.accept(x1, x2));
361  EXPECT_FALSE(filterInf.accept(x1, x4));
362 
363  auto filterMin = (SquaredDistance3D() >= 1.) ;
364  EXPECT_TRUE(filterMin.accept(x1, x3));
365  EXPECT_FALSE(filterMin.accept(x1, x2));
366  EXPECT_TRUE(filterMin.accept(x1, x4));
367 
368  auto filterInf2 = (1 < SquaredDistance3D()) ;
369  EXPECT_TRUE(filterInf2.accept(x1, x3));
370  EXPECT_FALSE(filterInf2.accept(x1, x2));
371  EXPECT_FALSE(filterInf2.accept(x1, x4));
372 
373  auto filterMin2 = (1 <= SquaredDistance3D()) ;
374  EXPECT_TRUE(filterMin2.accept(x1, x3));
375  EXPECT_FALSE(filterMin2.accept(x1, x2));
376  EXPECT_TRUE(filterMin2.accept(x1, x4));
377 
378  auto filterRange = (0. < SquaredDistance3D() < 1);
379  EXPECT_FALSE(filterRange.accept(x1, x1));
380  EXPECT_TRUE(filterRange.accept(x1, x2));
381  EXPECT_FALSE(filterRange.accept(x1, x3));
382  EXPECT_FALSE(filterRange.accept(x1, x4));
383 
384  // cppcheck-suppress compareBoolExpressionWithInt
385  auto filterClosedRange = (0. <= SquaredDistance3D() <= 1);
386  EXPECT_TRUE(filterClosedRange.accept(x1, x1));
387  EXPECT_TRUE(filterClosedRange.accept(x1, x2));
388  EXPECT_FALSE(filterClosedRange.accept(x1, x3));
389  EXPECT_TRUE(filterClosedRange.accept(x1, x4));
390 
391  }
392 
393 
395  TEST_F(FilterTest, BooleanOperations)
396  {
397 
398 
399  spacePoint x1(0.0f, 0.0f, 0.0f);
400  spacePoint x2(1.0f, 0.0f, 0.0f);
401  spacePoint x3(2.0f, 0.0f, 0.0f);
402 
403  auto filter = !(SquaredDistance3D() > 1.);
404  EXPECT_TRUE(filter.accept(x1, x2));
405  EXPECT_TRUE(filter.accept(x1, x1));
406  EXPECT_FALSE(filter.accept(x1, x3));
407 
408  auto filter2 =
409  !(SquaredDistance3D() > 1.) &&
410  !(SquaredDistance3D() < 1);
411  // i.e. SquaredDistance3D == 1
412  EXPECT_TRUE(filter2.accept(x1, x2));
413  EXPECT_FALSE(filter2.accept(x1, x1));
414  EXPECT_FALSE(filter2.accept(x1, x3));
415 
416 
417  auto filter3 =
418  (SquaredDistance3D() > 1.) ||
419  (SquaredDistance3D() < 1);
420  // i.e. SquaredDistance3D != 1
421  EXPECT_FALSE(filter3.accept(x1, x2));
422  EXPECT_TRUE(filter3.accept(x1, x1));
423  EXPECT_TRUE(filter3.accept(x1, x3));
424 
425 
426  }
427 
428 
430  TEST_F(FilterTest, ShortCircuitsEvaluation)
431  {
432  auto filter(
433  (SquaredDistance2Dxy() < 1).observeLeaf(Observer()) &&
434  (SquaredDistance3D() < 1).observeLeaf(Observer())
435  );
436 
437  spacePoint x1(0.0f, 0.0f, 0.0f);
438  spacePoint x3(2.0f, 0.0f, 0.0f);
439 
440  counter< SquaredDistance3D >::N = 0;
441  counter< SquaredDistance2Dxy >::N = 0;
442 
443  EXPECT_FALSE(filter.accept(x1, x3));
444  // since the pair x1, x3 does not satisfy the SquaredDistance2Dxy
445  // requirement, we do expect SquaredDistance2Dxy evaluated once:
446  EXPECT_EQ(1, counter< SquaredDistance2Dxy >::N);
447  // and SquaredDistance3D not evaluated at all
448  EXPECT_EQ(0, counter< SquaredDistance3D >::N);
449 
450  EXPECT_TRUE(filter.accept(x1, x1));
451  // in this case Distance2Dxy is satisfied
452  EXPECT_EQ(2, counter< SquaredDistance2Dxy >::N);
453  // and Distance3D is evaluated
454  EXPECT_EQ(1, counter< SquaredDistance3D >::N);
455 
456  }
457 
458 
460  TEST_F(FilterTest, BooleanVariableShortcuts)
461  {
462  auto filter1(BooleanVariable() == true);
463  auto filter2(false == BooleanVariable());
464  spacePoint x1(0.0f, 0.0f, 0.0f);
465  spacePoint x2(1.0f, 0.0f, 0.0f);
466 
467  EXPECT_TRUE(filter1.accept(x1, x1));
468  EXPECT_FALSE(filter1.accept(x1, x2));
469 
470 
471  EXPECT_FALSE(filter2.accept(x1, x1));
472  EXPECT_TRUE(filter2.accept(x1, x2));
473 
474 
475 
476  }
477 
478 }
Represents a closed lower bounded set of arithmetic types.
Represents a closed set of arithmetic types.
Definition: ClosedRange.h:32
Represents an upper bounded set of arithmetic types.
This class is used to select pairs, triplets...
Definition: Filter.h:34
Represents a lower bounded set of arithmetic types.
Observer base class which can be used to evaluate the VXDTF2's Filters.
Definition: Observer.h:19
Represents a range of arithmetic types.
Definition: Range.h:29
Base class of the selection variable objects used for pair filtering.
Represents an upper bounded set of arithmetic types.
The most CPU efficient Observer for the VXDTF filter tools (even if useless).
Definition: VoidObserver.h:30
a small filter illustrating the behavior of a filter which is compatible with boolean comparisons
Definition: filters.cc:85
static float value(const spacePoint &p1, const spacePoint &p2)
value function does the actual calculation of this class.
Definition: filters.cc:91
static const std::string name(void)
return name of the class
Definition: filters.cc:88
Test class for Filter object.
Definition: filters.cc:138
this observer does simply count the number of times, the attached Filter was used
Definition: filters.cc:124
static void notify(const Var &, const otherTypes &...)
notify function is called by the filter, this one increases the counter.
Definition: filters.cc:128
a small filter illustrating the behavior of a distance1D-filter in X
Definition: filters.cc:70
static float value(const spacePoint &p1, const spacePoint &p2)
value function does the actual calculation of this class.
Definition: filters.cc:76
static const std::string name(void)
return name of the class
Definition: filters.cc:73
a small filter illustrating the behavior of a distance2D-filter in XY
Definition: filters.cc:54
static float value(const spacePoint &p1, const spacePoint &p2)
value function does the actual calculation of this class.
Definition: filters.cc:60
static const std::string name(void)
return name of the class
Definition: filters.cc:57
a small filter illustrating the behavior of a distance3D-filter
Definition: filters.cc:37
static float value(const spacePoint &p1, const spacePoint &p2)
value function does the actual calculation of this class.
Definition: filters.cc:43
static const std::string name(void)
return name of the class
Definition: filters.cc:40
small class counting usage.
Definition: filters.cc:100
static int N
counter.
Definition: filters.cc:102
~counter()
constructor.
Definition: filters.cc:104
just a small proto-container storing coordinates
Definition: filters.cc:24
spacePoint(const spacePoint &)=delete
private copy constructor to test that all the arguments are passed by reference.
spacePoint(float x, float y, float z)
Constructor accepting coordinates.
Definition: filters.cc:27
TEST_F(GlobalLabelTest, LargeNumberOfTimeDependentParameters)
Test large number of time-dep params for registration and retrieval.
Definition: globalLabel.cc:72
std::map< ExpRun, std::pair< double, double > > filter(const std::map< ExpRun, std::pair< double, double >> &runs, double cut, std::map< ExpRun, std::pair< double, double >> &runsRemoved)
filter events to remove runs shorter than cut, it stores removed runs in runsRemoved
Definition: Splitter.cc:38
Abstract base class for different kinds of events.