@@ -4507,19 +4507,11 @@ cdef class _Lambdify(object):
4507
4507
cdef _load(self , const string & s):
4508
4508
raise ValueError (" Not supported" )
4509
4509
4510
- cdef void unsafe_real_ptr(self , double * inp, double * out) nogil:
4511
- with gil:
4512
- raise ValueError (" Not supported" )
4513
-
4514
4510
cpdef unsafe_real(self ,
4515
4511
double [::1 ] inp, double [::1 ] out,
4516
4512
int inp_offset = 0 , int out_offset = 0 ):
4517
4513
raise ValueError (" Not supported" )
4518
4514
4519
- cdef void unsafe_complex_ptr(self , double complex * inp, double complex * out) nogil:
4520
- with gil:
4521
- raise ValueError (" Not supported" )
4522
-
4523
4515
cpdef unsafe_complex(self , double complex [::1 ] inp, double complex [::1 ] out,
4524
4516
int inp_offset = 0 , int out_offset = 0 ):
4525
4517
raise ValueError (" Not supported" )
@@ -4670,6 +4662,9 @@ cdef double _scipy_callback_lambda_real(int n, double *x, void *user_data) nogil
4670
4662
deref(lamb).call(& result, x)
4671
4663
return result
4672
4664
4665
+ cdef void _ctypes_callback_lambda_real(double * output, const double * input , void * user_data) nogil:
4666
+ cdef symengine.LambdaRealDoubleVisitor* lamb = < symengine.LambdaRealDoubleVisitor * > user_data
4667
+ deref(lamb).call(output, input )
4673
4668
4674
4669
IF HAVE_SYMENGINE_LLVM:
4675
4670
cdef double _scipy_callback_llvm_real(int n, double * x, void * user_data) nogil:
@@ -4678,6 +4673,10 @@ IF HAVE_SYMENGINE_LLVM:
4678
4673
deref(lamb).call(& result, x)
4679
4674
return result
4680
4675
4676
+ cdef void _ctypes_callback_llvm_real(double * output, const double * input , void * user_data) nogil:
4677
+ cdef symengine.LLVMDoubleVisitor* lamb = < symengine.LLVMDoubleVisitor * > user_data
4678
+ deref(lamb).call(output, input )
4679
+
4681
4680
4682
4681
def create_low_level_callable (lambdify , *args ):
4683
4682
from scipy import LowLevelCallable
@@ -4698,17 +4697,11 @@ cdef class LambdaDouble(_Lambdify):
4698
4697
self .lambda_double_complex.resize(1 )
4699
4698
self .lambda_double_complex[0 ].init(args_, outs_, cse)
4700
4699
4701
- cdef void unsafe_real_ptr(self , double * inp, double * out) nogil:
4702
- self .lambda_double[0 ].call(out, inp)
4703
-
4704
4700
cpdef unsafe_real(self , double [::1 ] inp, double [::1 ] out, int inp_offset = 0 , int out_offset = 0 ):
4705
- self .unsafe_real_ptr(& inp[inp_offset], & out[out_offset])
4706
-
4707
- cdef void unsafe_complex_ptr(self , double complex * inp, double complex * out) nogil:
4708
- self .lambda_double_complex[0 ].call(out, inp)
4701
+ self .lambda_double[0 ].call(& out[out_offset], & inp[inp_offset])
4709
4702
4710
4703
cpdef unsafe_complex(self , double complex [::1 ] inp, double complex [::1 ] out, int inp_offset = 0 , int out_offset = 0 ):
4711
- self .unsafe_complex_ptr( & inp[inp_offset ], & out[out_offset ])
4704
+ self .lambda_double_complex[ 0 ].call( & out[out_offset ], & inp[inp_offset ])
4712
4705
4713
4706
cpdef as_scipy_low_level_callable(self ):
4714
4707
from ctypes import c_double, c_void_p, c_int, cast, POINTER, CFUNCTYPE
@@ -4721,6 +4714,23 @@ cdef class LambdaDouble(_Lambdify):
4721
4714
addr2 = cast(< size_t> & self .lambda_double[0 ], c_void_p)
4722
4715
return create_low_level_callable(self , addr1, addr2)
4723
4716
4717
+ cpdef as_ctypes(self ):
4718
+ """
4719
+ Returns a tuple with first element being a ctypes function with signature
4720
+
4721
+ void func(double * output, const double *input, void *user_data)
4722
+
4723
+ and second element being a ctypes void pointer. This void pointer needs to be
4724
+ passed as input to the function as the third argument `user_data`.
4725
+ """
4726
+ from ctypes import c_double, c_void_p, c_int, cast, POINTER, CFUNCTYPE
4727
+ if not self .real:
4728
+ raise RuntimeError (" Lambda function has to be real" )
4729
+ addr1 = cast(< size_t> & _ctypes_callback_lambda_real,
4730
+ CFUNCTYPE(c_void_p, POINTER(c_double), POINTER(c_double), c_void_p))
4731
+ addr2 = cast(< size_t> & self .lambda_double[0 ], c_void_p)
4732
+ return addr1, addr2
4733
+
4724
4734
4725
4735
IF HAVE_SYMENGINE_LLVM:
4726
4736
cdef class LLVMDouble(_Lambdify):
@@ -4740,23 +4750,37 @@ IF HAVE_SYMENGINE_LLVM:
4740
4750
return llvm_loading_func, (self .args_size, self .tot_out_size, self .out_shapes, self .real, \
4741
4751
self .n_exprs, self .order, self .accum_out_sizes, self .numpy_dtype, s)
4742
4752
4743
- cdef void unsafe_real_ptr(self , double * inp, double * out) nogil:
4744
- self .lambda_double[0 ].call(out, inp)
4745
-
4746
4753
cpdef unsafe_real(self , double [::1 ] inp, double [::1 ] out, int inp_offset = 0 , int out_offset = 0 ):
4747
- self .unsafe_real_ptr( & inp[inp_offset ], & out[out_offset ])
4754
+ self .lambda_double[ 0 ].call( & out[out_offset ], & inp[inp_offset ])
4748
4755
4749
4756
cpdef as_scipy_low_level_callable(self ):
4750
4757
from ctypes import c_double, c_void_p, c_int, cast, POINTER, CFUNCTYPE
4751
4758
if not self .real:
4752
4759
raise RuntimeError (" Lambda function has to be real" )
4753
4760
if self .tot_out_size > 1 :
4754
4761
raise RuntimeError (" SciPy LowLevelCallable supports only functions with 1 output" )
4755
- addr1 = cast(< size_t> & _scipy_callback_lambda_real ,
4762
+ addr1 = cast(< size_t> & _scipy_callback_llvm_real ,
4756
4763
CFUNCTYPE(c_double, c_int, POINTER(c_double), c_void_p))
4757
4764
addr2 = cast(< size_t> & self .lambda_double[0 ], c_void_p)
4758
4765
return create_low_level_callable(self , addr1, addr2)
4759
4766
4767
+ cpdef as_ctypes(self ):
4768
+ """
4769
+ Returns a tuple with first element being a ctypes function with signature
4770
+
4771
+ void func(double * output, const double *input, void *user_data)
4772
+
4773
+ and second element being a ctypes void pointer. This void pointer needs to be
4774
+ passed as input to the function as the third argument `user_data`.
4775
+ """
4776
+ from ctypes import c_double, c_void_p, c_int, cast, POINTER, CFUNCTYPE
4777
+ if not self .real:
4778
+ raise RuntimeError (" Lambda function has to be real" )
4779
+ addr1 = cast(< size_t> & _ctypes_callback_llvm_real,
4780
+ CFUNCTYPE(c_void_p, POINTER(c_double), POINTER(c_double), c_void_p))
4781
+ addr2 = cast(< size_t> & self .lambda_double[0 ], c_void_p)
4782
+ return addr1, addr2
4783
+
4760
4784
def llvm_loading_func (*args ):
4761
4785
return LLVMDouble(args, _load = True )
4762
4786
0 commit comments