diff --git a/Makefile b/Makefile index 3515580..d597d4a 100644 --- a/Makefile +++ b/Makefile @@ -119,7 +119,7 @@ test: ## Run tests (opt="-s") to verbose output the tests, (opt="-c='Test Maximu coverage: ## Run tests and generate coverage report (build/index.html) @echo ">>> Building tests with coverage..." - @which $(lcov) || (echo ">>> Please install lcov"; exit 1) + @which $(lcov) || (echo ">>ease install lcov"; exit 1) @if [ ! -f $(f_debug)/tests/coverage.info ] ; then $(MAKE) test ; fi @echo ">>> Building report..." @cd $(f_debug)/tests; \ diff --git a/bayesnet/CMakeLists.txt b/bayesnet/CMakeLists.txt index 2aef26a..62929ce 100644 --- a/bayesnet/CMakeLists.txt +++ b/bayesnet/CMakeLists.txt @@ -1,5 +1,5 @@ include_directories( - ${BayesNet_SOURCE_DIR}/lib/mdlp + ${BayesNet_SOURCE_DIR}/lib/mdlp/src ${BayesNet_SOURCE_DIR}/lib/folding ${BayesNet_SOURCE_DIR}/lib/json/include ${BayesNet_SOURCE_DIR} diff --git a/bayesnet/network/Network.cc b/bayesnet/network/Network.cc index ceede5b..f26e19d 100644 --- a/bayesnet/network/Network.cc +++ b/bayesnet/network/Network.cc @@ -95,6 +95,12 @@ namespace bayesnet { if (nodes.find(child) == nodes.end()) { throw std::invalid_argument("Child node " + child + " does not exist"); } + // Check if the edge is already in the graph + for (auto& node : nodes[parent]->getChildren()) { + if (node->getName() == child) { + throw std::invalid_argument("Edge " + parent + " -> " + child + " already exists"); + } + } // Temporarily add edge to check for cycles nodes[parent]->addChild(nodes[child].get()); nodes[child]->addParent(nodes[parent].get()); diff --git a/bayesnet/network/Node.cc b/bayesnet/network/Node.cc index fcb1e53..28eba72 100644 --- a/bayesnet/network/Node.cc +++ b/bayesnet/network/Node.cc @@ -119,6 +119,7 @@ namespace bayesnet { cpTable.index_put_({ coordinates }, cpTable.index({ coordinates }) + weights.index({ n_sample }).item()); } // Normalize the counts + // Divide each row by the sum of the row cpTable = cpTable / cpTable.sum(0); } float Node::getFactorValue(std::map& evidence) diff --git a/lib/mdlp b/lib/mdlp index 7b0673f..e36d9af 160000 --- a/lib/mdlp +++ b/lib/mdlp @@ -1 +1 @@ -Subproject commit 7b0673fd4b05135ce90f711b2dc410eb1a2fa5ff +Subproject commit e36d9af8f939a57266e30ca96e1cf84fc7d107b0 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1ff33ee..9abab26 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -2,7 +2,7 @@ if(ENABLE_TESTING) include_directories( ${BayesNet_SOURCE_DIR}/tests/lib/Files ${BayesNet_SOURCE_DIR}/lib/folding - ${BayesNet_SOURCE_DIR}/lib/mdlp + ${BayesNet_SOURCE_DIR}/lib/mdlp/src ${BayesNet_SOURCE_DIR}/lib/json/include ${BayesNet_SOURCE_DIR} ${CMAKE_BINARY_DIR}/configured_files/include diff --git a/tests/TestBayesNetwork.cc b/tests/TestBayesNetwork.cc index 0663ca2..9a22214 100644 --- a/tests/TestBayesNetwork.cc +++ b/tests/TestBayesNetwork.cc @@ -358,6 +358,9 @@ TEST_CASE("Edges troubles", "[Network]") REQUIRE_THROWS_WITH(net.addEdge("A", "C"), "Child node C does not exist"); REQUIRE_THROWS_AS(net.addEdge("C", "A"), std::invalid_argument); REQUIRE_THROWS_WITH(net.addEdge("C", "A"), "Parent node C does not exist"); + net.addEdge("A", "B"); + REQUIRE_THROWS_AS(net.addEdge("A", "B"), std::invalid_argument); + REQUIRE_THROWS_WITH(net.addEdge("A", "B"), "Edge A -> B already exists"); } TEST_CASE("Dump CPT", "[Network]") { @@ -457,10 +460,9 @@ TEST_CASE("Dump CPT", "[Network]") REQUIRE(res == expected); } -TEST_CASE("Test Smoothing", "[Network]") +TEST_CASE("Test Smoothing A", "[Network]") { /* - Tomando m = 1 Pa = 0.5 Si estoy calculando P(A | C), con C en{ 0,1,2 } y tengo : AC = { 11, 12, 11, 10, 10, 12, 10, 01, 00, 02 } @@ -523,3 +525,43 @@ TEST_CASE("Test Smoothing", "[Network]") } } } +TEST_CASE("Test Smoothing B", "[Network]") +{ + auto net = bayesnet::Network(); + net.addNode("X"); + net.addNode("Y"); + net.addNode("Z"); + net.addNode("C"); + net.addEdge("C", "X"); + net.addEdge("C", "Y"); + net.addEdge("C", "Z"); + net.addEdge("Y", "Z"); + std::vector C = { 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1 }; + std::vector> Data = { + { 0,0,1,1,0,1,0,1,0,1,0,0,0,1,0,1,0,0}, + { 1,2,0,2,2,2,1,0,0,1,1,1,0,1,2,1,0,2}, + { 2,1,3,3,2,0,0,1,3,2,1,2,2,3,0,0,1,2} + }; + std::map> states = { + { "X", {0, 1} }, + { "Y", {0, 1, 2} }, + { "Z", {0, 1, 2, 3} }, + { "C", {0, 1} } + }; + auto weights = std::vector(C.size(), 1); + // Simple + std::cout << "LAPLACE\n"; + net.fit(Data, C, weights, { "X", "Y", "Z" }, "C", states, bayesnet::Smoothing_t::LAPLACE); + std::cout << net.dump_cpt(); + std::cout << "Predict proba of {0, 1, 2} y {1, 2, 3} = " << net.predict_proba({ {0, 1}, {1, 2}, {2, 3} }) << std::endl; + std::cout << "ORIGINAL\n"; + net.fit(Data, C, weights, { "X", "Y", "Z" }, "C", states, bayesnet::Smoothing_t::ORIGINAL); + std::cout << net.dump_cpt(); + std::cout << "Predict proba of {0, 1, 2} y {1, 2, 3} = " << net.predict_proba({ {0, 1}, {1, 2}, {2, 3} }) << std::endl; + std::cout << "CESTNIK\n"; + net.fit(Data, C, weights, { "X", "Y", "Z" }, "C", states, bayesnet::Smoothing_t::CESTNIK); + std::cout << net.dump_cpt(); + std::cout << "Predict proba of {0, 1, 2} y {1, 2, 3} = " << net.predict_proba({ {0, 1}, {1, 2}, {2, 3} }) << std::endl; + + +} diff --git a/tests/TestModulesVersions.cc b/tests/TestModulesVersions.cc index 5a64fe4..fdcaa05 100644 --- a/tests/TestModulesVersions.cc +++ b/tests/TestModulesVersions.cc @@ -16,7 +16,7 @@ #include "TestUtils.h" std::map modules = { - { "mdlp", "1.2.2" }, + { "mdlp", "2.0.0" }, { "Folding", "1.1.0" }, { "json", "3.11" }, { "ArffFiles", "1.1.0" }