From 2b55cb4f943b2ec8a0c8471068b4e0f23a22bfaf Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Sun, 14 Apr 2019 16:46:05 +0100 Subject: [PATCH] MAINT: Remove Cython conditionals Remove Cython conditional compilation and use preprocessor only --- numpy/random/pcg64.pyx | 67 +++++++++++++--------------------- numpy/random/src/pcg64/pcg64.c | 44 ++++++++++++++++++++++ numpy/random/src/pcg64/pcg64.h | 9 ++++- 3 files changed, 77 insertions(+), 43 deletions(-) diff --git a/numpy/random/pcg64.pyx b/numpy/random/pcg64.pyx index 726bae02716c..af98bbd84c30 100644 --- a/numpy/random/pcg64.pyx +++ b/numpy/random/pcg64.pyx @@ -17,24 +17,8 @@ np.import_array() # IF PCG_EMULATED_MATH==1: cdef extern from "src/pcg64/pcg64.h": - - ctypedef struct pcg128_t: - uint64_t high - uint64_t low -# ELSE: -# cdef extern from "inttypes.h": -# ctypedef unsigned long long __uint128_t -# -# cdef extern from "src/pcg64/pcg64.h": -# ctypedef __uint128_t pcg128_t - -cdef extern from "src/pcg64/pcg64.h": - - cdef struct pcg_state_setseq_128: - pcg128_t state - pcg128_t inc - - ctypedef pcg_state_setseq_128 pcg64_random_t + # Use int as generic type, actual type read from pcg64.h and is platform dependent + ctypedef int pcg64_random_t struct s_pcg64_state: pcg64_random_t *pcg_state @@ -48,6 +32,8 @@ cdef extern from "src/pcg64/pcg64.h": void pcg64_jump(pcg64_state *state) void pcg64_advance(pcg64_state *state, uint64_t *step) void pcg64_set_seed(pcg64_state *state, uint64_t *seed, uint64_t *inc) + void pcg64_get_state(pcg64_state *state, uint64_t *state_arr, int *has_uint32, uint32_t *uinteger) + void pcg64_set_state(pcg64_state *state, uint64_t *state_arr, int has_uint32, uint32_t uinteger) cdef uint64_t pcg64_uint64(void* st) nogil: return pcg64_next64(st) @@ -280,40 +266,39 @@ cdef class PCG64: Dictionary containing the information required to describe the state of the RNG """ - # IF PCG_EMULATED_MATH==1: - # TODO: push this into an #ifdef in the C code - state = 2 **64 * self.rng_state.pcg_state.state.high - state += self.rng_state.pcg_state.state.low - inc = 2 **64 * self.rng_state.pcg_state.inc.high - inc += self.rng_state.pcg_state.inc.low - # ELSE: - # state = self.rng_state.pcg_state.state - # inc = self.rng_state.pcg_state.inc - + cdef np.ndarray state_vec + cdef int has_uint32 + cdef uint32_t uinteger + + # state_vec is state.high, state.low, inc.high, inc.low + state_vec = np.empty(4, dtype=np.uint64) + pcg64_get_state(self.rng_state, state_vec.data, &has_uint32, &uinteger) + state = int(state_vec[0]) * 2**64 + int(state_vec[1]) + inc = int(state_vec[2]) * 2**64 + int(state_vec[3]) return {'brng': self.__class__.__name__, 'state': {'state': state, 'inc': inc}, - 'has_uint32': self.rng_state.has_uint32, - 'uinteger': self.rng_state.uinteger} + 'has_uint32': has_uint32, + 'uinteger': uinteger} @state.setter def state(self, value): + cdef np.ndarray state_vec + cdef int has_uint32 + cdef uint32_t uinteger if not isinstance(value, dict): raise TypeError('state must be a dict') brng = value.get('brng', '') if brng != self.__class__.__name__: raise ValueError('state must be for a {0} ' 'RNG'.format(self.__class__.__name__)) - # IF PCG_EMULATED_MATH==1: - self.rng_state.pcg_state.state.high = value['state']['state'] // 2 ** 64 - self.rng_state.pcg_state.state.low = value['state']['state'] % 2 ** 64 - self.rng_state.pcg_state.inc.high = value['state']['inc'] // 2 ** 64 - self.rng_state.pcg_state.inc.low = value['state']['inc'] % 2 ** 64 - # ELSE: - # self.rng_state.pcg_state.state = value['state']['state'] - # self.rng_state.pcg_state.inc = value['state']['inc'] - - self.rng_state.has_uint32 = value['has_uint32'] - self.rng_state.uinteger = value['uinteger'] + state_vec = np.empty(4, dtype=np.uint64) + state_vec[0] = value['state']['state'] // 2 ** 64 + state_vec[1] = value['state']['state'] % 2 ** 64 + state_vec[2] = value['state']['inc'] // 2 ** 64 + state_vec[3] = value['state']['inc'] % 2 ** 64 + has_uint32 = value['has_uint32'] + uinteger = value['uinteger'] + pcg64_set_state(self.rng_state, state_vec.data, has_uint32, uinteger) def advance(self, delta): """ diff --git a/numpy/random/src/pcg64/pcg64.c b/numpy/random/src/pcg64/pcg64.c index c7c1eb045a41..faec0c248b60 100644 --- a/numpy/random/src/pcg64/pcg64.c +++ b/numpy/random/src/pcg64/pcg64.c @@ -116,3 +116,47 @@ extern void pcg64_set_seed(pcg64_state *state, uint64_t *seed, uint64_t *inc) { #endif pcg64_srandom_r(state->pcg_state, s, i); } + +extern void pcg64_get_state(pcg64_state *state, uint64_t *state_arr, + int *has_uint32, uint32_t *uinteger) { + /* + * state_arr contains state.high, state.low, inc.high, inc.low + * which are interpreted as the upper 64 bits (high) or lower + * 64 bits of a uint128_t variable + * + */ +#if __SIZEOF_INT128__ && !defined(PCG_FORCE_EMULATED_128BIT_MATH) + state_arr[0] = (uint64_t)(state->pcg_state->state >> 64); + state_arr[1] = (uint64_t)(state->pcg_state->state & 0xFFFFFFFFFFFFFFFFULL); + state_arr[2] = (uint64_t)(state->pcg_state->inc >> 64); + state_arr[3] = (uint64_t)(state->pcg_state->inc & 0xFFFFFFFFFFFFFFFFULL); +#else + state_arr[0] = (uint64_t)state->pcg_state->state.high; + state_arr[1] = (uint64_t)state->pcg_state->state.low; + state_arr[2] = (uint64_t)state->pcg_state->inc.high; + state_arr[3] = (uint64_t)state->pcg_state->inc.low; +#endif + has_uint32[0] = state->has_uint32; + uinteger[0] = state->uinteger; +} + +extern void pcg64_set_state(pcg64_state *state, uint64_t *state_arr, + int has_uint32, uint32_t uinteger) { + /* + * state_arr contains state.high, state.low, inc.high, inc.low + * which are interpreted as the upper 64 bits (high) or lower + * 64 bits of a uint128_t variable + * + */ +#if __SIZEOF_INT128__ && !defined(PCG_FORCE_EMULATED_128BIT_MATH) + state->pcg_state->state = (((pcg128_t)state_arr[0]) << 64) | state_arr[1]; + state->pcg_state->inc = (((pcg128_t)state_arr[2]) << 64) | state_arr[3]; +#else + state->pcg_state->state.high = state_arr[0]; + state->pcg_state->state.low = state_arr[1]; + state->pcg_state->inc.high = state_arr[2]; + state->pcg_state->inc.low = state_arr[3]; +#endif + state->has_uint32 = has_uint32; + state->uinteger = uinteger; +} diff --git a/numpy/random/src/pcg64/pcg64.h b/numpy/random/src/pcg64/pcg64.h index 156c73a36988..e42dc4d63e70 100644 --- a/numpy/random/src/pcg64/pcg64.h +++ b/numpy/random/src/pcg64/pcg64.h @@ -100,7 +100,7 @@ static inline void _pcg_mult64(uint64_t x, uint64_t y, uint64_t *z1, uint64_t *z0) { #if defined _WIN32 && _MSC_VER >= 1900 && _M_AMD64 - z0[0] = _umul128(x, y, z1); + z0[0] = _umul128(x, y, z1); #else uint64_t x0, x1, y0, y1; uint64_t w0, w1, w2, t; @@ -118,7 +118,6 @@ static inline void _pcg_mult64(uint64_t x, uint64_t y, uint64_t *z1, w1 += x0 * y1; *z1 = x1 * y1 + w2 + (w1 >> 32); #endif - } 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); void pcg64_set_seed(pcg64_state *state, uint64_t *seed, uint64_t *inc); +void pcg64_get_state(pcg64_state *state, uint64_t *state_arr, int *has_uint32, + uint32_t *uinteger); + +void pcg64_set_state(pcg64_state *state, uint64_t *state_arr, int has_uint32, + uint32_t uinteger); + #endif /* PCG64_H_INCLUDED */