@@ -27,6 +27,20 @@ cdef np.npy_intp compute_numel(size):
2727 n = size
2828 return n
2929
30+ cdef check_output(object out, object dtype, object size):
31+ if out is None :
32+ return
33+ cdef np.ndarray out_array = < np.ndarray> out
34+ if not (np.PyArray_CHKFLAGS(out_array, np.NPY_CARRAY) or
35+ np.PyArray_CHKFLAGS(out_array, np.NPY_FARRAY)):
36+ raise ValueError (' Supplied output array is not contiguous, writable or aligned.' )
37+ if out_array.dtype != dtype:
38+ raise TypeError (' Supplied output array has the wrong type. '
39+ ' Expected {0}, got {0}' .format(dtype, out_array.dtype))
40+ if size is not None :
41+ # TODO: enable this !!! if tuple(size) != out_array.shape:
42+ raise ValueError (' size and out cannot be simultaneously used' )
43+
3044cdef double POISSON_LAM_MAX = < double > np.iinfo(' l' ).max - np.sqrt(np.iinfo(' l' ).max)* 10
3145
3246cdef enum ConstraintType:
@@ -101,7 +115,8 @@ cdef int check_constraint(double val, object name, constraint_type cons) except
101115 return 0
102116
103117cdef object cont_broadcast_1(aug_state* state, void * func, object size, object lock,
104- np.ndarray a_arr, object a_name, constraint_type a_constraint):
118+ np.ndarray a_arr, object a_name, constraint_type a_constraint,
119+ object out):
105120
106121 cdef np.ndarray randoms
107122 cdef double a_val
@@ -113,10 +128,12 @@ cdef object cont_broadcast_1(aug_state* state, void* func, object size, object l
113128 if a_constraint != CONS_NONE:
114129 check_array_constraint(a_arr, a_name, a_constraint)
115130
116- if size is not None :
131+ if size is not None and out is None :
117132 randoms = < np.ndarray> np.empty(size, np.double)
118- else :
133+ elif out is None :
119134 randoms = np.PyArray_SimpleNew(np.PyArray_NDIM(a_arr), np.PyArray_DIMS(a_arr), np.NPY_DOUBLE)
135+ else :
136+ randoms = < np.ndarray> out
120137
121138 randoms_data = < double * > np.PyArray_DATA(randoms)
122139 n = np.PyArray_SIZE(randoms)
@@ -214,11 +231,13 @@ cdef object cont_broadcast_3(aug_state* state, void* func, object size, object l
214231cdef object cont(aug_state* state, void * func, object size, object lock, int narg,
215232 object a, object a_name, constraint_type a_constraint,
216233 object b, object b_name, constraint_type b_constraint,
217- object c, object c_name, constraint_type c_constraint):
234+ object c, object c_name, constraint_type c_constraint,
235+ object out):
218236
219237 cdef np.ndarray a_arr, b_arr, c_arr
220238 cdef double _a = 0.0 , _b = 0.0 , _c = 0.0
221239 cdef bint is_scalar = True
240+ check_output(out, np.float64, size)
222241 if narg > 0 :
223242 a_arr = < np.ndarray> np.PyArray_FROM_OTF(a, np.NPY_DOUBLE, np.NPY_ALIGNED)
224243 is_scalar = is_scalar and np.PyArray_NDIM(a_arr) == 0
@@ -232,7 +251,8 @@ cdef object cont(aug_state* state, void* func, object size, object lock, int nar
232251 if not is_scalar:
233252 if narg == 1 :
234253 return cont_broadcast_1(state, func, size, lock,
235- a_arr, a_name, a_constraint)
254+ a_arr, a_name, a_constraint,
255+ out)
236256 elif narg == 2 :
237257 return cont_broadcast_2(state, func, size, lock,
238258 a_arr, a_name, a_constraint,
@@ -256,7 +276,7 @@ cdef object cont(aug_state* state, void* func, object size, object lock, int nar
256276 if c_constraint != CONS_NONE and is_scalar:
257277 check_constraint(_c, c_name, c_constraint)
258278
259- if size is None :
279+ if size is None and out is None :
260280 with lock:
261281 if narg == 0 :
262282 return (< random_double_0> func)(state)
@@ -267,8 +287,15 @@ cdef object cont(aug_state* state, void* func, object size, object lock, int nar
267287 elif narg == 3 :
268288 return (< random_double_3> func)(state, _a, _b, _c)
269289
270- cdef np.npy_intp i, n = compute_numel(size)
271- cdef np.ndarray randoms = np.empty(n, np.double)
290+ cdef np.npy_intp i, n
291+ cdef np.ndarray randoms
292+ if out is None :
293+ n = compute_numel(size)
294+ randoms = np.empty(n, np.double)
295+ else :
296+ randoms = < np.ndarray> out
297+ n = np.PyArray_SIZE(randoms)
298+
272299 cdef double * randoms_data = < double * > np.PyArray_DATA(randoms)
273300 cdef random_double_0 f0;
274301 cdef random_double_1 f1;
@@ -293,7 +320,10 @@ cdef object cont(aug_state* state, void* func, object size, object lock, int nar
293320 for i in range (n):
294321 randoms_data[i] = f3(state, _a, _b, _c)
295322
296- return np.asarray(randoms).reshape(size)
323+ if out is None :
324+ return np.asarray(randoms).reshape(size)
325+ else :
326+ return out
297327
298328cdef object discrete_broadcast_d(aug_state* state, void * func, object size, object lock,
299329 np.ndarray a_arr, object a_name, constraint_type a_constraint):
@@ -602,7 +632,8 @@ cdef object disc(aug_state* state, void* func, object size, object lock,
602632
603633
604634cdef object cont_broadcast_float_1(aug_state* state, void * func, object size, object lock,
605- np.ndarray a_arr, object a_name, constraint_type a_constraint):
635+ np.ndarray a_arr, object a_name, constraint_type a_constraint,
636+ object out):
606637
607638 cdef np.ndarray randoms
608639 cdef float a_val
@@ -614,12 +645,14 @@ cdef object cont_broadcast_float_1(aug_state* state, void* func, object size, ob
614645 if a_constraint != CONS_NONE:
615646 check_array_constraint(a_arr, a_name, a_constraint)
616647
617- if size is not None :
648+ if size is not None and out is None :
618649 randoms = < np.ndarray> np.empty(size, np.float32)
619- else :
650+ elif out is None :
620651 randoms = np.PyArray_SimpleNew(np.PyArray_NDIM(a_arr),
621652 np.PyArray_DIMS(a_arr),
622653 np.NPY_FLOAT32)
654+ else :
655+ randoms = < np.ndarray> out
623656
624657 randoms_data = < float * > np.PyArray_DATA(randoms)
625658 n = np.PyArray_SIZE(randoms)
@@ -635,36 +668,46 @@ cdef object cont_broadcast_float_1(aug_state* state, void* func, object size, ob
635668 return randoms
636669
637670cdef object cont_float(aug_state* state, void * func, object size, object lock,
638- object a, object a_name, constraint_type a_constraint):
671+ object a, object a_name, constraint_type a_constraint,
672+ object out):
639673
640674 cdef np.ndarray a_arr, b_arr, c_arr
641675 cdef float _a
642676 cdef bint is_scalar = True
643677 cdef int requirements = np.NPY_ALIGNED | np.NPY_FORCECAST
644-
678+ check_output(out, np.float32, size)
645679 a_arr = < np.ndarray> np.PyArray_FROMANY(a, np.NPY_FLOAT32, 0 , 0 , requirements)
646680 # a_arr = <np.ndarray>np.PyArray_FROM_OTF(a, np.NPY_FLOAT32, np.NPY_ALIGNED)
647681 is_scalar = np.PyArray_NDIM(a_arr) == 0
648682
649683 if not is_scalar:
650- return cont_broadcast_float_1(state, func, size, lock, a_arr, a_name, a_constraint)
684+ return cont_broadcast_float_1(state, func, size, lock, a_arr, a_name, a_constraint, out )
651685
652686 _a = < float > PyFloat_AsDouble(a)
653687 if a_constraint != CONS_NONE:
654688 check_constraint(_a, a_name, a_constraint)
655689
656- if size is None :
690+ if size is None and out is None :
657691 with lock:
658692 return (< random_float_1> func)(state, _a)
659693
660- cdef np.npy_intp i, n = compute_numel(size)
661- cdef np.ndarray randoms = np.empty(n, np.float32)
694+ cdef np.npy_intp i, n
695+ cdef np.ndarray randoms
696+ if out is None :
697+ n = compute_numel(size)
698+ randoms = np.empty(n, np.float32)
699+ else :
700+ randoms = < np.ndarray> out
701+ n = np.PyArray_SIZE(randoms)
702+
662703 cdef float * randoms_data = < float * > np.PyArray_DATA(randoms)
663704 cdef random_float_1 f1 = < random_float_1> func;
664705
665706 with lock, nogil:
666707 for i in range (n):
667708 randoms_data[i] = f1(state, _a)
668709
669- return np.asarray(randoms).reshape(size)
670-
710+ if out is None :
711+ return np.asarray(randoms).reshape(size)
712+ else :
713+ return out
0 commit comments