-
Notifications
You must be signed in to change notification settings - Fork 221
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
Add b-Suitor algorithm and b-Matching classes #1109
base: master
Are you sure you want to change the base?
Conversation
1d26d92
to
bccb01f
Compare
f8d17a9
to
c7fde94
Compare
d342c99
to
b993e0e
Compare
7e34f0b
to
18f97b0
Compare
aae6c0c
to
c66a1fe
Compare
058d191
to
91c4bfd
Compare
networkit/cpp/matching/BMatching.cpp
Outdated
for (node v : G.nodeRange()) { | ||
for (index i = 0; i < b.at(i); i++) { | ||
node w = data[v][i]; | ||
if ((v != w) && (w != none) && !G.hasEdge(v, w)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aren't self loops allowed in b-matchings (with b>1
)? Also, this can be tested in one loop with the one above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, undirected simple graphs are considered.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Merged the loops in 14494fe.
networkit/cpp/matching/BMatching.cpp
Outdated
for (node v : G.nodeRange()) { | ||
for (index i = 0; i < b.at(i); i++) { | ||
node w = data[v][i]; | ||
if (w != none && std::find(data[w].begin(), data[w].end(), v) == data[w].end()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the reason for a none
matching? If its happening because of #Neighbors(u) < b
, maybe you can escape the inner loop early.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I restructured the BMatching class in 14494fe. Now, there are no more none
nodes in the matching and a range based loop is used.
networkit/cpp/matching/BMatching.cpp
Outdated
namespace NetworKit { | ||
|
||
BMatching::BMatching(const std::vector<count> &b, count z) | ||
: data(z, std::vector<node>(b.size(), none)), b(b) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The initialization of data looks wrong (b.size()
likely equals number of nodes, not number of matchings per node).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ohhhh yes, thank you. I chaned this to b.at(i)
in some other branch but I completely forgot to cherry pick this commit. Added it now.
if (self < v.id) | ||
weight += v.weight; | ||
if (size == max_size && !list.empty()) { | ||
min = *std::min_element(list.begin(), list.end(), [](const Node &a, const Node &b) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Be consistent concerning lambda function parameter names. This makes the code more readable. Also b
is already used for the node variable matching indicators. Better not reuse it in another related context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change some names in cb0aa0e including this one.
networkit/cpp/matching/BMatching.cpp
Outdated
data[u][i] = v; | ||
} | ||
{ | ||
auto i = findFirstFreeIndex(v); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a lot of std::find
done in the code. Even though b is likely to be small, have you checked whether std::set
(or a struct based on it) is a faster solution?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Restructured BMatching in 14494fe. Used std::set
instead.
std::vector<count> getB() const; | ||
|
||
protected: | ||
std::vector<std::vector<node>> data; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest using a more precise name for class member variables.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done in 14494fe.
void buildBMatching(); | ||
|
||
private: | ||
std::vector<std::unique_ptr<Suitors>> S; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest not using single char names for class member variables.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done in cb0aa0e.
bf9d6ee
to
ffb09b9
Compare
ffb09b9
to
8ce89d4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, I left some comments.
const std::vector<std::set<node>> &getMatches() const; | ||
std::vector<count> getB() const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are public functions, please add proper documentation.
std::vector<count> getB() const; | ||
|
||
protected: | ||
std::vector<std::set<node>> matches; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you need to keep the matches sorted? If not, I think we could use a std::unordered_set
.
|
||
namespace NetworKit { | ||
|
||
struct Node { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This defines a NetworKit::Node
struct. I think that this name is too generic for a struct used only by this class. I suggest using something more specific, e.g., WeightedNode
, or moving these structs into the BSuitorMatcher
.
if (partners.size() < max_size) { | ||
return {none, 0}; | ||
} else { | ||
auto ret = min; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More readable:
auto ret = min; | |
Node min_copy = min; |
if (v.id == u) { | ||
return true; | ||
} | ||
return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (v.id == u) { | |
return true; | |
} | |
return false; | |
return v.id == u; |
|
||
for (auto n : G->weightNeighborRange(u)) { | ||
const Node v = Node(n.first, n.second); | ||
if (!hasProposedTo(v.id)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can save an indentation level with:
if (!hasProposedTo(v.id)) { | |
if (hasProposedTo(v.id)) continue; |
const Node v = Node(n.first, n.second); | ||
if (!hasProposedTo(v.id)) { | ||
if (v.weight > best.weight || (v.weight == best.weight && v.id < best.id)) { | ||
const auto n_suitor_weight = Suitors.at(v.id)->min.weight; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const auto n_suitor_weight = Suitors.at(v.id)->min.weight; | |
const edgeweight n_suitor_weight = Suitors.at(v.id)->min.weight; |
G->forNodes([&](node u) { | ||
G->forNodes([&](node v) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can stop iterating once sym
is false. I suggest replacing these two loops with two for (node u : G->nodeRange())
loops and break once sym
is false.
// TODO make parallel | ||
G->forNodes([&](node x) { | ||
assert(Suitors.at(x)->partners.size() <= b.at(x)); | ||
for (auto y : Suitors.at(x)->partners) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for (auto y : Suitors.at(x)->partners) { | |
for (node y : Suitors.at(x)->partners) { |
*/ | ||
void run() override; | ||
|
||
void buildBMatching(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing documentation.
Implementation of the sequential b-Suitor algorithm by Khan et al. and required b-matching classes.
BMatching.hpp
represents basic properties of a b-matching data structure. It has a similar functionality as theMatching.hpp
class. (They could be merged or inherit as 1-matching from b-matching if the performance remains stable.)BMatcher.hpp
is the abstract base class for b-matching algorithms.BSuitorMatcher.hpp
adds the sequential b-Suitor with a b-function. It can be used to compute a b-matching for a given undirected weighted graph and any b. E.g.:computes the 2-matching for the tiny_02 graph
in (vertex_neighbor,edge_weight) METIS-like format with a weight of 19.