### Re: [Cython] Interest in contributing to the project

Sturla Molden <

sturla@...>

2011-04-03 23:49:37 GMT

Den 03.04.2011 04:17, skrev Arthur de Souza Ribeiro:
>
> static PyMethodDef cmath_methods[] = {
> {"acos", cmath_acos, METH_VARARGS, c_acos_doc},
> {"acosh", cmath_acosh, METH_VARARGS, c_acosh_doc},
> {"asin", cmath_asin, METH_VARARGS, c_asin_doc},
> {"asinh", cmath_asinh, METH_VARARGS, c_asinh_doc},
> {"atan", cmath_atan, METH_VARARGS, c_atan_doc},
> {"atanh", cmath_atanh, METH_VARARGS, c_atanh_doc},
> {"cos", cmath_cos, METH_VARARGS, c_cos_doc},
> {"cosh", cmath_cosh, METH_VARARGS, c_cosh_doc},
> {"exp", cmath_exp, METH_VARARGS, c_exp_doc},
> {"isfinite", cmath_isfinite, METH_VARARGS, cmath_isfinite_doc},
> {"isinf", cmath_isinf, METH_VARARGS, cmath_isinf_doc},
> {"isnan", cmath_isnan, METH_VARARGS, cmath_isnan_doc},
> {"log", cmath_log, METH_VARARGS, cmath_log_doc},
> {"log10", cmath_log10, METH_VARARGS, c_log10_doc},
> {"phase", cmath_phase, METH_VARARGS, cmath_phase_doc},
> {"polar", cmath_polar, METH_VARARGS, cmath_polar_doc},
> {"rect", cmath_rect, METH_VARARGS, cmath_rect_doc},
> {"sin", cmath_sin, METH_VARARGS, c_sin_doc},
> {"sinh", cmath_sinh, METH_VARARGS, c_sinh_doc},
> {"sqrt", cmath_sqrt, METH_VARARGS, c_sqrt_doc},
> {"tan", cmath_tan, METH_VARARGS, c_tan_doc},
> {"tanh", cmath_tanh, METH_VARARGS, c_tanh_doc},
> {NULL, NULL} /* sentinel */
> };
>
>
> static struct PyModuleDef cmathmodule = {
> PyModuleDef_HEAD_INIT,
> "cmath",
> module_doc,
> -1,
> cmath_methods,
> NULL,
> NULL,
> NULL,
> NULL
> };
>
Cython will make this, do not care about it. You don't have to set up
jump tables to make Python get the right function from Cython generated
C code. If you have 22 Python-callable functions (i.e. declared def or
cpdef), Cython will make a jump table for those as above.
> Another stuff that I'm getting in trouble in this initial part is how
> we would translate functions like PyArg_ParseTuple, any clue? I'm
> studing ways to replace too.
>
Do not care about PyArg_ParseTuple either. It's what C Python needs to
parse function call arguments from a tuple into C primitives. Cython
will do this, which is some of the raison d'etre for using Cython.
Also observe that any initialisation done in PyInit_cmathshould go as a
module level function call in Cython, i.e. PyInit_cmathis called on
import just like module level Python and Cython code.
I don't have time to implement all of cmathmodule.c, but here is a
starter (not tested & not complete).
It might actually be that we should use "cdef complex z" instead of
"cdef double complex z". There might be a distinction in the generated
C/C++ code between those types, e.g. Py_complex for complex and "double
_Complex" or "std::complex<double>" for double complex, even though
they are binary equivalent. I'm not sure about the state of Cython with
respect to complex numbers, so just try it and see which works better
Also observe that we do not release the GIL here. That is not because
these functions are not thread-safe, they are, but yielding the GIL will
slow things terribly.
Sturla
cimport math
cimport stdlib
cdef extern from "_math.h":
int Py_IS_FINITE(double)
int Py_IS_NAN(double)
double copysign(double,double)
cdef enum special_types:
ST_NINF # 0, negative infinity
ST_NEG # 1, negative finite number (nonzero)
ST_NZERO # 2, -0.
ST_PZERO # 3, +0.
ST_POS # 4, positive finite number (nonzero)
ST_PINF # 5, positive infinity
ST_NAN # 6, Not a Number
cdef inline special_types special_type(double d):
if (Py_IS_FINITE(d)):
if (d != 0):
if (copysign(1., d) == 1.):
return ST_POS
else
return ST_NEG
else:
if (copysign(1., d) == 1.):
return ST_PZERO
else
return ST_NZERO
if (Py_IS_NAN(d)):
return ST_NAN
if (copysign(1., d) == 1.):
return ST_PINF
else:
return ST_NINF
cdef void INIT_SPECIAL_VALUES( double complex *table,
double complex arc[][7]):
stdlib.memcpy(table, &(src[0][0]), 7*7*sizeof(double complex))
cdef inline double complex *SPECIAL_VALUE(double complex z, double
complex table[][7]):
if (not Py_IS_FINITE(z.real)) or (not Py_IS_FINITE(z.imag)):
errno = 0
return &(table[special_type(z.real)][special_type(z.imag)])
else:
return NULL
cdef double complex acosh_special_values[7][7]
INIT_SPECIAL_VALUES( acos_special_values, {
C(P34,INF) C(P,INF) C(P,INF) C(P,-INF) C(P,-INF) C(P34,-INF) C(N,INF)
C(P12,INF) C(U,U) C(U,U) C(U,U) C(U,U) C(P12,-INF) C(N,N)
C(P12,INF) C(U,U) C(P12,0.) C(P12,-0.) C(U,U) C(P12,-INF) C(P12,N)
C(P12,INF) C(U,U) C(P12,0.) C(P12,-0.) C(U,U) C(P12,-INF) C(P12,N)
C(P12,INF) C(U,U) C(U,U) C(U,U) C(U,U) C(P12,-INF) C(N,N)
C(P14,INF) C(0.,INF) C(0.,INF) C(0.,-INF) C(0.,-INF) C(P14,-INF) C(N,INF)
C(N,INF) C(N,N) C(N,N) C(N,N) C(N,N) C(N,-INF) C(N,N)
})
cdef double complex cmath_acosh(double complex z):
cdef double complex s1, s2, r, *psv
psv = SPECIAL_VALUE(z, acosh_special_values)
if (psv != NULL):
return psv[0]
if (math.fabs(z.real) > CM_LARGE_DOUBLE or math.fabs(z.imag) >
CM_LARGE_DOUBLE):
# avoid unnecessary overflow for large arguments
r.real = math.log(hypot(z.real/2., z.imag/2.)) + M_LN2*2.
r.imag = math.atan2(z.imag, z.real)
else:
s1.real = z.real - 1.
s1.imag = z.imag
s1 = cmath_sqrt(s1) # cdef double complex cmath_sqrt(double
complex z)
s2.real = z.real + 1.
s2.imag = z.imag
s2 = cmath_sqrt(s2)
r.real = math.asinh(s1.real*s2.real + s1.imag*s2.imag)
r.imag = 2.*math.atan2(s1.imag, s2.real)
errno = 0
return r
def acosh(object arg):
"""acos(x)
Return the arc cosine of x."""
double complex z
z = cmath_acosh(<double complex> arg)
return complex(z)