Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ISSUE 87: vf2 algorithm refactor #185

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
88e416f
typo in graph.h on a comment about method description, I am assuming …
Sep 4, 2023
961c455
working version of the algorithm
Oct 24, 2023
51c20a2
error in interpreting the core sets for the final mapping, fixed it
Oct 24, 2023
ac10f06
added comments to the header file, need to finish adding comments for…
Oct 25, 2023
6f62549
refactoring code
Nov 3, 2023
7c41e14
added comments and formatted code according to clang-format style Google
Nov 4, 2023
6276f24
Delete include/graaflib/algorithm/.graph_isomorphism.h.swp
sracha4355 Nov 8, 2023
f8d7978
created vf2_mapping and vf2_target_sets classes for the refactor
Dec 24, 2023
208b5b1
finished translating code into classes and putting the classes togeth…
Dec 30, 2023
d31bd22
dummy commit so I can safely switch to prev branch
Dec 30, 2023
6cab701
added inital check for isomorphism function, without it large graphs …
Dec 31, 2023
b2196fc
updated tests
Jan 10, 2024
71e91f9
made newly requested pr changes
Jan 16, 2024
8169a25
Merge remote-tracking branch 'upstream/main' into vf2_refactor
Jan 16, 2024
8366090
added pr changes and created folders to mimic the wanted fil structure
Jan 16, 2024
4bc5d2c
Delete include/graaflib/algorithm/graph_isomorphism.h
sracha4355 Jan 16, 2024
019c399
Delete include/graaflib/algorithm/graph_isomorphism.tpp
sracha4355 Jan 16, 2024
03c1676
Delete include/graaflib/algorithm/graph_isomorphism_util.h
sracha4355 Jan 16, 2024
667673f
Delete include/graaflib/algorithm/graph_isomorphism_util.tpp
sracha4355 Jan 16, 2024
be8b0a9
Delete test/graaflib/algorithm/graph_isomorphism.cpp
sracha4355 Jan 16, 2024
2a876bc
Delete test/graaflib/algorithm/graph_isomorphism_test.cpp
sracha4355 Jan 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions include/graaflib/algorithm/graph_isomorphism/graph_isomorphism.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#pragma once

#include <graaflib/graph.h>
#include <graaflib/types.h>
#include <graaflib/algorithm/graph_isomorphism/graph_isomorphism_util.h>

#include <algorithm>
#include <optional>
#include <unordered_map>
#include <unordered_set>
#include <vector>




