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/database/DBTranslator4LabelizedVariable.h>
27 #include <agrum/tools/database/DBTranslatorSet.h>
28 #include <agrum/BN/learning/aprioris/aprioriSmoothing.h>
29 #include <agrum/BN/learning/scores_and_tests/scoreAIC.h>
30 
31 namespace gum_tests {
32 
33   class ScoreAICTestSuite: public CxxTest::TestSuite {
34     private:
_score_(const std::vector<double> & N_ijk,const std::vector<double> & N_ij,const double penalty)35     double _score_(const std::vector< double >& N_ijk,
36                    const std::vector< double >& N_ij,
37                    const double                 penalty) const {
38       double score = -penalty;
39       double N     = 0;
40       for (const auto n_ijk: N_ijk)
41         if (n_ijk) {
42           score += n_ijk * std::log2(n_ijk);
43           N += n_ijk;
44         }
45       if (!N_ij.empty()) {
46         for (const auto n_ij: N_ij)
47           if (n_ij) score -= n_ij * std::log2(n_ij);
48       } else
49         score -= N * std::log2(N);
50       return score;
51     }
52 
53 
_equal_(const double x,const double y)54     bool _equal_(const double x, const double y) const {
55       double dev = x >= y ? (x - y) / x : (y - x) / y;
56       if (dev < 0) dev = -dev;
57       return dev <= TS_GUM_SMALL_ERROR;
58     }
59 
60 
61     public:
_test_no_range_no_nodeId2col()62     void _test_no_range_no_nodeId2col() {
63       // create the translator set
64       gum::LabelizedVariable var("X1", "", 0);
65       var.addLabel("0");
66       var.addLabel("1");
67       var.addLabel("2");
68 
69       gum::learning::DBTranslatorSet<> trans_set;
70       {
71         const std::vector< std::string >                miss;
72         gum::learning::DBTranslator4LabelizedVariable<> translator(var, miss);
73         std::vector< std::string >                      names{"A", "B", "C", "D", "E", "F"};
74 
75         for (std::size_t i = std::size_t(0); i < names.size(); ++i) {
76           translator.setVariableName(names[i]);
77           trans_set.insertTranslator(translator, i);
78         }
79       }
80 
81       // create the database
82       gum::learning::DatabaseTable<> database(trans_set);
83       std::vector< std::string >     row0{"0", "1", "0", "2", "1", "1"};
84       std::vector< std::string >     row1{"1", "2", "0", "1", "2", "2"};
85       std::vector< std::string >     row2{"2", "1", "0", "1", "1", "0"};
86       std::vector< std::string >     row3{"1", "0", "0", "0", "0", "0"};
87       std::vector< std::string >     row4{"0", "0", "0", "1", "1", "1"};
88       for (int i = 0; i < 1000; ++i)
89         database.insertRow(row0);
90       for (int i = 0; i < 50; ++i)
91         database.insertRow(row1);
92       for (int i = 0; i < 75; ++i)
93         database.insertRow(row2);
94       for (int i = 0; i < 75; ++i)
95         database.insertRow(row3);
96       for (int i = 0; i < 200; ++i)
97         database.insertRow(row4);
98 
99       // create the parser
100       gum::learning::DBRowGeneratorSet<>    genset;
101       gum::learning::DBRowGeneratorParser<> parser(database.handler(), genset);
102 
103       gum::learning::AprioriSmoothing<> apriori(database);
104       gum::learning::ScoreAIC<>         score(parser, apriori);
105 
106       TS_GUM_ASSERT_THROWS_NOTHING(gum::learning::ScoreAIC<>::isAprioriCompatible(
107          gum::learning::AprioriSmoothing<>::type::type));
108       TS_GUM_ASSERT_THROWS_NOTHING(gum::learning::ScoreAIC<>::isAprioriCompatible(apriori));
109       TS_GUM_ASSERT_THROWS_NOTHING(
110          score.isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
111       TS_GUM_ASSERT_THROWS_NOTHING(score.isAprioriCompatible(apriori));
112 
113       gum::NodeId                node0 = 0;
114       gum::NodeId                node1 = 1;
115       gum::NodeId                node3 = 3;
116       std::vector< gum::NodeId > cond_empty;
117       std::vector< gum::NodeId > cond2{node1};
118       std::vector< gum::NodeId > cond3{node3};
119 
120       gum::learning::IdCondSet<> idset1(node0, cond_empty);    // #3,#0
121       gum::learning::IdCondSet<> idset2(node0, cond2, true);   // #9,#3
122       gum::learning::IdCondSet<> idset3(node0, cond3, true);   // #9,#3
123 
124       // idset1: node0 | emptyset
125       double                penalty_1 = 2;
126       std::vector< double > N_ijk_1{1201.0, 126.0, 76.0};
127       std::vector< double > N_ij_1;
128       double                xscore_1 = _score_(N_ijk_1, N_ij_1, penalty_1);
129       TS_ASSERT(_equal_(xscore_1, score.score(node0)))
130 
131       // idset2: node0 | node1
132       double                penalty_2 = 6;
133       std::vector< double > N_ijk_2{201, 76, 1, 1001, 1, 76, 1, 51, 1};
134       std::vector< double > N_ij_2{278, 1078, 53};
135       double                xscore_2 = _score_(N_ijk_2, N_ij_2, penalty_2);
136       TS_ASSERT(_equal_(xscore_2, score.score(node0, cond2)))
137 
138       // idset3: node0 | node3
139       double                penalty_3 = 6;
140       std::vector< double > N_ijk_3{1, 76, 1, 201, 51, 76, 1001, 1, 1};
141       std::vector< double > N_ij_3{78, 328, 1003};
142       double                xscore_3 = _score_(N_ijk_3, N_ij_3, penalty_3);
143       TS_ASSERT(_equal_(xscore_3, score.score(node0, cond3)))
144 
145 
146       gum::learning::ScoreAIC<> score2(score);
147       TS_GUM_ASSERT_THROWS_NOTHING(
148          score2.isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
149       TS_GUM_ASSERT_THROWS_NOTHING(score2.isAprioriCompatible(apriori));
150 
151       TS_ASSERT(_equal_(xscore_1, score2.score(node0)))
152       TS_ASSERT(_equal_(xscore_2, score2.score(node0, cond2)))
153       TS_ASSERT(_equal_(xscore_3, score2.score(node0, cond3)))
154 
155       gum::learning::ScoreAIC<> score3(std::move(score2));
156       TS_GUM_ASSERT_THROWS_NOTHING(
157          score3.isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
158       TS_GUM_ASSERT_THROWS_NOTHING(score3.isAprioriCompatible(apriori));
159 
160       TS_ASSERT(_equal_(xscore_1, score3.score(node0)))
161       TS_ASSERT(_equal_(xscore_2, score3.score(node0, cond2)))
162       TS_ASSERT(_equal_(xscore_3, score3.score(node0, cond3)))
163 
164       gum::learning::ScoreAIC<>* score4 = score3.clone();
165       TS_GUM_ASSERT_THROWS_NOTHING(
166          score4->isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
167       TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
168 
169       TS_ASSERT(_equal_(xscore_1, score4->score(node0)))
170       TS_ASSERT(_equal_(xscore_2, score4->score(node0, cond2)))
171       TS_ASSERT(_equal_(xscore_3, score4->score(node0, cond3)))
172 
173       score4->operator=(score);
174       TS_GUM_ASSERT_THROWS_NOTHING(
175          score4->isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
176       TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
177 
178       TS_ASSERT(_equal_(xscore_1, score4->score(node0)))
179       TS_ASSERT(_equal_(xscore_2, score4->score(node0, cond2)))
180       TS_ASSERT(_equal_(xscore_3, score4->score(node0, cond3)))
181 
182       score4->operator=(std::move(score));
183       TS_GUM_ASSERT_THROWS_NOTHING(
184          score4->isAprioriCompatible(gum::learning::AprioriSmoothing<>::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       delete score4;
192     }
193 
194 
_test_no_range_has_nodeId2col()195     void _test_no_range_has_nodeId2col() {
196       // create the translator set
197       gum::LabelizedVariable var("X1", "", 0);
198       var.addLabel("0");
199       var.addLabel("1");
200       var.addLabel("2");
201 
202       gum::learning::DBTranslatorSet<> trans_set;
203       {
204         const std::vector< std::string >                miss;
205         gum::learning::DBTranslator4LabelizedVariable<> translator(var, miss);
206         std::vector< std::string >                      names{"A", "B", "C", "D", "E", "F"};
207 
208         for (std::size_t i = std::size_t(0); i < names.size(); ++i) {
209           translator.setVariableName(names[i]);
210           trans_set.insertTranslator(translator, i);
211         }
212       }
213 
214       // create the database
215       gum::learning::DatabaseTable<> database(trans_set);
216       std::vector< std::string >     row0{"0", "1", "0", "2", "1", "1"};
217       std::vector< std::string >     row1{"1", "2", "0", "1", "2", "2"};
218       std::vector< std::string >     row2{"2", "1", "0", "1", "1", "0"};
219       std::vector< std::string >     row3{"1", "0", "0", "0", "0", "0"};
220       std::vector< std::string >     row4{"0", "0", "0", "1", "1", "1"};
221       for (int i = 0; i < 1000; ++i)
222         database.insertRow(row0);
223       for (int i = 0; i < 50; ++i)
224         database.insertRow(row1);
225       for (int i = 0; i < 75; ++i)
226         database.insertRow(row2);
227       for (int i = 0; i < 75; ++i)
228         database.insertRow(row3);
229       for (int i = 0; i < 200; ++i)
230         database.insertRow(row4);
231 
232       // create the parser
233       gum::learning::DBRowGeneratorSet<>    genset;
234       gum::learning::DBRowGeneratorParser<> parser(database.handler(), genset);
235 
236       gum::Bijection< gum::NodeId, std::size_t > nodeId2columns;
237       gum::NodeId                                node0 = 0;
238       gum::NodeId                                node1 = 1;
239       gum::NodeId                                node2 = 2;
240       gum::NodeId                                node3 = 3;
241       gum::NodeId                                node4 = 4;
242       gum::NodeId                                node5 = 5;
243       nodeId2columns.insert(node0, std::size_t(4));
244       nodeId2columns.insert(node1, std::size_t(3));
245       nodeId2columns.insert(node2, std::size_t(0));
246       nodeId2columns.insert(node3, std::size_t(2));
247       nodeId2columns.insert(node4, std::size_t(5));
248       nodeId2columns.insert(node5, std::size_t(1));
249 
250       gum::learning::AprioriSmoothing<> apriori(database, nodeId2columns);
251       gum::learning::ScoreAIC<>         score(parser, apriori, nodeId2columns);
252 
253       TS_GUM_ASSERT_THROWS_NOTHING(gum::learning::ScoreAIC<>::isAprioriCompatible(
254          gum::learning::AprioriSmoothing<>::type::type));
255       TS_GUM_ASSERT_THROWS_NOTHING(gum::learning::ScoreAIC<>::isAprioriCompatible(apriori));
256       TS_GUM_ASSERT_THROWS_NOTHING(
257          score.isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
258       TS_GUM_ASSERT_THROWS_NOTHING(score.isAprioriCompatible(apriori));
259 
260       std::vector< gum::NodeId > cond_empty;
261       std::vector< gum::NodeId > cond2{node5};
262       std::vector< gum::NodeId > cond3{node1};
263 
264       gum::learning::IdCondSet<> idset1(node2, cond_empty);    // #3,#0
265       gum::learning::IdCondSet<> idset2(node2, cond2, true);   // #9,#3
266       gum::learning::IdCondSet<> idset3(node2, cond3, true);   // #9,#3
267 
268       // idset1: node2 | emptyset
269       double                penalty_1 = 2;
270       std::vector< double > N_ijk_1{1201.0, 126.0, 76.0};
271       std::vector< double > N_ij_1;
272       double                xscore_1 = _score_(N_ijk_1, N_ij_1, penalty_1);
273       TS_ASSERT(_equal_(xscore_1, score.score(node2)))
274 
275 
276       // idset2: node2 | node5
277       double                penalty_2 = 6;
278       std::vector< double > N_ijk_2{201, 76, 1, 1001, 1, 76, 1, 51, 1};
279       std::vector< double > N_ij_2{278, 1078, 53};
280       double                xscore_2 = _score_(N_ijk_2, N_ij_2, penalty_2);
281       TS_ASSERT(_equal_(xscore_2, score.score(node2, cond2)))
282 
283       // idset3: node2 | node1
284       double                penalty_3 = 6;
285       std::vector< double > N_ijk_3{1, 76, 1, 201, 51, 76, 1001, 1, 1};
286       std::vector< double > N_ij_3{78, 328, 1003};
287       double                xscore_3 = _score_(N_ijk_3, N_ij_3, penalty_3);
288       TS_ASSERT(_equal_(xscore_3, score.score(node2, cond3)))
289 
290 
291       gum::learning::ScoreAIC<> score2(score);
292       TS_GUM_ASSERT_THROWS_NOTHING(
293          score2.isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
294       TS_GUM_ASSERT_THROWS_NOTHING(score2.isAprioriCompatible(apriori));
295 
296       TS_ASSERT(_equal_(xscore_1, score2.score(node2)))
297       TS_ASSERT(_equal_(xscore_2, score2.score(node2, cond2)))
298       TS_ASSERT(_equal_(xscore_3, score2.score(node2, cond3)))
299 
300       gum::learning::ScoreAIC<> score3(std::move(score2));
301       TS_GUM_ASSERT_THROWS_NOTHING(
302          score3.isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
303       TS_GUM_ASSERT_THROWS_NOTHING(score3.isAprioriCompatible(apriori));
304 
305       TS_ASSERT(_equal_(xscore_1, score3.score(node2)))
306       TS_ASSERT(_equal_(xscore_2, score3.score(node2, cond2)))
307       TS_ASSERT(_equal_(xscore_3, score3.score(node2, cond3)))
308 
309       gum::learning::ScoreAIC<>* score4 = score3.clone();
310       TS_GUM_ASSERT_THROWS_NOTHING(
311          score4->isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
312       TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
313 
314       TS_ASSERT(_equal_(xscore_1, score4->score(node2)))
315       TS_ASSERT(_equal_(xscore_2, score4->score(node2, cond2)))
316       TS_ASSERT(_equal_(xscore_3, score4->score(node2, cond3)))
317 
318       score4->operator=(score);
319       TS_GUM_ASSERT_THROWS_NOTHING(
320          score4->isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
321       TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
322 
323       TS_ASSERT(_equal_(xscore_1, score4->score(node2)))
324       TS_ASSERT(_equal_(xscore_2, score4->score(node2, cond2)))
325       TS_ASSERT(_equal_(xscore_3, score4->score(node2, cond3)))
326 
327       score4->operator=(std::move(score));
328       TS_GUM_ASSERT_THROWS_NOTHING(
329          score4->isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
330       TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
331 
332       TS_ASSERT(_equal_(xscore_1, score4->score(node2)))
333       TS_ASSERT(_equal_(xscore_2, score4->score(node2, cond2)))
334       TS_ASSERT(_equal_(xscore_3, score4->score(node2, cond3)))
335 
336       delete score4;
337     }
338 
339 
_test_has_range_no_nodeId2col()340     void _test_has_range_no_nodeId2col() {
341       // create the translator set
342       gum::LabelizedVariable var("X1", "", 0);
343       var.addLabel("0");
344       var.addLabel("1");
345       var.addLabel("2");
346 
347       gum::learning::DBTranslatorSet<> trans_set;
348       {
349         const std::vector< std::string >                miss;
350         gum::learning::DBTranslator4LabelizedVariable<> translator(var, miss);
351         std::vector< std::string >                      names{"A", "B", "C", "D", "E", "F"};
352 
353         for (std::size_t i = std::size_t(0); i < names.size(); ++i) {
354           translator.setVariableName(names[i]);
355           trans_set.insertTranslator(translator, i);
356         }
357       }
358 
359       // create the database
360       gum::learning::DatabaseTable<> database(trans_set);
361       std::vector< std::string >     row0{"0", "1", "0", "2", "1", "1"};
362       std::vector< std::string >     row1{"1", "2", "0", "1", "2", "2"};
363       std::vector< std::string >     row2{"2", "1", "0", "1", "1", "0"};
364       std::vector< std::string >     row3{"1", "0", "0", "0", "0", "0"};
365       std::vector< std::string >     row4{"0", "0", "0", "1", "1", "1"};
366       for (int i = 0; i < 1000; ++i)
367         database.insertRow(row0);
368       for (int i = 0; i < 50; ++i)
369         database.insertRow(row1);
370       for (int i = 0; i < 75; ++i)
371         database.insertRow(row2);
372       for (int i = 0; i < 75; ++i)
373         database.insertRow(row3);
374       for (int i = 0; i < 200; ++i)
375         database.insertRow(row4);
376 
377       // create the parser
378       gum::learning::DBRowGeneratorSet<>    genset;
379       gum::learning::DBRowGeneratorParser<> parser(database.handler(), genset);
380 
381       std::vector< std::pair< std::size_t, std::size_t > > ranges{{800, 1000}, {1050, 1400}};
382       gum::learning::AprioriSmoothing<>                    apriori(database);
383       gum::learning::ScoreAIC<>                            score(parser, apriori, ranges);
384 
385       TS_GUM_ASSERT_THROWS_NOTHING(gum::learning::ScoreAIC<>::isAprioriCompatible(
386          gum::learning::AprioriSmoothing<>::type::type));
387       TS_GUM_ASSERT_THROWS_NOTHING(gum::learning::ScoreAIC<>::isAprioriCompatible(apriori));
388       TS_GUM_ASSERT_THROWS_NOTHING(
389          score.isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
390       TS_GUM_ASSERT_THROWS_NOTHING(score.isAprioriCompatible(apriori));
391 
392       gum::NodeId                node0 = 0;
393       gum::NodeId                node1 = 1;
394       gum::NodeId                node3 = 3;
395       std::vector< gum::NodeId > cond_empty;
396       std::vector< gum::NodeId > cond2{node1};
397       std::vector< gum::NodeId > cond3{node3};
398 
399       gum::learning::IdCondSet<> idset1(node0, cond_empty);    // #3,#0
400       gum::learning::IdCondSet<> idset2(node0, cond2, true);   // #9,#3
401       gum::learning::IdCondSet<> idset3(node0, cond3, true);   // #9,#3
402 
403       // idset1: node0 | emptyset
404       double                penalty_1 = 2;
405       std::vector< double > N_ijk_1{401.0, 76.0, 76.0};
406       std::vector< double > N_ij_1;
407       double                xscore_1 = _score_(N_ijk_1, N_ij_1, penalty_1);
408       TS_ASSERT(_equal_(xscore_1, score.score(node0)))
409 
410       // idset2: node0 | node1
411       double                penalty_2 = 6;
412       std::vector< double > N_ijk_2{201, 76, 1, 201, 1, 76, 1, 1, 1};
413       std::vector< double > N_ij_2{278, 278, 3};
414       double                xscore_2 = _score_(N_ijk_2, N_ij_2, penalty_2);
415       TS_ASSERT(_equal_(xscore_2, score.score(node0, cond2)))
416 
417       // idset3: node0 | node3
418       double                penalty_3 = 6;
419       std::vector< double > N_ijk_3{1, 76, 1, 201, 1, 76, 201, 1, 1};
420       std::vector< double > N_ij_3{78, 278, 203};
421       double                xscore_3 = _score_(N_ijk_3, N_ij_3, penalty_3);
422       TS_ASSERT(_equal_(xscore_3, score.score(node0, cond3)))
423 
424 
425       gum::learning::ScoreAIC<> score2(score);
426       TS_GUM_ASSERT_THROWS_NOTHING(
427          score2.isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
428       TS_GUM_ASSERT_THROWS_NOTHING(score2.isAprioriCompatible(apriori));
429 
430       TS_ASSERT(_equal_(xscore_1, score2.score(node0)))
431       TS_ASSERT(_equal_(xscore_2, score2.score(node0, cond2)))
432       TS_ASSERT(_equal_(xscore_3, score2.score(node0, cond3)))
433 
434       gum::learning::ScoreAIC<> score3(std::move(score2));
435       TS_GUM_ASSERT_THROWS_NOTHING(
436          score3.isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
437       TS_GUM_ASSERT_THROWS_NOTHING(score3.isAprioriCompatible(apriori));
438 
439       TS_ASSERT(_equal_(xscore_1, score3.score(node0)))
440       TS_ASSERT(_equal_(xscore_2, score3.score(node0, cond2)))
441       TS_ASSERT(_equal_(xscore_3, score3.score(node0, cond3)))
442 
443       gum::learning::ScoreAIC<>* score4 = score3.clone();
444       TS_GUM_ASSERT_THROWS_NOTHING(
445          score4->isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
446       TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
447 
448       TS_ASSERT(_equal_(xscore_1, score4->score(node0)))
449       TS_ASSERT(_equal_(xscore_2, score4->score(node0, cond2)))
450       TS_ASSERT(_equal_(xscore_3, score4->score(node0, cond3)))
451 
452       score4->operator=(score);
453       TS_GUM_ASSERT_THROWS_NOTHING(
454          score4->isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
455       TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
456 
457       TS_ASSERT(_equal_(xscore_1, score4->score(node0)))
458       TS_ASSERT(_equal_(xscore_2, score4->score(node0, cond2)))
459       TS_ASSERT(_equal_(xscore_3, score4->score(node0, cond3)))
460 
461       score4->operator=(std::move(score));
462       TS_GUM_ASSERT_THROWS_NOTHING(
463          score4->isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
464       TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
465 
466       TS_ASSERT(_equal_(xscore_1, score4->score(node0)))
467       TS_ASSERT(_equal_(xscore_2, score4->score(node0, cond2)))
468       TS_ASSERT(_equal_(xscore_3, score4->score(node0, cond3)))
469 
470       delete score4;
471     }
472 
473 
_test_has_range_has_nodeId2col()474     void _test_has_range_has_nodeId2col() {
475       // create the translator set
476       gum::LabelizedVariable var("X1", "", 0);
477       var.addLabel("0");
478       var.addLabel("1");
479       var.addLabel("2");
480 
481       gum::learning::DBTranslatorSet<> trans_set;
482       {
483         const std::vector< std::string >                miss;
484         gum::learning::DBTranslator4LabelizedVariable<> translator(var, miss);
485         std::vector< std::string >                      names{"A", "B", "C", "D", "E", "F"};
486 
487         for (std::size_t i = std::size_t(0); i < names.size(); ++i) {
488           translator.setVariableName(names[i]);
489           trans_set.insertTranslator(translator, i);
490         }
491       }
492 
493       // create the database
494       gum::learning::DatabaseTable<> database(trans_set);
495       std::vector< std::string >     row0{"0", "1", "0", "2", "1", "1"};
496       std::vector< std::string >     row1{"1", "2", "0", "1", "2", "2"};
497       std::vector< std::string >     row2{"2", "1", "0", "1", "1", "0"};
498       std::vector< std::string >     row3{"1", "0", "0", "0", "0", "0"};
499       std::vector< std::string >     row4{"0", "0", "0", "1", "1", "1"};
500       for (int i = 0; i < 1000; ++i)
501         database.insertRow(row0);
502       for (int i = 0; i < 50; ++i)
503         database.insertRow(row1);
504       for (int i = 0; i < 75; ++i)
505         database.insertRow(row2);
506       for (int i = 0; i < 75; ++i)
507         database.insertRow(row3);
508       for (int i = 0; i < 200; ++i)
509         database.insertRow(row4);
510 
511       // create the parser
512       gum::learning::DBRowGeneratorSet<>    genset;
513       gum::learning::DBRowGeneratorParser<> parser(database.handler(), genset);
514 
515       std::vector< std::pair< std::size_t, std::size_t > > ranges{{800, 1000}, {1050, 1400}};
516 
517       gum::Bijection< gum::NodeId, std::size_t > nodeId2columns;
518       gum::NodeId                                node0 = 0;
519       gum::NodeId                                node1 = 1;
520       gum::NodeId                                node2 = 2;
521       gum::NodeId                                node3 = 3;
522       gum::NodeId                                node4 = 4;
523       gum::NodeId                                node5 = 5;
524       nodeId2columns.insert(node0, std::size_t(4));
525       nodeId2columns.insert(node1, std::size_t(3));
526       nodeId2columns.insert(node2, std::size_t(0));
527       nodeId2columns.insert(node3, std::size_t(2));
528       nodeId2columns.insert(node4, std::size_t(5));
529       nodeId2columns.insert(node5, std::size_t(1));
530 
531       gum::learning::AprioriSmoothing<> apriori(database, nodeId2columns);
532       gum::learning::ScoreAIC<>         score(parser, apriori, ranges, nodeId2columns);
533 
534       TS_GUM_ASSERT_THROWS_NOTHING(gum::learning::ScoreAIC<>::isAprioriCompatible(
535          gum::learning::AprioriSmoothing<>::type::type));
536       TS_GUM_ASSERT_THROWS_NOTHING(gum::learning::ScoreAIC<>::isAprioriCompatible(apriori));
537       TS_GUM_ASSERT_THROWS_NOTHING(
538          score.isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
539       TS_GUM_ASSERT_THROWS_NOTHING(score.isAprioriCompatible(apriori));
540 
541       std::vector< gum::NodeId > cond_empty;
542       std::vector< gum::NodeId > cond2{node5};
543       std::vector< gum::NodeId > cond3{node1};
544 
545       gum::learning::IdCondSet<> idset1(node2, cond_empty);    // #3,#0
546       gum::learning::IdCondSet<> idset2(node2, cond2, true);   // #9,#3
547       gum::learning::IdCondSet<> idset3(node2, cond3, true);   // #9,#3
548 
549       // idset1: node2 | emptyset
550       double                penalty_1 = 2;
551       std::vector< double > N_ijk_1{401.0, 76.0, 76.0};
552       std::vector< double > N_ij_1;
553       double                xscore_1 = _score_(N_ijk_1, N_ij_1, penalty_1);
554       TS_ASSERT(_equal_(xscore_1, score.score(node2)))
555 
556       // idset2: node2 | node5
557       double                penalty_2 = 6;
558       std::vector< double > N_ijk_2{201, 76, 1, 201, 1, 76, 1, 1, 1};
559       std::vector< double > N_ij_2{278, 278, 3};
560       double                xscore_2 = _score_(N_ijk_2, N_ij_2, penalty_2);
561       TS_ASSERT(_equal_(xscore_2, score.score(node2, cond2)))
562 
563       // idset3: node2 | node1
564       double                penalty_3 = 6;
565       std::vector< double > N_ijk_3{1, 76, 1, 201, 1, 76, 201, 1, 1};
566       std::vector< double > N_ij_3{78, 278, 203};
567       double                xscore_3 = _score_(N_ijk_3, N_ij_3, penalty_3);
568       TS_ASSERT(_equal_(xscore_3, score.score(node2, cond3)))
569 
570 
571       gum::learning::ScoreAIC<> score2(score);
572       TS_GUM_ASSERT_THROWS_NOTHING(
573          score2.isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
574       TS_GUM_ASSERT_THROWS_NOTHING(score2.isAprioriCompatible(apriori));
575 
576       TS_ASSERT(_equal_(xscore_1, score2.score(node2)))
577       TS_ASSERT(_equal_(xscore_2, score2.score(node2, cond2)))
578       TS_ASSERT(_equal_(xscore_3, score2.score(node2, cond3)))
579 
580       gum::learning::ScoreAIC<> score3(std::move(score2));
581       TS_GUM_ASSERT_THROWS_NOTHING(
582          score3.isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
583       TS_GUM_ASSERT_THROWS_NOTHING(score3.isAprioriCompatible(apriori));
584 
585       TS_ASSERT(_equal_(xscore_1, score3.score(node2)))
586       TS_ASSERT(_equal_(xscore_2, score3.score(node2, cond2)))
587       TS_ASSERT(_equal_(xscore_3, score3.score(node2, cond3)))
588 
589       gum::learning::ScoreAIC<>* score4 = score3.clone();
590       TS_GUM_ASSERT_THROWS_NOTHING(
591          score4->isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
592       TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
593 
594       TS_ASSERT(_equal_(xscore_1, score4->score(node2)))
595       TS_ASSERT(_equal_(xscore_2, score4->score(node2, cond2)))
596       TS_ASSERT(_equal_(xscore_3, score4->score(node2, cond3)))
597 
598       score4->operator=(score);
599       TS_GUM_ASSERT_THROWS_NOTHING(
600          score4->isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
601       TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
602 
603       TS_ASSERT(_equal_(xscore_1, score4->score(node2)))
604       TS_ASSERT(_equal_(xscore_2, score4->score(node2, cond2)))
605       TS_ASSERT(_equal_(xscore_3, score4->score(node2, cond3)))
606 
607       score4->operator=(std::move(score));
608       TS_GUM_ASSERT_THROWS_NOTHING(
609          score4->isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
610       TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
611 
612       TS_ASSERT(_equal_(xscore_1, score4->score(node2)))
613       TS_ASSERT(_equal_(xscore_2, score4->score(node2, cond2)))
614       TS_ASSERT(_equal_(xscore_3, score4->score(node2, cond3)))
615 
616       delete score4;
617     }
618 
619 
test_multicore()620     void test_multicore() {
621       // create the translator set
622       gum::LabelizedVariable var("X1", "", 0);
623       var.addLabel("0");
624       var.addLabel("1");
625       var.addLabel("2");
626 
627       gum::learning::DBTranslatorSet<> trans_set;
628       {
629         const std::vector< std::string >                miss;
630         gum::learning::DBTranslator4LabelizedVariable<> translator(var, miss);
631         std::vector< std::string >                      names{"A", "B", "C", "D", "E", "F"};
632 
633         for (std::size_t i = std::size_t(0); i < names.size(); ++i) {
634           translator.setVariableName(names[i]);
635           trans_set.insertTranslator(translator, i);
636         }
637       }
638 
639       // create the database
640       gum::learning::DatabaseTable<> database(trans_set);
641       std::vector< std::string >     row0{"0", "1", "0", "2", "1", "1"};
642       std::vector< std::string >     row1{"1", "2", "0", "1", "2", "2"};
643       std::vector< std::string >     row2{"2", "1", "0", "1", "1", "0"};
644       std::vector< std::string >     row3{"1", "0", "0", "0", "0", "0"};
645       std::vector< std::string >     row4{"0", "0", "0", "1", "1", "1"};
646       for (int i = 0; i < 1000; ++i)
647         database.insertRow(row0);
648       for (int i = 0; i < 50; ++i)
649         database.insertRow(row1);
650       for (int i = 0; i < 75; ++i)
651         database.insertRow(row2);
652       for (int i = 0; i < 75; ++i)
653         database.insertRow(row3);
654       for (int i = 0; i < 200; ++i)
655         database.insertRow(row4);
656 
657       // create the parser
658       gum::learning::DBRowGeneratorSet<>    genset;
659       gum::learning::DBRowGeneratorParser<> parser(database.handler(), genset);
660 
661       std::vector< std::pair< std::size_t, std::size_t > > ranges{{800, 1000}, {1050, 1400}};
662       gum::learning::AprioriSmoothing<>                    apriori(database);
663 
664 
665       for (std::size_t i = std::size_t(1); i < std::size_t(24); ++i) {
666         gum::learning::ScoreAIC<> score(parser, apriori, ranges);
667         score.setMaxNbThreads(i);
668 
669         TS_GUM_ASSERT_THROWS_NOTHING(gum::learning::ScoreAIC<>::isAprioriCompatible(
670            gum::learning::AprioriSmoothing<>::type::type));
671         TS_GUM_ASSERT_THROWS_NOTHING(gum::learning::ScoreAIC<>::isAprioriCompatible(apriori));
672         TS_GUM_ASSERT_THROWS_NOTHING(
673            score.isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
674         TS_GUM_ASSERT_THROWS_NOTHING(score.isAprioriCompatible(apriori));
675 
676         gum::NodeId                node0 = 0;
677         gum::NodeId                node1 = 1;
678         gum::NodeId                node3 = 3;
679         std::vector< gum::NodeId > cond_empty;
680         std::vector< gum::NodeId > cond2{node1};
681         std::vector< gum::NodeId > cond3{node3};
682 
683         gum::learning::IdCondSet<> idset1(node0, cond_empty);    // #3,#0
684         gum::learning::IdCondSet<> idset2(node0, cond2, true);   // #9,#3
685         gum::learning::IdCondSet<> idset3(node0, cond3, true);   // #9,#3
686 
687         // idset1: node0 | emptyset
688         double                penalty_1 = 2;
689         std::vector< double > N_ijk_1{401.0, 76.0, 76.0};
690         std::vector< double > N_ij_1;
691         double                xscore_1 = _score_(N_ijk_1, N_ij_1, penalty_1);
692         TS_ASSERT(_equal_(xscore_1, score.score(node0)))
693 
694         // idset2: node0 | node1
695         double                penalty_2 = 6;
696         std::vector< double > N_ijk_2{201, 76, 1, 201, 1, 76, 1, 1, 1};
697         std::vector< double > N_ij_2{278, 278, 3};
698         double                xscore_2 = _score_(N_ijk_2, N_ij_2, penalty_2);
699         TS_ASSERT(_equal_(xscore_2, score.score(node0, cond2)))
700 
701         // idset3: node0 | node3
702         double                penalty_3 = 6;
703         std::vector< double > N_ijk_3{1, 76, 1, 201, 1, 76, 201, 1, 1};
704         std::vector< double > N_ij_3{78, 278, 203};
705         double                xscore_3 = _score_(N_ijk_3, N_ij_3, penalty_3);
706         TS_ASSERT(_equal_(xscore_3, score.score(node0, cond3)))
707 
708 
709         gum::learning::ScoreAIC<> score2(score);
710         TS_GUM_ASSERT_THROWS_NOTHING(
711            score2.isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
712         TS_GUM_ASSERT_THROWS_NOTHING(score2.isAprioriCompatible(apriori));
713 
714         TS_ASSERT(_equal_(xscore_1, score2.score(node0)))
715         TS_ASSERT(_equal_(xscore_2, score2.score(node0, cond2)))
716         TS_ASSERT(_equal_(xscore_3, score2.score(node0, cond3)))
717 
718         gum::learning::ScoreAIC<> score3(std::move(score2));
719         TS_GUM_ASSERT_THROWS_NOTHING(
720            score3.isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
721         TS_GUM_ASSERT_THROWS_NOTHING(score3.isAprioriCompatible(apriori));
722 
723         TS_ASSERT(_equal_(xscore_1, score3.score(node0)))
724         TS_ASSERT(_equal_(xscore_2, score3.score(node0, cond2)))
725         TS_ASSERT(_equal_(xscore_3, score3.score(node0, cond3)))
726 
727         gum::learning::ScoreAIC<>* score4 = score3.clone();
728         TS_GUM_ASSERT_THROWS_NOTHING(
729            score4->isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
730         TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
731 
732         TS_ASSERT(_equal_(xscore_1, score4->score(node0)))
733         TS_ASSERT(_equal_(xscore_2, score4->score(node0, cond2)))
734         TS_ASSERT(_equal_(xscore_3, score4->score(node0, cond3)))
735 
736         score4->operator=(score);
737         TS_GUM_ASSERT_THROWS_NOTHING(
738            score4->isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
739         TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
740 
741         TS_ASSERT(_equal_(xscore_1, score4->score(node0)))
742         TS_ASSERT(_equal_(xscore_2, score4->score(node0, cond2)))
743         TS_ASSERT(_equal_(xscore_3, score4->score(node0, cond3)))
744 
745         score4->operator=(std::move(score));
746         TS_GUM_ASSERT_THROWS_NOTHING(
747            score4->isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
748         TS_GUM_ASSERT_THROWS_NOTHING(score4->isAprioriCompatible(apriori));
749 
750         TS_ASSERT(_equal_(xscore_1, score4->score(node0)))
751         TS_ASSERT(_equal_(xscore_2, score4->score(node0, cond2)))
752         TS_ASSERT(_equal_(xscore_3, score4->score(node0, cond3)))
753 
754         delete score4;
755       }
756     }
757 
testChangeRanges()758     void testChangeRanges() {
759       // create the translator set
760       gum::LabelizedVariable var("X1", "", 0);
761       var.addLabel("0");
762       var.addLabel("1");
763       var.addLabel("2");
764 
765       gum::learning::DBTranslatorSet<> trans_set;
766       {
767         const std::vector< std::string >                miss;
768         gum::learning::DBTranslator4LabelizedVariable<> translator(var, miss);
769         std::vector< std::string >                      names{"A", "B", "C", "D", "E", "F"};
770 
771         for (std::size_t i = std::size_t(0); i < names.size(); ++i) {
772           translator.setVariableName(names[i]);
773           trans_set.insertTranslator(translator, i);
774         }
775       }
776 
777       // create the database
778       gum::learning::DatabaseTable<> database(trans_set);
779       std::vector< std::string >     row0{"0", "1", "0", "2", "1", "1"};
780       std::vector< std::string >     row1{"1", "2", "0", "1", "2", "2"};
781       std::vector< std::string >     row2{"2", "1", "0", "1", "1", "0"};
782       std::vector< std::string >     row3{"1", "0", "0", "0", "0", "0"};
783       std::vector< std::string >     row4{"0", "0", "0", "1", "1", "1"};
784       for (int i = 0; i < 1000; ++i)
785         database.insertRow(row0);
786       for (int i = 0; i < 50; ++i)
787         database.insertRow(row1);
788       for (int i = 0; i < 75; ++i)
789         database.insertRow(row2);
790       for (int i = 0; i < 75; ++i)
791         database.insertRow(row3);
792       for (int i = 0; i < 200; ++i)
793         database.insertRow(row4);
794 
795       // create the parser
796       gum::learning::DBRowGeneratorSet<>    genset;
797       gum::learning::DBRowGeneratorParser<> parser(database.handler(), genset);
798 
799       gum::learning::AprioriSmoothing<> apriori(database);
800       gum::learning::ScoreAIC<>         score(parser, apriori);
801 
802       TS_GUM_ASSERT_THROWS_NOTHING(gum::learning::ScoreAIC<>::isAprioriCompatible(
803          gum::learning::AprioriSmoothing<>::type::type));
804       TS_GUM_ASSERT_THROWS_NOTHING(gum::learning::ScoreAIC<>::isAprioriCompatible(apriori));
805       TS_GUM_ASSERT_THROWS_NOTHING(
806          score.isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
807       TS_GUM_ASSERT_THROWS_NOTHING(score.isAprioriCompatible(apriori));
808 
809       gum::NodeId                node0 = 0;
810       gum::NodeId                node1 = 1;
811       gum::NodeId                node3 = 3;
812       std::vector< gum::NodeId > cond_empty;
813       std::vector< gum::NodeId > cond2{node1};
814       std::vector< gum::NodeId > cond3{node3};
815 
816       gum::learning::IdCondSet<> idset1(node0, cond_empty);    // #3,#0
817       gum::learning::IdCondSet<> idset2(node0, cond2, true);   // #9,#3
818       gum::learning::IdCondSet<> idset3(node0, cond3, true);   // #9,#3
819 
820       // idset1: node0 | emptyset
821       double                penalty_1 = 2;
822       std::vector< double > N_ijk_1{1201.0, 126.0, 76.0};
823       std::vector< double > N_ij_1;
824       double                xscore_1 = _score_(N_ijk_1, N_ij_1, penalty_1);
825       TS_ASSERT(_equal_(xscore_1, score.score(node0)))
826 
827       // idset2: node0 | node1
828       double                penalty_2 = 6;
829       std::vector< double > N_ijk_2{201, 76, 1, 1001, 1, 76, 1, 51, 1};
830       std::vector< double > N_ij_2{278, 1078, 53};
831       double                xscore_2 = _score_(N_ijk_2, N_ij_2, penalty_2);
832       TS_ASSERT(_equal_(xscore_2, score.score(node0, cond2)))
833 
834       // idset3: node0 | node3
835       double                penalty_3 = 6;
836       std::vector< double > N_ijk_3{1, 76, 1, 201, 51, 76, 1001, 1, 1};
837       std::vector< double > N_ij_3{78, 328, 1003};
838       double                xscore_3 = _score_(N_ijk_3, N_ij_3, penalty_3);
839       TS_ASSERT(_equal_(xscore_3, score.score(node0, cond3)))
840 
841       gum::learning::ScoreAIC<> score2(score);
842       TS_GUM_ASSERT_THROWS_NOTHING(
843          score2.isAprioriCompatible(gum::learning::AprioriSmoothing<>::type::type));
844       TS_GUM_ASSERT_THROWS_NOTHING(score2.isAprioriCompatible(apriori));
845 
846       TS_ASSERT(_equal_(xscore_1, score2.score(node0)))
847       TS_ASSERT(_equal_(xscore_2, score2.score(node0, cond2)))
848       TS_ASSERT(_equal_(xscore_3, score2.score(node0, cond3)))
849 
850       std::vector< std::pair< std::size_t, std::size_t > > ranges{{800, 1000}, {1050, 1400}};
851 
852       score.setRanges(ranges);
853 
854       // idset1: node0 | emptyset
855       double                xpenalty_1 = 2;
856       std::vector< double > xN_ijk_1{401.0, 76.0, 76.0};
857       std::vector< double > xN_ij_1;
858       double                xxscore_1 = _score_(xN_ijk_1, xN_ij_1, xpenalty_1);
859       TS_ASSERT(_equal_(xxscore_1, score.score(node0)))
860 
861       // idset2: node0 | node1
862       double                xpenalty_2 = 6;
863       std::vector< double > xN_ijk_2{201, 76, 1, 201, 1, 76, 1, 1, 1};
864       std::vector< double > xN_ij_2{278, 278, 3};
865       double                xxscore_2 = _score_(xN_ijk_2, xN_ij_2, xpenalty_2);
866       TS_ASSERT(_equal_(xxscore_2, score.score(node0, cond2)))
867 
868       // idset3: node0 | node3
869       double                xpenalty_3 = 6;
870       std::vector< double > xN_ijk_3{1, 76, 1, 201, 1, 76, 201, 1, 1};
871       std::vector< double > xN_ij_3{78, 278, 203};
872       double                xxscore_3 = _score_(xN_ijk_3, xN_ij_3, xpenalty_3);
873       TS_ASSERT(_equal_(xxscore_3, score.score(node0, cond3)))
874 
875       TS_ASSERT(_equal_(xscore_1, score2.score(node0)))
876       TS_ASSERT(_equal_(xscore_2, score2.score(node0, cond2)))
877       TS_ASSERT(_equal_(xscore_3, score2.score(node0, cond3)))
878 
879       score2.setRanges(ranges);
880 
881       TS_ASSERT(_equal_(xxscore_1, score2.score(node0)))
882       TS_ASSERT(_equal_(xxscore_2, score2.score(node0, cond2)))
883       TS_ASSERT(_equal_(xxscore_3, score2.score(node0, cond3)))
884 
885       score2.setRanges(ranges);
886 
887       TS_ASSERT(_equal_(xxscore_1, score2.score(node0)))
888       TS_ASSERT(_equal_(xxscore_2, score2.score(node0, cond2)))
889       TS_ASSERT(_equal_(xxscore_3, score2.score(node0, cond3)))
890 
891       TS_ASSERT_EQUALS(score2.ranges(), ranges)
892 
893       score2.clearRanges();
894       TS_ASSERT(_equal_(xscore_1, score2.score(node0)))
895       TS_ASSERT(_equal_(xscore_2, score2.score(node0, cond2)))
896       TS_ASSERT(_equal_(xscore_3, score2.score(node0, cond3)))
897     }
898   };
899 
900 
901 } /* namespace gum_tests */
902