Эх сурвалжийг харах

Merge pull request #1062 from ycjungSubhuman/master

Use std::shuffle instead of std::random_shuffle in igl/randperm
Jérémie Dumas 6 жил өмнө
parent
commit
4575cbd670

+ 34 - 6
include/igl/randperm.cpp

@@ -7,21 +7,49 @@
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include "randperm.h"
 #include "colon.h"
-#include <algorithm> 
+#include <algorithm>
 
-template <typename DerivedI>
+template <typename DerivedI, typename URBG>
 IGL_INLINE void igl::randperm(
   const int n,
-  Eigen::PlainObjectBase<DerivedI> & I)
+  Eigen::PlainObjectBase<DerivedI> & I,
+  URBG urbg)
 {
   Eigen::VectorXi II;
   igl::colon(0,1,n-1,II);
   I = II;
-  std::random_shuffle(I.data(),I.data()+n);
+
+  std::shuffle(I.data(),I.data()+n, urbg);
+}
+
+template <typename DerivedI>
+IGL_INLINE void igl::randperm(
+  const int n,
+  Eigen::PlainObjectBase<DerivedI> & I)
+{
+  return igl::randperm(n, I, std::minstd_rand(std::rand()));
 }
 
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template instantiation
-template void igl::randperm<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
-template void igl::randperm<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::randperm<Eigen::Matrix<int, -1, 1, 0, -1, 1>, std::minstd_rand0>(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, std::minstd_rand0);
+template void igl::randperm<Eigen::Matrix<int, -1, -1, 0, -1, -1>, std::minstd_rand0>(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, std::minstd_rand0);
+template void igl::randperm<Eigen::Matrix<int, -1, 1, 0, -1, 1>, std::minstd_rand>(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, std::minstd_rand);
+template void igl::randperm<Eigen::Matrix<int, -1, -1, 0, -1, -1>, std::minstd_rand>(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, std::minstd_rand);
+template void igl::randperm<Eigen::Matrix<int, -1, 1, 0, -1, 1>, std::mt19937>(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, std::mt19937);
+template void igl::randperm<Eigen::Matrix<int, -1, -1, 0, -1, -1>, std::mt19937>(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, std::mt19937);
+template void igl::randperm<Eigen::Matrix<int, -1, 1, 0, -1, 1>, std::mt19937_64>(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, std::mt19937_64);
+template void igl::randperm<Eigen::Matrix<int, -1, -1, 0, -1, -1>, std::mt19937_64>(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, std::mt19937_64);
+template void igl::randperm<Eigen::Matrix<int, -1, 1, 0, -1, 1>, std::ranlux24_base>(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, std::ranlux24_base);
+template void igl::randperm<Eigen::Matrix<int, -1, -1, 0, -1, -1>, std::ranlux24_base>(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, std::ranlux24_base);
+template void igl::randperm<Eigen::Matrix<int, -1, 1, 0, -1, 1>, std::ranlux48_base>(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, std::ranlux48_base);
+template void igl::randperm<Eigen::Matrix<int, -1, -1, 0, -1, -1>, std::ranlux48_base>(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, std::ranlux48_base);
+template void igl::randperm<Eigen::Matrix<int, -1, 1, 0, -1, 1>, std::ranlux24>(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, std::ranlux24);
+template void igl::randperm<Eigen::Matrix<int, -1, -1, 0, -1, -1>, std::ranlux24>(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, std::ranlux24);
+template void igl::randperm<Eigen::Matrix<int, -1, 1, 0, -1, 1>, std::ranlux48>(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, std::ranlux48);
+template void igl::randperm<Eigen::Matrix<int, -1, -1, 0, -1, -1>, std::ranlux48>(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, std::ranlux48);
+template void igl::randperm<Eigen::Matrix<int, -1, 1, 0, -1, 1>, std::knuth_b>(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, std::knuth_b);
+template void igl::randperm<Eigen::Matrix<int, -1, -1, 0, -1, -1>, std::knuth_b>(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, std::knuth_b);
+template void igl::randperm<Eigen::Matrix<int, -1, 1, 0, -1, 1>>(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::randperm<Eigen::Matrix<int, -1, -1, 0, -1, -1>>(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 #endif

+ 10 - 0
include/igl/randperm.h

@@ -9,14 +9,24 @@
 #define IGL_RANDPERM_H
 #include "igl_inline.h"
 #include <Eigen/Core>
+#include <random>
 namespace igl
 {
   // Like matlab's randperm(n) but minus 1
   //
+  // When urbg is not specified, randperm will use default random bit generator
+  // std::minstd_rand initialized with random seed generated by std::rand()
+  //
   // Inputs:
   //   n  number of elements
+  //   urbg An instance of UnformRandomBitGenerator.
   // Outputs:
   //   I  n list of rand permutation of 0:n-1
+  template <typename DerivedI, typename URBG>
+  IGL_INLINE void randperm(
+    const int n,
+    Eigen::PlainObjectBase<DerivedI> & I,
+    URBG urbg);
   template <typename DerivedI>
   IGL_INLINE void randperm(
     const int n,

+ 91 - 0
tests/include/igl/randperm.cpp

@@ -0,0 +1,91 @@
+#include <test_common.h>
+#include <igl/randperm.h>
+#include <random>
+
+TEST_CASE("randperm: default_rng_reproduce_identity", "[igl]")
+{
+  int n = 100;
+  Eigen::VectorXi I1, I2;
+
+  std::srand(6);
+  igl::randperm(100, I1);
+  std::srand(6);
+  igl::randperm(100, I2);
+
+  test_common::assert_eq(I1, I2);
+}
+
+namespace randperm
+{
+  template<typename URBG>
+  void test_reproduce()
+  {
+    int n = 100;
+    Eigen::VectorXi I1, I2;
+    Eigen::MatrixXi Ix1, Ix2;
+    URBG rng1(6);
+    URBG rng2(6);
+
+    igl::randperm(100, I1, rng1);
+    igl::randperm(100, I2, rng2);
+
+    igl::randperm(100, Ix1, rng1);
+    igl::randperm(100, Ix2, rng2);
+
+    test_common::assert_eq(I1, I2);
+    test_common::assert_eq(Ix1, Ix2);
+  }
+}
+
+TEST_CASE("randperm: minstd_rand0_reproduce_identity", "[igl]")
+{
+  randperm::test_reproduce<std::minstd_rand0>();
+}
+TEST_CASE("randperm: minstd_rand_reproduce_identity", "[igl]")
+{
+  randperm::test_reproduce<std::minstd_rand>();
+}
+TEST_CASE("randperm: mt19937_reproduce_identity", "[igl]")
+{
+  randperm::test_reproduce<std::mt19937>();
+}
+TEST_CASE("randperm: mt19937_64_reproduce_identity", "[igl]")
+{
+  randperm::test_reproduce<std::mt19937_64>();
+}
+TEST_CASE("randperm: ranlux24_base_reproduce_identity", "[igl]")
+{
+  randperm::test_reproduce<std::ranlux24_base>();
+}
+TEST_CASE("randperm: ranlux48_base_reproduce_identity", "[igl]")
+{
+  randperm::test_reproduce<std::ranlux48_base>();
+}
+TEST_CASE("randperm: ranlux24_reproduce_identity", "[igl]")
+{
+  randperm::test_reproduce<std::ranlux24>();
+}
+TEST_CASE("randperm: ranlux48_reproduce_identity", "[igl]")
+{
+  randperm::test_reproduce<std::ranlux48>();
+}
+TEST_CASE("randperm: knuth_b_reproduce_identity", "[igl]")
+{
+  randperm::test_reproduce<std::knuth_b>();
+}
+TEST_CASE("randperm: default_identity", "[igl]")
+{
+  int n = 100;
+  Eigen::VectorXi I1, I2;
+  Eigen::MatrixXi Ix1, Ix2;
+
+  std::srand(0);
+  igl::randperm(100, I1);
+  igl::randperm(100, Ix1);
+  std::srand(0);
+  igl::randperm(100, I2);
+  igl::randperm(100, Ix2);
+
+  test_common::assert_eq(I1, I2);
+  test_common::assert_eq(Ix1, Ix2);
+}