-
Notifications
You must be signed in to change notification settings - Fork 27
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
Non-Deterministic Results while using binary #198
Comments
Just now, I tested ibm01.hgr along with my target graph file. That means I changed target graph file from target.graph in your project to mine. Then this problem occurred again. My target graph files are as follows:
or
Both of them, as the mapped graph file, have the non-deterministic problem. Did I write the target graph file incorrectly or are there some other reasons for this? |
Hi @LeaveryF, thanks for the detailed report! You probably did nothing wrong and there is actually an issue with the algorithm. I'm afraid support for steiner trees is still a bit experimental, specifically with regards to the deterministic configuration. From the results you showed, it seems that the main partitioning step is deterministic, however the mapping to the target graph is different in both cases. Therefore, the most likely cause is that some part of the mapping procedure is not deterministic. I will try to investigate it this week and see whether I can fix the problem. |
Could you check whether the branch |
Mapping to small target graph, such as the two files above, the results have been stable, but larger target graph still have this problem.
It does happen more rarely. Using test_instance.hgr in your project and my target graph file can reproduce this problem, maybe. |
Okay, I found another bug which was a bit more tricky and actually affected the non-deterministic mode, too. Could you try again with the new commit @LeaveryF ? Also, the issue that I found implies that the steiner trees only work for k <= 64 for now. Is this a problem for your use case? With some additional work it would be possible to allow larger k. Note however that the running time might degrade for large k anyways due to the high computational complexity of the steiner tree metric. |
It works well in my cases now. Thank you very much. And, my use case just need k <= 64, so that's not a problem for me now. |
Hi, I have another question. It's small and not so important maybe. In deterministic preset type, do the c library interfaces "mt_kahypar_create_hypergraph" and "mt_kahypar_read_hypergraph_from_file" construct the same hypergraph? I have tried both with my data structure and hypergraph files, but they seem different. @N-Maas |
Could you specify what you mean with "seem different"? If the data in the file and the data provided to Note that you need to be a bit careful with the input to |
Well, I have some raw hypergraph data, and I have tried to process it in different ways... In the first time, I read the data and transformed it into my data structure, then passed them to In the second time, I processed the data into an hmetis file, then used In the third time, I processed the data into an hmetis file, then used mt binary to process the hypergraph. All of them were set the same imbalance, seed, and deterministic preset type, along with the same steiner tree mapped target graph. The results(steiner tree metric, and final partition results) for 2 and 3 are the same, which I think that means the problem does not lie in partition process. While 1 is different from them, which I personally think the problem may lie in this c library interface. I think I followed the input format of |
I found that mapping This is the params: ./build/mt-kahypar/application/MtKaHyPar \
-h ./tests/instances/hypergraph_with_node_and_edge_weights.hgr \
--preset-type=deterministic \
-t 4 \
-k 8 \
-e 0.03 \
-g ./tests/instances/graph_with_edge_weights.graph \
-o steiner_tree \ |
So there are two problems with the input: Note that the changes are already on the master branch. I don't know whether this is related to the non-deterministic results with the C interface, but probably not. For the latter, an example input to reproduce the problem would be helpful. |
Oh, yes. I ignored the isolated node. And for the c interface, I wrote a simple program as follows. Changing the boolean variable #include <fstream>
#include <iostream>
#include <memory>
#include <sstream>
#include <thread>
#include <vector>
#include "libmtkahypar.h"
int main(int argc, char *argv[]) {
// Initialize thread pool
mt_kahypar_initialize_thread_pool(4, true);
// Setup partitioning context
mt_kahypar_context_t *context = mt_kahypar_context_new();
mt_kahypar_load_preset(context, DETERMINISTIC);
// mt_kahypar_configure_context_from_file(context, "config.ini");
mt_kahypar_set_partitioning_parameters(context, 8, 0.03, KM1);
// Enable logging
mt_kahypar_set_context_parameter(context, VERBOSE, "1");
// Set seed
// mt_kahypar_set_seed(0);
mt_kahypar_hypergraph_t hypergraph;
bool use_file = true;
std::string hgr_file = "../../examples/ibm01.hgr";
if (use_file) {
hypergraph = mt_kahypar_read_hypergraph_from_file(
hgr_file.c_str(), DETERMINISTIC, HMETIS);
} else {
std::ifstream fin(hgr_file);
int m, n, sum = 0;
fin >> m >> n;
std::vector<std::vector<int>> edge_vec(m);
for (int i = 0; i < m; i++) {
std::string line;
std::getline(fin, line);
std::istringstream iss(line);
int v;
while (iss >> v) {
edge_vec[i].push_back(v - 1);
}
sum += edge_vec[i].size();
}
std::unique_ptr<size_t[]> hyperedge_indices =
std::make_unique<size_t[]>(m + 1);
size_t cnt = 0;
for (int i = 0; i < m; i++) {
hyperedge_indices[i] = cnt;
cnt += edge_vec[i].size();
}
hyperedge_indices[m] = cnt;
std::unique_ptr<mt_kahypar_hyperedge_id_t[]> hyperedges =
std::make_unique<mt_kahypar_hyperedge_id_t[]>(sum);
int index = 0;
for (const auto &v : edge_vec) {
for (const auto &e : v) {
hyperedges[index++] = e;
}
}
hypergraph = mt_kahypar_create_hypergraph(
DETERMINISTIC, n, m, hyperedge_indices.get(), hyperedges.get(), nullptr,
nullptr);
}
// Read target graph file
mt_kahypar_target_graph_t *target_graph =
mt_kahypar_read_target_graph_from_file("../../examples/target.graph");
// Map hypergraph onto target graph
mt_kahypar_partitioned_hypergraph_t partitioned_hg =
mt_kahypar_map(hypergraph, target_graph, context);
// Extract Mapping
std::unique_ptr<mt_kahypar_partition_id_t[]> mapping =
std::make_unique<mt_kahypar_partition_id_t[]>(
mt_kahypar_num_hypernodes(hypergraph));
mt_kahypar_get_partition(partitioned_hg, mapping.get());
// Extract Block Weights
std::unique_ptr<mt_kahypar_hypernode_weight_t[]> block_weights =
std::make_unique<mt_kahypar_hypernode_weight_t[]>(8);
mt_kahypar_get_block_weights(partitioned_hg, block_weights.get());
// Compute Metrics
const double imbalance = mt_kahypar_imbalance(partitioned_hg, context);
const double steiner_tree_metric =
mt_kahypar_steiner_tree(partitioned_hg, target_graph);
// Output Results
std::cout << "Partitioning Results:" << std::endl;
std::cout << "Imbalance = " << imbalance << std::endl;
std::cout << "Steiner Tree Metric = " << steiner_tree_metric << std::endl;
for (size_t i = 0; i < 8; ++i) {
std::cout << "Weight of Block " << i << " = " << block_weights[i]
<< std::endl;
}
mt_kahypar_free_context(context);
mt_kahypar_free_hypergraph(hypergraph);
mt_kahypar_free_partitioned_hypergraph(partitioned_hg);
mt_kahypar_free_target_graph(target_graph);
} |
There is actually an issue with both your code and the C interface. You have a small bug in the parsing of the hypergraph file. Currently, you prepend an empty hyperedge and ignore the last hyperedge (since the line break remains after parsing the header). You should instead do something like this: std::string line;
std::ifstream fin(hgr_file);
std::getline(fin, line);
std::istringstream iss(line);
int m, n, sum = 0;
iss >> m >> n;
std::vector<std::vector<int>> edge_vec(m);
for (int i = 0; i < m; i++) {
std::getline(fin, line);
std::istringstream iss(line);
int v;
while (iss >> v) {
edge_vec[i].push_back(v - 1);
}
sum += edge_vec[i].size();
} However, the C interface also differs from reading the hypergraph from the file. The difference is that reading from a file will sort the pins of each hyperedge in ascending order, while the C interface leaves the order unchanged. This is unfortunate and we should probably unify the behavior of the two APIs. For the moment, you can use the The change won't make it to master for the moment, since doing this properly (specifically, such that it also works for the python interface) is a bit more complicated. |
OK, I see it! Thank you. |
Hello.
When I use mtkahypar with c library, I also met the problem of "Non-Deterministic Results", as is shown in #190 and #189 . Then I switched from c library to binary. However, this problem still exists.
This is how I run mtkahypar binary:
where mt_input_hypergraph.txt and mt_input_target_graph.txt are generated by my project.
And this is the different results:
Also, it seems that the larger the scale of the (hyper)graph file, the more likely and clearly the results will differ.
Interestingly, when I use instances in mtkahypar project, for example, the ibm01.hgr and target.graph, this problem didn't occur. So, it seems the problem lies in my (hyper)graph file?
I have no idea what I should do. If you want my (hyper)graph files, I'm willing to offer them.
The text was updated successfully, but these errors were encountered: