Spectra
1.2.0
Header-only C++ Library for Large Scale Eigenvalue Problems
Toggle main menu visibility
Loading...
Searching...
No Matches
SimpleRandom.h
1
// Copyright (C) 2016-2025 Yixuan Qiu <yixuan.qiu@cos.name>
2
//
3
// This Source Code Form is subject to the terms of the Mozilla
4
// Public License v. 2.0. If a copy of the MPL was not distributed
5
// with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
7
#ifndef SPECTRA_SIMPLE_RANDOM_H
8
#define SPECTRA_SIMPLE_RANDOM_H
9
10
#include <Eigen/Core>
11
#include <complex>
12
14
15
namespace
Spectra {
16
17
// We need a simple pseudo random number generator here:
18
// 1. It is used to generate initial and restarted residual vector.
19
// 2. It is not necessary to be so "random" and advanced. All we hope
20
// is that the residual vector is not in the space spanned by the
21
// current Krylov space. This should be met almost surely.
22
// 3. We don't want to call RNG in C++, since we actually want the
23
// algorithm to be deterministic. Also, calling RNG in C/C++ is not
24
// allowed in R packages submitted to CRAN.
25
// 4. The method should be as simple as possible, so an LCG is enough.
26
// 5. Based on public domain code by Ray Gardner
27
// http://stjarnhimlen.se/snippets/rg_rand.c
28
29
// Given a 32-bit integer as the seed, generate a pseudo random 32-bit integer
30
inline
long
next_long_rand(
long
seed)
31
{
32
constexpr
unsigned
int
m_a = 16807;
// multiplier
33
constexpr
unsigned
long
m_max = 2147483647L;
// 2^31 - 1
34
35
unsigned
long
lo, hi;
36
37
lo = m_a * (long) (seed & 0xFFFF);
38
hi = m_a * (long) ((
unsigned
long
) seed >> 16);
39
lo += (hi & 0x7FFF) << 16;
40
if
(lo > m_max)
41
{
42
lo &= m_max;
43
++lo;
44
}
45
lo += hi >> 15;
46
if
(lo > m_max)
47
{
48
lo &= m_max;
49
++lo;
50
}
51
return
(
long
) lo;
52
}
53
54
// Generate a random scalar from the given random seed
55
// Also overwrite seed with the new random integer
56
template
<
typename
Scalar>
57
struct
RandomScalar
58
{
59
static
Scalar run(
long
& seed)
60
{
61
constexpr
unsigned
long
m_max = 2147483647L;
// 2^31 - 1
62
63
seed = next_long_rand(seed);
64
return
Scalar(seed) / Scalar(m_max) - Scalar(0.5);
65
}
66
};
67
// Specialization for complex values
68
template
<
typename
RealScalar>
69
struct
RandomScalar<std::complex<RealScalar>>
70
{
71
static
std::complex<RealScalar> run(
long
& seed)
72
{
73
RealScalar r = RandomScalar<RealScalar>::run(seed);
74
RealScalar i = RandomScalar<RealScalar>::run(seed);
75
return
std::complex<RealScalar>(r, i);
76
}
77
};
78
79
// A simple random generator class
80
template
<
typename
Scalar =
double
>
81
class
SimpleRandom
82
{
83
private
:
84
// The real part type of the matrix element
85
using
RealScalar =
typename
Eigen::NumTraits<Scalar>::Real;
86
using
Index = Eigen::Index;
87
using
Vector = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
88
89
long
m_rand;
// RNG state
90
91
public
:
92
SimpleRandom(
unsigned
long
init_seed)
93
{
94
constexpr
unsigned
long
m_max = 2147483647L;
// 2^31 - 1
95
m_rand = init_seed ? (init_seed & m_max) : 1;
96
}
97
98
// Return a single random number, ranging from -0.5 to 0.5
99
Scalar random()
100
{
101
return
RandomScalar<Scalar>::run(m_rand);
102
}
103
104
// Fill the given vector with random numbers
105
// Ranging from -0.5 to 0.5
106
void
random_vec(Vector& vec)
107
{
108
const
Index len = vec.size();
109
for
(Index i = 0; i < len; i++)
110
{
111
vec[i] = random();
112
}
113
}
114
115
// Return a vector of random numbers
116
// Ranging from -0.5 to 0.5
117
Vector random_vec(
const
Index len)
118
{
119
Vector res(len);
120
random_vec(res);
121
return
res;
122
}
123
};
124
125
}
// namespace Spectra
126
128
129
#endif
// SPECTRA_SIMPLE_RANDOM_H
Spectra
Util
SimpleRandom.h
Generated by
1.17.0