Reduce the number of individual PRNG instances
Use same instance of a PRNG throughout by passing it to methods and
functions as an argument to generate random numbers without breaking the
sequence.
Change-Id: Ib024bbc1ea2d14e4b9afb71857856a5fb77b1667
diff --git a/internal/ceres/autodiff_test.cc b/internal/ceres/autodiff_test.cc
index 629eea8..0916a45 100644
--- a/internal/ceres/autodiff_test.cc
+++ b/internal/ceres/autodiff_test.cc
@@ -30,6 +30,8 @@
#include "ceres/internal/autodiff.h"
+#include <algorithm>
+#include <iterator>
#include <random>
#include "gtest/gtest.h"
@@ -173,9 +175,9 @@
// Make random P and X, in a single vector.
double PX[12 + 4];
- for (double& PX_i : PX) {
- PX_i = uniform01(prng);
- }
+ std::generate(std::begin(PX), std::end(PX), [&prng, &uniform01] {
+ return uniform01(prng);
+ });
// Handy names for the P and X parts.
double* P = PX + 0;
@@ -294,7 +296,10 @@
double qcX[4 + 3 + 3];
std::mt19937 prng;
std::uniform_real_distribution<double> uniform01(0.0, 1.0);
- for (double& qcX_i : qcX) qcX_i = uniform01(prng);
+
+ std::generate(std::begin(qcX), std::end(qcX), [&prng, &uniform01] {
+ return uniform01(prng);
+ });
// Handy names.
double* q = qcX;
diff --git a/internal/ceres/block_sparse_matrix.cc b/internal/ceres/block_sparse_matrix.cc
index ae6bd3a..90bd926 100644
--- a/internal/ceres/block_sparse_matrix.cc
+++ b/internal/ceres/block_sparse_matrix.cc
@@ -375,7 +375,7 @@
}
std::unique_ptr<BlockSparseMatrix> BlockSparseMatrix::CreateRandomMatrix(
- const BlockSparseMatrix::RandomMatrixOptions& options) {
+ const BlockSparseMatrix::RandomMatrixOptions& options, std::mt19937& prng) {
CHECK_GT(options.num_row_blocks, 0);
CHECK_GT(options.min_row_block_size, 0);
CHECK_GT(options.max_row_block_size, 0);
@@ -383,7 +383,6 @@
CHECK_GT(options.block_density, 0.0);
CHECK_LE(options.block_density, 1.0);
- std::mt19937 prng;
std::uniform_int_distribution<int> col_distribution(
options.min_col_block_size, options.max_col_block_size);
std::uniform_int_distribution<int> row_distribution(
@@ -436,9 +435,10 @@
auto matrix = std::make_unique<BlockSparseMatrix>(bs);
double* values = matrix->mutable_values();
std::normal_distribution<double> standard_normal_distribution;
- for (int i = 0; i < matrix->num_nonzeros(); ++i) {
- values[i] = standard_normal_distribution(prng);
- }
+ std::generate_n(
+ values, matrix->num_nonzeros(), [&standard_normal_distribution, &prng] {
+ return standard_normal_distribution(prng);
+ });
return matrix;
}
diff --git a/internal/ceres/block_sparse_matrix.h b/internal/ceres/block_sparse_matrix.h
index 7cef18d..44cb5e5 100644
--- a/internal/ceres/block_sparse_matrix.h
+++ b/internal/ceres/block_sparse_matrix.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2022 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,7 @@
#define CERES_INTERNAL_BLOCK_SPARSE_MATRIX_H_
#include <memory>
+#include <random>
#include "ceres/block_structure.h"
#include "ceres/crs_matrix.h"
@@ -123,7 +124,7 @@
// distributed and whose structure is determined by
// RandomMatrixOptions.
static std::unique_ptr<BlockSparseMatrix> CreateRandomMatrix(
- const RandomMatrixOptions& options);
+ const RandomMatrixOptions& options, std::mt19937& prng);
private:
int num_rows_;
diff --git a/internal/ceres/compressed_row_sparse_matrix.cc b/internal/ceres/compressed_row_sparse_matrix.cc
index 574b0c0..ce587da 100644
--- a/internal/ceres/compressed_row_sparse_matrix.cc
+++ b/internal/ceres/compressed_row_sparse_matrix.cc
@@ -119,11 +119,12 @@
transpose_rows[0] = 0;
}
+template <class RandomNormalFunctor>
void AddRandomBlock(const int num_rows,
const int num_cols,
const int row_block_begin,
const int col_block_begin,
- std::function<double()> dist,
+ RandomNormalFunctor&& randn,
std::vector<int>* rows,
std::vector<int>* cols,
std::vector<double>* values) {
@@ -131,20 +132,21 @@
for (int c = 0; c < num_cols; ++c) {
rows->push_back(row_block_begin + r);
cols->push_back(col_block_begin + c);
- values->push_back(dist());
+ values->push_back(randn());
}
}
}
+template <class RandomNormalFunctor>
void AddSymmetricRandomBlock(const int num_rows,
const int row_block_begin,
- std::function<double()> dist,
+ RandomNormalFunctor&& randn,
std::vector<int>* rows,
std::vector<int>* cols,
std::vector<double>* values) {
for (int r = 0; r < num_rows; ++r) {
for (int c = r; c < num_rows; ++c) {
- const double v = dist();
+ const double v = randn();
rows->push_back(row_block_begin + r);
cols->push_back(row_block_begin + c);
values->push_back(v);
@@ -625,7 +627,8 @@
std::unique_ptr<CompressedRowSparseMatrix>
CompressedRowSparseMatrix::CreateRandomMatrix(
- CompressedRowSparseMatrix::RandomMatrixOptions options) {
+ CompressedRowSparseMatrix::RandomMatrixOptions options,
+ std::mt19937& prng) {
CHECK_GT(options.num_row_blocks, 0);
CHECK_GT(options.min_row_block_size, 0);
CHECK_GT(options.max_row_block_size, 0);
@@ -651,7 +654,6 @@
vector<int> col_blocks;
col_blocks.reserve(options.num_col_blocks);
- std::mt19937 prng;
std::uniform_int_distribution<int> col_distribution(
options.min_col_block_size, options.max_col_block_size);
std::uniform_int_distribution<int> row_distribution(
@@ -708,6 +710,9 @@
// Randomly determine if this block is present or not.
if (uniform01(prng) <= options.block_density) {
+ auto randn = [&standard_normal_distribution, &prng] {
+ return standard_normal_distribution(prng);
+ };
// If the matrix is symmetric, then we take care to generate
// symmetric diagonal blocks.
if (options.storage_type == StorageType::UNSYMMETRIC || r != c) {
@@ -715,14 +720,14 @@
col_blocks[c],
row_block_begin,
col_block_begin,
- values_dist,
+ randn,
&tsm_rows,
&tsm_cols,
&tsm_values);
} else {
AddSymmetricRandomBlock(row_blocks[r],
row_block_begin,
- values_dist,
+ randn,
&tsm_rows,
&tsm_cols,
&tsm_values);
diff --git a/internal/ceres/compressed_row_sparse_matrix.h b/internal/ceres/compressed_row_sparse_matrix.h
index 2580045..d164bef 100644
--- a/internal/ceres/compressed_row_sparse_matrix.h
+++ b/internal/ceres/compressed_row_sparse_matrix.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2022 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,7 @@
#define CERES_INTERNAL_COMPRESSED_ROW_SPARSE_MATRIX_H_
#include <memory>
+#include <random>
#include <vector>
#include "ceres/internal/disable_warnings.h"
@@ -195,7 +196,7 @@
// normally distributed and whose structure is determined by
// RandomMatrixOptions.
static std::unique_ptr<CompressedRowSparseMatrix> CreateRandomMatrix(
- RandomMatrixOptions options);
+ RandomMatrixOptions options, std::mt19937& prng);
private:
static std::unique_ptr<CompressedRowSparseMatrix> FromTripletSparseMatrix(
diff --git a/internal/ceres/compressed_row_sparse_matrix_test.cc b/internal/ceres/compressed_row_sparse_matrix_test.cc
index 42f5498..718a659 100644
--- a/internal/ceres/compressed_row_sparse_matrix_test.cc
+++ b/internal/ceres/compressed_row_sparse_matrix_test.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2022 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -328,6 +328,7 @@
}
TEST(CompressedRowSparseMatrix, FromTripletSparseMatrix) {
+ std::mt19937 prng;
TripletSparseMatrix::RandomMatrixOptions options;
options.num_rows = 5;
options.num_cols = 7;
@@ -336,7 +337,7 @@
const int kNumTrials = 10;
for (int i = 0; i < kNumTrials; ++i) {
std::unique_ptr<TripletSparseMatrix> tsm =
- TripletSparseMatrix::CreateRandomMatrix(options);
+ TripletSparseMatrix::CreateRandomMatrix(options, prng);
std::unique_ptr<CompressedRowSparseMatrix> crsm =
CompressedRowSparseMatrix::FromTripletSparseMatrix(*tsm);
@@ -354,6 +355,7 @@
}
TEST(CompressedRowSparseMatrix, FromTripletSparseMatrixTransposed) {
+ std::mt19937 prng;
TripletSparseMatrix::RandomMatrixOptions options;
options.num_rows = 5;
options.num_cols = 7;
@@ -362,7 +364,7 @@
const int kNumTrials = 10;
for (int i = 0; i < kNumTrials; ++i) {
std::unique_ptr<TripletSparseMatrix> tsm =
- TripletSparseMatrix::CreateRandomMatrix(options);
+ TripletSparseMatrix::CreateRandomMatrix(options, prng);
std::unique_ptr<CompressedRowSparseMatrix> crsm =
CompressedRowSparseMatrix::FromTripletSparseMatrixTransposed(*tsm);
@@ -421,7 +423,7 @@
options.block_density = uniform(prng);
options.storage_type = ::testing::get<0>(param);
std::unique_ptr<CompressedRowSparseMatrix> matrix =
- CompressedRowSparseMatrix::CreateRandomMatrix(options);
+ CompressedRowSparseMatrix::CreateRandomMatrix(options, prng);
const int num_rows = matrix->num_rows();
const int num_cols = matrix->num_cols();
@@ -491,7 +493,7 @@
options.block_density = uniform(prng);
options.storage_type = ::testing::get<0>(param);
std::unique_ptr<CompressedRowSparseMatrix> matrix =
- CompressedRowSparseMatrix::CreateRandomMatrix(options);
+ CompressedRowSparseMatrix::CreateRandomMatrix(options, prng);
const int num_rows = matrix->num_rows();
const int num_cols = matrix->num_cols();
@@ -561,7 +563,7 @@
options.block_density = uniform(prng);
options.storage_type = ::testing::get<0>(param);
std::unique_ptr<CompressedRowSparseMatrix> matrix =
- CompressedRowSparseMatrix::CreateRandomMatrix(options);
+ CompressedRowSparseMatrix::CreateRandomMatrix(options, prng);
const int num_cols = matrix->num_cols();
Vector actual(num_cols);
diff --git a/internal/ceres/corrector_test.cc b/internal/ceres/corrector_test.cc
index 7f58efa..a5dd29c 100644
--- a/internal/ceres/corrector_test.cc
+++ b/internal/ceres/corrector_test.cc
@@ -32,7 +32,6 @@
#include <algorithm>
#include <cmath>
-#include <cstdlib>
#include <cstring>
#include <random>
diff --git a/internal/ceres/gradient_checker_test.cc b/internal/ceres/gradient_checker_test.cc
index 3c5f5da..8d7d10f 100644
--- a/internal/ceres/gradient_checker_test.cc
+++ b/internal/ceres/gradient_checker_test.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2021 Google Inc. All rights reserved.
+// Copyright 2022 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -33,7 +33,6 @@
#include "ceres/gradient_checker.h"
#include <cmath>
-#include <cstdlib>
#include <random>
#include <utility>
#include <vector>
@@ -59,16 +58,16 @@
// version, they are both block vectors, of course.
class GoodTestTerm : public CostFunction {
public:
- GoodTestTerm(int arity, int const* dim) : arity_(arity), return_value_(true) {
- std::mt19937 prng;
- std::uniform_real_distribution<double> distribution(-1.0, 1.0);
-
+ template <class UniformRandomFunctor>
+ GoodTestTerm(int arity, int const* dim, UniformRandomFunctor&& randu)
+ : arity_(arity), return_value_(true) {
+ std::uniform_real_distribution distribution(-1.0, 1.0);
// Make 'arity' random vectors.
a_.resize(arity_);
for (int j = 0; j < arity_; ++j) {
a_[j].resize(dim[j]);
for (int u = 0; u < dim[j]; ++u) {
- a_[j][u] = distribution(prng);
+ a_[j][u] = randu();
}
}
@@ -121,15 +120,15 @@
class BadTestTerm : public CostFunction {
public:
- BadTestTerm(int arity, int const* dim) : arity_(arity) {
- std::mt19937 prng;
- std::uniform_real_distribution<double> distribution(-1.0, 1.0);
+ template <class UniformRandomFunctor>
+ BadTestTerm(int arity, int const* dim, UniformRandomFunctor&& randu)
+ : arity_(arity) {
// Make 'arity' random vectors.
a_.resize(arity_);
for (int j = 0; j < arity_; ++j) {
a_[j].resize(dim[j]);
for (int u = 0; u < dim[j]; ++u) {
- a_[j][u] = distribution(prng);
+ a_[j][u] = randu();
}
}
@@ -210,10 +209,11 @@
FixedArray<double*> parameters(num_parameters);
std::mt19937 prng;
std::uniform_real_distribution<double> distribution(-1.0, 1.0);
+ auto randu = [&prng, &distribution] { return distribution(prng); };
for (int j = 0; j < num_parameters; ++j) {
parameters[j] = new double[parameter_sizes[j]];
for (int u = 0; u < parameter_sizes[j]; ++u) {
- parameters[j][u] = distribution(prng);
+ parameters[j][u] = randu();
}
}
@@ -221,7 +221,7 @@
GradientChecker::ProbeResults results;
// Test that Probe returns true for correct Jacobians.
- GoodTestTerm good_term(num_parameters, parameter_sizes.data());
+ GoodTestTerm good_term(num_parameters, parameter_sizes.data(), randu);
std::vector<const Manifold*>* manifolds = nullptr;
GradientChecker good_gradient_checker(
&good_term, manifolds, numeric_diff_options);
@@ -258,7 +258,7 @@
EXPECT_FALSE(results.error_log.empty());
// Test that Probe returns false for incorrect Jacobians.
- BadTestTerm bad_term(num_parameters, parameter_sizes.data());
+ BadTestTerm bad_term(num_parameters, parameter_sizes.data(), randu);
GradientChecker bad_gradient_checker(
&bad_term, manifolds, numeric_diff_options);
EXPECT_FALSE(
diff --git a/internal/ceres/gradient_checking_cost_function_test.cc b/internal/ceres/gradient_checking_cost_function_test.cc
index caf4f25..87c3278 100644
--- a/internal/ceres/gradient_checking_cost_function_test.cc
+++ b/internal/ceres/gradient_checking_cost_function_test.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2022 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -69,15 +69,15 @@
public:
// The constructor of this function needs to know the number
// of blocks desired, and the size of each block.
- TestTerm(int arity, int const* dim) : arity_(arity) {
- std::mt19937 prng;
- std::uniform_real_distribution<double> uniform01(-1.0, 1.0);
+ template <class UniformRandomFunctor>
+ TestTerm(int arity, int const* dim, UniformRandomFunctor&& randu)
+ : arity_(arity) {
// Make 'arity' random vectors.
a_.resize(arity_);
for (int j = 0; j < arity_; ++j) {
a_[j].resize(dim[j]);
for (int u = 0; u < dim[j]; ++u) {
- a_[j][u] = uniform01(prng);
+ a_[j][u] = randu();
}
}
@@ -139,11 +139,12 @@
// Make a random set of blocks.
vector<double*> parameters(arity);
std::mt19937 prng;
- std::uniform_real_distribution<double> uniform01(-1.0, 1.0);
+ std::uniform_real_distribution<double> distribution(-1.0, 1.0);
+ auto randu = [&prng, &distribution] { return distribution(prng); };
for (int j = 0; j < arity; ++j) {
parameters[j] = new double[dim[j]];
for (int u = 0; u < dim[j]; ++u) {
- parameters[j][u] = uniform01(prng);
+ parameters[j][u] = randu();
}
}
@@ -162,7 +163,7 @@
const double kRelativeStepSize = 1e-6;
const double kRelativePrecision = 1e-4;
- TestTerm<-1, -1> term(arity, dim);
+ TestTerm<-1, -1> term(arity, dim, randu);
GradientCheckingIterationCallback callback;
auto gradient_checking_cost_function =
CreateGradientCheckingCostFunction(&term,
@@ -196,11 +197,12 @@
// Make a random set of blocks.
vector<double*> parameters(arity);
std::mt19937 prng;
- std::uniform_real_distribution<double> uniform01(-1.0, 1.0);
+ std::uniform_real_distribution<double> distribution(-1.0, 1.0);
+ auto randu = [&prng, &distribution] { return distribution(prng); };
for (int j = 0; j < arity; ++j) {
parameters[j] = new double[dim[j]];
for (int u = 0; u < dim[j]; ++u) {
- parameters[j][u] = uniform01(prng);
+ parameters[j][u] = randu();
}
}
@@ -218,7 +220,7 @@
// Should have one term that's bad, causing everything to get dumped.
LOG(INFO) << "Bad gradient";
{
- TestTerm<1, 2> term(arity, dim);
+ TestTerm<1, 2> term(arity, dim, randu);
GradientCheckingIterationCallback callback;
auto gradient_checking_cost_function =
CreateGradientCheckingCostFunction(&term,
@@ -238,7 +240,7 @@
// The gradient is correct, so no errors are reported.
LOG(INFO) << "Good gradient";
{
- TestTerm<-1, -1> term(arity, dim);
+ TestTerm<-1, -1> term(arity, dim, randu);
GradientCheckingIterationCallback callback;
auto gradient_checking_cost_function =
CreateGradientCheckingCostFunction(&term,
diff --git a/internal/ceres/inner_product_computer_test.cc b/internal/ceres/inner_product_computer_test.cc
index 5bd4c50..4573b6b 100644
--- a/internal/ceres/inner_product_computer_test.cc
+++ b/internal/ceres/inner_product_computer_test.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2022 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -109,7 +109,7 @@
VLOG(2) << "block density: " << options.block_density;
std::unique_ptr<BlockSparseMatrix> random_matrix(
- BlockSparseMatrix::CreateRandomMatrix(options));
+ BlockSparseMatrix::CreateRandomMatrix(options, prng));
TripletSparseMatrix tsm(random_matrix->num_rows(),
random_matrix->num_cols(),
@@ -169,7 +169,7 @@
VLOG(2) << "block density: " << options.block_density;
std::unique_ptr<BlockSparseMatrix> random_matrix(
- BlockSparseMatrix::CreateRandomMatrix(options));
+ BlockSparseMatrix::CreateRandomMatrix(options, prng));
const std::vector<CompressedRow>& row_blocks =
random_matrix->block_structure()->rows;
diff --git a/internal/ceres/normal_prior_test.cc b/internal/ceres/normal_prior_test.cc
index 25e6322..881038f 100644
--- a/internal/ceres/normal_prior_test.cc
+++ b/internal/ceres/normal_prior_test.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2022 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -42,6 +42,7 @@
TEST(NormalPriorTest, ResidualAtRandomPosition) {
std::mt19937 prng;
std::uniform_real_distribution<double> distribution(-1.0, 1.0);
+ auto randu = [&distribution, &prng] { return distribution(prng); };
for (int num_rows = 1; num_rows < 5; ++num_rows) {
for (int num_cols = 1; num_cols < 5; ++num_cols) {
Vector b(num_cols);
@@ -50,7 +51,7 @@
A.setRandom();
auto* x = new double[num_cols];
- for (int i = 0; i < num_cols; ++i) x[i] = distribution(prng);
+ std::generate_n(x, num_cols, randu);
auto* jacobian = new double[num_rows * num_cols];
Vector residuals(num_rows);
@@ -77,6 +78,7 @@
TEST(NormalPriorTest, ResidualAtRandomPositionNullJacobians) {
std::mt19937 prng;
std::uniform_real_distribution<double> distribution(-1.0, 1.0);
+ auto randu = [&distribution, &prng] { return distribution(prng); };
for (int num_rows = 1; num_rows < 5; ++num_rows) {
for (int num_cols = 1; num_cols < 5; ++num_cols) {
Vector b(num_cols);
@@ -85,7 +87,7 @@
A.setRandom();
auto* x = new double[num_cols];
- for (int i = 0; i < num_cols; ++i) x[i] = distribution(prng);
+ std::generate_n(x, num_cols, randu);
double* jacobians[1];
jacobians[0] = nullptr;
diff --git a/internal/ceres/numeric_diff_cost_function_test.cc b/internal/ceres/numeric_diff_cost_function_test.cc
index b9a0beb..dcffcff 100644
--- a/internal/ceres/numeric_diff_cost_function_test.cc
+++ b/internal/ceres/numeric_diff_cost_function_test.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2022 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,7 @@
#include <array>
#include <cmath>
#include <memory>
+#include <random>
#include <string>
#include <vector>
@@ -310,6 +311,7 @@
}
TEST(NumericDiffCostFunction, RandomizedFunctorRidders) {
+ std::mt19937 prng;
NumericDiffOptions options;
// Larger initial step size is chosen to produce robust results in the
// presence of random noise.
@@ -321,15 +323,16 @@
1, // number of residuals
1 // size of x1
>>(
- new RandomizedFunctor(kNoiseFactor, kRandomSeed),
+ new RandomizedFunctor(kNoiseFactor, prng),
TAKE_OWNERSHIP,
1,
options);
- RandomizedFunctor functor(kNoiseFactor, kRandomSeed);
+ RandomizedFunctor functor(kNoiseFactor, prng);
functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function);
}
TEST(NumericDiffCostFunction, RandomizedCostFunctionRidders) {
+ std::mt19937 prng;
NumericDiffOptions options;
// Larger initial step size is chosen to produce robust results in the
// presence of random noise.
@@ -341,12 +344,12 @@
1, // number of residuals
1 // size of x1
>>(
- new RandomizedCostFunction(kNoiseFactor, kRandomSeed),
+ new RandomizedCostFunction(kNoiseFactor, prng),
TAKE_OWNERSHIP,
1,
options);
- RandomizedFunctor functor(kNoiseFactor, kRandomSeed);
+ RandomizedFunctor functor(kNoiseFactor, prng);
functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function);
}
diff --git a/internal/ceres/numeric_diff_test_utils.cc b/internal/ceres/numeric_diff_test_utils.cc
index 3d78e36..9da514e 100644
--- a/internal/ceres/numeric_diff_test_utils.cc
+++ b/internal/ceres/numeric_diff_test_utils.cc
@@ -226,14 +226,7 @@
}
bool RandomizedFunctor::operator()(const double* x1, double* residuals) const {
- double random_value =
- static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
-
- // Normalize noise to [-factor, factor].
- random_value *= 2.0;
- random_value -= 1.0;
- random_value *= noise_factor_;
-
+ double random_value = uniform_distribution_(*prng_);
residuals[0] = x1[0] * x1[0] + random_value;
return true;
}
@@ -244,9 +237,6 @@
const double kTolerance = 2e-4;
- // Initialize random number generator with given seed.
- srand(random_seed_);
-
for (double& test : kTests) {
double* parameters[] = {&test};
double dydx;
diff --git a/internal/ceres/numeric_diff_test_utils.h b/internal/ceres/numeric_diff_test_utils.h
index 68ae5ed..8d3f14b 100644
--- a/internal/ceres/numeric_diff_test_utils.h
+++ b/internal/ceres/numeric_diff_test_utils.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2022 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,8 @@
#ifndef CERES_INTERNAL_NUMERIC_DIFF_TEST_UTILS_H_
#define CERES_INTERNAL_NUMERIC_DIFF_TEST_UTILS_H_
+#include <random>
+
#include "ceres/cost_function.h"
#include "ceres/internal/export.h"
#include "ceres/sized_cost_function.h"
@@ -116,8 +118,10 @@
// y = x^2 + [random noise], dy/dx ~ 2x
class CERES_NO_EXPORT RandomizedFunctor {
public:
- RandomizedFunctor(double noise_factor, unsigned int random_seed)
- : noise_factor_(noise_factor), random_seed_(random_seed) {}
+ RandomizedFunctor(double noise_factor, std::mt19937& prng)
+ : noise_factor_(noise_factor),
+ prng_(&prng),
+ uniform_distribution_{-noise_factor, noise_factor} {}
bool operator()(const double* x1, double* residuals) const;
void ExpectCostFunctionEvaluationIsNearlyCorrect(
@@ -125,13 +129,16 @@
private:
double noise_factor_;
- unsigned int random_seed_;
+ // Store the generator as a pointer to be able to modify the instance the
+ // pointer is pointing to.
+ std::mt19937* prng_;
+ mutable std::uniform_real_distribution<> uniform_distribution_;
};
class CERES_NO_EXPORT RandomizedCostFunction : public SizedCostFunction<1, 1> {
public:
- RandomizedCostFunction(double noise_factor, unsigned int random_seed)
- : functor_(noise_factor, random_seed) {}
+ RandomizedCostFunction(double noise_factor, std::mt19937& prng)
+ : functor_(noise_factor, prng) {}
bool Evaluate(double const* const* parameters,
double* residuals,
diff --git a/internal/ceres/partitioned_matrix_view_test.cc b/internal/ceres/partitioned_matrix_view_test.cc
index cb3dd14..e4484dd 100644
--- a/internal/ceres/partitioned_matrix_view_test.cc
+++ b/internal/ceres/partitioned_matrix_view_test.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2022 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
diff --git a/internal/ceres/reorder_program_test.cc b/internal/ceres/reorder_program_test.cc
index 872f381..d6a6577 100644
--- a/internal/ceres/reorder_program_test.cc
+++ b/internal/ceres/reorder_program_test.cc
@@ -265,7 +265,7 @@
problem.GetResidualBlocks(&residual_block_ids);
std::vector<ResidualBlock*> residual_blocks =
problem.program().residual_blocks();
- auto rng = std::default_random_engine{};
+ auto rng = std::mt19937{};
for (int i = 1; i < 6; ++i) {
std::shuffle(
std::begin(residual_block_ids), std::end(residual_block_ids), rng);
diff --git a/internal/ceres/rotation_test.cc b/internal/ceres/rotation_test.cc
index d6de650..97ea514 100644
--- a/internal/ceres/rotation_test.cc
+++ b/internal/ceres/rotation_test.cc
@@ -32,6 +32,7 @@
#include <cmath>
#include <limits>
+#include <random>
#include <string>
#include "ceres/internal/eigen.h"
@@ -56,11 +57,6 @@
const double kPi = 3.14159265358979323846;
const double kHalfSqrt2 = 0.707106781186547524401;
-static double RandDouble() {
- double r = rand();
- return r / RAND_MAX;
-}
-
// A tolerance value for floating-point comparisons.
static double const kTolerance = numeric_limits<double>::epsilon() * 10;
@@ -322,20 +318,22 @@
// Takes a bunch of random axis/angle values, converts them to quaternions,
// and back again.
TEST(Rotation, AngleAxisToQuaterionAndBack) {
- srand(5);
+ std::mt19937 prng;
+ std::uniform_real_distribution<double> uniform_distribution{-1.0, 1.0};
for (int i = 0; i < kNumTrials; i++) {
double axis_angle[3];
// Make an axis by choosing three random numbers in [-1, 1) and
// normalizing.
double norm = 0;
for (double& coeff : axis_angle) {
- coeff = RandDouble() * 2 - 1;
+ coeff = uniform_distribution(prng);
norm += coeff * coeff;
}
norm = sqrt(norm);
// Angle in [-pi, pi).
- double theta = kPi * 2 * RandDouble() - kPi;
+ double theta = uniform_distribution(
+ prng, std::uniform_real_distribution<double>::param_type{-kPi, kPi});
for (double& coeff : axis_angle) {
coeff = coeff * theta / norm;
}
@@ -355,13 +353,14 @@
// Takes a bunch of random quaternions, converts them to axis/angle,
// and back again.
TEST(Rotation, QuaterionToAngleAxisAndBack) {
- srand(5);
+ std::mt19937 prng;
+ std::uniform_real_distribution<double> uniform_distribution{-1.0, 1.0};
for (int i = 0; i < kNumTrials; i++) {
double quaternion[4];
// Choose four random numbers in [-1, 1) and normalize.
double norm = 0;
for (double& coeff : quaternion) {
- coeff = RandDouble() * 2 - 1;
+ coeff = uniform_distribution(prng);
norm += coeff * coeff;
}
norm = sqrt(norm);
@@ -432,20 +431,24 @@
double matrix[9];
double out_axis_angle[3];
- srand(5);
+ std::mt19937 prng;
+ std::uniform_real_distribution<double> uniform_distribution{-1.0, 1.0};
for (int i = 0; i < kNumTrials; i++) {
// Make an axis by choosing three random numbers in [-1, 1) and
// normalizing.
double norm = 0;
for (double& coeff : in_axis_angle) {
- coeff = RandDouble() * 2 - 1;
+ coeff = uniform_distribution(prng);
norm += coeff * coeff;
}
norm = sqrt(norm);
// Angle in [pi - kMaxSmallAngle, pi).
- const double kMaxSmallAngle = 1e-8;
- double theta = kPi - kMaxSmallAngle * RandDouble();
+ constexpr double kMaxSmallAngle = 1e-8;
+ double theta =
+ uniform_distribution(prng,
+ std::uniform_real_distribution<double>::param_type{
+ kPi - kMaxSmallAngle, kPi});
for (double& coeff : in_axis_angle) {
coeff *= (theta / norm);
@@ -531,20 +534,22 @@
// Takes a bunch of random axis/angle values, converts them to rotation
// matrices, and back again.
TEST(Rotation, AngleAxisToRotationMatrixAndBack) {
- srand(5);
+ std::mt19937 prng;
+ std::uniform_real_distribution<double> uniform_distribution{-1.0, 1.0};
for (int i = 0; i < kNumTrials; i++) {
double axis_angle[3];
// Make an axis by choosing three random numbers in [-1, 1) and
// normalizing.
double norm = 0;
for (double& i : axis_angle) {
- i = RandDouble() * 2 - 1;
+ i = uniform_distribution(prng);
norm += i * i;
}
norm = sqrt(norm);
// Angle in [-pi, pi).
- double theta = kPi * 2 * RandDouble() - kPi;
+ double theta = uniform_distribution(
+ prng, std::uniform_real_distribution<double>::param_type{-kPi, kPi});
for (double& i : axis_angle) {
i = i * theta / norm;
}
@@ -564,20 +569,25 @@
// Takes a bunch of random axis/angle values near zero, converts them
// to rotation matrices, and back again.
TEST(Rotation, AngleAxisToRotationMatrixAndBackNearZero) {
- srand(5);
+ std::mt19937 prng;
+ std::uniform_real_distribution<double> uniform_distribution{-1.0, 1.0};
for (int i = 0; i < kNumTrials; i++) {
double axis_angle[3];
// Make an axis by choosing three random numbers in [-1, 1) and
// normalizing.
double norm = 0;
for (double& i : axis_angle) {
- i = RandDouble() * 2 - 1;
+ i = uniform_distribution(prng);
norm += i * i;
}
norm = sqrt(norm);
// Tiny theta.
- double theta = 1e-16 * (kPi * 2 * RandDouble() - kPi);
+ constexpr double kScale = 1e-16;
+ double theta =
+ uniform_distribution(prng,
+ std::uniform_real_distribution<double>::param_type{
+ -kScale * kPi, kScale * kPi});
for (double& i : axis_angle) {
i = i * theta / norm;
}
@@ -647,11 +657,12 @@
// Test that a random rotation produces an orthonormal rotation
// matrix.
TEST(EulerAnglesToRotationMatrix, IsOrthonormal) {
- srand(5);
+ std::mt19937 prng;
+ std::uniform_real_distribution<double> uniform_distribution{-180.0, 180.0};
for (int trial = 0; trial < kNumTrials; ++trial) {
double euler_angles_degrees[3];
for (double& euler_angles_degree : euler_angles_degrees) {
- euler_angles_degree = RandDouble() * 360.0 - 180.0;
+ euler_angles_degree = uniform_distribution(prng);
}
double rotation_matrix[9];
EulerAnglesToRotationMatrix(euler_angles_degrees, 3, rotation_matrix);
@@ -906,13 +917,15 @@
// Verify that (a * b) * c == a * (b * c).
TEST(Quaternion, MultiplicationIsAssociative) {
+ std::mt19937 prng;
+ std::uniform_real_distribution<double> uniform_distribution{-1.0, 1.0};
double a[4];
double b[4];
double c[4];
for (int i = 0; i < 4; ++i) {
- a[i] = 2 * RandDouble() - 1;
- b[i] = 2 * RandDouble() - 1;
- c[i] = 2 * RandDouble() - 1;
+ a[i] = uniform_distribution(prng);
+ b[i] = uniform_distribution(prng);
+ c[i] = uniform_distribution(prng);
}
double ab[4];
@@ -932,6 +945,8 @@
}
TEST(AngleAxis, RotatePointGivesSameAnswerAsRotationMatrix) {
+ std::mt19937 prng;
+ std::uniform_real_distribution<double> uniform_distribution{-1.0, 1.0};
double angle_axis[3];
double R[9];
double p[3];
@@ -943,8 +958,8 @@
for (int j = 0; j < 50; ++j) {
double norm2 = 0.0;
for (int k = 0; k < 3; ++k) {
- angle_axis[k] = 2.0 * RandDouble() - 1.0;
- p[k] = 2.0 * RandDouble() - 1.0;
+ angle_axis[k] = uniform_distribution(prng);
+ p[k] = uniform_distribution(prng);
norm2 = angle_axis[k] * angle_axis[k];
}
@@ -976,6 +991,8 @@
}
TEST(AngleAxis, NearZeroRotatePointGivesSameAnswerAsRotationMatrix) {
+ std::mt19937 prng;
+ std::uniform_real_distribution<double> uniform_distribution{-1.0, 1.0};
double angle_axis[3];
double R[9];
double p[3];
@@ -985,8 +1002,8 @@
for (int i = 0; i < 10000; ++i) {
double norm2 = 0.0;
for (int k = 0; k < 3; ++k) {
- angle_axis[k] = 2.0 * RandDouble() - 1.0;
- p[k] = 2.0 * RandDouble() - 1.0;
+ angle_axis[k] = uniform_distribution(prng);
+ p[k] = uniform_distribution(prng);
norm2 = angle_axis[k] * angle_axis[k];
}
@@ -1111,7 +1128,12 @@
}
TEST(RotationMatrixToAngleAxis, ExhaustiveRoundTrip) {
- const double kMaxSmallAngle = 1e-8;
+ constexpr double kMaxSmallAngle = 1e-8;
+ std::mt19937 prng;
+ std::uniform_real_distribution<double> uniform_distribution1{
+ kPi - kMaxSmallAngle, kPi};
+ std::uniform_real_distribution<double> uniform_distribution2{
+ -1.0, 2.0 * kMaxSmallAngle - 1.0};
const int kNumSteps = 1000;
for (int i = 0; i < kNumSteps; ++i) {
const double theta = static_cast<double>(i) / kNumSteps * 2.0 * kPi;
@@ -1121,10 +1143,10 @@
CheckRotationMatrixToAngleAxisRoundTrip(theta, phi, kPi);
// Rotation of angle approximately Pi.
CheckRotationMatrixToAngleAxisRoundTrip(
- theta, phi, kPi - kMaxSmallAngle * RandDouble());
+ theta, phi, uniform_distribution1(prng));
// Rotations of angle approximately zero.
CheckRotationMatrixToAngleAxisRoundTrip(
- theta, phi, kMaxSmallAngle * 2.0 * RandDouble() - 1.0);
+ theta, phi, uniform_distribution2(prng));
}
}
}
diff --git a/internal/ceres/schur_eliminator_benchmark.cc b/internal/ceres/schur_eliminator_benchmark.cc
index 0973e73..c6425ce 100644
--- a/internal/ceres/schur_eliminator_benchmark.cc
+++ b/internal/ceres/schur_eliminator_benchmark.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2022 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -91,11 +91,9 @@
matrix_ = std::make_unique<BlockSparseMatrix>(bs);
double* values = matrix_->mutable_values();
- std::mt19937 prng;
- std::normal_distribution<double> standard_normal;
- for (int i = 0; i < matrix_->num_nonzeros(); ++i) {
- values[i] = standard_normal(prng);
- }
+ std::generate_n(values, matrix_->num_nonzeros(), [this] {
+ return standard_normal(prng);
+ });
b_.resize(matrix_->num_rows());
b_.setRandom();
@@ -128,6 +126,8 @@
Vector diagonal_;
Vector z_;
Vector y_;
+ std::mt19937 prng;
+ std::normal_distribution<> standard_normal;
};
static void BM_SchurEliminatorEliminate(benchmark::State& state) {
diff --git a/internal/ceres/schur_eliminator_test.cc b/internal/ceres/schur_eliminator_test.cc
index da27019..17ce67d 100644
--- a/internal/ceres/schur_eliminator_test.cc
+++ b/internal/ceres/schur_eliminator_test.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2022 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -284,10 +284,10 @@
BlockSparseMatrix matrix(bs);
double* values = matrix.mutable_values();
std::mt19937 prng;
- std::normal_distribution<double> standard_normal;
- for (int i = 0; i < matrix.num_nonzeros(); ++i) {
- values[i] = standard_normal(prng);
- }
+ std::normal_distribution<> standard_normal;
+ std::generate_n(values, matrix.num_nonzeros(), [&prng, &standard_normal] {
+ return standard_normal(prng);
+ });
Vector b(matrix.num_rows());
b.setRandom();
diff --git a/internal/ceres/sparse_cholesky_test.cc b/internal/ceres/sparse_cholesky_test.cc
index 73e1455..2397fdd 100644
--- a/internal/ceres/sparse_cholesky_test.cc
+++ b/internal/ceres/sparse_cholesky_test.cc
@@ -55,7 +55,8 @@
const int num_col_blocks,
const int min_col_block_size,
const int max_col_block_size,
- const double block_density) {
+ const double block_density,
+ std::mt19937& prng) {
// Create a random matrix
BlockSparseMatrix::RandomMatrixOptions options;
options.num_col_blocks = num_col_blocks;
@@ -66,7 +67,7 @@
options.min_row_block_size = 1;
options.max_row_block_size = max_col_block_size;
options.block_density = block_density;
- auto random_matrix = BlockSparseMatrix::CreateRandomMatrix(options);
+ auto random_matrix = BlockSparseMatrix::CreateRandomMatrix(options, prng);
// Add a diagonal block sparse matrix to make it full rank.
Vector diagonal = Vector::Ones(random_matrix->num_cols());
@@ -110,7 +111,8 @@
const int num_blocks,
const int min_block_size,
const int max_block_size,
- const double block_density) {
+ const double block_density,
+ std::mt19937& prng) {
LinearSolver::Options sparse_cholesky_options;
sparse_cholesky_options.sparse_linear_algebra_library_type =
sparse_linear_algebra_library_type;
@@ -120,7 +122,7 @@
sparse_cholesky->StorageType();
auto m = CreateRandomFullRankMatrix(
- num_blocks, min_block_size, max_block_size, block_density);
+ num_blocks, min_block_size, max_block_size, block_density, prng);
auto inner_product_computer = InnerProductComputer::Create(*m, storage_type);
inner_product_computer->Compute();
CompressedRowSparseMatrix* lhs = inner_product_computer->mutable_result();
@@ -184,7 +186,8 @@
num_blocks,
kMinBlockSize,
kMaxBlockSize,
- block_density);
+ block_density,
+ prng);
}
}
}
diff --git a/internal/ceres/subset_preconditioner_test.cc b/internal/ceres/subset_preconditioner_test.cc
index cd86695..5fb7f26 100644
--- a/internal/ceres/subset_preconditioner_test.cc
+++ b/internal/ceres/subset_preconditioner_test.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2022 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,7 @@
#include "ceres/subset_preconditioner.h"
#include <memory>
+#include <random>
#include "Eigen/Dense"
#include "Eigen/SparseCore"
@@ -100,13 +101,13 @@
options.max_row_block_size = 4;
options.block_density = 0.9;
- m_ = BlockSparseMatrix::CreateRandomMatrix(options);
+ m_ = BlockSparseMatrix::CreateRandomMatrix(options, prng);
start_row_block_ = m_->block_structure()->rows.size();
// Ensure that the bottom part of the matrix has the same column
// block structure.
options.col_blocks = m_->block_structure()->cols;
- b_ = BlockSparseMatrix::CreateRandomMatrix(options);
+ b_ = BlockSparseMatrix::CreateRandomMatrix(options, prng);
m_->AppendRows(*b_);
// Create a Identity block diagonal matrix with the same column
@@ -132,6 +133,7 @@
std::unique_ptr<Preconditioner> preconditioner_;
Vector diagonal_;
int start_row_block_;
+ std::mt19937 prng;
};
TEST_P(SubsetPreconditionerTest, foo) {
diff --git a/internal/ceres/triplet_sparse_matrix.cc b/internal/ceres/triplet_sparse_matrix.cc
index 49d367a..37a779f 100644
--- a/internal/ceres/triplet_sparse_matrix.cc
+++ b/internal/ceres/triplet_sparse_matrix.cc
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2022 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -310,7 +310,8 @@
}
std::unique_ptr<TripletSparseMatrix> TripletSparseMatrix::CreateRandomMatrix(
- const TripletSparseMatrix::RandomMatrixOptions& options) {
+ const TripletSparseMatrix::RandomMatrixOptions& options,
+ std::mt19937& prng) {
CHECK_GT(options.num_rows, 0);
CHECK_GT(options.num_cols, 0);
CHECK_GT(options.density, 0.0);
@@ -319,7 +320,6 @@
std::vector<int> rows;
std::vector<int> cols;
std::vector<double> values;
- std::mt19937 prng;
std::uniform_real_distribution<double> uniform01(0.0, 1.0);
std::normal_distribution<double> standard_normal;
while (rows.empty()) {
diff --git a/internal/ceres/triplet_sparse_matrix.h b/internal/ceres/triplet_sparse_matrix.h
index c962455..549966a 100644
--- a/internal/ceres/triplet_sparse_matrix.h
+++ b/internal/ceres/triplet_sparse_matrix.h
@@ -1,5 +1,5 @@
// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2022 Google Inc. All rights reserved.
// http://ceres-solver.org/
//
// Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,7 @@
#define CERES_INTERNAL_TRIPLET_SPARSE_MATRIX_H_
#include <memory>
+#include <random>
#include <vector>
#include "ceres/crs_matrix.h"
@@ -135,7 +136,8 @@
// normally distributed and whose structure is determined by
// RandomMatrixOptions.
static std::unique_ptr<TripletSparseMatrix> CreateRandomMatrix(
- const TripletSparseMatrix::RandomMatrixOptions& options);
+ const TripletSparseMatrix::RandomMatrixOptions& options,
+ std::mt19937& prng);
// Load a triplet sparse matrix from a text file.
static std::unique_ptr<TripletSparseMatrix> CreateFromTextFile(FILE* file);