Skip to content

Commit 5a0a5c6

Browse files
authored
Merge pull request #12 from bashtage/pcg-128-preprocessor
MAINT: Remove Cython conditionals
2 parents 67d596c + 2b55cb4 commit 5a0a5c6

File tree

3 files changed

+77
-43
lines changed

3 files changed

+77
-43
lines changed

numpy/random/pcg64.pyx

Lines changed: 26 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,8 @@ np.import_array()
1717

1818
# IF PCG_EMULATED_MATH==1:
1919
cdef extern from "src/pcg64/pcg64.h":
20-
21-
ctypedef struct pcg128_t:
22-
uint64_t high
23-
uint64_t low
24-
# ELSE:
25-
# cdef extern from "inttypes.h":
26-
# ctypedef unsigned long long __uint128_t
27-
#
28-
# cdef extern from "src/pcg64/pcg64.h":
29-
# ctypedef __uint128_t pcg128_t
30-
31-
cdef extern from "src/pcg64/pcg64.h":
32-
33-
cdef struct pcg_state_setseq_128:
34-
pcg128_t state
35-
pcg128_t inc
36-
37-
ctypedef pcg_state_setseq_128 pcg64_random_t
20+
# Use int as generic type, actual type read from pcg64.h and is platform dependent
21+
ctypedef int pcg64_random_t
3822

3923
struct s_pcg64_state:
4024
pcg64_random_t *pcg_state
@@ -48,6 +32,8 @@ cdef extern from "src/pcg64/pcg64.h":
4832
void pcg64_jump(pcg64_state *state)
4933
void pcg64_advance(pcg64_state *state, uint64_t *step)
5034
void pcg64_set_seed(pcg64_state *state, uint64_t *seed, uint64_t *inc)
35+
void pcg64_get_state(pcg64_state *state, uint64_t *state_arr, int *has_uint32, uint32_t *uinteger)
36+
void pcg64_set_state(pcg64_state *state, uint64_t *state_arr, int has_uint32, uint32_t uinteger)
5137

5238
cdef uint64_t pcg64_uint64(void* st) nogil:
5339
return pcg64_next64(<pcg64_state *>st)
@@ -280,40 +266,39 @@ cdef class PCG64:
280266
Dictionary containing the information required to describe the
281267
state of the RNG
282268
"""
283-
# IF PCG_EMULATED_MATH==1:
284-
# TODO: push this into an #ifdef in the C code
285-
state = 2 **64 * self.rng_state.pcg_state.state.high
286-
state += self.rng_state.pcg_state.state.low
287-
inc = 2 **64 * self.rng_state.pcg_state.inc.high
288-
inc += self.rng_state.pcg_state.inc.low
289-
# ELSE:
290-
# state = self.rng_state.pcg_state.state
291-
# inc = self.rng_state.pcg_state.inc
292-
269+
cdef np.ndarray state_vec
270+
cdef int has_uint32
271+
cdef uint32_t uinteger
272+
273+
# state_vec is state.high, state.low, inc.high, inc.low
274+
state_vec = <np.ndarray>np.empty(4, dtype=np.uint64)
275+
pcg64_get_state(self.rng_state, <uint64_t *>state_vec.data, &has_uint32, &uinteger)
276+
state = int(state_vec[0]) * 2**64 + int(state_vec[1])
277+
inc = int(state_vec[2]) * 2**64 + int(state_vec[3])
293278
return {'brng': self.__class__.__name__,
294279
'state': {'state': state, 'inc': inc},
295-
'has_uint32': self.rng_state.has_uint32,
296-
'uinteger': self.rng_state.uinteger}
280+
'has_uint32': has_uint32,
281+
'uinteger': uinteger}
297282

298283
@state.setter
299284
def state(self, value):
285+
cdef np.ndarray state_vec
286+
cdef int has_uint32
287+
cdef uint32_t uinteger
300288
if not isinstance(value, dict):
301289
raise TypeError('state must be a dict')
302290
brng = value.get('brng', '')
303291
if brng != self.__class__.__name__:
304292
raise ValueError('state must be for a {0} '
305293
'RNG'.format(self.__class__.__name__))
306-
# IF PCG_EMULATED_MATH==1:
307-
self.rng_state.pcg_state.state.high = value['state']['state'] // 2 ** 64
308-
self.rng_state.pcg_state.state.low = value['state']['state'] % 2 ** 64
309-
self.rng_state.pcg_state.inc.high = value['state']['inc'] // 2 ** 64
310-
self.rng_state.pcg_state.inc.low = value['state']['inc'] % 2 ** 64
311-
# ELSE:
312-
# self.rng_state.pcg_state.state = value['state']['state']
313-
# self.rng_state.pcg_state.inc = value['state']['inc']
314-
315-
self.rng_state.has_uint32 = value['has_uint32']
316-
self.rng_state.uinteger = value['uinteger']
294+
state_vec = <np.ndarray>np.empty(4, dtype=np.uint64)
295+
state_vec[0] = value['state']['state'] // 2 ** 64
296+
state_vec[1] = value['state']['state'] % 2 ** 64
297+
state_vec[2] = value['state']['inc'] // 2 ** 64
298+
state_vec[3] = value['state']['inc'] % 2 ** 64
299+
has_uint32 = value['has_uint32']
300+
uinteger = value['uinteger']
301+
pcg64_set_state(self.rng_state, <uint64_t *>state_vec.data, has_uint32, uinteger)
317302

318303
def advance(self, delta):
319304
"""

