1 /**
2  *
3  *   Copyright (c) 2005-2021 by Pierre-Henri WUILLEMIN(_at_LIP6) & Christophe GONZALES(_at_AMU)
4  *   info_at_agrum_dot_org
5  *
6  *  This library is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU Lesser General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public License
17  *  along with this library.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 
22 #include <gumtest/AgrumTestSuite.h>
23 #include <gumtest/testsuite_utils.h>
24 #include <iostream>
25 
26 #include <agrum/tools/core/math/gammaLog2.h>
27 #include <agrum/tools/database/DBTranslator4LabelizedVariable.h>
28 #include <agrum/tools/database/DBTranslatorSet.h>
29 #include <agrum/BN/learning/aprioris/aprioriNoApriori.h>
30 #include <agrum/BN/learning/scores_and_tests/scoreK2.h>
31 
32 namespace gum_tests {
33 
34   class ScoreK2TestSuite: public CxxTest::TestSuite {
35     private:
36     gum::GammaLog2 _gammalog2_;
37     bool           _gum_destructor_increased_{false};
38 
setUp()39     void setUp() {}
40 
tearDown()41     void tearDown() {
42       if (!_gum_destructor_increased_) {
43         GUM_DESTRUCTOR(GammaLog2);
44         _gum_destructor_increased_ = true;
45       }
46     }
47 
_score_(const std::vector<double> & N_ijk,const std::vector<double> & N_ij)48     double _score_(const std::vector< double >& N_ijk, const std::vector< double >& N_ij) const {
49       double score = 0.0;
50 
51       if (!N_ij.empty()) {
52         const double ri = double(N_ijk.size() / N_ij.size());
53         score           = N_ij.size() * _gammalog2_(ri);
54 
55         for (const auto n_ij: N_ij) {
56           score -= _gammalog2_(n_ij + ri);
57         }
58         for (const auto n_ijk: N_ijk) {
59           score += _gammalog2_(n_ijk + 1);
60         }
61       } else {
62         const double ri = double(N_ijk.size());
63         score           = _gammalog2_(ri);
64         double N        = 0;
65         for (const auto n_ijk: N_ijk) {
66           score += _gammalog2_(n_ijk + 1);
67           N += n_ijk;
68         }
69         score -= _gammalog2_(N + ri);
70       }
71 
72       return score;
73     }
74 
75 
_equal_(const double x,const double y)76     bool _equal_(const double x, const double y) const {
77       double dev = x >= y ? (x - y) / x : (y - x) / y;
78       if (dev < 0) dev = -dev;
79       return dev <= TS_GUM_SMALL_ERROR;
80     }
81 
82 
83     public:
_test_no_range_no_nodeId2col()84     void _test_no_range_no_nodeId2col() {
85       // create the translator set
86       gum::LabelizedVariable var("X1", "", 0);
87       var.addLabel("0");
88       var.addLabel("1");
89       var.addLabel("2");
90 
91       gum::learning::DBTranslatorSet<> trans_set;
92       {
93         const std::vector< std::string >                miss;
94         gum::learning::DBTranslator4LabelizedVariable<> translator(var, miss);
95         std::vector< std::string >                      names{"A", "B", "C", "D", "E", "F"};
96 
97         for (std::size_t i = std::size_t(0); i < names.size(); ++i) {
98           translator.setVariableName(names[i]);
99           trans_set.insertTranslator(translator, i);
100         }
101       }
102 
103       // create the database
104       gum::learning::DatabaseTable<> database(trans_set);
105       std::vector< std::string >     row0{"0", "1", "0", "2", "1", "1"};
106       std::vector< std::string >     row1{"1", "2", "0", "1", "2", "2"};
107       std::vector< std::string >     row2{"2", "1", "0", "1", "1", "0"};
108       std::vector< std::string >     row3{"1", "0", "0", "0", "0", "0"};
109       std::vector< std::string >     row4{"0", "0", "0", "1", "1", "1"};
110       for (int i = 0; i < 1000; ++i)
111         database.insertRow(row0);
112       for (int i = 0; i < 50; ++i)
113         database.insertRow(row1);
114       for (int i = 0; i < 75; ++i)
115         database.insertRow(row2);
116       for (int i = 0; i < 75; ++i)
117         database.insertRow(row3);
118       for (int i = 0; i < 200; ++i)
119         database.insertRow(row4);
120 
121       // create the parser
122       gum::learning::DBRowGeneratorSet<>    genset;
123       gum::learning::DBRowGeneratorParser<> parser(database.handler(), genset);
124 
125       gum::learning::AprioriNoApriori<> apriori(database);
126       gum::learning::ScoreK2<>          score(parser, apriori);
127 
128       TS_GUM_ASSERT_THROWS_NOTHING(gum::learning::ScoreK2<>::isAprioriCompatible(
129          gum::learning::AprioriNoApriori<>::type::type));
130       TS_GUM_ASSERT_THROWS_NOTHING(gum::learning::ScoreK2<>::isAprioriCompatible(apriori));
131       TS_GUM_ASSERT_THROWS_NOTHING(
132          score.isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
133       TS_GUM_ASSERT_THROWS_NOTHING(score.isAprioriCompatible(apriori));
134 
135       gum::NodeId                node0 = 0;
136       gum::NodeId                node1 = 1;
137       gum::NodeId                node3 = 3;
138       std::vector< gum::NodeId > cond_empty;
139       std::vector< gum::NodeId > cond2{node1};
140       std::vector< gum::NodeId > cond3{node3};
141 
142       gum::learning::IdCondSet<> idset1(node0, cond_empty);    // #3,#0
143       gum::learning::IdCondSet<> idset2(node0, cond2, true);   // #9,#3
144       gum::learning::IdCondSet<> idset3(node0, cond3, true);   // #9,#3
145 
146       // idset1: node0 | emptyset
147       std::vector< double > N_ijk_1{1200.0, 125.0, 75.0};
148       std::vector< double > N_ij_1;
149       double                xscore_1 = _score_(N_ijk_1, N_ij_1);
150       TS_ASSERT(_equal_(xscore_1, score.score(node0)))
151 
152       // idset2: node0 | node1
153       std::vector< double > N_ijk_2{200, 75, 0, 1000, 0, 75, 0, 50, 0};
154       std::vector< double > N_ij_2{275, 1075, 50};
155       double                xscore_2 = _score_(N_ijk_2, N_ij_2);
156       TS_ASSERT(_equal_(xscore_2, score.score(node0, cond2)))
157 
158       // idset3: node0 | node3
159       std::vector< double > N_ijk_3{0, 75, 0, 200, 50, 75, 1000, 0, 0};
160       std::vector< double > N_ij_3{75, 325, 1000};
161       double                xscore_3 = _score_(N_ijk_3, N_ij_3);
162       TS_ASSERT(_equal_(xscore_3, score.score(node0, cond3)))
163 
164       gum::learning::ScoreK2<> score2(score);
165       TS_GUM_ASSERT_THROWS_NOTHING(
166          score2.isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
167       TS_GUM_ASSERT_THROWS_NOTHING(score2.isAprioriCompatible(apriori));
168 
169       TS_ASSERT(_equal_(xscore_1, score2.score(node0)))
170       TS_ASSERT(_equal_(xscore_2, score2.score(node0, cond2)))
171       TS_ASSERT(_equal_(xscore_3, score2.score(node0, cond3)))
172 
173       gum::learning::ScoreK2<> score3(std::move(score2));
174       TS_GUM_ASSERT_THROWS_NOTHING(
175          score3.isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
176       TS_GUM_ASSERT_THROWS_NOTHING(score3.isAprioriCompatible(apriori));
177 
178       TS_ASSERT(_equal_(xscore_1, score3.score(node0)))
179       TS_ASSERT(_equal_(xscore_2, score3.score(node0, cond2)))
180       TS_ASSERT(_equal_(xscore_3, score3.score(node0, cond3)))
181 
182       gum::learning::ScoreK2<>* score4 = score3.clone();
183       TS_GUM_ASSERT_THROWS_NOTHING(
184          score4->isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
185       TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
186 
187       TS_ASSERT(_equal_(xscore_1, score4->score(node0)))
188       TS_ASSERT(_equal_(xscore_2, score4->score(node0, cond2)))
189       TS_ASSERT(_equal_(xscore_3, score4->score(node0, cond3)))
190 
191       score4->operator=(score);
192       TS_GUM_ASSERT_THROWS_NOTHING(
193          score4->isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
194       TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
195 
196       TS_ASSERT(_equal_(xscore_1, score4->score(node0)))
197       TS_ASSERT(_equal_(xscore_2, score4->score(node0, cond2)))
198       TS_ASSERT(_equal_(xscore_3, score4->score(node0, cond3)))
199 
200       score4->operator=(std::move(score));
201       TS_GUM_ASSERT_THROWS_NOTHING(
202          score4->isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
203       TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
204 
205       TS_ASSERT(_equal_(xscore_1, score4->score(node0)))
206       TS_ASSERT(_equal_(xscore_2, score4->score(node0, cond2)))
207       TS_ASSERT(_equal_(xscore_3, score4->score(node0, cond3)))
208 
209       delete score4;
210     }
211 
212 
_test_no_range_has_nodeId2col()213     void _test_no_range_has_nodeId2col() {
214       // create the translator set
215       gum::LabelizedVariable var("X1", "", 0);
216       var.addLabel("0");
217       var.addLabel("1");
218       var.addLabel("2");
219 
220       gum::learning::DBTranslatorSet<> trans_set;
221       {
222         const std::vector< std::string >                miss;
223         gum::learning::DBTranslator4LabelizedVariable<> translator(var, miss);
224         std::vector< std::string >                      names{"A", "B", "C", "D", "E", "F"};
225 
226         for (std::size_t i = std::size_t(0); i < names.size(); ++i) {
227           translator.setVariableName(names[i]);
228           trans_set.insertTranslator(translator, i);
229         }
230       }
231 
232       // create the database
233       gum::learning::DatabaseTable<> database(trans_set);
234       std::vector< std::string >     row0{"0", "1", "0", "2", "1", "1"};
235       std::vector< std::string >     row1{"1", "2", "0", "1", "2", "2"};
236       std::vector< std::string >     row2{"2", "1", "0", "1", "1", "0"};
237       std::vector< std::string >     row3{"1", "0", "0", "0", "0", "0"};
238       std::vector< std::string >     row4{"0", "0", "0", "1", "1", "1"};
239       for (int i = 0; i < 1000; ++i)
240         database.insertRow(row0);
241       for (int i = 0; i < 50; ++i)
242         database.insertRow(row1);
243       for (int i = 0; i < 75; ++i)
244         database.insertRow(row2);
245       for (int i = 0; i < 75; ++i)
246         database.insertRow(row3);
247       for (int i = 0; i < 200; ++i)
248         database.insertRow(row4);
249 
250       // create the parser
251       gum::learning::DBRowGeneratorSet<>    genset;
252       gum::learning::DBRowGeneratorParser<> parser(database.handler(), genset);
253 
254       gum::Bijection< gum::NodeId, std::size_t > nodeId2columns;
255       gum::NodeId                                node0 = 0;
256       gum::NodeId                                node1 = 1;
257       gum::NodeId                                node2 = 2;
258       gum::NodeId                                node3 = 3;
259       gum::NodeId                                node4 = 4;
260       gum::NodeId                                node5 = 5;
261       nodeId2columns.insert(node0, std::size_t(4));
262       nodeId2columns.insert(node1, std::size_t(3));
263       nodeId2columns.insert(node2, std::size_t(0));
264       nodeId2columns.insert(node3, std::size_t(2));
265       nodeId2columns.insert(node4, std::size_t(5));
266       nodeId2columns.insert(node5, std::size_t(1));
267 
268       gum::learning::AprioriNoApriori<> apriori(database, nodeId2columns);
269       gum::learning::ScoreK2<>          score(parser, apriori, nodeId2columns);
270 
271       TS_GUM_ASSERT_THROWS_NOTHING(gum::learning::ScoreK2<>::isAprioriCompatible(
272          gum::learning::AprioriNoApriori<>::type::type));
273       TS_GUM_ASSERT_THROWS_NOTHING(gum::learning::ScoreK2<>::isAprioriCompatible(apriori));
274       TS_GUM_ASSERT_THROWS_NOTHING(
275          score.isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
276       TS_GUM_ASSERT_THROWS_NOTHING(score.isAprioriCompatible(apriori));
277 
278       std::vector< gum::NodeId > cond_empty;
279       std::vector< gum::NodeId > cond2{node5};
280       std::vector< gum::NodeId > cond3{node1};
281 
282       gum::learning::IdCondSet<> idset1(node2, cond_empty);    // #3,#0
283       gum::learning::IdCondSet<> idset2(node2, cond2, true);   // #9,#3
284       gum::learning::IdCondSet<> idset3(node2, cond3, true);   // #9,#3
285 
286       // idset1: node2 | emptyset
287       std::vector< double > N_ijk_1{1200.0, 125.0, 75.0};
288       std::vector< double > N_ij_1;
289       double                xscore_1 = _score_(N_ijk_1, N_ij_1);
290       TS_ASSERT(_equal_(xscore_1, score.score(node2)))
291 
292 
293       // idset2: node2 | node5
294       std::vector< double > N_ijk_2{200, 75, 0, 1000, 0, 75, 0, 50, 0};
295       std::vector< double > N_ij_2{275, 1075, 50};
296       double                xscore_2 = _score_(N_ijk_2, N_ij_2);
297       TS_ASSERT(_equal_(xscore_2, score.score(node2, cond2)))
298 
299       // idset3: node2 | node1
300       std::vector< double > N_ijk_3{0, 75, 0, 200, 50, 75, 1000, 0, 0};
301       std::vector< double > N_ij_3{75, 325, 1000};
302       double                xscore_3 = _score_(N_ijk_3, N_ij_3);
303       TS_ASSERT(_equal_(xscore_3, score.score(node2, cond3)))
304 
305 
306       gum::learning::ScoreK2<> score2(score);
307       TS_GUM_ASSERT_THROWS_NOTHING(
308          score2.isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
309       TS_GUM_ASSERT_THROWS_NOTHING(score2.isAprioriCompatible(apriori));
310 
311       TS_ASSERT(_equal_(xscore_1, score2.score(node2)))
312       TS_ASSERT(_equal_(xscore_2, score2.score(node2, cond2)))
313       TS_ASSERT(_equal_(xscore_3, score2.score(node2, cond3)))
314 
315       gum::learning::ScoreK2<> score3(std::move(score2));
316       TS_GUM_ASSERT_THROWS_NOTHING(
317          score3.isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
318       TS_GUM_ASSERT_THROWS_NOTHING(score3.isAprioriCompatible(apriori));
319 
320       TS_ASSERT(_equal_(xscore_1, score3.score(node2)))
321       TS_ASSERT(_equal_(xscore_2, score3.score(node2, cond2)))
322       TS_ASSERT(_equal_(xscore_3, score3.score(node2, cond3)))
323 
324       gum::learning::ScoreK2<>* score4 = score3.clone();
325       TS_GUM_ASSERT_THROWS_NOTHING(
326          score4->isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
327       TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
328 
329       TS_ASSERT(_equal_(xscore_1, score4->score(node2)))
330       TS_ASSERT(_equal_(xscore_2, score4->score(node2, cond2)))
331       TS_ASSERT(_equal_(xscore_3, score4->score(node2, cond3)))
332 
333       score4->operator=(score);
334       TS_GUM_ASSERT_THROWS_NOTHING(
335          score4->isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
336       TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
337 
338       TS_ASSERT(_equal_(xscore_1, score4->score(node2)))
339       TS_ASSERT(_equal_(xscore_2, score4->score(node2, cond2)))
340       TS_ASSERT(_equal_(xscore_3, score4->score(node2, cond3)))
341 
342       score4->operator=(std::move(score));
343       TS_GUM_ASSERT_THROWS_NOTHING(
344          score4->isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
345       TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
346 
347       TS_ASSERT(_equal_(xscore_1, score4->score(node2)))
348       TS_ASSERT(_equal_(xscore_2, score4->score(node2, cond2)))
349       TS_ASSERT(_equal_(xscore_3, score4->score(node2, cond3)))
350 
351       delete score4;
352     }
353 
354 
_test_has_range_no_nodeId2col()355     void _test_has_range_no_nodeId2col() {
356       // create the translator set
357       gum::LabelizedVariable var("X1", "", 0);
358       var.addLabel("0");
359       var.addLabel("1");
360       var.addLabel("2");
361 
362       gum::learning::DBTranslatorSet<> trans_set;
363       {
364         const std::vector< std::string >                miss;
365         gum::learning::DBTranslator4LabelizedVariable<> translator(var, miss);
366         std::vector< std::string >                      names{"A", "B", "C", "D", "E", "F"};
367 
368         for (std::size_t i = std::size_t(0); i < names.size(); ++i) {
369           translator.setVariableName(names[i]);
370           trans_set.insertTranslator(translator, i);
371         }
372       }
373 
374       // create the database
375       gum::learning::DatabaseTable<> database(trans_set);
376       std::vector< std::string >     row0{"0", "1", "0", "2", "1", "1"};
377       std::vector< std::string >     row1{"1", "2", "0", "1", "2", "2"};
378       std::vector< std::string >     row2{"2", "1", "0", "1", "1", "0"};
379       std::vector< std::string >     row3{"1", "0", "0", "0", "0", "0"};
380       std::vector< std::string >     row4{"0", "0", "0", "1", "1", "1"};
381       for (int i = 0; i < 1000; ++i)
382         database.insertRow(row0);
383       for (int i = 0; i < 50; ++i)
384         database.insertRow(row1);
385       for (int i = 0; i < 75; ++i)
386         database.insertRow(row2);
387       for (int i = 0; i < 75; ++i)
388         database.insertRow(row3);
389       for (int i = 0; i < 200; ++i)
390         database.insertRow(row4);
391 
392       // create the parser
393       gum::learning::DBRowGeneratorSet<>    genset;
394       gum::learning::DBRowGeneratorParser<> parser(database.handler(), genset);
395 
396       std::vector< std::pair< std::size_t, std::size_t > > ranges{{800, 1000}, {1050, 1400}};
397 
398       gum::learning::AprioriNoApriori<> apriori(database);
399       gum::learning::ScoreK2<>          score(parser, apriori, ranges);
400 
401       TS_GUM_ASSERT_THROWS_NOTHING(gum::learning::ScoreK2<>::isAprioriCompatible(
402          gum::learning::AprioriNoApriori<>::type::type));
403       TS_GUM_ASSERT_THROWS_NOTHING(gum::learning::ScoreK2<>::isAprioriCompatible(apriori));
404       TS_GUM_ASSERT_THROWS_NOTHING(
405          score.isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
406       TS_GUM_ASSERT_THROWS_NOTHING(score.isAprioriCompatible(apriori));
407 
408       gum::NodeId                node0 = 0;
409       gum::NodeId                node1 = 1;
410       gum::NodeId                node3 = 3;
411       std::vector< gum::NodeId > cond_empty;
412       std::vector< gum::NodeId > cond2{node1};
413       std::vector< gum::NodeId > cond3{node3};
414 
415       gum::learning::IdCondSet<> idset1(node0, cond_empty);    // #3,#0
416       gum::learning::IdCondSet<> idset2(node0, cond2, true);   // #9,#3
417       gum::learning::IdCondSet<> idset3(node0, cond3, true);   // #9,#3
418 
419       // idset1: node0 | emptyset
420       std::vector< double > N_ijk_1{400.0, 75.0, 75.0};
421       std::vector< double > N_ij_1;
422       double                xscore_1 = _score_(N_ijk_1, N_ij_1);
423       TS_ASSERT(_equal_(xscore_1, score.score(node0)))
424 
425       // idset2: node0 | node1
426       std::vector< double > N_ijk_2{200, 75, 0, 200, 0, 75, 0, 0, 0};
427       std::vector< double > N_ij_2{275, 275, 0};
428       double                xscore_2 = _score_(N_ijk_2, N_ij_2);
429       TS_ASSERT(_equal_(xscore_2, score.score(node0, cond2)))
430 
431       // idset3: node0 | node3
432       std::vector< double > N_ijk_3{0, 75, 0, 200, 0, 75, 200, 0, 0};
433       std::vector< double > N_ij_3{75, 275, 200};
434       double                xscore_3 = _score_(N_ijk_3, N_ij_3);
435       TS_ASSERT(_equal_(xscore_3, score.score(node0, cond3)))
436 
437       gum::learning::ScoreK2<> score2(score);
438       TS_GUM_ASSERT_THROWS_NOTHING(
439          score2.isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
440       TS_GUM_ASSERT_THROWS_NOTHING(score2.isAprioriCompatible(apriori));
441 
442       TS_ASSERT(_equal_(xscore_1, score2.score(node0)))
443       TS_ASSERT(_equal_(xscore_2, score2.score(node0, cond2)))
444       TS_ASSERT(_equal_(xscore_3, score2.score(node0, cond3)))
445 
446       gum::learning::ScoreK2<> score3(std::move(score2));
447       TS_GUM_ASSERT_THROWS_NOTHING(
448          score3.isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
449       TS_GUM_ASSERT_THROWS_NOTHING(score3.isAprioriCompatible(apriori));
450 
451       TS_ASSERT(_equal_(xscore_1, score3.score(node0)))
452       TS_ASSERT(_equal_(xscore_2, score3.score(node0, cond2)))
453       TS_ASSERT(_equal_(xscore_3, score3.score(node0, cond3)))
454 
455       gum::learning::ScoreK2<>* score4 = score3.clone();
456       TS_GUM_ASSERT_THROWS_NOTHING(
457          score4->isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
458       TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
459 
460       TS_ASSERT(_equal_(xscore_1, score4->score(node0)))
461       TS_ASSERT(_equal_(xscore_2, score4->score(node0, cond2)))
462       TS_ASSERT(_equal_(xscore_3, score4->score(node0, cond3)))
463 
464       score4->operator=(score);
465       TS_GUM_ASSERT_THROWS_NOTHING(
466          score4->isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
467       TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
468 
469       TS_ASSERT(_equal_(xscore_1, score4->score(node0)))
470       TS_ASSERT(_equal_(xscore_2, score4->score(node0, cond2)))
471       TS_ASSERT(_equal_(xscore_3, score4->score(node0, cond3)))
472 
473       score4->operator=(std::move(score));
474       TS_GUM_ASSERT_THROWS_NOTHING(
475          score4->isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
476       TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
477 
478       TS_ASSERT(_equal_(xscore_1, score4->score(node0)))
479       TS_ASSERT(_equal_(xscore_2, score4->score(node0, cond2)))
480       TS_ASSERT(_equal_(xscore_3, score4->score(node0, cond3)))
481 
482       delete score4;
483     }
484 
485 
_test_has_range_has_nodeId2col()486     void _test_has_range_has_nodeId2col() {
487       // create the translator set
488       gum::LabelizedVariable var("X1", "", 0);
489       var.addLabel("0");
490       var.addLabel("1");
491       var.addLabel("2");
492 
493       gum::learning::DBTranslatorSet<> trans_set;
494       {
495         const std::vector< std::string >                miss;
496         gum::learning::DBTranslator4LabelizedVariable<> translator(var, miss);
497         std::vector< std::string >                      names{"A", "B", "C", "D", "E", "F"};
498 
499         for (std::size_t i = std::size_t(0); i < names.size(); ++i) {
500           translator.setVariableName(names[i]);
501           trans_set.insertTranslator(translator, i);
502         }
503       }
504 
505       // create the database
506       gum::learning::DatabaseTable<> database(trans_set);
507       std::vector< std::string >     row0{"0", "1", "0", "2", "1", "1"};
508       std::vector< std::string >     row1{"1", "2", "0", "1", "2", "2"};
509       std::vector< std::string >     row2{"2", "1", "0", "1", "1", "0"};
510       std::vector< std::string >     row3{"1", "0", "0", "0", "0", "0"};
511       std::vector< std::string >     row4{"0", "0", "0", "1", "1", "1"};
512       for (int i = 0; i < 1000; ++i)
513         database.insertRow(row0);
514       for (int i = 0; i < 50; ++i)
515         database.insertRow(row1);
516       for (int i = 0; i < 75; ++i)
517         database.insertRow(row2);
518       for (int i = 0; i < 75; ++i)
519         database.insertRow(row3);
520       for (int i = 0; i < 200; ++i)
521         database.insertRow(row4);
522 
523       // create the parser
524       gum::learning::DBRowGeneratorSet<>    genset;
525       gum::learning::DBRowGeneratorParser<> parser(database.handler(), genset);
526 
527       std::vector< std::pair< std::size_t, std::size_t > > ranges{{800, 1000}, {1050, 1400}};
528 
529       gum::Bijection< gum::NodeId, std::size_t > nodeId2columns;
530       gum::NodeId                                node0 = 0;
531       gum::NodeId                                node1 = 1;
532       gum::NodeId                                node2 = 2;
533       gum::NodeId                                node3 = 3;
534       gum::NodeId                                node4 = 4;
535       gum::NodeId                                node5 = 5;
536       nodeId2columns.insert(node0, std::size_t(4));
537       nodeId2columns.insert(node1, std::size_t(3));
538       nodeId2columns.insert(node2, std::size_t(0));
539       nodeId2columns.insert(node3, std::size_t(2));
540       nodeId2columns.insert(node4, std::size_t(5));
541       nodeId2columns.insert(node5, std::size_t(1));
542 
543       gum::learning::AprioriNoApriori<> apriori(database, nodeId2columns);
544       gum::learning::ScoreK2<>          score(parser, apriori, ranges, nodeId2columns);
545 
546       TS_GUM_ASSERT_THROWS_NOTHING(gum::learning::ScoreK2<>::isAprioriCompatible(
547          gum::learning::AprioriNoApriori<>::type::type));
548       TS_GUM_ASSERT_THROWS_NOTHING(gum::learning::ScoreK2<>::isAprioriCompatible(apriori));
549       TS_GUM_ASSERT_THROWS_NOTHING(
550          score.isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
551       TS_GUM_ASSERT_THROWS_NOTHING(score.isAprioriCompatible(apriori));
552 
553       std::vector< gum::NodeId > cond_empty;
554       std::vector< gum::NodeId > cond2{node5};
555       std::vector< gum::NodeId > cond3{node1};
556 
557       gum::learning::IdCondSet<> idset1(node2, cond_empty);    // #3,#0
558       gum::learning::IdCondSet<> idset2(node2, cond2, true);   // #9,#3
559       gum::learning::IdCondSet<> idset3(node2, cond3, true);   // #9,#3
560 
561       // idset1: node2 | emptyset
562       std::vector< double > N_ijk_1{400.0, 75.0, 75.0};
563       std::vector< double > N_ij_1;
564       double                xscore_1 = _score_(N_ijk_1, N_ij_1);
565       TS_ASSERT(_equal_(xscore_1, score.score(node2)))
566 
567 
568       // idset2: node2 | node5
569       std::vector< double > N_ijk_2{200, 75, 0, 200, 0, 75, 0, 0, 0};
570       std::vector< double > N_ij_2{275, 275, 0};
571       double                xscore_2 = _score_(N_ijk_2, N_ij_2);
572       TS_ASSERT(_equal_(xscore_2, score.score(node2, cond2)))
573 
574       // idset3: node2 | node1
575       std::vector< double > N_ijk_3{0, 75, 0, 200, 0, 75, 200, 0, 0};
576       std::vector< double > N_ij_3{75, 275, 200};
577       double                xscore_3 = _score_(N_ijk_3, N_ij_3);
578       TS_ASSERT(_equal_(xscore_3, score.score(node2, cond3)))
579 
580 
581       gum::learning::ScoreK2<> score2(score);
582       TS_GUM_ASSERT_THROWS_NOTHING(
583          score2.isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
584       TS_GUM_ASSERT_THROWS_NOTHING(score2.isAprioriCompatible(apriori));
585 
586       TS_ASSERT(_equal_(xscore_1, score2.score(node2)))
587       TS_ASSERT(_equal_(xscore_2, score2.score(node2, cond2)))
588       TS_ASSERT(_equal_(xscore_3, score2.score(node2, cond3)))
589 
590       gum::learning::ScoreK2<> score3(std::move(score2));
591       TS_GUM_ASSERT_THROWS_NOTHING(
592          score3.isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
593       TS_GUM_ASSERT_THROWS_NOTHING(score3.isAprioriCompatible(apriori));
594 
595       TS_ASSERT(_equal_(xscore_1, score3.score(node2)))
596       TS_ASSERT(_equal_(xscore_2, score3.score(node2, cond2)))
597       TS_ASSERT(_equal_(xscore_3, score3.score(node2, cond3)))
598 
599       gum::learning::ScoreK2<>* score4 = score3.clone();
600       TS_GUM_ASSERT_THROWS_NOTHING(
601          score4->isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
602       TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
603 
604       TS_ASSERT(_equal_(xscore_1, score4->score(node2)))
605       TS_ASSERT(_equal_(xscore_2, score4->score(node2, cond2)))
606       TS_ASSERT(_equal_(xscore_3, score4->score(node2, cond3)))
607 
608       score4->operator=(score);
609       TS_GUM_ASSERT_THROWS_NOTHING(
610          score4->isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
611       TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
612 
613       TS_ASSERT(_equal_(xscore_1, score4->score(node2)))
614       TS_ASSERT(_equal_(xscore_2, score4->score(node2, cond2)))
615       TS_ASSERT(_equal_(xscore_3, score4->score(node2, cond3)))
616 
617       score4->operator=(std::move(score));
618       TS_GUM_ASSERT_THROWS_NOTHING(
619          score4->isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
620       TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
621 
622       TS_ASSERT(_equal_(xscore_1, score4->score(node2)))
623       TS_ASSERT(_equal_(xscore_2, score4->score(node2, cond2)))
624       TS_ASSERT(_equal_(xscore_3, score4->score(node2, cond3)))
625 
626       delete score4;
627     }
628 
629 
test_multicore()630     void test_multicore() {
631       // create the translator set
632       gum::LabelizedVariable var("X1", "", 0);
633       var.addLabel("0");
634       var.addLabel("1");
635       var.addLabel("2");
636 
637       gum::learning::DBTranslatorSet<> trans_set;
638       {
639         const std::vector< std::string >                miss;
640         gum::learning::DBTranslator4LabelizedVariable<> translator(var, miss);
641         std::vector< std::string >                      names{"A", "B", "C", "D", "E", "F"};
642 
643         for (std::size_t i = std::size_t(0); i < names.size(); ++i) {
644           translator.setVariableName(names[i]);
645           trans_set.insertTranslator(translator, i);
646         }
647       }
648 
649       // create the database
650       gum::learning::DatabaseTable<> database(trans_set);
651       std::vector< std::string >     row0{"0", "1", "0", "2", "1", "1"};
652       std::vector< std::string >     row1{"1", "2", "0", "1", "2", "2"};
653       std::vector< std::string >     row2{"2", "1", "0", "1", "1", "0"};
654       std::vector< std::string >     row3{"1", "0", "0", "0", "0", "0"};
655       std::vector< std::string >     row4{"0", "0", "0", "1", "1", "1"};
656       for (int i = 0; i < 1000; ++i)
657         database.insertRow(row0);
658       for (int i = 0; i < 50; ++i)
659         database.insertRow(row1);
660       for (int i = 0; i < 75; ++i)
661         database.insertRow(row2);
662       for (int i = 0; i < 75; ++i)
663         database.insertRow(row3);
664       for (int i = 0; i < 200; ++i)
665         database.insertRow(row4);
666 
667       // create the parser
668       gum::learning::DBRowGeneratorSet<>    genset;
669       gum::learning::DBRowGeneratorParser<> parser(database.handler(), genset);
670 
671       std::vector< std::pair< std::size_t, std::size_t > > ranges{{800, 1000}, {1050, 1400}};
672 
673       gum::learning::AprioriNoApriori<> apriori(database);
674       for (std::size_t i = std::size_t(1); i < std::size_t(24); ++i) {
675         gum::learning::ScoreK2<> score(parser, apriori, ranges);
676         score.setMaxNbThreads(i);
677 
678         TS_GUM_ASSERT_THROWS_NOTHING(gum::learning::ScoreK2<>::isAprioriCompatible(
679            gum::learning::AprioriNoApriori<>::type::type));
680         TS_GUM_ASSERT_THROWS_NOTHING(gum::learning::ScoreK2<>::isAprioriCompatible(apriori));
681         TS_GUM_ASSERT_THROWS_NOTHING(
682            score.isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
683         TS_GUM_ASSERT_THROWS_NOTHING(score.isAprioriCompatible(apriori));
684 
685         gum::NodeId                node0 = 0;
686         gum::NodeId                node1 = 1;
687         gum::NodeId                node3 = 3;
688         std::vector< gum::NodeId > cond_empty;
689         std::vector< gum::NodeId > cond2{node1};
690         std::vector< gum::NodeId > cond3{node3};
691 
692         gum::learning::IdCondSet<> idset1(node0, cond_empty);    // #3,#0
693         gum::learning::IdCondSet<> idset2(node0, cond2, true);   // #9,#3
694         gum::learning::IdCondSet<> idset3(node0, cond3, true);   // #9,#3
695 
696         // idset1: node0 | emptyset
697         std::vector< double > N_ijk_1{400.0, 75.0, 75.0};
698         std::vector< double > N_ij_1;
699         double                xscore_1 = _score_(N_ijk_1, N_ij_1);
700         TS_ASSERT(_equal_(xscore_1, score.score(node0)))
701 
702         // idset2: node0 | node1
703         std::vector< double > N_ijk_2{200, 75, 0, 200, 0, 75, 0, 0, 0};
704         std::vector< double > N_ij_2{275, 275, 0};
705         double                xscore_2 = _score_(N_ijk_2, N_ij_2);
706         TS_ASSERT(_equal_(xscore_2, score.score(node0, cond2)))
707 
708         // idset3: node0 | node3
709         std::vector< double > N_ijk_3{0, 75, 0, 200, 0, 75, 200, 0, 0};
710         std::vector< double > N_ij_3{75, 275, 200};
711         double                xscore_3 = _score_(N_ijk_3, N_ij_3);
712         TS_ASSERT(_equal_(xscore_3, score.score(node0, cond3)))
713 
714         gum::learning::ScoreK2<> score2(score);
715         TS_GUM_ASSERT_THROWS_NOTHING(
716            score2.isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
717         TS_GUM_ASSERT_THROWS_NOTHING(score2.isAprioriCompatible(apriori));
718 
719         TS_ASSERT(_equal_(xscore_1, score2.score(node0)))
720         TS_ASSERT(_equal_(xscore_2, score2.score(node0, cond2)))
721         TS_ASSERT(_equal_(xscore_3, score2.score(node0, cond3)))
722 
723         gum::learning::ScoreK2<> score3(std::move(score2));
724         TS_GUM_ASSERT_THROWS_NOTHING(
725            score3.isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
726         TS_GUM_ASSERT_THROWS_NOTHING(score3.isAprioriCompatible(apriori));
727 
728         TS_ASSERT(_equal_(xscore_1, score3.score(node0)))
729         TS_ASSERT(_equal_(xscore_2, score3.score(node0, cond2)))
730         TS_ASSERT(_equal_(xscore_3, score3.score(node0, cond3)))
731 
732         gum::learning::ScoreK2<>* score4 = score3.clone();
733         TS_GUM_ASSERT_THROWS_NOTHING(
734            score4->isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
735         TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
736 
737         TS_ASSERT(_equal_(xscore_1, score4->score(node0)))
738         TS_ASSERT(_equal_(xscore_2, score4->score(node0, cond2)))
739         TS_ASSERT(_equal_(xscore_3, score4->score(node0, cond3)))
740 
741         score4->operator=(score);
742         TS_GUM_ASSERT_THROWS_NOTHING(
743            score4->isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
744         TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
745 
746         TS_ASSERT(_equal_(xscore_1, score4->score(node0)))
747         TS_ASSERT(_equal_(xscore_2, score4->score(node0, cond2)))
748         TS_ASSERT(_equal_(xscore_3, score4->score(node0, cond3)))
749 
750         score4->operator=(std::move(score));
751         TS_GUM_ASSERT_THROWS_NOTHING(
752            score4->isAprioriCompatible(gum::learning::AprioriNoApriori<>::type::type));
753         TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
754 
755         TS_ASSERT(_equal_(xscore_1, score4->score(node0)))
756         TS_ASSERT(_equal_(xscore_2, score4->score(node0, cond2)))
757         TS_ASSERT(_equal_(xscore_3, score4->score(node0, cond3)))
758 
759         delete score4;
760       }
761     }
762   };
763 
764 
765 } /* namespace gum_tests */
766