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