Skip to content

Commit 5a193df

Browse files
committed
[FEATURE]: class for random transect sampling in analysis lib
1 parent f4fc134 commit 5a193df

File tree

5 files changed

+1037
-0
lines changed

5 files changed

+1037
-0
lines changed

src/analysis/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ SET(QGIS_ANALYSIS_SRCS
3434
raster/qgsrastercalcnode.cpp
3535
raster/qgsrastercalculator.cpp
3636
raster/qgsrastermatrix.cpp
37+
vector/mersenne-twister.cpp
3738
vector/qgsgeometryanalyzer.cpp
39+
vector/qgstransectsample.cpp
3840
vector/qgszonalstatistics.cpp
3941
vector/qgsoverlayanalyzer.cpp
4042

+226
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
/*
2+
* The Mersenne Twister pseudo-random number generator (PRNG)
3+
*
4+
* This is an implementation of fast PRNG called MT19937,
5+
* meaning it has a period of 2^19937-1, which is a Mersenne
6+
* prime.
7+
*
8+
* This PRNG is fast and suitable for non-cryptographic code.
9+
* For instance, it would be perfect for Monte Carlo simulations,
10+
* etc.
11+
*
12+
* For all the details on this algorithm, see the original paper:
13+
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/ARTICLES/mt.pdf
14+
*
15+
* Written by Christian Stigen Larsen
16+
* http://csl.sublevel3.org
17+
*
18+
* Distributed under the modified BSD license.
19+
*
20+
* 2012-01-11
21+
*/
22+
23+
#include <stdio.h>
24+
#include <stdint.h>
25+
#include <limits>
26+
#include "mersenne-twister.h"
27+
28+
/*
29+
* We have an array of 624 32-bit values, and there are
30+
* 31 unused bits, so we have a seed value of
31+
* 624*32-31 = 19937 bits.
32+
*/
33+
static const unsigned SIZE = 624;
34+
static const unsigned PERIOD = 397;
35+
static const unsigned DIFF = SIZE-PERIOD;
36+
37+
static uint32_t MT[SIZE];
38+
static unsigned index = 0;
39+
40+
#define M32(x) (0x80000000 & x) // 32nd Most Significant Bit
41+
#define L31(x) (0x7FFFFFFF & x) // 31 Least Significant Bits
42+
#define ODD(x) (x & 1) // Check if number is odd
43+
44+
#define UINT32_MAX std::numeric_limits<uint32_t>::max()
45+
46+
static inline void generate_numbers()
47+
{
48+
/*
49+
* Originally, we had one loop with i going from [0, SIZE) and
50+
* two modulus operations:
51+
*
52+
* for ( register unsigned i=0; i<SIZE; ++i ) {
53+
* register uint32_t y = M32(MT[i]) | L31(MT[(i+1) % SIZE]);
54+
* MT[i] = MT[(i + PERIOD) % SIZE] ^ (y>>1);
55+
* if ( ODD(y) ) MT[i] ^= 0x9908b0df;
56+
* }
57+
*
58+
* For performance reasons, we've unrolled the loop three times, thus
59+
* mitigating the need for any modulus operations.
60+
*
61+
* Anyway, it seems this trick is old hat:
62+
* http://www.quadibloc.com/crypto/co4814.htm
63+
*
64+
*/
65+
66+
static const uint32_t MATRIX[2] = {0, 0x9908b0df};
67+
register uint32_t y, i;
68+
69+
// i = [0 ... 226]
70+
for ( i=0; i<DIFF; ++i ) {
71+
/*
72+
* We're doing 226 = 113*2, an even number of steps, so we can
73+
* safely unroll one more step here for speed:
74+
*/
75+
y = M32(MT[i]) | L31(MT[i+1]);
76+
MT[i] = MT[i+PERIOD] ^ (y>>1) ^ MATRIX[ODD(y)];
77+
78+
++i;
79+
y = M32(MT[i]) | L31(MT[i+1]);
80+
MT[i] = MT[i+PERIOD] ^ (y>>1) ^ MATRIX[ODD(y)];
81+
}
82+
83+
#define UNROLL \
84+
y = M32(MT[i]) | L31(MT[i+1]); \
85+
MT[i] = MT[i-DIFF] ^ (y>>1) ^ MATRIX[ODD(y)]; \
86+
++i;
87+
88+
// i = [227 ... 622]
89+
for ( i=DIFF; i<(SIZE-1); ) {
90+
/*
91+
* 623-227 = 396 = 2*2*3*3*11, so we can unroll this loop in any
92+
* number that evenly divides 396 (2, 4, 6, etc).
93+
*/
94+
95+
// 11 times
96+
UNROLL; UNROLL; UNROLL;
97+
UNROLL; UNROLL; UNROLL;
98+
99+
UNROLL; UNROLL; UNROLL;
100+
UNROLL; UNROLL;
101+
}
102+
103+
// i = [623]
104+
y = M32(MT[SIZE-1]) | L31(MT[SIZE-1]);
105+
MT[SIZE-1] = MT[PERIOD-1] ^ (y>>1) ^ MATRIX[ODD(y)];
106+
}
107+
108+
extern "C" void seed(uint32_t value)
109+
{
110+
/*
111+
* The equation below is a linear congruential generator (LCG),
112+
* one of the oldest known pseudo-random number generator
113+
* algorithms, in the form X_(n+1) = = (a*X_n + c) (mod m).
114+
*
115+
* We've implicitly got m=32 (mask + word size of 32 bits), so
116+
* there is no need to explicitly use modulus.
117+
*
118+
* What is interesting is the multiplier a. The one we have
119+
* below is 0x6c07865 --- 1812433253 in decimal, and is called
120+
* the Borosh-Niederreiter multiplier for modulus 2^32.
121+
*
122+
* It is mentioned in passing in Knuth's THE ART OF COMPUTER
123+
* PROGRAMMING, Volume 2, page 106, Table 1, line 13. LCGs are
124+
* treated in the same book, pp. 10-26
125+
*
126+
* You can read the original paper by Borosh and Niederreiter
127+
* as well. It's called OPTIMAL MULTIPLIERS FOR PSEUDO-RANDOM
128+
* NUMBER GENERATION BY THE LINEAR CONGRUENTIAL METHOD (1983) at
129+
* http://www.springerlink.com/content/n7765ku70w8857l7/
130+
*
131+
* You can read about LCGs at:
132+
* http://en.wikipedia.org/wiki/Linear_congruential_generator
133+
*
134+
* From that page, it says:
135+
* "A common Mersenne twister implementation, interestingly
136+
* enough, uses an LCG to generate seed data.",
137+
*
138+
* Since our we're using 32-bits data types for our MT array,
139+
* we can skip the masking with 0xFFFFFFFF below.
140+
*/
141+
142+
MT[0] = value;
143+
index = 0;
144+
145+
for ( register unsigned i=1; i<SIZE; ++i )
146+
MT[i] = 0x6c078965*(MT[i-1] ^ MT[i-1]>>30) + i;
147+
}
148+
149+
extern "C" uint32_t rand_u32()
150+
{
151+
if ( !index )
152+
generate_numbers();
153+
154+
register uint32_t y = MT[index];
155+
156+
// Tempering
157+
y ^= y>>11;
158+
y ^= y<< 7 & 0x9d2c5680;
159+
y ^= y<<15 & 0xefc60000;
160+
y ^= y>>18;
161+
162+
if ( ++index == SIZE )
163+
index = 0;
164+
165+
return y;
166+
}
167+
168+
extern "C" int mt_rand()
169+
{
170+
/*
171+
* PORTABILITY WARNING:
172+
*
173+
* rand_u32() uses all 32-bits for the pseudo-random number,
174+
* but rand() must return a number from 0 ... RAND_MAX.
175+
*
176+
* We'll just assume that rand() only uses 31 bits worth of
177+
* data, and that we're on a two's complement system.
178+
*
179+
* So, to output an integer compatible with rand(), we have
180+
* two options: Either mask off the highest (32nd) bit, or
181+
* shift right by one bit. Masking with 0x7FFFFFFF will be
182+
* compatible with 64-bit MT[], so we'll just use that here.
183+
*
184+
*/
185+
return static_cast<int>(0x7FFFFFFF & rand_u32());
186+
}
187+
188+
extern "C" void mt_srand(unsigned value)
189+
{
190+
seed(static_cast<uint32_t>(value));
191+
}
192+
193+
extern "C" float randf_cc()
194+
{
195+
return static_cast<float>(rand_u32())/UINT32_MAX;
196+
}
197+
198+
extern "C" float randf_co()
199+
{
200+
return static_cast<float>(rand_u32())/(UINT32_MAX+1.0f);
201+
}
202+
203+
extern "C" float randf_oo()
204+
{
205+
return (static_cast<float>(rand_u32())+0.5f)/(UINT32_MAX+1.0f);
206+
}
207+
208+
extern "C" double randd_cc()
209+
{
210+
return static_cast<double>(rand_u32())/UINT32_MAX;
211+
}
212+
213+
extern "C" double randd_co()
214+
{
215+
return static_cast<double>(rand_u32())/(UINT32_MAX+1.0);
216+
}
217+
218+
extern "C" double randd_oo()
219+
{
220+
return (static_cast<double>(rand_u32())+0.5)/(UINT32_MAX+1.0);
221+
}
222+
223+
extern "C" uint64_t rand_u64()
224+
{
225+
return static_cast<uint64_t>(rand_u32())<<32 | rand_u32();
226+
}
+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* The Mersenne Twister pseudo-random number generator (PRNG)
3+
*
4+
* This is an implementation of fast PRNG called MT19937,
5+
* meaning it has a period of 2^19937-1, which is a Mersenne
6+
* prime.
7+
*
8+
* This PRNG is fast and suitable for non-cryptographic code.
9+
* For instance, it would be perfect for Monte Carlo simulations,
10+
* etc.
11+
*
12+
* This code has been designed as a drop-in replacement for libc rand and
13+
* srand(). If you need to mix them, you should encapsulate this code in a
14+
* namespace.
15+
*
16+
* Written by Christian Stigen Larsen
17+
* 2012-01-11 -- http://csl.sublevel3.org
18+
*
19+
* Distributed under the modified BSD license.
20+
*/
21+
22+
#ifndef MERSENNE_TWISTER_H
23+
#define MERSENNE_TWISTER_H
24+
25+
#include <stdint.h>
26+
27+
#ifdef __cplusplus
28+
extern "C" {
29+
#endif
30+
31+
/*
32+
* Maximum number you can get from rand().
33+
*/
34+
#define RAND_MAX INT32_MAX
35+
36+
/*
37+
* Initialize the number generator with given seed.
38+
* (LIBC REPLACEMENT FUNCTION)
39+
*/
40+
void mt_srand(unsigned seed_value);
41+
42+
/*
43+
* Extract a pseudo-random integer in the range 0 ... RAND_MAX.
44+
* (LIBC REPLACEMENT FUNCTION)
45+
*/
46+
int mt_rand();
47+
48+
/*
49+
* Extract a pseudo-random unsigned 32-bit integer in the range 0 ... UINT32_MAX
50+
*/
51+
uint32_t rand_u32();
52+
53+
/*
54+
* Combine two unsigned 32-bit pseudo-random numbers into one 64-bit
55+
*/
56+
uint64_t rand_u64();
57+
58+
/*
59+
* Initialize Mersenne Twister with given seed value.
60+
*/
61+
void seed(uint32_t seed_value);
62+
63+
/*
64+
* Return a random float in the CLOSED range [0, 1]
65+
* Mnemonic: randf_co = random float 0=closed 1=closed
66+
*/
67+
float randf_cc();
68+
69+
/*
70+
* Return a random float in the OPEN range [0, 1>
71+
* Mnemonic: randf_co = random float 0=closed 1=open
72+
*/
73+
float randf_co();
74+
75+
/*
76+
* Return a random float in the OPEN range <0, 1>
77+
* Mnemonic: randf_oo = random float 0=open 1=open
78+
*/
79+
float randf_oo();
80+
81+
/*
82+
* Return a random double in the CLOSED range [0, 1]
83+
* Mnemonic: randd_co = random double 0=closed 1=closed
84+
*/
85+
double randd_cc();
86+
87+
/*
88+
* Return a random double in the OPEN range [0, 1>
89+
* Mnemonic: randd_co = random double 0=closed 1=open
90+
*/
91+
double randd_co();
92+
93+
/*
94+
* Return a random double in the OPEN range <0, 1>
95+
* Mnemonic: randd_oo = random double 0=open 1=open
96+
*/
97+
double randd_oo();
98+
99+
#ifdef __cplusplus
100+
} // extern "C"
101+
#endif
102+
103+
#endif // MERSENNE_TWISTER_H

0 commit comments

Comments
 (0)