namespace graaf::algorithm {

/**
* @brief Checks if two graphs are isomorphic.
*
* This function checks whether two given graphs are isomorphic, meaning
* they are structurally identical up to vertex and edge relabeling.
* If the graphs are isomorphic, the function returns an optional containing
* a mapping from the vertices of the first graph to the vertices of the second
* graph. If the graphs are not isomorphic, the function returns std::nullopt.
*
* @tparam V The vertex type of the graphs.
* @tparam E The edge type of the graphs.
* @tparam T The graph type of the graphs (directed or undirected).
* @param lhs The first graph to compare.
* @param rhs The second graph to compare.
* @return An optional containing a mapping from the vertices of lhs to those of
* rhs if isomorphic; otherwise std::nullopt.
*/

template <typename V, typename E, graph_type T>
std::optional<std::unordered_map<vertex_id_t, vertex_id_t>> check_isomorphism(
const graph<V, E, T>& lhs, const graph<V, E, T>& rhs);
} // namespace graaf::algorithm
#include "graph_isomorphism.tpp"
52 changes: 52 additions & 0 deletions include/graaflib/algorithm/graph_isomorphism/graph_isomorphism.tpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
namespace graaf::algorithm{


template <typename V, typename E, graph_type T>
bool check_for_possibility_of_isomorphism(const graph<V,E,T>& lhs, const graph<V,E,T>& rhs){
if (lhs.vertex_count() != rhs.vertex_count() || lhs.edge_count() != rhs.edge_count())
return false;
std::vector<std::size_t> lhs_node_degrees, rhs_node_degrees;
for (const auto& vertex : lhs.get_vertices()) {
std::size_t number_of_conn = lhs.get_neighbors(vertex.first).size();
lhs_node_degrees.push_back(number_of_conn);
}
for (const auto& vertex : rhs.get_vertices()) {
std::size_t number_of_conn = rhs.get_neighbors(vertex.first).size();
rhs_node_degrees.push_back(number_of_conn);
}
std::sort(lhs_node_degrees.begin(), lhs_node_degrees.end());
std::sort(rhs_node_degrees.begin(), rhs_node_degrees.end());
return lhs_node_degrees == rhs_node_degrees;
}


template <typename V, typename E, graph_type T>
vertex_mapping generate_final_mapping(
const graph<V,E,T>& graph1,
const std::unique_ptr<vf2_information<V,E,T>>& state
){
vertex_mapping isomorphic_mapping;
for(int i = 0; i < graph1.vertex_count(); i++){
isomorphic_mapping = state -> sets -> generate_final_mapping(*(state -> mapper));
}
return isomorphic_mapping;
}

Check warning on line 33 in include/graaflib/algorithm/graph_isomorphism/graph_isomorphism.tpp

View check run for this annotation

Codecov / codecov/patch

include/graaflib/algorithm/graph_isomorphism/graph_isomorphism.tpp#L33

Added line #L33 was not covered by tests

template <typename V, typename E, graph_type T>
std::optional<std::unordered_map<vertex_id_t, vertex_id_t>> check_isomorphism(
const graph<V, E, T>& graph1,
const graph<V, E, T>& graph2
){

if(!check_for_possibility_of_isomorphism(graph1, graph2)) {
return std::nullopt;
}
std::unique_ptr<vf2_information<V,E,T>> state = std::make_unique<vf2_information<V,E,T>>(graph1, graph2);
vf2_isomorphism_feasibility_checker<V,E,T> checker;
bool valid_mapping_found = check_isomorphism(graph1, graph2, state, checker, 0);
if(valid_mapping_found){
return generate_final_mapping(graph1, state);
}
return std::nullopt;
}
}
157 changes: 157 additions & 0 deletions include/graaflib/algorithm/graph_isomorphism/graph_isomorphism_util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
#pragma once

#include <graaflib/graph.h>
#include <graaflib/types.h>
#include <cstddef>
#include <memory>
#include <optional>


/**
HELPER CLASSES
*/

