From fb42c03199543dc71312385cac98901e911e5b2d Mon Sep 17 00:00:00 2001 From: AntonChern Date: Fri, 23 Dec 2022 19:21:16 +0300 Subject: [PATCH] Replace the graph with boost graph txt-files replaced with dot-files. Balancing logic moved to a separate class. Added algorithm phases. --- CMakeLists.txt | 2 +- src/CMakeLists.txt | 3 +- src/algorithms/algo_factory.h | 6 +- src/algorithms/gfd/balancer.cpp | 164 ++++ src/algorithms/gfd/balancer.h | 8 + src/algorithms/gfd/gfd.cpp | 26 - src/algorithms/gfd/gfd.h | 29 +- src/algorithms/gfd/gfd_validation.cpp | 865 ++++++------------ src/algorithms/gfd/gfd_validation.h | 70 +- src/algorithms/gfd/graph.cpp | 14 - src/algorithms/gfd/graph.h | 28 - src/algorithms/gfd/graph_descriptor.h | 19 + src/algorithms/gfd/parser.cpp | 255 ++++-- src/algorithms/gfd/parser.h | 28 +- src/algorithms/gfd/pattern.cpp | 103 --- src/algorithms/gfd/pattern.h | 37 - tests/CMakeLists.txt | 2 +- tests/input_data/graph_data/directors.dot | 23 + tests/input_data/graph_data/directors.txt | 22 - tests/input_data/graph_data/directors_gfd.dot | 7 + tests/input_data/graph_data/directors_gfd.txt | 6 - .../{family_tree.txt => family_tree.dot} | 27 +- .../graph_data/family_tree_gfd1.dot | 7 + .../graph_data/family_tree_gfd1.txt | 6 - ...ily_tree_gfd2.txt => family_tree_gfd2.dot} | 11 +- ...ily_tree_gfd3.txt => family_tree_gfd3.dot} | 11 +- .../{quadrangle.txt => quadrangle.dot} | 15 +- .../input_data/graph_data/quadrangle_gfd.dot | 7 + .../input_data/graph_data/quadrangle_gfd.txt | 6 - tests/test_gfd_validation.cpp | 64 +- 30 files changed, 837 insertions(+), 1034 deletions(-) create mode 100644 src/algorithms/gfd/balancer.cpp create mode 100644 src/algorithms/gfd/balancer.h delete mode 100644 src/algorithms/gfd/gfd.cpp delete mode 100644 src/algorithms/gfd/graph.cpp delete mode 100644 src/algorithms/gfd/graph.h create mode 100644 src/algorithms/gfd/graph_descriptor.h delete mode 100644 src/algorithms/gfd/pattern.cpp delete mode 100644 src/algorithms/gfd/pattern.h create mode 100644 tests/input_data/graph_data/directors.dot delete mode 100644 tests/input_data/graph_data/directors.txt create mode 100644 tests/input_data/graph_data/directors_gfd.dot delete mode 100644 tests/input_data/graph_data/directors_gfd.txt rename tests/input_data/graph_data/{family_tree.txt => family_tree.dot} (70%) create mode 100644 tests/input_data/graph_data/family_tree_gfd1.dot delete mode 100644 tests/input_data/graph_data/family_tree_gfd1.txt rename tests/input_data/graph_data/{family_tree_gfd2.txt => family_tree_gfd2.dot} (52%) rename tests/input_data/graph_data/{family_tree_gfd3.txt => family_tree_gfd3.dot} (57%) rename tests/input_data/graph_data/{quadrangle.txt => quadrangle.dot} (58%) create mode 100644 tests/input_data/graph_data/quadrangle_gfd.dot delete mode 100644 tests/input_data/graph_data/quadrangle_gfd.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d56f33a10..b737de85eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ endif() # configuring boost set(Boost_USE_STATIC_LIBS ON) -find_package(Boost 1.72.0 REQUIRED COMPONENTS container program_options thread) +find_package(Boost 1.72.0 REQUIRED COMPONENTS container program_options thread graph) include_directories(${Boost_INCLUDE_DIRS}) message(${Boost_INCLUDE_DIRS}) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 39bd9bad48..8268ca1417 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -19,5 +19,4 @@ set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) add_executable(${BINARY}_run ${run_sources}) target_link_libraries(${BINARY}_run PUBLIC ${CMAKE_PROJECT_NAME}_lib) -target_link_libraries(${BINARY}_run LINK_PUBLIC ${Boost_LIBRARIES} Threads::Threads easyloggingpp) - +target_link_libraries(${BINARY}_run LINK_PUBLIC ${Boost_LIBRARIES} Threads::Threads easyloggingpp Boost::graph) diff --git a/src/algorithms/algo_factory.h b/src/algorithms/algo_factory.h index db33b19bbc..b8139f8962 100644 --- a/src/algorithms/algo_factory.h +++ b/src/algorithms/algo_factory.h @@ -86,14 +86,16 @@ std::unique_ptr CreateGFDValidationInstance(ParamsMap&& params) { auto graph_path = std::filesystem::current_path() / "input_data" / ExtractOptionValue(params, onam::kData); std::ifstream f(graph_path); - Graph graph = GFDtools::Parser::parse_graph(f); + graph_t graph; + GFDtools::Parser::read_graph(f, graph); f.close(); std::vector gfds = {}; auto gfd_paths = ExtractOptionValue>(params, onam::kGFDData); for (const auto& path : gfd_paths) { auto gfd_path = std::filesystem::current_path() / "input_data" / path; f.open(gfd_path); - GFD gfd = GFDtools::Parser::parse_gfd(f); + GFD gfd = GFD(); + GFDtools::Parser::read_gfd(f, gfd); f.close(); gfds.push_back(gfd); } diff --git a/src/algorithms/gfd/balancer.cpp b/src/algorithms/gfd/balancer.cpp new file mode 100644 index 0000000000..f2cb720680 --- /dev/null +++ b/src/algorithms/gfd/balancer.cpp @@ -0,0 +1,164 @@ +#include +#include +#include +#include + +#include "balancer.h" + +std::vector> +Balancer::balance(const std::vector& weights, const int& processors_num) { + int m = std::min(processors_num, (int)weights.size()); + std::vector> result = {}; + if (weights.begin() == weights.end()) { + for (int i = 0; i < processors_num; ++i) { + std::vector temp = {}; + result.push_back(temp); + } + return result; + } + for (int i = 0; i < m; ++i) { + // the first value is index + std::vector temp = { i }; + result.push_back(temp); + } + // fill processors initially + // count optimal + double optimal = 0; + int i = 0; + for (const int& weight : weights) { + result.at(i++).push_back(weight); + i = i == m ? 0 : i; + optimal += weight; + } + optimal /= m; + // sort processors (for convenience) + for (std::vector& processor : result) { + std::sort(processor.begin() + 1, processor.end()); + } + // ALGORITHM + // 1st step + std::vector deleted_large = {}; + std::vector deleted_small = {}; + for (std::vector& processor : result) { + auto border = processor.end(); + for (auto it = --processor.end(); it != processor.begin() + 1; --it) { + if (*(it - 1) > optimal / 2) { + deleted_large.push_back(*it); + border = it; + } + else { + break; + } + } + processor.erase(border, processor.end()); + } + // 2nd step + std::map> quality; + for (int i = 0; i < m; ++i) { + quality.emplace(i, std::tuple(0, 0, 0)); + } + for (const std::vector& processor : result) { + auto last_small = processor.end(); + auto last = processor.end(); + if (*(--processor.end()) > optimal / 2) { + --last_small; + } + if (processor.begin() + 1 == last_small) { + continue; + } + int a = 0; + int b = 0; + float sum_small = + std::accumulate(processor.begin() + 1, last_small, 0, std::plus()); + float sum = + std::accumulate(processor.begin() + 1, last, 0, std::plus()); + while (sum_small > optimal / 2) { + ++a; + --last_small; + sum_small -= *last_small; + } + while (sum > optimal) { + ++b; + --last; + sum -= *last; + } + std::get<0>(quality.at(processor.at(0))) = a; + std::get<1>(quality.at(processor.at(0))) = b; + std::get<2>(quality.at(processor.at(0))) = a - b; + } + // 3rd step + // sort for convenience + std::vector> small_processors = {}; + std::vector> large_processors = {}; + for (const std::vector& processor : result) { + if (*(--processor.end()) > optimal / 2) { + large_processors.push_back(processor); + } + else { + small_processors.push_back(processor); + } + } + auto cGreater = [&quality](std::vector a, std::vector b) { + return std::get<2>(quality.at(a.at(0))) > std::get<2>(quality.at(b.at(0))); + }; + sort(small_processors.begin(), small_processors.end(), cGreater); + sort(large_processors.begin(), large_processors.end(), cGreater); + result.clear(); + result.insert(result.end(), small_processors.begin(), small_processors.end()); + result.insert(result.end(), large_processors.begin(), large_processors.end()); + int numOfLarges = large_processors.size() + deleted_large.size(); + // work + auto border = numOfLarges < m ? result.end() - numOfLarges : result.begin(); + for (auto it = border; it != result.end(); ++it) { + auto last = it->end(); + if (*(last - 1) > optimal / 2) { + --last; + } + for (auto cur = last - std::get<0>(quality.at(*it->begin())); cur != last; ++cur) { + deleted_small.push_back(*cur); + } + it->erase(last - std::get<0>(quality.at(*it->begin())), last); + } + // 4th step + for (auto it = result.begin(); it != border; ++it) { + auto last = it->end(); + for (auto cur = last - std::get<1>(quality.at(*it->begin())); cur != last; ++cur) { + deleted_small.push_back(*cur); + } + it->erase(last - std::get<1>(quality.at(*it->begin())), last); + } + // 5th step + i = 0; + for (const int& weight : deleted_large) { + if (i < m - large_processors.size()) { + (result.begin() + i)->push_back(weight); + } + else { + sort(result.begin(), result.end(), + [](std::vector a, std::vector b) { + return std::accumulate(a.begin(), a.end(), 0, std::plus()) < + std::accumulate(b.begin(), b.end(), 0, std::plus()); + }); + result.begin()->push_back(weight); + } + ++i; + } + // 6th step + for (const int& weight : deleted_small) { + sort(result.begin(), result.end(), + [](std::vector a, std::vector b) { + return std::accumulate(a.begin(), a.end(), 0, std::plus()) < + std::accumulate(b.begin(), b.end(), 0, std::plus()); + }); + result.begin()->push_back(weight); + } + // delete indices + for (std::vector& processor : result) { + processor.erase(processor.begin()); + } + for (int i = 0; i < processors_num - m; ++i) { + std::vector empty = {}; + result.push_back(empty); + } + return result; +} diff --git a/src/algorithms/gfd/balancer.h b/src/algorithms/gfd/balancer.h new file mode 100644 index 0000000000..18a2517917 --- /dev/null +++ b/src/algorithms/gfd/balancer.h @@ -0,0 +1,8 @@ +#pragma once +#include + +class Balancer { +public: + static std::vector> balance(const std::vector& weights, const int& processors_num); +}; + diff --git a/src/algorithms/gfd/gfd.cpp b/src/algorithms/gfd/gfd.cpp deleted file mode 100644 index 631e76dd97..0000000000 --- a/src/algorithms/gfd/gfd.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include - -#include "gfd.h" - -void GFD::print(std::vector literals) const { - for (const Literal &l : literals) { - auto fst_token = l.first; - auto snd_token = l.second; - if (fst_token.first != -1) { - std::cout << fst_token.first << "."; - } - std::cout << fst_token.second << "="; - if (snd_token.first != -1) { - std::cout << snd_token.first << "."; - } - std::cout << snd_token.second << "; "; - } -} - -void GFD::print() const { - this->pattern.print(); - std::cout << std::endl << "Premises: "; - print(this->premises); - std::cout << std::endl << "=>" << std::endl << "Conclusion: "; - print(this->conclusion); -} diff --git a/src/algorithms/gfd/gfd.h b/src/algorithms/gfd/gfd.h index c79dc173a5..72bc8d8e0c 100644 --- a/src/algorithms/gfd/gfd.h +++ b/src/algorithms/gfd/gfd.h @@ -1,28 +1,27 @@ #pragma once #include +#include -#include "pattern.h" +#include "graph_descriptor.h" typedef std::pair Token; typedef std::pair Literal; class GFD { - private: - Pattern pattern; - std::vector premises; - std::vector conclusion; - void print(std::vector) const; - + graph_t pattern; + std::vector premises; + std::vector conclusion; public: - GFD() {}; - GFD(Pattern &pattern_, std::vector &premises_, - std::vector &conclusion_) - : pattern(pattern_), premises(premises_), conclusion(conclusion_) {} + GFD() = default; + GFD(graph_t &pattern_, std::vector &premises_, std::vector &conclusion_) + : pattern(pattern_), premises(premises_), conclusion(conclusion_) {} - Pattern getPattern() const { return this->pattern; } - std::vector getPremises() const { return this->premises; } - std::vector getConclusion() const { return this->conclusion; } + graph_t getPattern() const { return this->pattern; } + std::vector getPremises() const { return this->premises; } + std::vector getConclusion() const { return this->conclusion; } - void print() const; + void setPattern(graph_t& pattern_) { this->pattern = pattern_; } + void setPremises(std::vector& premises_) { this->premises = premises_; } + void setConclusion(std::vector& conclusion_) { this->conclusion = conclusion_; } }; diff --git a/src/algorithms/gfd/gfd_validation.cpp b/src/algorithms/gfd/gfd_validation.cpp index c9ef9fced0..44fc6c1280 100644 --- a/src/algorithms/gfd/gfd_validation.cpp +++ b/src/algorithms/gfd/gfd_validation.cpp @@ -1,609 +1,354 @@ #include -#include -#include -#include #include -#include +#include +#include +#include +#include +#include -#include "gfd.h" #include "gfd_validation.h" -#include "graph.h" +#include "balancer.h" namespace algos { - + void GFDValidation::FitInternal(model::IDatasetStream& data_stream) {} -Eigen::MatrixXi GFDValidation::convert(const Eigen::VectorXi &vec, - const int &cols) { - Eigen::MatrixXi result = Eigen::MatrixXi::Zero(vec.rows(), cols); - for (int i = 0; i < vec.rows(); ++i) { - result(i, vec(i)) = 1; - } - return result; -} +template +bool GFDValidation::all_shortest_paths(const graph_type& pattern, DistancesMatrix& dm) { + typedef boost::adjacency_list struct_graph; + typedef boost::graph_traits::edge_descriptor edge_t; -bool GFDValidation::isSubgraph(const Pattern &query, const Pattern &graph, - const Eigen::MatrixXi &match) { - Eigen::MatrixXi Q = query.getAdjacencyMatrix(); - Eigen::MatrixXi G = graph.getAdjacencyMatrix(); - if ((match * (match * G).transpose()).transpose().cwiseProduct(Q) != Q) { - return false; - } - Eigen::VectorXi mask = Eigen::VectorXi::Zero(G.rows()); - for (int i = 0; i < G.rows(); ++i) { - mask(i) = i; - } - for (const auto &edge_label : query.getEdges()) { - std::pair edge = edge_label.first; - Eigen::VectorXi index1 = Eigen::VectorXi::Zero(Q.rows()); - index1(edge.first) = 1; - int i = mask.cwiseProduct((index1.transpose() * match).transpose()).sum(); - Eigen::VectorXi index2 = Eigen::VectorXi::Zero(Q.rows()); - index2(edge.second) = 1; - int j = mask.cwiseProduct((index2.transpose() * match).transpose()).sum(); - if (edge_label.second != graph.getEdges().at(std::pair(i, j))) { - return false; - } - } - return true; -} + typedef boost::constant_property_map WeightMap; -std::vector -GFDValidation::getCandidateMatches(const Pattern &query, const Pattern &graph, - const std::pair &link) { - std::vector result = {}; - Eigen::MatrixXi Q = query.getAdjacencyMatrix(); - Eigen::MatrixXi G = graph.getAdjacencyMatrix(); - - Eigen::MatrixXi graph_degrees = graph.getVertexDegrees(); - Eigen::MatrixXi query_degrees = query.getVertexDegrees(); - - std::vector> available_vertices = {}; - for (int i = 0; i < Q.rows(); ++i) { - std::vector temp = {}; - available_vertices.push_back(temp); - } - - for (int i = 0; i < Q.rows(); ++i) { - if (i == link.first) { - available_vertices.at(i).push_back(link.second); - } else { - for (int j = 0; j < G.rows(); ++j) { - if (query.getVertices().at(i) == graph.getVertices().at(j) && - query_degrees(i, 0) <= graph_degrees(j, 0) && - query_degrees(i, 1) <= graph_degrees(j, 1)) { - available_vertices.at(i).push_back(j); - } - } - } - } - - std::vector current = {}; - for (int j = 0; j < available_vertices.at(0).size(); ++j) { - Eigen::VectorXi temp = Eigen::VectorXi::Zero(Q.rows()); - temp(0) = available_vertices.at(0).at(j); - current.push_back(temp); - } - for (int i = 1; i < available_vertices.size(); ++i) { - std::vector new_vecs = {}; - for (const Eigen::VectorXi &vec : current) { - for (int j = 0; j < available_vertices.at(i).size(); ++j) { - bool contains = false; - int index = available_vertices.at(i).at(j); - for (int k = 0; k < i; ++k) { - if (vec(k) == index) { - contains = true; - break; - } - } - if (!contains) { - Eigen::VectorXi temp = vec; - temp(i) = index; - new_vecs.push_back(temp); + struct_graph temp(boost::num_vertices(pattern)); + + typename boost::graph_traits::edge_iterator it, end; + for (boost::tie(it, end) = edges(pattern); it != end; ++it) { + auto e = *it; + if (!boost::edge(boost::source(e, pattern), boost::target(e, pattern), temp).second && + !boost::edge(boost::target(e, pattern), boost::source(e, pattern), temp).second) { + boost::add_edge(boost::source(e, pattern), boost::target(e, pattern), temp); } - } } - current.clear(); - current = new_vecs; - } - - for (const Eigen::VectorXi &vec : current) { - result.push_back(vec); - } - return result; -} -std::vector -GFDValidation::getMatches(const Pattern &query, const Pattern &graph, - const std::pair &link) { - std::vector result = {}; - std::vector candidates = - getCandidateMatches(query, graph, link); - for (const Eigen::VectorXi &match : candidates) { - if (isSubgraph(query, graph, - convert(match, graph.getAdjacencyMatrix().rows()))) { - result.push_back(match); - } - } - return result; + WeightMap wm(1); + return boost::floyd_warshall_all_pairs_shortest_paths(temp, dm, weight_map(wm)); } -bool GFDValidation::satisfied(const Graph &graph, const Eigen::VectorXi &match, - const std::vector &literals) { - for (const Literal &l : literals) { - auto fst_token = l.first; - auto snd_token = l.second; - std::string fst; - std::string snd; - if (fst_token.first == -1) { - fst = fst_token.second; - } else { - int index = match(fst_token.first); - auto attrs = graph.getAttributes().at(index); - if (attrs.find(fst_token.second) == attrs.end()) { - return false; - } - fst = attrs.at(fst_token.second); - } - if (snd_token.first == -1) { - snd = snd_token.second; - } else { - int index = match(snd_token.first); - auto attrs = graph.getAttributes().at(index); - if (attrs.find(snd_token.second) == attrs.end()) { - return false; - } - snd = attrs.at(snd_token.second); - } - if (fst != snd) { - return false; +template +typename boost::graph_traits::vertex_descriptor +GFDValidation::getCenter(const graph_type& pattern, int& out) { + typedef boost::exterior_vertex_property DistanceProperty; + typedef typename DistanceProperty::matrix_type DistanceMatrix; + typedef typename DistanceProperty::matrix_map_type DistanceMatrixMap; + + typedef boost::exterior_vertex_property EccentricityProperty; + typedef typename EccentricityProperty::container_type EccentricityContainer; + typedef typename EccentricityProperty::map_type EccentricityMap; + + DistanceMatrix distances(boost::num_vertices(pattern)); + DistanceMatrixMap dm(distances, pattern); + all_shortest_paths(pattern, dm); + + int r, d; + EccentricityContainer eccs(boost::num_vertices(pattern)); + EccentricityMap em(eccs, pattern); + boost::tie(r, d) = all_eccentricities(pattern, dm, em); + out = r; + + typename boost::graph_traits::vertex_iterator i, end; + for (boost::tie(i, end) = vertices(pattern); i != end; ++i) { + bool is_center = true; + typename boost::graph_traits::vertex_iterator j; + for (j = vertices(pattern).first; j != end; ++j) { + if (get(get(dm, *i), *j) > r) { + is_center = false; + break; + } + } + if (is_center) { + return pattern[*i].node_id; + } } - } - return true; } -bool GFDValidation::isSatisfiedLinked(const Graph &graph, const GFD &gfd, - const std::pair &link) { - std::vector matches = - getMatches(gfd.getPattern(), graph, link); - - for (const Eigen::VectorXi &match : matches) { - if (!satisfied(graph, match, gfd.getPremises())) { - continue; +template +graph_type GFDValidation::getSubgraph(const graph_type& graph, + const int& index, const int& radius, int& pin) { + typedef boost::exterior_vertex_property DistanceProperty; + typedef typename DistanceProperty::matrix_type DistanceMatrix; + typedef typename DistanceProperty::matrix_map_type DistanceMatrixMap; + + DistanceMatrix distances(boost::num_vertices(graph)); + DistanceMatrixMap dm(distances, graph); + all_shortest_paths(graph, dm); + + graph_type result; + + std::map::vertex_descriptor, + typename boost::graph_traits::vertex_descriptor> iso; + + typename boost::graph_traits::vertex_descriptor v = boost::vertex(index, graph); + typename boost::graph_traits::vertex_iterator it_vert, end_vert; + for (boost::tie(it_vert, end_vert) = vertices(graph); it_vert != end_vert; ++it_vert) { + if (get(get(dm, v), *it_vert) <= radius) { + auto desc = boost::add_vertex(result); + result[desc] = graph[*it_vert]; + result[desc].node_id = get(boost::vertex_index, result)[desc]; + iso.emplace(*it_vert, desc); + } } + pin = get(boost::vertex_index, result)[iso.at(v)]; - if (!satisfied(graph, match, gfd.getConclusion())) { - return false; + typename boost::graph_traits::edge_iterator it_edge, end_edge; + for (boost::tie(it_edge, end_edge) = edges(graph); it_edge != end_edge; ++it_edge) { + if (iso.find(boost::source(*it_edge, graph)) == iso.end() || + iso.find(boost::target(*it_edge, graph)) == iso.end()) { + continue; + } + auto desc = boost::add_edge(iso.at(boost::source(*it_edge, graph)), + iso.at(boost::target(*it_edge, graph)), result).first; + result[desc] = graph[*it_edge]; } - - // bool satisfied = true; - // for (const Literal &l : gfd.getPremises()) { - // std::vector vars = l.getVars(); - // std::vector values = l.getValues(); - // int query_index1 = vars.at(0); - // int graph_index1 = match(query_index1); - // std::map current_attrs1 = - // graph.getAttributes().at(graph_index1); - // if (vars.size() == 1) { - // // ConstLiteral - // if ((current_attrs1.find(values.at(0)) != current_attrs1.end()) && - // (current_attrs1.at(values.at(0)) != values.at(1))) { - // // next match - // satisfied = false; - // break; - // } - // } else { - // // VarLiteral - // int query_index2 = vars.at(1); - // int graph_index2 = match(query_index2); - // std::map current_attrs2 = - // graph.getAttributes().at(graph_index2); - // if ((current_attrs1.find(values.at(0)) != current_attrs1.end()) && - // (current_attrs2.find(values.at(1)) != current_attrs2.end()) && - // (current_attrs1.at(values.at(0)) != - // current_attrs2.at(values.at(1)))) { - // // next match - // satisfied = false; - // break; - // } - // } - // } - - // if (!satisfied) { - // break; - // } - - // for (const Literal &l : gfd.getConclusion()) { - // std::vector vars = l.getVars(); - // std::vector values = l.getValues(); - // int query_index1 = vars.at(0); - // int graph_index1 = match(query_index1); - // std::map current_attrs1 = - // graph.getAttributes().at(graph_index1); - // if (vars.size() == 1) { - // // ConstLiteral - // if ((current_attrs1.find(values.at(0)) == current_attrs1.end()) || - // (current_attrs1.at(values.at(0)) != values.at(1))) { - // return false; - // } - // } else { - // // VarLiteral - // int query_index2 = vars.at(1); - // int graph_index2 = match(query_index2); - // std::map current_attrs2 = - // graph.getAttributes().at(graph_index2); - // if ((current_attrs1.find(values.at(0)) == current_attrs1.end()) || - // (current_attrs2.find(values.at(1)) == current_attrs2.end()) || - // (current_attrs1.at(values.at(0)) != - // current_attrs2.at(values.at(1)))) { - // return false; - // } - // } - // } - } - return true; + return result; } -std::vector> -GFDValidation::balanced(const std::vector &weights, - const int &processors_num) { - int m = std::min(processors_num, (int)weights.size()); - std::vector> result = {}; - if (weights.begin() == weights.end()) { - for (int i = 0; i < processors_num; ++i) { - std::vector temp = {}; - result.push_back(temp); +template +std::vector +GFDValidation::getCandidateVertices(const graph_type& graph, + const std::string& label, + const std::pair& degrees) { + std::vector result = {}; + typename boost::graph_traits::vertex_iterator i, end; + for (boost::tie(i, end) = vertices(graph); i != end; ++i) { + auto out = boost::out_degree(*i, graph); + auto in = boost::in_degree(*i, graph); + if (out >= degrees.first && in >= degrees.second && + graph[*i].attributes.at("label") == label) { + result.push_back(graph[*i].node_id); + } } return result; - } - for (int i = 0; i < m; ++i) { - // the first value is index - std::vector temp = {i}; - result.push_back(temp); - } - // fill processors initially - // count optimal - double optimal = 0; - int i = 0; - for (const int &weight : weights) { - result.at(i++).push_back(weight); - i = i == m ? 0 : i; - optimal += weight; - } - optimal /= m; - // sort processors (for convenience) - for (std::vector &processor : result) { - std::sort(processor.begin() + 1, processor.end()); - } - // ALGORITHM - // 1st step - std::vector deleted_large = {}; - std::vector deleted_small = {}; - for (std::vector &processor : result) { - auto border = processor.end(); - for (auto it = --processor.end(); it != processor.begin() + 1; --it) { - if (*(it - 1) > optimal / 2) { - deleted_large.push_back(*it); - border = it; - } else { - break; - } - } - processor.erase(border, processor.end()); - } - // 2nd step - Eigen::MatrixXi quality = Eigen::MatrixXi::Zero(m, 3); - for (const std::vector &processor : result) { - auto last_small = processor.end(); - auto last = processor.end(); - if (*(--processor.end()) > optimal / 2) { - --last_small; - } - if (processor.begin() + 1 == last_small) { - continue; - } - int a = 0; - int b = 0; - float sum_small = - std::accumulate(processor.begin() + 1, last_small, 0, std::plus()); - float sum = - std::accumulate(processor.begin() + 1, last, 0, std::plus()); - while (sum_small > optimal / 2) { - ++a; - --last_small; - sum_small -= *last_small; - } - while (sum > optimal) { - ++b; - --last; - sum -= *last; - } - quality(processor.at(0), 0) = a; - quality(processor.at(0), 1) = b; - quality(processor.at(0), 2) = a - b; - } - // 3rd step - // sort for convenience - std::vector> small_processors = {}; - std::vector> large_processors = {}; - for (const std::vector &processor : result) { - if (*(--processor.end()) > optimal / 2) { - large_processors.push_back(processor); - } else { - small_processors.push_back(processor); - } - } - auto cGreater = [&quality](std::vector a, std::vector b) { - return quality(a.at(0), 2) > quality(b.at(0), 2); - }; - sort(small_processors.begin(), small_processors.end(), cGreater); - sort(large_processors.begin(), large_processors.end(), cGreater); - result.clear(); - result.insert(result.end(), small_processors.begin(), small_processors.end()); - result.insert(result.end(), large_processors.begin(), large_processors.end()); - int numOfLarges = large_processors.size() + deleted_large.size(); - // work - auto border = numOfLarges < m ? result.end() - numOfLarges : result.begin(); - for (auto it = border; it != result.end(); ++it) { - auto last = it->end(); - if (*(last - 1) > optimal / 2) { - --last; - } - for (auto cur = last - quality(*it->begin(), 0); cur != last; ++cur) { - deleted_small.push_back(*cur); - } - it->erase(last - quality(*it->begin(), 0), last); - } - // 4th step - for (auto it = result.begin(); it != border; ++it) { - auto last = it->end(); - for (auto cur = last - quality(*it->begin(), 1); cur != last; ++cur) { - deleted_small.push_back(*cur); - } - it->erase(last - quality(*it->begin(), 1), last); - } - // 5th step - i = 0; - for (const int &weight : deleted_large) { - if (i < m - large_processors.size()) { - (result.begin() + i)->push_back(weight); - } else { - sort(result.begin(), result.end(), - [](std::vector a, std::vector b) { - return std::accumulate(a.begin(), a.end(), 0, std::plus()) < - std::accumulate(b.begin(), b.end(), 0, std::plus()); - }); - result.begin()->push_back(weight); - } - ++i; - } - // 6th step - for (const int &weight : deleted_small) { - sort(result.begin(), result.end(), - [](std::vector a, std::vector b) { - return std::accumulate(a.begin(), a.end(), 0, std::plus()) < - std::accumulate(b.begin(), b.end(), 0, std::plus()); - }); - result.begin()->push_back(weight); - } - // delete indices - for (std::vector &processor : result) { - processor.erase(processor.begin()); - } - for (int i = 0; i < processors_num - m; ++i) { - std::vector empty = {}; - result.push_back(empty); - } - return result; } -Graph GFDValidation::getSubgraph(const Graph &graph, const int &index, - const int &radius, int &out) { - Eigen::MatrixXi m = graph.getAdjacencyMatrix(); - Eigen::MatrixXi temp = m + m.transpose(); - Eigen::MatrixXi neighbours = Eigen::MatrixXi::Zero(temp.rows(), temp.cols()); - for (int i = 0; i < radius; ++i) { - Eigen::MatrixXi cur = temp; - for (int j = 0; j < i; ++j) { - cur = cur * temp; - } - neighbours += cur; - } - std::set needed_vertices = {index}; +template +struct SaveCallback { +private: + const Graph1& graph1_; + const Graph2& graph2_; + std::vector>& isos; +public: + SaveCallback(const Graph1& graph1, const Graph2& graph2, std::vector>& isos_) + : graph1_(graph1), graph2_(graph2), isos(isos_) {} + + template + bool operator()(CorrespondenceMap1To2 f, CorrespondenceMap2To1) const { + std::map iso; + BGL_FORALL_VERTICES_T(v, graph1_, Graph1) { + iso.emplace(graph1_[v].node_id, graph2_[get(f, v)].node_id); + } + isos.push_back(iso); + return true; + } +}; + +bool GFDValidation::isSatisfied(const GFD& gfd, const graph_t& graph, const std::pair& link) { + graph_t pattern = gfd.getPattern(); + + typedef boost::graph_traits::vertex_descriptor vertex_type; + typedef boost::graph_traits::edge_descriptor edge_type; + + struct VCompare { + const graph_t& pattern; + const graph_t& graph; + int pinted_fr; + int pinted_to; + + bool operator()(vertex_type fr, vertex_type to) const { + if (pattern[fr].node_id == pinted_fr && graph[to].node_id == pinted_to) { + return true; + } + if (pattern[fr].node_id == pinted_fr || graph[to].node_id == pinted_to) { + return false; + } + return pattern[fr].attributes.at("label") == graph[to].attributes.at("label"); + } + } vcompare{ pattern, graph, link.first, link.second }; - for (int i = 0; i < neighbours.rows(); ++i) { - if (neighbours(index, i) != 0) { - needed_vertices.insert(i); - } - } - - std::map vertices{}; - std::map> attributes{}; - int j = 0; - std::map isomorphism{}; - for (const int &i : needed_vertices) { - vertices.emplace(j, graph.getVertices().at(i)); - attributes.emplace(j, graph.getAttributes().at(i)); - isomorphism.emplace(i, j++); - } - std::map, std::string> edges{}; - for (const auto &edge_label : graph.getEdges()) { - std::pair edge = edge_label.first; - if ((needed_vertices.find(edge.first) != needed_vertices.end()) && - (needed_vertices.find(edge.second) != needed_vertices.end())) { - edges.emplace(std::pair(isomorphism.at(edge.first), - isomorphism.at(edge.second)), - edge_label.second); - } - } - Graph result = Graph(vertices, edges, attributes); - out = isomorphism.at(index); - return result; -} + struct ECompare { + const graph_t& pattern; + const graph_t& graph; -std::vector -GFDValidation::getCandidateVertices(const Pattern &pattern, - const std::string &label, - const std::pair °rees) { - std::vector result = {}; - Eigen::MatrixXi G = pattern.getAdjacencyMatrix(); - for (const auto &vertex_label : pattern.getVertices()) { - std::string current_label = vertex_label.second; - if (current_label != label) { - continue; - } - int index = vertex_label.first; - if ((G.row(index).sum() >= degrees.first) && - (G.col(index).sum() >= degrees.second)) { - result.push_back(index); - } - } - return result; -} + bool operator()(edge_type fr, edge_type to) const { + return pattern[fr].label == graph[to].label; + } + } ecompare{ pattern, graph }; + + std::vector> isos; + SaveCallback callback(pattern, graph, isos); + boost::vf2_subgraph_iso(pattern, graph, callback, get(boost::vertex_index, pattern), + get(boost::vertex_index, graph), vertex_order_by_mult(pattern), + ecompare, vcompare); + + auto satisfied = [&graph](const std::map& iso, + const std::vector literals) { + for (const Literal& l : literals) { + auto fst_token = l.first; + auto snd_token = l.second; + std::string fst; + std::string snd; + if (fst_token.first == -1) { + fst = fst_token.second; + } + else { + int index = iso.at(fst_token.first); + auto attrs = graph[get(boost::vertex_index, graph, index)].attributes; + if (attrs.find(fst_token.second) == attrs.end()) { + return false; + } + fst = attrs.at(fst_token.second); + } + if (snd_token.first == -1) { + snd = snd_token.second; + } + else { + int index = iso.at(snd_token.first); + auto attrs = graph[get(boost::vertex_index, graph, index)].attributes; + if (attrs.find(snd_token.second) == attrs.end()) { + return false; + } + snd = attrs.at(snd_token.second); + } + if (fst != snd) { + return false; + } + } + return true; + }; -int GFDValidation::getRadius(const Pattern &pattern, const int &index) { - Eigen::MatrixXi G = pattern.getAdjacencyMatrix(); - Eigen::MatrixXi m = G + G.transpose(); - Eigen::VectorXi result = Eigen::VectorXi::Zero(G.rows()); - result(index) = 1; - Eigen::VectorXi mask = Eigen::VectorXi(G.rows()); - mask.setConstant(1); - mask(index) = 0; - Eigen::VectorXi prev = Eigen::VectorXi(G.rows()); - prev.setConstant(1); - int answer = -1; - while (mask != prev) { - prev = mask; - result = (result.transpose() * m).transpose().cwiseProduct(mask); - // optimize? - for (int i = 0; i < G.rows(); ++i) { - if (result(i) != 0) { - mask(i) = 0; - } - } - ++answer; - } - return answer; -} + for (const std::map& iso : isos) { + if (!satisfied(iso, gfd.getPremises())) { + continue; + } -int GFDValidation::getCenter(const Pattern &pattern, int &out) { - int min = pattern.getAdjacencyMatrix().rows(); - int result = 0; - for (const int &index : pattern.getIndices()) { - int radius = getRadius(pattern, index); - if (radius <= min) { - min = radius; - result = index; + if (!satisfied(iso, gfd.getConclusion())) { + return false; + } } - } - out = min; - return result; + return true; } void GFDValidation::calculateUnsatisfied( - const std::vector> &messages, - const std::map &coded_gfds, - const std::map &coded_subgraphs, std::set &out) { - for (const auto &message : messages) { - int gfd_index = std::get<0>(message); - int subgraph_index = std::get<1>(message); - int center = std::get<2>(message); - int candidate = std::get<3>(message); - if (!isSatisfiedLinked(coded_subgraphs.at(subgraph_index), - coded_gfds.at(gfd_index), - std::pair(center, candidate))) { - out.insert(gfd_index); + const std::vector>& messages, + const std::map& coded_gfds, + const std::map& coded_subgraphs, std::set& out) { + for (const auto& message : messages) { + int gfd_index = std::get<0>(message); + int subgraph_index = std::get<1>(message); + int center = std::get<2>(message); + int candidate = std::get<3>(message); + + if (!isSatisfied(coded_gfds.at(gfd_index), + coded_subgraphs.at(subgraph_index), + std::pair(center, candidate))) { + out.insert(gfd_index); + } } - } } -std::vector GFDValidation::getSatisfiedGFDs(const Graph &graph, - const std::vector &gfds, - const int &m) { - std::vector result = {}; - std::set unsatisfied = {}; - std::map>> weighted_messages; - std::vector weights = {}; - - std::map coded_gfds; - std::map coded_subgraphs; - int i = 0; - int j = 0; - for (const GFD &gfd : gfds) { - coded_gfds.emplace(i, gfd); - - int radius = 0; - int center = getCenter(gfd.getPattern(), radius); - std::pair degrees(gfd.getPattern().getVertexDegrees()(center, 0), - gfd.getPattern().getVertexDegrees()(center, 1)); - std::vector candidate_vertices = getCandidateVertices( - graph, gfd.getPattern().getVertices().at(center), degrees); - - for (const int &candidate : candidate_vertices) { - int pin = 0; - Graph subgraph = getSubgraph(graph, candidate, radius, pin); - coded_subgraphs.emplace(j, subgraph); - std::tuple temp(i, j, center, pin); - int weight = subgraph.getSize(); - if (weighted_messages.find(weight) != weighted_messages.end()) { - weighted_messages.at(weight).push_back(temp); - } else { - std::vector> temps = {temp}; - weighted_messages.emplace(weight, temps); - } - weights.push_back(weight); - ++j; - } - ++i; - } - - std::vector> balanced_weights = balanced(weights, m); - - std::vector> answers = {}; - std::vector>> groups = {}; - for (int i = 0; i < m; ++i) { - std::set current = {}; - answers.push_back(current); - std::vector> messages = {}; - for (int &weight : balanced_weights.at(i)) { - std::tuple temp = - *(--weighted_messages.at(weight).end()); - weighted_messages.at(weight).erase(--weighted_messages.at(weight).end()); - messages.push_back(temp); - } - groups.push_back(messages); - } - std::vector threads = {}; - for (int i = 0; i < m; ++i) { - std::thread thrd(&GFDValidation::calculateUnsatisfied, this, - std::cref(groups.at(i)), std::cref(coded_gfds), - std::cref(coded_subgraphs), std::ref(answers.at(i))); - threads.push_back(std::move(thrd)); - } - for (std::thread &thrd : threads) { - if (thrd.joinable()) { - thrd.join(); +std::vector +GFDValidation::generateSatisfiedGFDs(const graph_t& graph, + const std::vector& gfds, const int& m) { + std::vector result = {}; + std::set unsatisfied = {}; + std::map>> weighted_messages; + std::vector weights = {}; + + std::map coded_gfds; + std::map coded_subgraphs; + int i = 0; + int j = 0; + for (const GFD& gfd : gfds) { + coded_gfds.emplace(i, gfd); + + graph_t pattern = gfd.getPattern(); + int radius = 0; + vertex_t center = getCenter(pattern, radius); + + std::pair degrees(boost::out_degree(center, pattern), + boost::in_degree(center, pattern)); + std::vector candidate_vertices = getCandidateVertices( + graph, pattern[center].attributes.at("label"), degrees); + + for (const int& candidate : candidate_vertices) { + int pin = 0; + graph_t subgraph = getSubgraph(graph, candidate, radius, pin); + coded_subgraphs.emplace(j, subgraph); + std::tuple temp(i, j, pattern[center].node_id, pin); + int weight = boost::num_vertices(subgraph) + boost::num_edges(subgraph); + if (weighted_messages.find(weight) != weighted_messages.end()) { + weighted_messages.at(weight).push_back(temp); + } + else { + std::vector> temps = { temp }; + weighted_messages.emplace(weight, temps); + } + weights.push_back(weight); + ++j; + } + ++i; + } + ToNextProgressPhase(); + + std::vector> balanced_weights = Balancer::balance(weights, m); + ToNextProgressPhase(); + + std::vector> answers = {}; + std::vector>> groups = {}; + for (int i = 0; i < m; ++i) { + std::set current = {}; + answers.push_back(current); + std::vector> messages = {}; + for (int& weight : balanced_weights.at(i)) { + std::tuple temp = + *(--weighted_messages.at(weight).end()); + weighted_messages.at(weight).erase(--weighted_messages.at(weight).end()); + messages.push_back(temp); + } + groups.push_back(messages); + } + std::vector threads = {}; + for (int i = 0; i < m; ++i) { + std::thread thrd(&GFDValidation::calculateUnsatisfied, this, + std::cref(groups.at(i)), std::cref(coded_gfds), + std::cref(coded_subgraphs), std::ref(answers.at(i))); + threads.push_back(std::move(thrd)); + } + for (std::thread& thrd : threads) { + if (thrd.joinable()) { + thrd.join(); + } } - } - for (const std::set &answer : answers) { - // optimize? - for (const int &gfd_index : answer) { - unsatisfied.insert(gfd_index); + ToNextProgressPhase(); + for (const std::set& answer : answers) { + // optimize? + for (const int& gfd_index : answer) { + unsatisfied.insert(gfd_index); + } } - } - for (int i = 0; i < gfds.size(); ++i) { - if (unsatisfied.find(i) == unsatisfied.end()) { - result.push_back(coded_gfds.at(i)); + for (int i = 0; i < gfds.size(); ++i) { + if (unsatisfied.find(i) == unsatisfied.end()) { + result.push_back(coded_gfds.at(i)); + } } - } - return result; + return result; } unsigned long long GFDValidation::ExecuteInternal() { auto start_time = std::chrono::system_clock::now(); - this->result = this->getSatisfiedGFDs(this->graph, this->gfds, - std::thread::hardware_concurrency()); + this->result = this->generateSatisfiedGFDs(this->graph, this->gfds, + std::thread::hardware_concurrency()); auto elapsed_milliseconds = std::chrono::duration_cast( diff --git a/src/algorithms/gfd/gfd_validation.h b/src/algorithms/gfd/gfd_validation.h index 4fe925f909..f1bae2862c 100644 --- a/src/algorithms/gfd/gfd_validation.h +++ b/src/algorithms/gfd/gfd_validation.h @@ -3,47 +3,49 @@ #include "algorithms/primitive.h" #include "gfd.h" -#include "graph.h" #include "parser.h" namespace algos { class GFDValidation : public Primitive { private: - Graph graph; - std::vector gfds; - std::vector result; - - Eigen::MatrixXi convert(const Eigen::VectorXi &, const int &); - bool isSubgraph(const Pattern &, const Pattern &, const Eigen::MatrixXi &); - std::vector getCandidateMatches(const Pattern &, - const Pattern &, - const std::pair &); - std::vector getMatches(const Pattern &, const Pattern &, - const std::pair &); - bool satisfied(const Graph &, const Eigen::VectorXi &, - const std::vector &); - bool isSatisfiedLinked(const Graph &, const GFD &, - const std::pair &); - std::vector> balanced(const std::vector &, const int &); - Graph getSubgraph(const Graph &, const int &, const int &, int &); - std::vector getCandidateVertices(const Pattern &, const std::string &, - const std::pair &); - int getRadius(const Pattern &, const int &); - int getCenter(const Pattern &, int &); - void calculateUnsatisfied(const std::vector> &, - const std::map &, - const std::map &, std::set &); - std::vector getSatisfiedGFDs(const Graph &, const std::vector &, - const int &); - - void FitInternal(model::IDatasetStream& data_stream); - unsigned long long ExecuteInternal(); + graph_t graph; + std::vector gfds; + std::vector result; + + template + bool all_shortest_paths(const graph_type& pattern, DistancesMatrix& dm); + template + typename boost::graph_traits::vertex_descriptor + getCenter(const graph_type& pattern, int& out); + template + graph_type getSubgraph(const graph_type& graph, const int& index, + const int& radius, int& pin); + template + std::vector getCandidateVertices(const graph_type& graph, + const std::string& label, + const std::pair& degrees); + bool isSatisfied(const GFD& gfd, const graph_t& graph, + const std::pair& link); + void calculateUnsatisfied( + const std::vector>& messages, + const std::map& coded_gfds, + const std::map& coded_subgraphs, std::set& out); + + void FitInternal(model::IDatasetStream& data_stream); + unsigned long long ExecuteInternal(); + std::vector generateSatisfiedGFDs(const graph_t& graph, + const std::vector& gfds, + const int& m = 1); public: - GFDValidation() : Primitive({}) {}; - GFDValidation(Graph graph_, std::vector gfds_) - : Primitive({}), graph(graph_), gfds(gfds_) { ExecutePrepare(); } - std::vector GFDList() { return this->result; } + GFDValidation() : Primitive({}) {}; + GFDValidation(graph_t graph_, std::vector gfds_) + : Primitive({"Message generation", "Load balancing", "Validation", "Result calculation"}), + graph(graph_), gfds(gfds_) { ExecutePrepare(); } + + std::vector GFDList() { return this->result; } + void setGraph(graph_t graph_) { graph = graph_; }; + void setGFDs(std::vector gfds_) { gfds = gfds_; }; }; } // namespace algos diff --git a/src/algorithms/gfd/graph.cpp b/src/algorithms/gfd/graph.cpp deleted file mode 100644 index 8b00f05f23..0000000000 --- a/src/algorithms/gfd/graph.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include - -#include "graph.h" - -void Graph::print() const { - Pattern::print(); - std::cout << std::endl << "Attributes:"; - for (const auto &attr : this->attributes) { - std::cout << std::endl << attr.first << " -> "; - for (const auto &value : attr.second) { - std::cout << value.first << ":" << value.second << "; "; - } - } -} diff --git a/src/algorithms/gfd/graph.h b/src/algorithms/gfd/graph.h deleted file mode 100644 index 408915568a..0000000000 --- a/src/algorithms/gfd/graph.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include -#include -#include -#include - -#include "pattern.h" - -class Graph : public Pattern { -private: - std::map> attributes; - -public: - Graph() {}; - Graph(const std::map &vertices_, - const std::map, std::string> &edges_, - const std::map> - &attributes_) noexcept(false) - : Pattern(vertices_, edges_) { - this->attributes = attributes_; - } - - std::map> getAttributes() const { - return this->attributes; - } - - void print() const; -}; diff --git a/src/algorithms/gfd/graph_descriptor.h b/src/algorithms/gfd/graph_descriptor.h new file mode 100644 index 0000000000..bb3f735985 --- /dev/null +++ b/src/algorithms/gfd/graph_descriptor.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include +#include + +struct vertex { + int node_id; + std::map attributes; +}; + +struct edge { + std::string label; +}; + +typedef boost::adjacency_list graph_t; +typedef boost::graph_traits::vertex_descriptor vertex_t; +typedef boost::graph_traits::edge_descriptor edge_t; \ No newline at end of file diff --git a/src/algorithms/gfd/parser.cpp b/src/algorithms/gfd/parser.cpp index cf2b754e13..d077b912a6 100644 --- a/src/algorithms/gfd/parser.cpp +++ b/src/algorithms/gfd/parser.cpp @@ -1,117 +1,172 @@ +#include +#include +#include +#include +#include +// #include +// #include +// #include +// #include "/usr/local/lib/libboost_graph.so" + +// #include "/home/anton/boost_1_72_0/libs/graph/src/read_graphviz_new.cpp" +// #include "/home/anton/boost_1_72_0/libs/graph/src/read_graphviz_new.cpp" +// #include "/usr/local/include/boost/graph/detail/read_graphviz_new.cpp" + #include "parser.h" namespace GFDtools { -std::vector Parser::split(std::string str, std::string sep) { - std::vector result = {}; - if (str.empty()) { - return result; - } - size_t pos = 0; - while ((pos = str.find(sep)) != std::string::npos) { - result.push_back(str.substr(0, pos)); - str.erase(0, pos + sep.length()); - } - result.push_back(str); - return result; -} +typedef boost::property_map vertex::*>::type AMap; +typedef boost::property_map::type RMap; + +namespace { + template + struct NewAttr { + typedef boost::shared_ptr Ptr; + private: + template + static Ptr make_dyn(PMap m) { + typedef boost::detail::dynamic_property_map_adaptor DM; + boost::shared_ptr sp = boost::make_shared(m); + return boost::static_pointer_cast(sp); + } + public: + AMap attrs; + + NewAttr(AMap a) : attrs(a) {} + + Ptr operator()(std::string const& name, boost::any const& descr, + boost::any const&) const { + if (typeid(vertex_t) == descr.type()) + return make_dyn(boost::make_function_property_map( + boost::bind(*this, boost::placeholders::_1, name))); + + return Ptr(); + }; -std::vector Parser::parse_literals(std::istream &stream) { - std::vector result = {}; - - std::string line; - std::getline(stream, line); - line = line.substr(0, line.find("\r")).substr(0, line.find("\n")); - auto tokens = Parser::split(line, " "); - for (auto token : tokens) { - auto custom_names = Parser::split(token, "="); - auto names1 = Parser::split(custom_names.at(0), "."); - int index1 = names1.size() == 1 ? -1 : stoi(names1.at(0)); - std::string name1 = *(--names1.end()); - Token t1(index1, name1); - - auto names2 = Parser::split(custom_names.at(1), "."); - int index2 = names2.size() == 1 ? -1 : stoi(names2.at(0)); - std::string name2 = *(--names2.end()); - Token t2(index2, name2); - - result.push_back(Literal(t1, t2)); - } - - return result; + typedef std::string& result_type; + std::string& operator()(vertex_t v, std::string const& name) const { + return attrs[v][name]; + } + }; } -GFD Parser::parse_gfd(std::istream &stream) { - std::map vertices; - std::map, std::string> edges; +void Parser::read_graph(std::istream& stream, graph_t& result) { + NewAttr newattr(get(&vertex::attributes, result)); - std::string line; - std::getline(stream, line); - auto sizes = Parser::split(line, " "); - size_t vertices_num = stoi(sizes.at(0)); - size_t edges_num = stoi(sizes.at(1)); - for (int i = 0; i < vertices_num; ++i) { - std::getline(stream, line); - int index = stoi(line.substr(0, line.find("["))); - line = line.substr(line.find("[") + 1, line.find("]") - line.find("[") - 1); - auto names = Parser::split(line, "="); - vertices.emplace(index, names.at(1)); - } - for (int i = 0; i < edges_num; ++i) { - std::getline(stream, line); - auto indices = Parser::split(line.substr(0, line.find("[")), "->"); - int index1 = stoi(indices.at(0)); - int index2 = stoi(indices.at(1)); - line = line.substr(line.find("[") + 1, line.find("]") - line.find("[") - 1); - auto names = Parser::split(line, "="); - edges.emplace(std::pair(index1, index2), names.at(1)); - } - std::vector premises = Parser::parse_literals(stream); - std::vector conclusion = Parser::parse_literals(stream); - - Pattern pat = Pattern(vertices, edges); - GFD gfd = GFD(pat, premises, conclusion); - return gfd; + boost::dynamic_properties dp(newattr); + dp.property("label", get(&edge::label, result)); + dp.property("node_id", get(&vertex::node_id, result)); + read_graphviz(stream, result, dp); +}; + +void Parser::read_graph(std::string file_name, graph_t& result) { + std::ifstream f(file_name); + Parser::read_graph(f, result); + f.close(); +}; + +void Parser::write_graph(std::ostream& stream, graph_t& result) { + boost::attributes_writer vw(get(&vertex::attributes, result)); + boost::label_writer ew(get(&edge::label, result)); + write_graphviz(stream, result, vw, ew); +}; + +void Parser::write_graph(std::string file_name, graph_t& result) { + std::ofstream f(file_name); + Parser::write_graph(f, result); + f.close(); +}; + +std::vector Parser::split(std::string str, std::string sep) { + std::vector result = {}; + if (str == "") { + return result; + } + size_t pos = 0; + while ((pos = str.find(sep)) != std::string::npos) { + result.push_back(str.substr(0, pos)); + str.erase(0, pos + sep.length()); + } + result.push_back(str); + return result; } -Graph Parser::parse_graph(std::istream &stream) { - std::map vertices; - std::map, std::string> edges; - std::map> attributes; - - std::string line; - std::getline(stream, line); - auto sizes = Parser::split(line, " "); - size_t vertices_num = stoi(sizes.at(0)); - size_t edges_num = stoi(sizes.at(1)); - for (int i = 0; i < vertices_num; ++i) { - std::map attrs; +std::vector Parser::parse_literals(std::istream& stream) { + std::vector result = {}; + + std::string line; std::getline(stream, line); - int index = stoi(line.substr(0, line.find("["))); - line = line.substr(line.find("[") + 1, line.find("]") - line.find("[") - 1); + boost::algorithm::trim(line); auto tokens = Parser::split(line, " "); for (auto token : tokens) { - auto names = Parser::split(token, "="); - std::string fst = names.at(0); - std::string snd = names.at(1); - if (fst == "label") { - vertices.emplace(index, snd); - } else { - attrs.emplace(fst, snd); - } + auto custom_names = Parser::split(token, "="); + auto names1 = Parser::split(custom_names.at(0), "."); + int index1 = names1.size() == 1 ? -1 : stoi(names1.at(0)); + std::string name1 = *(--names1.end()); + Token t1(index1, name1); + + auto names2 = Parser::split(custom_names.at(1), "."); + int index2 = names2.size() == 1 ? -1 : stoi(names2.at(0)); + std::string name2 = *(--names2.end()); + Token t2(index2, name2); + + result.push_back(Literal(t1, t2)); } - attributes.emplace(index, attrs); - } - for (int i = 0; i < edges_num; ++i) { - std::getline(stream, line); - auto indices = Parser::split(line.substr(0, line.find("[")), "->"); - int index1 = stoi(indices.at(0)); - int index2 = stoi(indices.at(1)); - line = line.substr(line.find("[") + 1, line.find("]") - line.find("[") - 1); - auto names = Parser::split(line, "="); - edges.emplace(std::pair(index1, index2), names.at(1)); - } - return Graph(vertices, edges, attributes); + + return result; } +void Parser::write_literals(std::ostream& stream, const std::vector& literals) { + for (const Literal& l : literals) { + std::string token; + + Token fst_token = l.first; + token = fst_token.first == -1 ? "" : (std::to_string(fst_token.first) + "."); + token += fst_token.second; + stream << token; + + stream << "="; + + Token snd_token = l.second; + token = snd_token.first == -1 ? "" : (std::to_string(snd_token.first) + "."); + token += snd_token.second; + stream << token; + + stream << " "; + } + stream << std::endl; } + +void Parser::read_gfd(std::istream& stream, GFD& result) { + std::vector premises = Parser::parse_literals(stream); + std::vector conclusion = Parser::parse_literals(stream); + graph_t pattern; + read_graph(stream, pattern); + result.setPattern(pattern); + result.setPremises(premises); + result.setConclusion(conclusion); +}; + +void Parser::read_gfd(std::string file_name, GFD& result) { + std::ifstream f(file_name); + Parser::read_gfd(f, result); + f.close(); +}; + +void Parser::write_gfd(std::ostream& stream, GFD& result) { + write_literals(stream, result.getPremises()); + write_literals(stream, result.getConclusion()); + graph_t pattern = result.getPattern(); + write_graph(stream, pattern); +}; + +void Parser::write_gfd(std::string file_name, GFD& result) { + std::ofstream f(file_name); + Parser::write_gfd(f, result); + f.close(); +}; + +} // namespace GFDtools diff --git a/src/algorithms/gfd/parser.h b/src/algorithms/gfd/parser.h index d4156f0a48..d82319d55e 100644 --- a/src/algorithms/gfd/parser.h +++ b/src/algorithms/gfd/parser.h @@ -1,20 +1,30 @@ #pragma once -#include -#include +#include +#include +#include #include "gfd.h" -#include "graph.h" +#include "graph_descriptor.h" namespace GFDtools { class Parser { private: - static std::vector split(std::string, std::string); - static std::vector parse_literals(std::istream &); - + static std::vector split(std::string str, std::string sep); + static std::vector parse_literals(std::istream& stream); + static void write_literals(std::ostream& stream, const std::vector&); public: - static GFD parse_gfd(std::istream &); - static Graph parse_graph(std::istream &); + static void read_graph(std::istream& stream, graph_t& result); + static void read_graph(std::string file_name, graph_t& result); + + static void write_graph(std::ostream& stream, graph_t& result); + static void write_graph(std::string file_name, graph_t& result); + + static void read_gfd(std::istream& stream, GFD& result); + static void read_gfd(std::string file_name, GFD& result); + + static void write_gfd(std::ostream& stream, GFD& result); + static void write_gfd(std::string file_name, GFD& result); }; -} +} // namespace GFDtools diff --git a/src/algorithms/gfd/pattern.cpp b/src/algorithms/gfd/pattern.cpp deleted file mode 100644 index 6591982762..0000000000 --- a/src/algorithms/gfd/pattern.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include - -#include "pattern.h" - -Pattern::Pattern( - const std::map &vertices_, - const std::map, std::string> &edges_) noexcept(false) { - int max = 0; - for (auto node : vertices_) { - int index = node.first; - this->indices.insert(index); - max = max < index ? index : max; - } - if (max != this->indices.size() - 1) { - throw std::out_of_range("index mismatch"); - } - this->vertices = vertices_; - this->edges = edges_; - - this->adjacencyMatrix = - Eigen::MatrixXi::Zero(this->indices.size(), this->indices.size()); - for (auto edge_label : this->edges) { - std::pair edge = edge_label.first; - this->adjacencyMatrix(edge.first, edge.second) = 1; - } - this->degrees = Eigen::MatrixXi::Zero(this->adjacencyMatrix.rows(), 2); - for (int i = 0; i < this->adjacencyMatrix.rows(); ++i) { - this->degrees(i, 0) = this->adjacencyMatrix.row(i).sum(); - this->degrees(i, 1) = this->adjacencyMatrix.col(i).sum(); - } - this->vertexNum = this->vertices.size(); - this->size = vertexNum + this->edges.size(); -} - -bool Pattern::operator==(const Pattern &other) const { - if (this->vertexNum != other.getVertexNum()) { - return false; - } - if (this->size != other.getSize()) { - return false; - } - Eigen::MatrixXi other_degrees = other.getVertexDegrees(); - Eigen::VectorXi check_out = Eigen::VectorXi::Zero(this->vertexNum); - Eigen::VectorXi isomorphism = Eigen::VectorXi::Zero(this->vertexNum); - for (int i = 0; i < this->vertexNum; ++i) { - for (int j = 0; j < this->vertexNum; ++j) { - if (this->degrees.row(i) == other_degrees.row(j) && !check_out(j)) { - check_out(j) = 1; - isomorphism(i) = j; - break; - } - } - } - if (check_out.sum() != this->vertexNum) { - return false; - } - Eigen::MatrixXi match = - Eigen::MatrixXi::Zero(this->vertexNum, this->vertexNum); - for (int i = 0; i < this->vertexNum; ++i) { - match(i, isomorphism(i)) = 1; - } - Eigen::MatrixXi Q = this->adjacencyMatrix; - Eigen::MatrixXi G = other.getAdjacencyMatrix(); - if ((match * (match * G).transpose()).transpose().cwiseProduct(Q) != Q) { - return false; - } - Eigen::VectorXi mask = Eigen::VectorXi::Zero(G.rows()); - for (int i = 0; i < G.rows(); ++i) { - mask(i) = i; - } - for (const auto &edge_label : this->edges) { - std::pair edge = edge_label.first; - Eigen::VectorXi index1 = Eigen::VectorXi::Zero(Q.rows()); - index1(edge.first) = 1; - int i = mask.cwiseProduct((index1.transpose() * match).transpose()).sum(); - Eigen::VectorXi index2 = Eigen::VectorXi::Zero(Q.rows()); - index2(edge.second) = 1; - int j = mask.cwiseProduct((index2.transpose() * match).transpose()).sum(); - if (edge_label.second != other.getEdges().at(std::pair(i, j))) { - return false; - } - } - return true; -} - -bool Pattern::operator!=(const Pattern &other) const { - return !(*this == other); -} - -void Pattern::print() const { - std::cout << "Adjacency matrix:" << std::endl - << this->adjacencyMatrix << std::endl; - std::cout << "Vertex labels:" << std::endl; - for (const auto &node : this->vertices) { - std::cout << node.first << ":" << node.second << "; "; - } - std::cout << std::endl << "Edge labels:" << std::endl; - for (const auto &edge_label : this->edges) { - auto edge = edge_label.first; - std::cout << "(" << edge.first << "," << edge.second - << "):" << edge_label.second << "; "; - } -} diff --git a/src/algorithms/gfd/pattern.h b/src/algorithms/gfd/pattern.h deleted file mode 100644 index 7b280faccf..0000000000 --- a/src/algorithms/gfd/pattern.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once -#include -#include -#include -#include - -class Pattern { -protected: - std::set indices; - std::map vertices; - std::map, std::string> edges; - - Eigen::MatrixXi adjacencyMatrix; - Eigen::MatrixXi degrees; - int size; - int vertexNum; - -public: - Pattern() = default; - Pattern(const std::map &, - const std::map, std::string> &) noexcept(false); - - bool operator==(const Pattern &) const; - bool operator!=(const Pattern &) const; - - std::set getIndices() const { return this->indices; } - std::map getVertices() const { return this->vertices; } - std::map, std::string> getEdges() const { - return this->edges; - } - Eigen::MatrixXi getAdjacencyMatrix() const { return this->adjacencyMatrix; } - Eigen::MatrixXi getVertexDegrees() const { return this->degrees; } - int getSize() const { return this->size; } - int getVertexNum() const { return this->vertexNum; } - - void print() const; -}; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7b5f24a010..1494c51b78 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -10,7 +10,7 @@ add_test(NAME ${BINARY} COMMAND ${BINARY}) # linking with gtest and implemented classes target_link_libraries(${BINARY} PUBLIC ${CMAKE_PROJECT_NAME}_lib) -target_link_libraries(${BINARY} LINK_PUBLIC gtest gmock Boost::thread easyloggingpp) +target_link_libraries(${BINARY} LINK_PUBLIC gtest gmock Boost::thread easyloggingpp Boost::graph) # copying sample csv's for testing add_custom_target(copy-files ALL diff --git a/tests/input_data/graph_data/directors.dot b/tests/input_data/graph_data/directors.dot new file mode 100644 index 0000000000..14f64909fc --- /dev/null +++ b/tests/input_data/graph_data/directors.dot @@ -0,0 +1,23 @@ +digraph G { +0[label="person" name="James Cameron" celebrity="high"]; +1[label="film" name="Avatar" success="high" year="2009"]; +2[label="film" name="Titanic" success="high" year="1997"]; +3[label="film" name="Piranha II" success="low" year="1981"]; +4[label="film" name="Terminator" success="high" year="1984"]; +5[label="person" name="Robert Zemeckis" celebrity="high"]; +6[label="film" name="The Walk" success="high" year="2015"]; +7[label="film" name="Back to the future" success="high" year="1985"]; +8[label="film" name="Forrest Gump" success="high" year="1994"]; +9[label="person" name="James Toback" celebrity="low"]; +10[label="film" name="Tyson" success="high" year="2008"]; +11[label="film" name="Fingers" success="high" year="1978"]; +0->1 [label="directed"]; +0->2 [label="directed"]; +0->3 [label="directed"]; +0->4 [label="directed"]; +5->6 [label="directed"]; +5->7 [label="directed"]; +5->8 [label="directed"]; +9->10 [label="directed"]; +9->11 [label="directed"]; +} \ No newline at end of file diff --git a/tests/input_data/graph_data/directors.txt b/tests/input_data/graph_data/directors.txt deleted file mode 100644 index ac66fff9cf..0000000000 --- a/tests/input_data/graph_data/directors.txt +++ /dev/null @@ -1,22 +0,0 @@ -12 9 -0[label=person name=James_Cameron celebrity=high]; -1[label=film name=Avatar success=high year=2009]; -2[label=film name=Titanic success=high year=1997]; -3[label=film name=Piranha_II success= year=1981]; -4[label=film name=Terminator success=high year=1984]; -5[label=person name=Robert_Zemeckis celebrity=high]; -6[label=film name=The_Walk success=high year=2015]; -7[label=film name=Back_to_the_future success=high year=1985]; -8[label=film name=Forrest_Gump success=high year=1994]; -9[label=person name=James_Toback celebrity=low]; -10[label=film name=Tyson success=high year=2008]; -11[label=film name=Fingers success=high year=1978]; -0->1[label=directed]; -0->2[label=directed]; -0->3[label=directed]; -0->4[label=directed]; -5->6[label=directed]; -5->7[label=directed]; -5->8[label=directed]; -9->10[label=directed]; -9->11[label=directed]; \ No newline at end of file diff --git a/tests/input_data/graph_data/directors_gfd.dot b/tests/input_data/graph_data/directors_gfd.dot new file mode 100644 index 0000000000..6ce545ec3c --- /dev/null +++ b/tests/input_data/graph_data/directors_gfd.dot @@ -0,0 +1,7 @@ +0.celebrity=high +1.success=high +digraph G { +0[label=person]; +1[label=film]; +0->1 [label=directed]; +} \ No newline at end of file diff --git a/tests/input_data/graph_data/directors_gfd.txt b/tests/input_data/graph_data/directors_gfd.txt deleted file mode 100644 index da25926c19..0000000000 --- a/tests/input_data/graph_data/directors_gfd.txt +++ /dev/null @@ -1,6 +0,0 @@ -2 1 -0[label=person]; -1[label=film]; -0->1[label=directed]; -0.celebrity=high -1.success=high \ No newline at end of file diff --git a/tests/input_data/graph_data/family_tree.txt b/tests/input_data/graph_data/family_tree.dot similarity index 70% rename from tests/input_data/graph_data/family_tree.txt rename to tests/input_data/graph_data/family_tree.dot index 066ff382d4..b94a04efc9 100644 --- a/tests/input_data/graph_data/family_tree.txt +++ b/tests/input_data/graph_data/family_tree.dot @@ -1,4 +1,4 @@ -10 12 +digraph G { 0[label=person name=Milana eyes=brown body_type=mesomorph]; 1[label=person name=Kirill eyes=brown body_type=ectomorph]; 2[label=person name=Ksenia eyes=brown body_type=endomorph]; @@ -9,15 +9,16 @@ 7[label=person name=Geralt eyes=blue body_type=mesomorph]; 8[label=person name=Maksim eyes=green body_type=ectomorph]; 9[label=person name=Matvey eyes=brown body_type=ectomorph]; -4->0[label=mom]; -4->1[label=dad]; -5->0[label=mom]; -5->1[label=dad]; -6->2[label=mom]; -6->3[label=dad]; -7->2[label=mom]; -7->3[label=dad]; -8->5[label=mom]; -8->6[label=dad]; -9->5[label=mom]; -9->6[label=dad]; \ No newline at end of file +4->0 [label=mom]; +4->1 [label=dad]; +5->0 [label=mom]; +5->1 [label=dad]; +6->2 [label=mom]; +6->3 [label=dad]; +7->2 [label=mom]; +7->3 [label=dad]; +8->5 [label=mom]; +8->6 [label=dad]; +9->5 [label=mom]; +9->6 [label=dad]; +} \ No newline at end of file diff --git a/tests/input_data/graph_data/family_tree_gfd1.dot b/tests/input_data/graph_data/family_tree_gfd1.dot new file mode 100644 index 0000000000..dae9ffee37 --- /dev/null +++ b/tests/input_data/graph_data/family_tree_gfd1.dot @@ -0,0 +1,7 @@ +1.eyes=brown +0.eyes=brown +digraph G { +0[label=person]; +1[label=person]; +0->1 [label=mom]; +} \ No newline at end of file diff --git a/tests/input_data/graph_data/family_tree_gfd1.txt b/tests/input_data/graph_data/family_tree_gfd1.txt deleted file mode 100644 index 0c5fa70deb..0000000000 --- a/tests/input_data/graph_data/family_tree_gfd1.txt +++ /dev/null @@ -1,6 +0,0 @@ -2 1 -0[label=person]; -1[label=person]; -0->1[label=mom]; -1.eyes=brown -0.eyes=brown \ No newline at end of file diff --git a/tests/input_data/graph_data/family_tree_gfd2.txt b/tests/input_data/graph_data/family_tree_gfd2.dot similarity index 52% rename from tests/input_data/graph_data/family_tree_gfd2.txt rename to tests/input_data/graph_data/family_tree_gfd2.dot index 5acb717084..f59f8674dc 100644 --- a/tests/input_data/graph_data/family_tree_gfd2.txt +++ b/tests/input_data/graph_data/family_tree_gfd2.dot @@ -1,8 +1,9 @@ -3 2 +1.eyes=brown 2.eyes=brown +0.eyes=brown +digraph G { 0[label=person]; 1[label=person]; 2[label=person]; -0->1[label=mom]; -0->2[label=dad]; -1.eyes=brown 2.eyes=brown -0.eyes=brown \ No newline at end of file +0->1 [label=mom]; +0->2 [label=dad]; +} \ No newline at end of file diff --git a/tests/input_data/graph_data/family_tree_gfd3.txt b/tests/input_data/graph_data/family_tree_gfd3.dot similarity index 57% rename from tests/input_data/graph_data/family_tree_gfd3.txt rename to tests/input_data/graph_data/family_tree_gfd3.dot index 240d9cd7b4..339b003cee 100644 --- a/tests/input_data/graph_data/family_tree_gfd3.txt +++ b/tests/input_data/graph_data/family_tree_gfd3.dot @@ -1,8 +1,9 @@ -3 2 + +2.body_type=0.body_type +digraph G { 0[label=person]; 1[label=person]; 2[label=person]; -0->1[label=mom]; -1->2[label=dad]; - -2.body_type=0.body_type +0->1 [label=mom]; +1->2 [label=dad]; +} \ No newline at end of file diff --git a/tests/input_data/graph_data/quadrangle.txt b/tests/input_data/graph_data/quadrangle.dot similarity index 58% rename from tests/input_data/graph_data/quadrangle.txt rename to tests/input_data/graph_data/quadrangle.dot index 551f6fc280..45c9179be4 100644 --- a/tests/input_data/graph_data/quadrangle.txt +++ b/tests/input_data/graph_data/quadrangle.dot @@ -1,13 +1,14 @@ -6 6 +digraph G { 0[label=quadrilateral angles=arbitrary sides=arbitrary]; 1[label=parallelogram angles=pairwise_equal sides=pairwise_equal]; 2[label=trapezoid angles=arbitrary sides=parallel_and_arbitrary]; 3[label=rectangle angles=equal sides=pairwise_equal]; 4[label=rhombus angles=pairwise_equal sides=equal]; 5[label=square angles=equal sides=equal]; -0->1[label=two_pairs_of_parallel_sides]; -0->2[label=one_pair_of_parallel_sides]; -1->3[label=equality_of_angles]; -1->4[label=equality_of_sides]; -3->5[label=equality_of_sides]; -4->5[label=equality_of_angles]; \ No newline at end of file +0->1 [label=two_pairs_of_parallel_sides]; +0->2 [label=one_pair_of_parallel_sides]; +1->3 [label=equality_of_angles]; +1->4 [label=equality_of_sides]; +3->5 [label=equality_of_sides]; +4->5 [label=equality_of_angles]; +} \ No newline at end of file diff --git a/tests/input_data/graph_data/quadrangle_gfd.dot b/tests/input_data/graph_data/quadrangle_gfd.dot new file mode 100644 index 0000000000..2ba89a61f9 --- /dev/null +++ b/tests/input_data/graph_data/quadrangle_gfd.dot @@ -0,0 +1,7 @@ + +0.sides=1.sides +digraph G { +0[label=polygon]; +1[label=triangle]; +0->1 [label=three_sides]; +} \ No newline at end of file diff --git a/tests/input_data/graph_data/quadrangle_gfd.txt b/tests/input_data/graph_data/quadrangle_gfd.txt deleted file mode 100644 index b20099b63c..0000000000 --- a/tests/input_data/graph_data/quadrangle_gfd.txt +++ /dev/null @@ -1,6 +0,0 @@ -2 1 -0[label=polygon]; -1[label=triangle]; -0->1[label=three_sides]; - -0.sides=1.sides \ No newline at end of file diff --git a/tests/test_gfd_validation.cpp b/tests/test_gfd_validation.cpp index 083040d10e..2ba17b9ee4 100644 --- a/tests/test_gfd_validation.cpp +++ b/tests/test_gfd_validation.cpp @@ -4,24 +4,25 @@ #include #include "algorithms/gfd/gfd_validation.h" -#include "algorithms/gfd/pattern.h" #include "algorithms/gfd/parser.h" -using edge = std::pair; -using attr = std::map; -using field = std::pair; +// using edge = std::pair; +// using attr = std::map; +// using field = std::pair; using namespace GFDtools; auto current_path = std::filesystem::current_path() / "input_data" / "graph_data"; TEST(GFDValidationTest, TestTrivially) { - auto graph_path = current_path / "quadrangle.txt"; + auto graph_path = current_path / "quadrangle.dot"; std::ifstream f; f.open(graph_path); - Graph quadrilaterals = Parser::parse_graph(f); + graph_t quadrilaterals; + Parser::read_graph(f, quadrilaterals); f.close(); - auto gfd_path = current_path / "family_tree_gfd3.txt"; + auto gfd_path = current_path / "family_tree_gfd3.dot"; f.open(gfd_path); - GFD gfd = Parser::parse_gfd(f); + GFD gfd = GFD(); + Parser::read_gfd(f, gfd); f.close(); int expected_size = 1; @@ -31,18 +32,19 @@ TEST(GFDValidationTest, TestTrivially) { std::vector GFDList = algorithm.GFDList(); EXPECT_EQ(expected_size, GFDList.size()); - EXPECT_EQ(gfd.getPattern(), GFDList.at(0).getPattern()); } TEST(GFDValidationTest, TestExistingMatches0) { - auto graph_path = current_path / "directors.txt"; + auto graph_path = current_path / "directors.dot"; std::ifstream f; f.open(graph_path); - Graph directors = Parser::parse_graph(f); + graph_t directors; + Parser::read_graph(f, directors); f.close(); - auto gfd_path = current_path / "directors_gfd.txt"; + auto gfd_path = current_path / "directors_gfd.dot"; f.open(gfd_path); - GFD connection_director_film = Parser::parse_gfd(f); + GFD connection_director_film = GFD(); + Parser::read_gfd(f, connection_director_film); f.close(); int expected_size = 0; @@ -57,21 +59,25 @@ TEST(GFDValidationTest, TestExistingMatches0) { TEST(GFDValidationTest, TestExistingMatches1) { std::ifstream f; - auto graph_path = current_path / "family_tree.txt"; + auto graph_path = current_path / "family_tree.dot"; f.open(graph_path); - Graph family = Parser::parse_graph(f); + graph_t family; + Parser::read_graph(f, family); f.close(); - auto gfd_path1 = current_path / "family_tree_gfd1.txt"; + auto gfd_path1 = current_path / "family_tree_gfd1.dot"; f.open(gfd_path1); - GFD eyes_simple = Parser::parse_gfd(f); + GFD eyes_simple = GFD(); + Parser::read_gfd(f, eyes_simple); f.close(); - auto gfd_path2 = current_path / "family_tree_gfd2.txt"; + auto gfd_path2 = current_path / "family_tree_gfd2.dot"; f.open(gfd_path2); - GFD eyes_complex = Parser::parse_gfd(f); + GFD eyes_complex = GFD(); + Parser::read_gfd(f, eyes_complex); f.close(); - auto gfd_path3 = current_path / "family_tree_gfd3.txt"; + auto gfd_path3 = current_path / "family_tree_gfd3.dot"; f.open(gfd_path3); - GFD body_types = Parser::parse_gfd(f); + GFD body_types = GFD(); + Parser::read_gfd(f, body_types); f.close(); int expected_size = 2; @@ -82,15 +88,9 @@ TEST(GFDValidationTest, TestExistingMatches1) { std::vector GFDList = algorithm.GFDList(); EXPECT_EQ(expected_size, GFDList.size()); - - for (const GFD ¤t : GFDList) { - EXPECT_TRUE(current.getPattern() != eyes_simple.getPattern()); - } - EXPECT_TRUE(GFDList.begin()->getPattern() != - (++GFDList.begin())->getPattern()); - - for (const GFD ¤t : GFDList) { - EXPECT_TRUE(current.getPattern() == eyes_complex.getPattern() || - current.getPattern() == body_types.getPattern()); - } + + algorithm.setGFDs(std::vector{eyes_simple}); + algorithm.Execute(); + GFDList = algorithm.GFDList(); + EXPECT_EQ(0, GFDList.size()); }