UFO
test/ufo/RecursiveSplitter.h
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2019 Met Office UK
3  *
4  * This software is licensed under the terms of the Apache Licence Version 2.0
5  * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6  */
7 
8 #ifndef TEST_UFO_RECURSIVESPLITTER_H_
9 #define TEST_UFO_RECURSIVESPLITTER_H_
10 
12 
13 #include <iomanip>
14 #include <memory>
15 #include <set>
16 #include <string>
17 #include <vector>
18 
19 #include "eckit/testing/Test.h"
20 #include "oops/runs/Test.h"
21 #include "oops/util/Expect.h"
22 
23 namespace ufo {
24 namespace test {
25 
26 typedef std::set<size_t> Group;
27 typedef std::set<Group> Groups;
28 
30  Groups groups;
31  for (const auto &g : splitter.groups()) {
32  Group group;
33  for (auto index : g)
34  group.insert(index);
35  groups.insert(group);
36  }
37  return groups;
38 }
39 
41  Groups groups;
42  for (const auto &g : splitter.multiElementGroups()) {
43  Group group;
44  for (auto index : g)
45  group.insert(index);
46  groups.insert(group);
47  }
48  return groups;
49 }
50 
51 
52 void orderedComparison(const RecursiveSplitter &splitter,
53  const std::vector<std::vector<int>> &expected) {
54  int groupInd = -1;
55  int iterInd = -1;
56  for (const auto &g : splitter.groups()) {
57  groupInd++;
58  iterInd = -1;
59  for (auto index : g) {
60  iterInd++;
61  oops::Log::debug() << "group: " << groupInd << " index: " << index << " expected index: " <<
62  expected[groupInd][iterInd] << std::endl;
63  EXPECT_EQUAL(index, expected[groupInd][iterInd]);
64  }
65  }
66 }
67 
68 
69 CASE("ufo/RecursiveSplitter/ZeroIds") {
70  RecursiveSplitter splitter(0);
71  {
72  Groups expectedGroups;
73  Groups groups = getGroups(splitter);
74  EXPECT_EQUAL(groups, expectedGroups);
75 
76  Groups expectedMultiElementGroups;
77  Groups multiElementGroups = getMultiElementGroups(splitter);
78  EXPECT_EQUAL(multiElementGroups, expectedMultiElementGroups);
79  }
80 
81  {
82  std::vector<size_t> categories;
83  splitter.groupBy(categories);
84 
85  Groups expectedGroups;
86  Groups groups = getGroups(splitter);
87  EXPECT_EQUAL(groups, expectedGroups);
88 
89  Groups expectedMultiElementGroups;
90  Groups multiElementGroups = getMultiElementGroups(splitter);
91  EXPECT_EQUAL(multiElementGroups, expectedMultiElementGroups);
92  }
93 }
94 
95 CASE("ufo/RecursiveSplitter/OneId") {
96  RecursiveSplitter splitter(1);
97  {
98  Groups expectedGroups{{0}};
99  Groups groups = getGroups(splitter);
100  EXPECT_EQUAL(groups, expectedGroups);
101 
102  Groups expectedMultiElementGroups;
103  Groups multiElementGroups = getMultiElementGroups(splitter);
104  EXPECT_EQUAL(multiElementGroups, expectedMultiElementGroups);
105  }
106 
107  {
108  std::vector<size_t> categories{1};
109  splitter.groupBy(categories);
110 
111  Groups expectedGroups{{0}};
112  Groups groups = getGroups(splitter);
113  EXPECT_EQUAL(groups, expectedGroups);
114 
115  Groups expectedMultiElementGroups;
116  Groups multiElementGroups = getMultiElementGroups(splitter);
117  EXPECT_EQUAL(multiElementGroups, expectedMultiElementGroups);
118  }
119 }
120 
121 CASE("ufo/RecursiveSplitter/TenIds") {
122  RecursiveSplitter splitter(10);
123  {
124  Groups expectedGroups{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}};
125  Groups groups = getGroups(splitter);
126  EXPECT_EQUAL(groups, expectedGroups);
127 
128  Groups expectedMultiElementGroups{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}};
129  Groups multiElementGroups = getMultiElementGroups(splitter);
130  EXPECT_EQUAL(multiElementGroups, expectedMultiElementGroups);
131  }
132 
133  {
134  std::vector<size_t> categories{1, 2, 1, 2, 1, 2, 1, 2, 1, 2};
135  splitter.groupBy(categories);
136 
137  Groups expectedGroups{{0, 2, 4, 6, 8}, {1, 3, 5, 7, 9}};
138  Groups groups = getGroups(splitter);
139  EXPECT_EQUAL(groups, expectedGroups);
140 
141  Groups expectedMultiElementGroups{{0, 2, 4, 6, 8}, {1, 3, 5, 7, 9}};
142  Groups multiElementGroups = getMultiElementGroups(splitter);
143  EXPECT_EQUAL(multiElementGroups, expectedMultiElementGroups);
144  }
145 
146  {
147  // The first and last category in the first group have only a single element
148  std::vector<size_t> categories{3, 2, 1, 2, 3, 2, 4, 2, 3, 2};
149  splitter.groupBy(categories);
150 
151  Groups expectedGroups{{2}, {0, 4, 8}, {6}, {1, 3, 5, 7, 9}};
152  Groups groups = getGroups(splitter);
153  EXPECT_EQUAL(groups, expectedGroups);
154 
155  Groups expectedMultiElementGroups{{0, 4, 8}, {1, 3, 5, 7, 9}};
156  Groups multiElementGroups = getMultiElementGroups(splitter);
157  EXPECT_EQUAL(multiElementGroups, expectedMultiElementGroups);
158  }
159 
160  {
161  // Two multiple-element categories in the second group.
162  // Categories shared by multiple groups.
163  std::vector<size_t> categories{1, 3, 1, 3, 1, 2, 1, 1, 1, 1};
164  splitter.groupBy(categories);
165 
166  Groups expectedGroups{{2}, {0, 4, 8}, {6}, {1, 3}, {5}, {7, 9}};
167  Groups groups = getGroups(splitter);
168  EXPECT_EQUAL(groups, expectedGroups);
169 
170  Groups expectedMultiElementGroups{{0, 4, 8}, {7, 9}, {1, 3}};
171  Groups multiElementGroups = getMultiElementGroups(splitter);
172  EXPECT_EQUAL(multiElementGroups, expectedMultiElementGroups);
173  }
174 }
175 
176 CASE("ufo/RecursiveSplitter/IntCategories") {
177  RecursiveSplitter splitter(10);
178 
179  {
180  std::vector<int> categories{1, 2, 1, 2, 1, 2, 1, 2, 1, 2};
181  splitter.groupBy(categories);
182 
183  Groups expectedGroups{{0, 2, 4, 6, 8}, {1, 3, 5, 7, 9}};
184  Groups groups = getGroups(splitter);
185  EXPECT_EQUAL(groups, expectedGroups);
186 
187  Groups expectedMultiElementGroups{{0, 2, 4, 6, 8}, {1, 3, 5, 7, 9}};
188  Groups multiElementGroups = getMultiElementGroups(splitter);
189  EXPECT_EQUAL(multiElementGroups, expectedMultiElementGroups);
190  }
191 }
192 
193 CASE("ufo/RecursiveSplitter/StringCategories") {
194  RecursiveSplitter splitter(10);
195 
196  {
197  std::vector<std::string> categories{"abc", "def", "abc", "def",
198  "abc", "def", "abc", "def",
199  "abc", "def"};
200  splitter.groupBy(categories);
201 
202  Groups expectedGroups{{0, 2, 4, 6, 8}, {1, 3, 5, 7, 9}};
203  Groups groups = getGroups(splitter);
204  EXPECT_EQUAL(groups, expectedGroups);
205 
206  Groups expectedMultiElementGroups{{0, 2, 4, 6, 8}, {1, 3, 5, 7, 9}};
207  Groups multiElementGroups = getMultiElementGroups(splitter);
208  EXPECT_EQUAL(multiElementGroups, expectedMultiElementGroups);
209  }
210 }
211 
212 CASE("ufo/RecursiveSplitter/Recurse") {
213  std::vector<int> orig{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
214  RecursiveSplitter splitter(10);
215 
216  // First grouping
217  std::vector<int> categories{1, 1, 1, 1, 1, 0, 0, 0, 0, 0};
218  splitter.groupBy(categories);
219  std::vector<std::vector<int>> expected{{5, 6, 7, 8, 9}, {0, 1, 2, 3, 4}};
220  orderedComparison(splitter, expected);
221 
222  // Second grouping
223  categories = {1, 1, 0, 2, 2, 2, 2, 0, 1, 1};
224  splitter.groupBy(categories);
225  expected = {{7}, {8, 9}, {5, 6}, {2}, {0, 1}, {3, 4}};
226  orderedComparison(splitter, expected);
227 
228  // Final sorting of groups
229  categories = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; // effectively reverse ordering of final groups
230  splitter.sortGroupsBy([&categories](auto index) { return categories[index]; });
231  expected = {{7}, {9, 8}, {6, 5}, {2}, {1, 0}, {4, 3}};
232  orderedComparison(splitter, expected);
233 }
234 
235 
236 class RecursiveSplitter : public oops::Test {
237  public:
239 
240  private:
241  std::string testid() const override {return "ufo::test::RecursiveSplitter";}
242 
243  void register_tests() const override {}
244 
245  void clear() const override {}
246 };
247 
248 } // namespace test
249 } // namespace ufo
250 
251 #endif // TEST_UFO_RECURSIVESPLITTER_H_
std::string testid() const override
std::set< size_t > Group
void orderedComparison(const RecursiveSplitter &splitter, const std::vector< std::vector< int >> &expected)
CASE("ufo/DataExtractor/bilinearinterp/float_linear")
std::set< Group > Groups
Groups getGroups(const RecursiveSplitter &splitter)
Groups getMultiElementGroups(const RecursiveSplitter &splitter)
Definition: RunCRTM.h:27