1 # copyright 2016 Apache 2 sddekit authors
3 from libc
.stdlib cimport malloc
, free
4 from libc
.stdint cimport uint32_t
5 from cpython cimport PyObject
, Py_INCREF
, Py_DECREF
10 # gc-friendly c array wrapper
11 # based on https://gist.github.com/GaelVaroquaux/1249305 BSD-licensed.
12 cdef class CArrayWrapper
:
13 "Python wrapper for C array."
20 cdef init
(self, int size
, void *ptr
, int typenum
, int free_on_gc
=0):
24 self.typenum
= typenum
25 self.free_on_gc
= free_on_gc
28 "Obtain NumPy array from self."
29 cdef np
.npy_intp shape
[1]
30 shape
[0] = <np
.npy_intp
> self.size
31 return np
.PyArray_SimpleNewFromData
(1, shape
, self.typenum
, self.ptr
)
33 def __dealloc__
(self):
34 "Deallocate C array on Python garbage collect."
36 free
(<void*> self.ptr
)
38 cdef np
.ndarray np_of_ptr
(int size
, void *ptr
, int typenum
, int free_on_gc
):
39 "Wrap a given C array, returning a NumPy array."
40 cdef np
.ndarray ndarray
41 wrapper
= CArrayWrapper
()
42 wrapper
.init
(size
, ptr
, typenum
, free_on_gc
=free_on_gc
)
43 ndarray
= np
.array
(wrapper
, copy
=False
)
44 ndarray
.base
= <PyObject
*> wrapper
49 cdef extern from "sddekit.h":
51 ctypedef enum sd_stat
:
57 ctypedef struct sd_hfill
:
59 sd_stat
(*apply)(sd_hfill
*, uint32_t n
, double
* t
, uint32_t
*indices
, double
* buf
)
60 void (*free
)(sd_hfill
*)
62 ctypedef struct sd_hist
:
63 uint32_t
(*get_maxvi
)(sd_hist
*)
64 uint32_t
(*get_vi2i
)(sd_hist
*, uint32_t vi
)
65 uint32_t
(*get_nu
)(sd_hist
*h
)
66 void (*free
)(sd_hist
*h
)
67 sd_stat
(*fill
)(sd_hist
*h
, sd_hfill
*filler
)
68 void (*get
)(sd_hist
*h
, double t
, double
*aff
)
69 void (*set
)(sd_hist
*h
, double t
, double
*eff
)
70 uint32_t
(*nbytes
)(sd_hist
*h
)
71 double
(*get_buf_lin
)(sd_hist
*h
, uint32_t index
)
72 uint32_t
(*get_nd
)(sd_hist
*h
)
73 double
(*get_t
)(sd_hist
*h
)
74 double
(*get_dt
)(sd_hist
*h
)
75 uint32_t
(*get_lim
)(sd_hist
*h
, uint32_t i
)
76 uint32_t
(*get_len
)(sd_hist
*h
, uint32_t i
)
77 uint32_t
(*get_pos
)(sd_hist
*h
, uint32_t i
)
78 uint32_t
(*get_uvi
)(sd_hist
*h
, uint32_t i
)
79 double
(*get_maxd
)(sd_hist
*h
, uint32_t i
)
80 uint32_t
(*get_vi
)(sd_hist
*h
, uint32_t i
)
81 double
(*get_vd
)(sd_hist
*h
, uint32_t i
)
83 sd_hist
* sd_hist_new_default
(uint32_t nd
, uint32_t
*vi
, double
*vd
, double t0
, double dt
)
87 ctypedef struct hfill_py
:
91 cdef sd_stat hfill_py_apply
(sd_hfill
*hfill
, uint32_t n
, double
* t
, uint32_t
*i
, double
* buf
):
92 cdef hfill_py
*hp
= <hfill_py
*> hfill
.ptr
93 cdef np
.ndarray
[np
.float64_t
, ndim
=1] np_buf
94 t_
= np_of_ptr
(n
, t
, np
.NPY_DOUBLE
, 0)
95 i_
= np_of_ptr
(n
, t
, np
.NPY_UINT64
, 0)
97 np_buf
= (<object> hp
.fn
)(t_
, i_
).astype
(np
.float64
)
98 except Exception as exc
:
105 cdef void hfill_py_free
(sd_hfill
*h
):
108 cdef sd_hfill
* hfill_py_new
(object fn
):
109 cdef hfill_py
*h
= <hfill_py
*> malloc
(sizeof(hfill_py
))
111 raise Exception('alloc hfill_py failed.')
114 h
.hf
.apply = &hfill_py_apply
115 h
.hf
.free
= &hfill_py_free
118 cdef class Hist
(object):
121 np
.ndarray
[uint32_t
, ndim
=1, mode
="c"] vi
not None
,
122 np
.ndarray
[double
, ndim
=1, mode
="c"] vd
not None
, double t0
, double dt
):
123 self.h
= sd_hist_new_default
(vi
.size
, <uint32_t
*> vi
.data
, <double
*> vd
.data
, np
.float64
(t0
), np
.float64
(dt
))
127 def fill
(self, filler
):
128 cdef sd_hfill
*hf
= hfill_py_new
(filler
)
129 cdef sd_stat stat
= self.h
.fill
(self.h
, hf
)
132 raise Exception('fill failed.')
133 def get
(self, double t
):
134 cdef np
.ndarray
[double
, ndim
=1] aff
= np
.empty
((self.nd
(),), np
.float64
)
135 self.h
.get
(self.h
, t
, <double
*> aff
.data
)
137 def set
(self, double t
, np
.ndarray
[double
, ndim
=1] eff
):
138 # void sd_hist_set(sd_hist * h, double t, double * eff)
139 self.h
.set
(self.h
, t
, <double
*> eff
.data
)
141 return self.h
.get_maxvi
(self.h
)
143 return self.h
.get_nu
(self.h
)
145 return self.h
.get_nd
(self.h
)
147 return self.h
.get_t
(self.h
)
149 return self.h
.get_dt
(self.h
)
151 return self.h
.get_vi2i
(self.h
, i
)
152 def buf_lin
(self, i
):
153 return self.h
.get_buf_lin
(self.h
, i
)
155 return self.h
.get_lim
(self.h
, i
)
157 return self.h
.get_len
(self.h
, i
)
159 return self.h
.get_pos
(self.h
, i
)
161 return self.h
.get_uvi
(self.h
, i
)
163 return self.h
.get_maxd
(self.h
, i
)
165 return self.h
.get_vi
(self.h
, i
)
167 return self.h
.get_vd
(self.h
, i
)
170 cdef extern from "sddekit.h":
171 ctypedef struct sd_rng
:
173 void (*seed
)(sd_rng
*, uint32_t seed
)
174 double
(*norm
)(sd_rng
*)
175 void (*fill_norm
)(sd_rng
*, uint32_t n
, double
*x
)
176 uint32_t
(*nbytes
)(sd_rng
*)
177 void (*free
)(sd_rng
*)
178 sd_rng
* sd_rng_new_default
()
180 cdef class Rng
(object):
183 cdef object rng_of_ptr
(sd_rng
*r
):
189 cdef extern from "sddekit.h":
190 ctypedef struct sd_sys
:
191 uint32_t
(*ndim
)(sd_sys
*)
192 uint32_t
(*ndc
)(sd_sys
*)
193 uint32_t
(*nobs
)(sd_sys
*)
194 uint32_t
(*nrpar
)(sd_sys
*)
195 uint32_t
(*nipar
)(sd_sys
*)
196 sd_stat
(*apply)(sd_sys
*, sd_sys_in
*, sd_sys_out
*)
197 void (*free
)(sd_sys
*)
199 ctypedef struct sd_sys_in
:
204 ctypedef struct sd_sys_out
:
207 cdef uint32_t sys_py_ndim
(sd_sys
*s
):
208 cdef object sys
= <object> s
.ptr
209 cdef uint32_t i
= sys
.ndim
212 cdef uint32_t sys_py_ndc
(sd_sys
*s
):
213 cdef object sys
= <object> s
.ptr
214 cdef uint32_t i
= sys
.ndc
217 cdef uint32_t sys_py_nobs
(sd_sys
*s
):
218 cdef object sys
= <object> s
.ptr
219 cdef uint32_t i
= sys
.nobs
222 cdef uint32_t sys_py_nrpar
(sd_sys
*s
):
223 cdef object sys
= <object> s
.ptr
224 cdef uint32_t i
= sys
.nrpar
227 cdef uint32_t sys_py_nipar
(sd_sys
*s
):
228 cdef object sys
= <object> s
.ptr
229 cdef uint32_t i
= sys
.nipar
232 cdef sd_stat sys_py_apply
(sd_sys
*s
, sd_sys_in
*i
, sd_sys_out
*o
):
233 cdef object sys
= <object> s
.ptr
235 f
, g
, o
= sys
.apply(i
.hist
, i
.rng
, i
.id, i
.t
, i
.x
, i
.i
)
242 cdef void sys_py_free
(sd_sys
*s
):
243 Py_DECREF
(<object> s
.ptr
)
246 cdef class Sys
(object):
247 "Base class for system defintions, may be defined in C."
252 return self.s
.ndim
(self.s
)
256 return self.s
.ndc
(self.s
)
260 return self.s
.nobs
(self.s
)
264 return self.s
.nrpar
(self.s
)
268 return self.s
.nipar
(self.s
)
270 def apply(self, hist
, rng
, id, t
, x
, i
):
274 raise NotImplementedError
279 cdef class PySys
(Sys
):
280 "Base class for systems defined in Python."
283 "Construct system defined by Python subclass."
284 if self.__class__
.__name__
== 'PySys':
285 raise TypeError('PySys must be subclassed.')
286 self.s
= <sd_sys
*> malloc
(sizeof(sd_sys
))
288 self.s
.ptr
= <void*> self
289 self.s
.ndim
= &sys_py_ndim
290 self.s
.ndc
= &sys_py_ndc
291 self.s
.nobs
= &sys_py_nobs
292 self.s
.nrpar
= &sys_py_nrpar
293 self.s
.nipar
= &sys_py_nipar
294 self.s
.apply = &sys_py_apply
295 self.s
.free
= &sys_py_free
299 raise NotImplementedError
303 raise NotImplementedError
307 raise NotImplementedError
311 raise NotImplementedError
315 raise NotImplementedError
317 def apply(self, hist
, rng
, id, t
, x
, i
):
318 raise NotImplementedError
320 cdef object sys_of_ptr
(sd_sys
*s
):