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