CountersMap_test.cc
Go to the documentation of this file.
1 /**
2  * @file CountersMap_test.cc
3  * @brief Tests the counter map
4  * @author Gianluca Petrillo (petrillo@fnal.gov)
5  * @date 20140822
6  * @version 1.0
7  *
8  * See http://www.boost.org/libs/test for the Boost test library home page.
9  *
10  * Timing:
11  * version 1.0 takes about 30" on a 3 GHz machine.
12  */
13 
14 // C/C++ standard libraries
15 #include <map>
16 #include <random>
17 #include <iostream>
18 
19 // Boost libraries
20 /*
21  * Boost Magic: define the name of the module;
22  * and do that before the inclusion of Boost unit test headers
23  * because it will change what they provide.
24  * Among the those, there is a main() function and some wrapping catching
25  * unhandled exceptions and considering them test failures, and probably more.
26  * This also makes fairly complicate to receive parameters from the command line
27  * (for example, a random seed).
28  */
29 #define BOOST_TEST_MODULE ( CountersMap_test )
30 #include "boost/test/unit_test.hpp"
31 
32 // LArSoft libraries
34 
35 
36 /// The seed for the default random engine
37 constexpr unsigned int RandomSeed = 12345;
38 
39 
40 //------------------------------------------------------------------------------
41 //--- Test code
42 //
43 
44 /**
45  * @brief Tests with a vector of counter maps (Hough transfort use case)
46  *
47  * The test consists in filling a lot of points into a 2D sparse "image" (or
48  * histogram).
49  * Two structures are maintained, one with the standard STL map, another
50  * with the CountersMap.
51  * The test fails if the two images do not match.
52  */
54 
55  // the structure we are testing is a 2D "image" of integers;
56  // image is mostly empty (zero), but each abscissa has roughly the same
57  // number of non-empty pixels (NPoints), and at least one of them.
58 
59  constexpr unsigned int NPoints = 1000;
60  constexpr unsigned int NAngles = 10800;
61  constexpr unsigned int NDist = 2500; // half distance
62 
63  typedef std::map<int, int> BaseMap_t;
64 
65  // STL container
66  typedef std::vector<BaseMap_t> MapVectorI_t;
67  MapVectorI_t stl_image(NAngles);
68 
69  // CountersMap; uses chunks of 8 counters per block
70  std::vector<lar::CountersMap<int, int, 8>> cm_image(NAngles);
71  // the following should fail compilation
72 // std::vector<lar::CountersMap<int, int, 9>> cm_image_broken(NAngles);
73 
74  static std::default_random_engine random_engine(RandomSeed);
75  std::uniform_real_distribution<float> uniform(-1., 1.);
76 
77  for (unsigned int iPoint = 0; iPoint != NPoints; ++iPoint) {
78  // we add here some simple image, not to strain the test;
79  // this is a straight line
80  const float offset = uniform(random_engine) * NDist;
81  const float slope = uniform(random_engine);
82  float d = offset;
83  for (size_t iAngle = 0; iAngle < NAngles; ++iAngle) {
84  // add one entry on the (angle ; distance) plane
85  ++(stl_image[iAngle][int(d)]);
86  cm_image[iAngle].increment(int(d)); // different interface than usual map
87  // prepare for the next point; wrap in the [-NDist, NDist[ range
88  d += slope;
89  while (d >= (float) NDist) d -= 2*NDist;
90  while (d < 0) d += 2*NDist;
91  } // for iAngle
92  } // for iPoint
93 
94  std::cout << "Filling complete, now checking." << std::endl;
95 
96  // we have to provide a comparison between two "different" structures
97  // (having different allocators is enough to make them unrelated)
98  unsigned int nExtraKeys = 0, nMismatchValue = 0, nMissingKeys = 0;
99  auto stl_begin = stl_image.cbegin();
100  unsigned int iMap = 0;
101  for (const auto& cm_map: cm_image) {
102 
103  const MapVectorI_t::value_type& stl_map = *(stl_begin++);
104 
105  std::cout << "Map #" << iMap << " (" << cm_map.n_counters()
106  << " counters, " << stl_map.size() << " real)"
107  << std::endl;
108 
109  // compare the two maps; the CountersMap one has more elements,
110  // since the counters are allocated in blocks;
111  // if a key is in STL map, it must be also in the CountersMap;
112  // if a key is not in STL map, counter in CountersMap must be missing or 0
113  MapVectorI_t::value_type::const_iterator stl_iter = stl_map.begin(),
114  stl_end = stl_map.end();
115  for (auto p: cm_map) { // this should be a pair (index, counter)
116 
117  if (stl_iter != stl_end) { // we have still counters to find
118  // if counter is already beyond the next non-empty one froml STL map,
119  // then we are missing some
120  while (p.first > stl_iter->first) {
121  ++nMissingKeys;
122  std::cout << "ERROR missing key " << stl_iter->first << std::endl;
123  if (++stl_iter == stl_end) break;
124  }
125  } // if
126 
127  if (stl_iter != stl_end) { // we have still counters to find
128  if (p.first == stl_iter->first) {
129  // if the counter is in SLT map, the two counts must match
130  // std::cout << " " << p.first << " " << p.second << std::endl;
131  if (stl_iter->second != p.second) {
132  std::cout << "ERROR wrong counter value " << p.second
133  << ", expected " << stl_iter->second << std::endl;
134  ++nMismatchValue;
135  }
136  ++stl_iter; // done with it
137  }
138  else if (p.first < stl_iter->first) {
139  // if the counter is not in STL map, then it must be 0
140  if (p.second != 0) {
141  ++nExtraKeys;
142  std::cout << "ERROR extra key " << p.first << " (" << p.second << ")"
143  << std::endl;
144  }
145  // else {
146  // std::cout << " " << p.first << " " << p.second << " (not in STL)"
147  // << std::endl;
148  // }
149  }
150  }
151  else {
152  // no more keys in STL map
153  if (p.second != 0) {
154  ++nExtraKeys;
155  std::cout << "ERROR extra key " << p.first << " (" << p.second << ")"
156  << std::endl;
157  }
158  }
159  } // for element in map
160 
161  BOOST_TEST(cm_map.is_equal(stl_map));
162 
163  // if they were the same, make sure that now they differ
164  const_cast<MapVectorI_t::value_type&>(stl_map)[NDist / 2]++;
165  BOOST_TEST(!cm_map.is_equal(stl_map));
166 
167  ++iMap;
168  } // for map
169 
170  BOOST_TEST(nMismatchValue == 0U);
171  BOOST_TEST(nMissingKeys == 0U);
172  BOOST_TEST(nExtraKeys == 0U);
173 
174 
175 } // RunHoughTransformTreeTest()
176 
177 
178 //------------------------------------------------------------------------------
179 //--- registration of tests
180 //
181 // Boost needs now to know which tests we want to run.
182 // Tests are "automatically" registered, hence the BOOST_AUTO_TEST_CASE()
183 // macro name. The argument is a name for the test; each test will have a
184 // number of checks and it will fail if any of them does.
185 //
186 
187 BOOST_AUTO_TEST_CASE(RunHoughTransformTree) {
189  std::cout << "Done." << std::endl;
190 }
constexpr unsigned int RandomSeed
The seed for the default random engine.
intermediate_table::const_iterator const_iterator
void RunHoughTransformTreeTest()
Tests with a vector of counter maps (Hough transfort use case)
p
Definition: test.py:223
BOOST_AUTO_TEST_CASE(RunHoughTransformTree)
Map of counters, stored compactly.
QTextStream & endl(QTextStream &s)