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

VF2 graph isomorphism revised PR for issue #87, requesting review #172

Closed
wants to merge 7 commits into from

Conversation

sracha4355
Copy link

Changes I've made:

  • removed unnecessary functions from .h, .h contains only the function interface that will be used by the end-user
  • added comments to my code and tests
  • added some new tests to test isomorphism
  • formatted the code with clang-format using style Google
    I appreciate any constructive criticism you guys can offer. As for the comments, it is hard to tell the full story of the algorithm given it's complex nature, so in addition to my comments I linked the research paper if any devs are still confused.
    Thank you guys!

Copy link

codecov bot commented Nov 4, 2023

Codecov Report

Attention: 6 lines in your changes are missing coverage. Please review.

Files Coverage Δ
include/graaflib/graph.h 100.00% <ø> (ø)
test/graaflib/algorithm/graph_isomorphism.cpp 100.00% <100.00%> (ø)
include/graaflib/algorithm/graph_isomorphism.tpp 98.18% <98.18%> (ø)

... and 56 files with indirect coverage changes

📢 Thoughts on this report? Let us know!

@sracha4355
Copy link
Author

Most of the added lines in PR are from cmake files i forgot to push because I rebuilt the library.

@sracha4355
Copy link
Author

@bobluppes @joweich could I get a workflow approval?

@sracha4355 sracha4355 force-pushed the satvik_graaf_pr_changes branch from 40df7af to 7c41e14 Compare November 8, 2023 02:39
@sracha4355
Copy link
Author

@joweich can I get a review

Copy link
Collaborator

@joweich joweich left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @sracha4355, great to see you incorporated the feedback from last time!
I'll be a bit more specific with my feedback this time compared to the guardrails last time 🙂

  • The logic itself is quite hard to follow because the level of abstraction changes often and some sections are quite repetitive. I think we should put some thought into introducing some object orientation to be more concise about the dependencies. terminal_set or vf2_vertex would be candidates to consider introducing as structs/classes
  • There are several return statements that lack test coverage. There should be tests if the returns are necessary, otherwise we should remove them
  • You sometimes allocate memory with "naked" new statements. Most often, it's better (i.e. more robust against memory leaks) to use smart pointers. Won't go into detail here, but check e.g. this

I did not review every function, but I hope the bullets above and the inline-comments provide some useful advice already! 🙂

template <typename V, typename E, graph_type T>
vf2_state* init_vf2_state(const graph<V, E, T>& lhs,
const graph<V, E, T>& rhs) {
struct vf2_state* state = new vf2_state;
Copy link
Collaborator

@joweich joweich Nov 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
struct vf2_state* state = new vf2_state;
std::unique_ptr<vf2_state> state = std::make_unique<vf2_state>();

Using smart pointers will ensure that the caller takes ownership of the returned objects and are thus less prone to memory leaks

}

template <typename V, typename E, graph_type T>
vf2_state* init_vf2_state(const graph<V, E, T>& lhs,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function's only purpose is initialization of the vf2_state struct. It can thus be treated as a constructor and moved into the struct's body as such.

const graph<V, E, T>& rhs) {
if (!check_for_possibility_of_isomorphism(lhs, rhs)) return std::nullopt;

struct vf2_state* state = init_vf2_state(lhs, rhs);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
struct vf2_state* state = init_vf2_state(lhs, rhs);
std::unique_ptr<vf2_state> state = init_vf2_state(lhs, rhs);

Comment on lines +724 to +737
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());
for (int i = 0; i < lhs_node_degrees.size(); i++)
if (lhs_node_degrees[i] != rhs_node_degrees[i]) return false;
return true;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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());
for (int i = 0; i < lhs_node_degrees.size(); i++)
if (lhs_node_degrees[i] != rhs_node_degrees[i]) return false;
return true;
auto compute_and_sort_degrees = [](const graph<V, E, T>& graph) {
std::vector<std::size_t> node_degrees;
for (const auto& vertex : graph.get_vertices()) {
std::size_t number_of_conn = graph.get_neighbors(vertex.first).size();
node_degrees.push_back(number_of_conn);
}
std::sort(node_degrees.begin(), node_degrees.end());
return node_degrees;
};
const auto lhs_node_degrees = compute_and_sort_degrees(lhs);
const auto rhs_node_degrees = compute_and_sort_degrees(rhs);
return lhs_node_degrees == rhs_node_degrees;

I think using a lambda would be more concise here

Comment on lines +186 to +187
std::optional<vertex_mapping> _optional = mapping;
return _optional;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::optional<vertex_mapping> _optional = mapping;
return _optional;
return mapping;

This should be possible with implicit template deduction.

// a lookahead rule to see if the current partial vertex_mapping can lead to a
// complete isomorphic vertex_mapping
template <typename V, typename E, graph_type T>
bool r_new(const graph<V, E, T>& lhs, const graph<V, E, T>& rhs,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this function is very repetitive and its name should be more expressive

size_t depth, size_t& _terminal_set_length) {
for (const auto& node : vertices) {
if (_terminal_set[node] == -1) {
_terminal_set[node] = int(depth);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is depth defined as size_t when casted to int here?

@sracha4355
Copy link
Author

@joweich thank you for your comments, I'll take a look at each one and refactor the code!

Copy link
Contributor

Stale pull request message

@sracha4355
Copy link
Author

Hey guys, I got really busy with school, but now that I am on break I would like to refactor the code and get my code merged. Can we reopen the PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants