-
Notifications
You must be signed in to change notification settings - Fork 66
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
Random graph methods #1039
base: master
Are you sure you want to change the base?
Random graph methods #1039
Changes from all commits
ed1e439
7376b45
8450dbd
82201e4
cbe4c49
e772ab7
90325cd
5be2338
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. | ||
* See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. | ||
* Author(s): Vincent Rouvreau | ||
* | ||
* Copyright (C) 2024 Inria | ||
* | ||
* Modification(s): | ||
* - YYYY/MM Author: Description of the modification | ||
*/ | ||
|
||
#ifndef RANDOM__H_ | ||
#define RANDOM__H_ | ||
|
||
#include <random> // for std::random_device, std::mt19937, std::uniform_real_distribution | ||
#include <vector> | ||
#include <algorithm> // for std::generate | ||
#include <cstddef> // for std::size_t | ||
|
||
namespace Gudhi { | ||
std::random_device rd; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As a global object, it may cause trouble if you try to link 2 .o that both use gudhi. |
||
|
||
class Random { | ||
public: | ||
Random() : gen_(rd()) {} | ||
Random(std::uint_fast32_t seed) : gen_(seed) {} | ||
|
||
template <typename Type> | ||
Type get(const Type& min = 0, const Type& max = 1) { | ||
if constexpr (std::is_floating_point_v<Type>) { | ||
std::uniform_real_distribution<Type> dis(min, max); | ||
return dis(gen_); | ||
} else if constexpr (std::is_integral_v<Type>) { | ||
std::uniform_int_distribution<Type> dis(min, max); | ||
return dis(gen_); | ||
} | ||
} | ||
|
||
template <typename Type> | ||
std::vector<Type> get_range(std::size_t nbr, const Type& min = 0, const Type& max = 1) { | ||
std::vector<Type> result(nbr); | ||
if constexpr (std::is_floating_point_v<Type>) { | ||
std::uniform_real_distribution<Type> dis(min, max); | ||
std::generate(result.begin(), result.end(), [&]() { return dis(gen_); }); | ||
} else if constexpr (std::is_integral_v<Type>) { | ||
std::uniform_int_distribution<Type> dis(min, max); | ||
std::generate(result.begin(), result.end(), [&]() { return dis(gen_); }); | ||
} | ||
return result; | ||
} | ||
|
||
private: | ||
std::mt19937 gen_; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we pick one, mt19937_64 may be better, the platforms we target are all 64 bits (and then the seed is 64 bits as well). |
||
}; | ||
} // namespace Gudhi | ||
|
||
#endif // RANDOM__H_ |
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,98 @@ | ||||||||||
/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. | ||||||||||
* See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. | ||||||||||
* Author(s): Vincent Rouvreau | ||||||||||
* | ||||||||||
* Copyright (C) 2024 Inria | ||||||||||
* | ||||||||||
* Modification(s): | ||||||||||
* - YYYY/MM Author: Description of the modification | ||||||||||
*/ | ||||||||||
|
||||||||||
#ifndef RANDOM_GRAPH_GENERATORS_H_ | ||||||||||
#define RANDOM_GRAPH_GENERATORS_H_ | ||||||||||
|
||||||||||
#include <gudhi/Random.h> | ||||||||||
|
||||||||||
|
||||||||||
#include <algorithm> // for std::prev_permutation | ||||||||||
#include <vector> | ||||||||||
#include <array> | ||||||||||
#include <random> | ||||||||||
#include <numeric> // for std::iota | ||||||||||
#include <cstddef> // for std::size_t | ||||||||||
#include <type_traits> // for std::is_floating_point_v | ||||||||||
#ifdef DEBUG_TRACES | ||||||||||
#include <iostream> | ||||||||||
#endif // DEBUG_TRACES | ||||||||||
|
||||||||||
std::random_device rd; | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Argh! |
||||||||||
|
||||||||||
namespace Gudhi { | ||||||||||
|
||||||||||
template <typename Vertex_handle> | ||||||||||
std::vector<std::array<Vertex_handle, 2>> random_edges(Vertex_handle nb_vertices, double density = 0.15) { | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The algorithm in there seems very complicated. What do you want exactly?
|
||||||||||
std::vector<std::array<Vertex_handle, 2>> permutations; | ||||||||||
if (nb_vertices < 2) | ||||||||||
return permutations; | ||||||||||
|
||||||||||
std::vector<bool> to_permute(nb_vertices); | ||||||||||
std::fill(to_permute.begin(), to_permute.begin() + 2, true); | ||||||||||
|
||||||||||
std::size_t nb_permutations = (nb_vertices * (nb_vertices - 1)) / 2; | ||||||||||
auto random_values = Gudhi::Random().get_range<double>(nb_permutations); | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you are going to create Random objects left and right, I don't see how this will help determinism. There is no way for the user to specify a seed... |
||||||||||
std::size_t idx = 0; | ||||||||||
do { | ||||||||||
// Keep only X% of the possible edges | ||||||||||
if (random_values[idx] > density) { | ||||||||||
idx++; | ||||||||||
continue; | ||||||||||
} | ||||||||||
idx++; | ||||||||||
|
||||||||||
std::array<Vertex_handle, 2> permutation = {-1, -1}; | ||||||||||
for (Vertex_handle idx = 0; idx < nb_vertices; ++idx) { | ||||||||||
if (to_permute[idx]) { | ||||||||||
if (permutation[0] == -1) { | ||||||||||
permutation[0] = idx; | ||||||||||
} else { | ||||||||||
permutation[1] = idx; | ||||||||||
// No need to go further, only 2 'true' values | ||||||||||
break; | ||||||||||
} | ||||||||||
} | ||||||||||
} | ||||||||||
#ifdef DEBUG_TRACES | ||||||||||
std::cout << permutation.first << ", " << permutation.second << std::endl; | ||||||||||
#endif // DEBUG_TRACES | ||||||||||
permutations.push_back(permutation); | ||||||||||
//std::cout << permutation.first << ", " << permutation.second << "\n"; | ||||||||||
} while (std::prev_permutation(to_permute.begin(), to_permute.end())); | ||||||||||
|
||||||||||
return permutations; | ||||||||||
} | ||||||||||
|
||||||||||
template<typename Simplex_tree> | ||||||||||
void simplex_tree_random_flag_complex( | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It doesn't produce a flag complex, it produces a graph. |
||||||||||
Simplex_tree& st, | ||||||||||
typename Simplex_tree::Vertex_handle nb_vertices, | ||||||||||
double density = 0.15) { | ||||||||||
using Vertex_handle = typename Simplex_tree::Vertex_handle; | ||||||||||
std::vector<Vertex_handle> vertices(nb_vertices); | ||||||||||
std::iota(vertices.begin(), vertices.end(), 0); // vertices is { 0, 1, 2, ..., 99 } when nb_vertices is 100 | ||||||||||
st.insert_batch_vertices(vertices); | ||||||||||
Comment on lines
+80
to
+82
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
https://www.boost.org/doc/libs/1_85_0/libs/range/doc/html/range/reference/ranges/irange.html (or counting_range) |
||||||||||
|
||||||||||
auto edges = random_edges(nb_vertices, density); | ||||||||||
|
||||||||||
auto random_filtrations = Gudhi::Random().get_range<typename Simplex_tree::Filtration_value>(edges.size()); | ||||||||||
|
||||||||||
std::size_t idx = 0; | ||||||||||
for (auto edge : edges) { | ||||||||||
st.insert_simplex(edge, random_filtrations[idx]); | ||||||||||
idx++; | ||||||||||
} | ||||||||||
|
||||||||||
} | ||||||||||
|
||||||||||
} // namespace Gudhi | ||||||||||
|
||||||||||
#endif // RANDOM_GRAPH_GENERATORS_H_ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. | ||
* See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. | ||
* Author(s): Vincent Rouvreau | ||
* | ||
* Copyright (C) 2024 Inria | ||
* | ||
* Modification(s): | ||
* - YYYY/MM Author: Description of the modification | ||
*/ | ||
|
||
#include <gudhi/Random.h> | ||
|
||
#include <iostream> | ||
#include <vector> | ||
|
||
#define BOOST_TEST_DYN_LINK | ||
#define BOOST_TEST_MODULE "random" | ||
#include <boost/test/unit_test.hpp> | ||
#include <boost/mpl/list.hpp> | ||
|
||
using list_of_rnd_types = boost::mpl::list<double, float, int, unsigned int, long>; | ||
|
||
BOOST_AUTO_TEST_CASE_TEMPLATE(random_same_seed, RndType, list_of_rnd_types) { | ||
std::cout << " ## BOOST_AUTO_TEST_CASE( random_same_seed )" << std::endl; | ||
|
||
RndType min{0}; | ||
RndType max{100}; | ||
RndType first = Gudhi::Random(1).get<RndType>(min, max); | ||
RndType second = Gudhi::Random(1).get<RndType>(min, max); | ||
|
||
std::clog << "First random number: " << first << " - Second random number: " << second << std::endl; | ||
BOOST_CHECK(first >= min); | ||
BOOST_CHECK(first <= max); | ||
BOOST_CHECK(first == second); | ||
} | ||
|
||
BOOST_AUTO_TEST_CASE_TEMPLATE(random_different_seed, RndType, list_of_rnd_types) { | ||
std::cout << " ## BOOST_AUTO_TEST_CASE( random_different_seed )" << std::endl; | ||
|
||
RndType min{0}; | ||
RndType max{100}; | ||
RndType first = Gudhi::Random().get<RndType>(min, max); | ||
RndType second = Gudhi::Random().get<RndType>(min, max); | ||
|
||
std::clog << "First random number: " << first << " - Second random number: " << second << std::endl; | ||
BOOST_CHECK(first >= min); | ||
BOOST_CHECK(first <= max); | ||
} | ||
|
||
BOOST_AUTO_TEST_CASE_TEMPLATE(random_range, RndType, list_of_rnd_types) { | ||
std::cout << " ## BOOST_AUTO_TEST_CASE( random_range )" << std::endl; | ||
|
||
RndType min{0}; | ||
RndType max{100}; | ||
const std::size_t N{20}; | ||
std::vector<RndType> range = Gudhi::Random().get_range<RndType>(N, min, max); | ||
|
||
BOOST_CHECK(range.size() == N); | ||
|
||
for (const auto& value : range) { | ||
std::clog << "Random number: " << value << std::endl; | ||
BOOST_CHECK(value >= min); | ||
BOOST_CHECK(value <= max); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
/* This file is part of the Gudhi Library - https://gudhi.inria.fr/ - which is released under MIT. | ||
* See file LICENSE or go to https://gudhi.inria.fr/licensing/ for full license details. | ||
* Author(s): Vincent Rouvreau | ||
* | ||
* Copyright (C) 2024 Inria | ||
* | ||
* Modification(s): | ||
* - YYYY/MM Author: Description of the modification | ||
*/ | ||
|
||
#include <gudhi/random_graph_generators.h> | ||
#include <gudhi/Simplex_tree.h> | ||
|
||
#include <iostream> | ||
#include <array> | ||
#include <vector> | ||
|
||
#define BOOST_TEST_DYN_LINK | ||
#define BOOST_TEST_MODULE "random_graph_generators" | ||
#include <boost/test/unit_test.hpp> | ||
|
||
using Edge = std::array<int, 2>; | ||
using Edge_range = std::vector<Edge>; | ||
|
||
BOOST_AUTO_TEST_CASE( random_edges_limits ) { | ||
std::cout << " ## BOOST_AUTO_TEST_CASE( random_edges_limits )" << std::endl; | ||
Edge_range edges = Gudhi::random_edges(0); | ||
std::cout << "Gudhi::random_edges(0).size() = " << edges.size() << std::endl; | ||
BOOST_CHECK(edges.size() == 0); | ||
|
||
edges = Gudhi::random_edges(1); | ||
std::cout << "Gudhi::random_edges(1).size() = " << edges.size() << std::endl; | ||
BOOST_CHECK(edges.size() == 0); | ||
|
||
edges = Gudhi::random_edges(2, 1.); | ||
std::cout << "Gudhi::random_edges(2).size() = " << edges.size() << std::endl; | ||
BOOST_CHECK(edges.size() == 1); | ||
|
||
edges = Gudhi::random_edges(15, 0.); | ||
std::cout << "Gudhi::random_edges(15, 0.).size() = " << edges.size() << std::endl; | ||
BOOST_CHECK(edges.size() == 0); | ||
|
||
edges = Gudhi::random_edges(15, 1.); | ||
std::cout << "Gudhi::random_edges(15, 1.).size() = " << edges.size() << std::endl; | ||
BOOST_CHECK(edges.size() == 105); | ||
} | ||
|
||
BOOST_AUTO_TEST_CASE( random_edges_mean ) { | ||
std::cout << " ## BOOST_AUTO_TEST_CASE( random_edges_mean )" << std::endl; | ||
int nb_edges {0}; | ||
for (int idx = 0; idx < 100; ++idx) { | ||
Edge_range edges = Gudhi::random_edges(15); | ||
nb_edges += edges.size(); | ||
#ifdef DEBUG_TRACES | ||
std::cout << edges.size() << ", "; | ||
#endif // DEBUG_TRACES | ||
} | ||
#ifdef DEBUG_TRACES | ||
std::cout << "\n"; | ||
#endif // DEBUG_TRACES | ||
std::cout << "Total number of edges for 100 x Gudhi::random_edges(15) [aka. 15% of 105] = " << nb_edges << std::endl; | ||
// 1575 +/- 10% | ||
BOOST_CHECK(nb_edges < 1733); | ||
BOOST_CHECK(nb_edges > 1417); | ||
} | ||
|
||
BOOST_AUTO_TEST_CASE( simplex_tree_random_flag_complex_test ) { | ||
std::cout << " ## BOOST_AUTO_TEST_CASE( simplex_tree_random_flag_complex_test )" << std::endl; | ||
Gudhi::Simplex_tree<> stree; | ||
// Insert 100% of the possible edges, with 10 vertices | ||
simplex_tree_random_flag_complex(stree, 10, 1.); | ||
|
||
std::cout << "Random flag complex with " << stree.num_vertices() << " vertices and " << stree.num_simplices() << | ||
" simplices" << std::endl; | ||
BOOST_CHECK(stree.num_vertices() == 10); | ||
BOOST_CHECK(stree.num_simplices() == 55); | ||
} | ||
|
||
BOOST_AUTO_TEST_CASE( simplex_tree_random_flag_complex_test_1000 ) { | ||
std::cout << " ## BOOST_AUTO_TEST_CASE( simplex_tree_random_flag_complex_test_1000 )" << std::endl; | ||
Gudhi::Simplex_tree<> stree; | ||
// Insert 15% of the possible edges, with 1000 vertices | ||
simplex_tree_random_flag_complex(stree, 1000); | ||
|
||
std::cout << "Random flag complex with " << stree.num_vertices() << " vertices and " << stree.num_simplices() << | ||
" simplices" << std::endl; | ||
|
||
// 15 % of 499500 = 74925 | ||
// 74925 +/- 5% = [71178.75, 78671.25] | ||
BOOST_CHECK(stree.num_simplices() < 78671); | ||
BOOST_CHECK(stree.num_simplices() > 71178); | ||
} |
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.
Shouldn't we put GUDHI in the name of the macro, to reduce the risk of conflicts?