namespace graaf::algorithm{

struct predecessors_and_successors_of_vertex {
std::unordered_set<vertex_id_t> predecessors;
std::unordered_set<vertex_id_t> successors;
};

using vertex_mapping = std::unordered_map<vertex_id_t, vertex_id_t>;

enum class WhichGraph {
GRAPH_1,
GRAPH_2
};

template <typename V, typename E, graph_type T>
class vf2_isomorphism_feasibility_checker;

// maps vertices in a graph to a value between [0,N] where N = number of vertices in a graph
template <typename V, typename E, graph_type T>
class vf2_vertex_id_mapper {
public:
vf2_vertex_id_mapper(const graph<V, E, T>& _graph1, const graph<V, E, T>& _graph2);
std::unordered_set<vertex_id_t> get_predecessors(vertex_id_t, WhichGraph);
std::unordered_set<vertex_id_t> get_successors(vertex_id_t, WhichGraph);
friend class vf2_target_sets;

private:
void create_mapping(vertex_mapping&, const graph<V, E, T>& graph);
void create_reverse_mapping(vertex_mapping& map, vertex_mapping& reverse_map);

const graph<V, E, T>* graph1;
const graph<V, E, T>* graph2;

vertex_mapping graph1_mapping;
vertex_mapping graph1_reverse_mapping;
vertex_mapping graph2_mapping;
vertex_mapping graph2_reverse_mapping;
};

/*
alias for the target sets, which are responsible for narrowing the search space and vertex pairings
based on existing vertex pairs in the current mapping
*/
using target = std::vector<int>;
using graph_to_graph_mapping = std::vector<vertex_id_t>; // maps vertices' ids from one graph to another

class vf2_target_sets{
public:
vf2_target_sets(size_t, size_t);
void update_mappings(vertex_id_t, vertex_id_t, int);
void restore_mappings(vertex_id_t, vertex_id_t, int);
void update_target_sets(const predecessors_and_successors_of_vertex&, const predecessors_and_successors_of_vertex&, int);
void restore_target_sets(int);
std::vector<std::pair<vertex_id_t, vertex_id_t>> generate_potential_vertex_pairings();
size_t get_core_1_length();
size_t get_core_2_length();

template <typename V, typename E, graph_type T>
vertex_mapping generate_final_mapping(const vf2_vertex_id_mapper<V,E,T>&);

template <typename V, typename E, graph_type T>
friend class vf2_isomorphism_feasibility_checker;

private:
target tin_1;
target tin_2;
target tout_1;
target tout_2;
graph_to_graph_mapping core_1;
graph_to_graph_mapping core_2;

size_t tin_1_length = 0;
size_t tin_2_length = 0;
size_t tout_1_length = 0;
size_t tout_2_length = 0;
size_t core_1_length = 0;
size_t core_2_length = 0;
};

// Utility Functions
std::unordered_set<vertex_id_t> intersection_set(const std::unordered_set<vertex_id_t>& set_A, const std::unordered_set<vertex_id_t>& set_B) {
std::unordered_set<vertex_id_t> intersection;
for (const auto& element : set_A) {
if (set_B.find(element)!= set_B.end()) {
intersection.insert(element);
}
}
return intersection;
}

Check warning on line 102 in include/graaflib/algorithm/graph_isomorphism/graph_isomorphism_util.h

View check run for this annotation

Codecov / codecov/patch

include/graaflib/algorithm/graph_isomorphism/graph_isomorphism_util.h#L102

Added line #L102 was not covered by tests

template <typename V, typename E, graph_type T>
struct vf2_information{
std::unique_ptr<vf2_target_sets> sets;
std::unique_ptr<vf2_vertex_id_mapper<V, E, T>> mapper;

vf2_information(const graph<V, E, T>& graph1, const graph<V, E, T>& graph2){
sets = std::make_unique<vf2_target_sets>(graph1.vertex_count(), graph2.vertex_count());
mapper = std::make_unique<vf2_vertex_id_mapper<V,E,T>>(graph1, graph2);
}
};

template <typename V, typename E, graph_type T>
struct rule_parameters{
const vf2_information<V,E,T>& vf2_info;
const predecessors_and_successors_of_vertex& pred_succ_vertex1;
const predecessors_and_successors_of_vertex& pred_succ_vertex2;
rule_parameters(
const vf2_information<V,E,T>& _vf2_info,
const predecessors_and_successors_of_vertex& _pred_succ_vertex1,
const predecessors_and_successors_of_vertex& _pred_succ_vertex2
): pred_succ_vertex1(_pred_succ_vertex1), pred_succ_vertex2(_pred_succ_vertex2), vf2_info(_vf2_info){}
};

template <typename V, typename E, graph_type T>
class vf2_isomorphism_feasibility_checker {
public:
bool checkFeasibility(const std::unique_ptr<vf2_information<V,E,T>>&, const std::pair<vertex_id_t, vertex_id_t>&) const ;

private:
bool predecessors_consistency_rule(
const struct rule_parameters<V,E,T>& params
) const;
bool successors_consistency_rule(
const struct rule_parameters<V,E,T>& params
) const;
bool lookahead_tin_rule(
const struct rule_parameters<V,E,T>& params
) const;
bool lookahead_tout_rule(
const struct rule_parameters<V,E,T>& params
) const;
bool lookahead_new_rule(
const struct rule_parameters<V,E,T>& params
) const;
};

template <typename V, typename E, graph_type T>
bool check_isomorphism(const graph<V, E, T>& graph1, const graph<V, E, T>& graph2, const std::unique_ptr<vf2_information<V,E,T>>& state, const vf2_isomorphism_feasibility_checker<V,E,T>&, size_t depth);
}//namespace graaf::algorithm::vf2


#include "graph_isomorphism_util.tpp"


Loading
Loading