numpy/random/src/pcg64/pcg64.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,47 @@ extern void pcg64_set_seed(pcg64_state *state, uint64_t *seed, uint64_t *inc) {
116116
#endif
117117
pcg64_srandom_r(state->pcg_state, s, i);
118118
}
119+
120+
extern void pcg64_get_state(pcg64_state *state, uint64_t *state_arr,
121+
int *has_uint32, uint32_t *uinteger) {
122+
/*
123+
* state_arr contains state.high, state.low, inc.high, inc.low
124+
* which are interpreted as the upper 64 bits (high) or lower
125+
* 64 bits of a uint128_t variable
126+
*
127+
*/
128+
#if __SIZEOF_INT128__ && !defined(PCG_FORCE_EMULATED_128BIT_MATH)
129+
state_arr[0] = (uint64_t)(state->pcg_state->state >> 64);
130+
state_arr[1] = (uint64_t)(state->pcg_state->state & 0xFFFFFFFFFFFFFFFFULL);
131+
state_arr[2] = (uint64_t)(state->pcg_state->inc >> 64);
132+
state_arr[3] = (uint64_t)(state->pcg_state->inc & 0xFFFFFFFFFFFFFFFFULL);
133+
#else
134+
state_arr[0] = (uint64_t)state->pcg_state->state.high;
135+
state_arr[1] = (uint64_t)state->pcg_state->state.low;
136+
state_arr[2] = (uint64_t)state->pcg_state->inc.high;
137+
state_arr[3] = (uint64_t)state->pcg_state->inc.low;
138+
#endif
139+
has_uint32[0] = state->has_uint32;
140+
uinteger[0] = state->uinteger;
141+
}
142+
143+
extern void pcg64_set_state(pcg64_state *state, uint64_t *state_arr,
144+
int has_uint32, uint32_t uinteger) {
145+
/*
146+
* state_arr contains state.high, state.low, inc.high, inc.low
147+
* which are interpreted as the upper 64 bits (high) or lower
148+
* 64 bits of a uint128_t variable
149+
*
150+
*/
151+
#if __SIZEOF_INT128__ && !defined(PCG_FORCE_EMULATED_128BIT_MATH)
152+
state->pcg_state->state = (((pcg128_t)state_arr[0]) << 64) | state_arr[1];
153+
state->pcg_state->inc = (((pcg128_t)state_arr[2]) << 64) | state_arr[3];
154+
#else
155+
state->pcg_state->state.high = state_arr[0];
156+
state->pcg_state->state.low = state_arr[1];
157+
state->pcg_state->inc.high = state_arr[2];
158+
state->pcg_state->inc.low = state_arr[3];
159+
#endif
160+
state->has_uint32 = has_uint32;
161+
state->uinteger = uinteger;
162+
}

numpy/random/src/pcg64/pcg64.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ static inline void _pcg_mult64(uint64_t x, uint64_t y, uint64_t *z1,
100100
uint64_t *z0) {
101101

102102
#if defined _WIN32 && _MSC_VER >= 1900 && _M_AMD64
103-
z0[0] = _umul128(x, y, z1);
103+
z0[0] = _umul128(x, y, z1);
104104
#else
105105
uint64_t x0, x1, y0, y1;
106106
uint64_t w0, w1, w2, t;
@@ -118,7 +118,6 @@ static inline void _pcg_mult64(uint64_t x, uint64_t y, uint64_t *z1,
118118
w1 += x0 * y1;
119119
*z1 = x1 * y1 + w2 + (w1 >> 32);
120120
#endif
121-
122121
}
123122

124123
static inline pcg128_t _pcg128_mult(pcg128_t a, pcg128_t b) {
@@ -238,4 +237,10 @@ void pcg64_advance(pcg64_state *state, uint64_t *step);
238237

239238
void pcg64_set_seed(pcg64_state *state, uint64_t *seed, uint64_t *inc);
240239

240+
void pcg64_get_state(pcg64_state *state, uint64_t *state_arr, int *has_uint32,
241+
uint32_t *uinteger);
242+
243+
void pcg64_set_state(pcg64_state *state, uint64_t *state_arr, int has_uint32,
244+
uint32_t uinteger);
245+
241246
#endif /* PCG64_H_INCLUDED */

0 commit comments

Comments
 (0)