#include "wavelet.h"
/*
* Checks existing objects if they are of proper type, and if so check that
* they are big enough. If not allocate space of approbriate size.
*/
static int
PyGSL_transform_helpers_alloc(PyObject *s_o, PyObject *t_o, struct _pygsl_transform_help_rf_s * h, int n)
{
int check;
FUNC_MESS_BEGIN();
/* Set everything to zero first! */
h->free_space = 0;
h->free_table = 0;
h->table = NULL;
h->space = NULL;
if(h->func == 0)
GSL_ERROR("Functions not set!", GSL_EFAULT);
if(n <= 0)
GSL_ERROR("n<=0!", GSL_ESANITY);
DEBUG_MESS(3, "Allocating/Checking space for %d elements", n);
if(h->func->space_type != NOSPACE && s_o){
if(PyGSL_transform_space_check(s_o) && ((PyGSL_transform_space * )s_o)->type == h->func->space_type){
check = PyGSL_transform_space_get_n((PyGSL_transform_space * )s_o);
if(check == -1 || check < n)
GSL_ERROR("Work Space not big enough!", GSL_EINVAL);
h->space = ((PyGSL_transform_space * )s_o) ->space.v;
} else {
PyGSL_add_traceback(module, filename, __FUNCTION__, __LINE__ - 4);
GSL_ERROR("Need a pygsl transform space of proper type!", GSL_EINVAL);
}
}
if(h->func->space_type != NOSPACE && t_o){
if(PyGSL_transform_space_check(t_o) && ((PyGSL_transform_space * )t_o)->type == h->func->table_type){
check = PyGSL_transform_space_get_n((PyGSL_transform_space * )s_o);
if(check == -1 || check < n)
GSL_ERROR("Wave table not big enough!", GSL_EINVAL);
h->table = ((PyGSL_transform_space * )t_o) ->space.v;
} else {
PyGSL_add_traceback(module, filename, __FUNCTION__, __LINE__ - 4);
GSL_ERROR("Need a pygsl transform wave table of proper type!", GSL_EINVAL);
}
}
/* Check for the approbriate type and initialise it!*/
if((h->space) == NULL || (h->table) == NULL){
DEBUG_MESS(3, "func %p alloc table %p alloc space %p, space %p, table %p",
h->func, (void *) h->func->table_alloc,
(void *) h->func->space_alloc, h->space, h->table);
/* Store if I need to free these arrays */
if((h->space) == NULL && h->func->space_type != NOSPACE){
h->space = h->func->space_alloc(n);
h->free_space = 1;
}
if((h->table) == NULL && h->func->table_type != NOSPACE){
h->table = h->func->table_alloc(n);
h->free_table = 1;
}
if((h->space == NULL && h->func->space_type != NOSPACE) ||
(h->table == NULL && h->func->table_type != NOSPACE)){
return GSL_ENOMEM;
}
DEBUG_MESS(3, "Allocated space @ %p table @ %p", h->space, h->table);
}
FUNC_MESS_END();
return GSL_SUCCESS;
}
#define PyGSL_TRANSFORM_HELPERS_FREE(helpers) \
((helpers != NULL) && ((helpers->free_table != 0) && (helpers->free_space != 0)) ? \
PyGSL_transform_helpers_free(helpers) : 0)
static void
PyGSL_transform_helpers_free(struct _pygsl_transform_help_rf_s * h)
{
FUNC_MESS_BEGIN();
assert(h->func);
DEBUG_MESS(3, "func @ %p", h->func);
if( (h->free_table == 1) && (h->table != NULL)){
assert(h->table);
DEBUG_MESS(3, "Free Table %p with func %p", h->table,
(void *) h->func->table_free);
h->func->table_free(h->table);
h->table = NULL;
h->free_table = 0;
}
if((h->free_space == 1) && (h->space != NULL)){
assert(h->space);
DEBUG_MESS(3, "Free Space %p with func %p", h->space,
(void *) h->func->space_free);
h->func->space_free(h->space);
h->space = NULL;
h->free_space = 0;
}
FUNC_MESS_END();
}
/*
* The two D function. Currently only supports wavelet2d_matrix...
*/
static PyObject *
PyGSL_transform_2d_(PyObject *self, PyObject *args, pygsl_transform_help_s *helps)
{
PyObject *ret = NULL, *data=NULL, *s_o = NULL;
PyArrayObject *m=NULL;
PyGSL_wavelet *wavelet = NULL;
gsl_matrix_view mv;
const enum radix_mode radix2 = helps->info->radix2;
const enum PyArray_TYPES input_array_type=helps->info->input_array_type;
const int sizeoftype = sizeof(double);
int call_n, line=-1;
switch(radix2){
case WAVELET:
if(!PyGSL_WAVELET_CHECK(self)){
gsl_error("Should be a wavelet method!", filename, line, GSL_ESANITY);
line = __LINE__ - 1;
goto fail;
}
wavelet = (PyGSL_wavelet *) self;
break;
default:
gsl_error("Unknown switch!", filename, __LINE__, GSL_ESANITY);
goto fail;
}
/* Currently only implemented for wavelet 2d transform */
if(!PyArg_ParseTuple(args, "O|OO", &data, &s_o, &ret)){
line = __LINE__ - 1;
goto fail;
}
m = PyGSL_PyArray_prepare_gsl_matrix_view(data, input_array_type, 2,
-1, -1, PyGSL_CONTIGUOUS | PyGSL_INPUT_ARRAY, NULL);
if(m == NULL)
goto fail;
mv = gsl_matrix_view_array((double *)m->data, m->dimensions[0], m->dimensions[1]);
call_n = m->dimensions[0] + m->dimensions[1];
if (PyGSL_transform_helpers_alloc(s_o, NULL, helps->helpers, call_n) != GSL_SUCCESS){
line = __LINE__ -1;
goto fail;
}
if(PyGSL_ERROR_FLAG(helps->transform.wavelet2d(wavelet->wavelet, &mv.matrix, helps->helpers->space)) != GSL_SUCCESS){
line = __LINE__ -1;
goto fail;
}
PyGSL_TRANSFORM_HELPERS_FREE(helps->helpers);
ret = (PyObject *) m;
return ret;
fail:
FUNC_MESS("Fail");
PyGSL_add_traceback(module, filename, __FUNCTION__, line);
PyGSL_TRANSFORM_HELPERS_FREE(helps->helpers);
Py_XDECREF(m); m = NULL;
FUNC_MESS("Fail End");
return NULL;
}
/*
* Catch all for all one dimensional functions.
*/
static PyObject *
PyGSL_transform_(PyObject *self, PyObject *args, pygsl_transform_help_s *helps)
{
PyObject *ret = NULL, *s_o = NULL, *t_o = NULL, *data = NULL;
PyArrayObject *result = NULL, *a=NULL, *r=NULL;
PyGSL_wavelet *wavelet = NULL;
double eps=1e-6;
int line = -1;
int length=-1;
/*
* how will it be called and what array length will I need.
* In the HalfComplexReal and the reversed case, an array of double
* data is provided. But the real array is of CDOUBLE. This takes the
* computation in place into account and minimizes the necessary
* copies.
*/
int n=0, call_n=0, return_n=0, strides=0;
const enum PyArray_TYPES input_array_type=helps->info->input_array_type,
output_array_type=helps->info->output_array_type;
const enum transform_mode mode = helps->info->mode;
const enum radix_mode radix2 = helps->info->radix2;
/*
* Helper for STRIDE recalculation. numpy/numarray use strides as
* multiples of char. But GSL uses the basis as common denominator.
* Only complex transforms use complex numbers, so only for them
* n_type will be two, and it will be one for all others.
*/
const enum pygsl_packed_type n_type = helps->info->packed;
/*
* Double mode or float mode?
* complex double or complex float ?
*/
const int datatype = helps->info->datatype;
/* and its size */
const int sizeoftype = (datatype == MODE_DOUBLE) ? sizeof(double) : sizeof(float);
/*
* Normaly the element 0 of the return array is passed. In exceptional
* cases, e.g. RealHalfComplex for RADIX_FREE an offset is needed!
*/
const int call_offset= helps->info->data_offset;
void * vdata;
FUNC_MESS_BEGIN();
assert(args);
/*
* I never know when I will call the _free function. So better to define
* them here already as any jump can go to fail and will start to free
* the tables.
*/
if(helps->helpers){
helps->helpers->free_table=0;
helps->helpers->free_space=0;
helps->helpers->table=NULL;
helps->helpers->space=NULL;
}
assert(mode>0);
assert(radix2>0);
assert(datatype>0);
/*
* Parse the arguments. Depends on the type how many arguments we are going
* to support.
*/
switch(radix2){
case WAVELET:
FUNC_MESS("Wavelet");
/*
* Yes thats a method here.... UiUi not sure if it is not too
* much in one function
*/
if(!PyGSL_WAVELET_CHECK(self)){
gsl_error("Should be a wavelet method!", filename, line, GSL_ESANITY);
line = __LINE__ - 1;
goto fail;
}
wavelet = (PyGSL_wavelet *) self;
if(!PyArg_ParseTuple(args, "O|OO", &data, &s_o, &ret)){
line = __LINE__ - 1;
goto fail;
}
break;
case RADIX_FREE:
FUNC_MESS("Radix_Free");
assert(helps->helpers);
switch(mode){
case ComplexComplex :
FUNC_MESS("ComplexComplex");
if(!PyArg_ParseTuple(args, "O|OOO", &data, &s_o, &t_o, &ret)){
line = __LINE__ - 1;
goto fail;
}
break;
case RealHalfcomplex:
FUNC_MESS("Real");
if(!PyArg_ParseTuple(args, "O|OO",&data, &s_o, &t_o)){
line = __LINE__ - 1;
goto fail;
}
break;
case HalfComplexReal:
FUNC_MESS("Halfcomplex");
if(!PyArg_ParseTuple(args, "O|iOOd",&data, &length, &s_o, &t_o, &eps)){
line = __LINE__ - 1;
goto fail;
}
break;
default:
gsl_error("Unknown mode!", filename, __LINE__, GSL_ESANITY);
goto fail;
} /* mode */
break;
case RADIX_TWO:
FUNC_MESS("Radix_TWO");
assert(helps->helpers==NULL);
switch(mode){
case ComplexComplex :
FUNC_MESS("ComplexComplex");
if(!PyArg_ParseTuple(args, "O|O", &data, &ret)){
line = __LINE__ - 1;
goto fail;
}
break;
case RealHalfcomplex:
case HalfComplexReal:
FUNC_MESS("Real-Halfcomplex");
if(!PyArg_ParseTuple(args, "O",&data)){
line = __LINE__ - 1;
goto fail;
}
break;
default:
gsl_error("Unknown mode!", filename, __LINE__, GSL_ESANITY);
goto fail;
} /* mode */
break;
default:
gsl_error("Unknown radix!", filename, __LINE__, GSL_ESANITY);
goto fail;
}/* radix2 */
FUNC_MESS("mode");
assert(input_array_type >0);
assert(output_array_type >0);
assert(n_type >0);
assert(sizeoftype >0);
DEBUG_MESS(3, "Double?Float %d IN Array Type = %d OUT Array Type = %d", datatype, input_array_type, output_array_type);
DEBUG_MESS(3, "n_type = %d sizeofbasis = %d", n_type, sizeoftype);
{
const int io_type = ((ret == NULL) ? PyGSL_INPUT_ARRAY: PyGSL_IO_ARRAY) | PyGSL_NON_CONTIGUOUS;
if((a = PyGSL_PyArray_PREPARE_gsl_vector_view(data, input_array_type, io_type, -1, 1, NULL)) == NULL){
line = __LINE__ - 1;
goto fail;
}
}
n = a->dimensions[0];
/*
* Calculate the size of the return array and the call array
* Generate the return array
*/
FUNC_MESS("Return Array");
switch(radix2){
case WAVELET:
return_n = n;
call_n = n;
if((r = PyGSL_Shadow_array((PyObject *) ret, (PyObject *) a, datatype)) == NULL){
line = __LINE__ -1;
goto fail;
}
break;
case RADIX_FREE:
FUNC_MESS("Radix Free");
switch(mode){
case ComplexComplex:
FUNC_MESS("ComplexComplex");
return_n = n;
call_n = n;
if((r = PyGSL_Shadow_array((PyObject *) ret, (PyObject *) a, datatype)) == NULL){
line = __LINE__ -1;
goto fail;
}
break;
case RealHalfcomplex:
FUNC_MESS("RealHalfcomplex");
return_n = n / 2 + 1;
call_n = n;
if(((r = (PyArrayObject *) PyGSL_New_Array(1, &return_n, output_array_type)) == NULL) ||
(PyGSL_copy_real_to_complex(r, a, datatype) != GSL_SUCCESS)){
line = __LINE__ -2;
goto fail;
}
break;
case HalfComplexReal:
FUNC_MESS("HalfcomplexReal");
call_n = PyGSL_guess_halfcomplex_length(a, length, eps, datatype);
return_n = call_n;
if(((r = (PyArrayObject *) PyGSL_New_Array(1, &return_n, output_array_type)) == NULL) ||
(PyGSL_ERROR_FLAG(PyGSL_copy_halfcomplex_to_real(r, a, eps, datatype)) != GSL_SUCCESS)){
line = __LINE__ - 2;
goto fail;
}
break;
default:
line = __LINE__ -1;
goto fail;
}/* mode */
break;
case RADIX_TWO:
FUNC_MESS("Radix TWO");
return_n = n;
call_n = n;
if((r = (PyArrayObject *) PyGSL_Copy_Array(a)) == NULL){
line = __LINE__ -1;
goto fail;
}
break;
default:
line = __LINE__ -1;
goto fail;
} /* radix2 */
Py_DECREF(a);
a = NULL;
/* make sure that the ntype was set */
assert(n_type > 0);
DEBUG_MESS(2, "Type(r) = %d, r->nd = %d, r->dimensions[0] = %d, Strides r->strides[0] %d",
r->descr->type_num, r->nd, r->dimensions[0], r->strides[0]);
if(PyGSL_STRIDE_RECALC(r->strides[0], n_type * sizeoftype, &strides) != GSL_SUCCESS){
line = __LINE__ -1;
goto fail;
}
DEBUG_MESS(2, "Strides r->strides[0] %d strides = %d", r->strides[0], strides);
/* build the helpers if necessary */
switch(radix2){
case WAVELET:
case RADIX_FREE:
FUNC_MESS("Build Helpers");
if (PyGSL_transform_helpers_alloc(s_o, t_o, helps->helpers, call_n) != GSL_SUCCESS){
line = __LINE__ -1;
goto fail;
}
break;
default:
/* No helpers needed! */ ;
}/* radix2 */
#if DEBUG > 0
if(PyGSL_Check_Array_Length(r, call_n, datatype, n_type) != GSL_SUCCESS){
line = __LINE__ -1;
goto fail;
}
#endif
vdata = (void *) r->data;
if(call_offset!=0){
switch(datatype){
case MODE_DOUBLE: vdata = (void *) (((double *) r->data) + call_offset); break;
case MODE_FLOAT: vdata = (void *) (((float *) r->data) + call_offset); break;
}
DEBUG_MESS(3, "Original Pointer at %p new pointer at %p", r->data, vdata);
}
/* call the function */
switch(radix2){
case RADIX_FREE:
FUNC_MESS("Transform free length");
assert(helps->helpers->table);
assert(helps->helpers->space);
DEBUG_MESS(3, "vdata = %f, strides = %d, call_n = %d", *((double *)(vdata)), strides, call_n);
if(PyGSL_ERROR_FLAG(helps->transform.free(vdata, strides, call_n,
helps->helpers->table,
helps->helpers->space)) != GSL_SUCCESS){
line = __LINE__ -1;
goto fail;
}
DEBUG_MESS(3, "Transformed: r->data[0] = %f, strides = %d, call_n = %d", *((double *)(r->data)), strides, call_n);
break;
case RADIX_TWO:
FUNC_MESS("Tranform radix2");
if(PyGSL_ERROR_FLAG(helps->transform.radix2(vdata, strides, call_n)) != GSL_SUCCESS){
line = __LINE__ -1;
goto fail;
}
break;
case WAVELET:
FUNC_MESS("Tranform wavelet");
assert(wavelet);
assert(helps->helpers->space);
if(PyGSL_ERROR_FLAG(helps->transform.wavelet(wavelet->wavelet, (double *)vdata, strides, call_n,
helps->helpers->space)) != GSL_SUCCESS){
line = __LINE__ -1;
goto fail;
}
break;
default:
line = __LINE__ -1;
goto fail;
}
/* restore the array */
switch(radix2){
case RADIX_FREE:
switch(mode){
case RealHalfcomplex:
FUNC_MESS("halfcomplex unpack");
if(PyGSL_fft_halfcomplex_unpack(r, call_n, datatype) != GSL_SUCCESS){
line = __LINE__ -1;
goto fail;
}
break;
case RealReal:
case HalfComplexReal:
case ComplexComplex: break;
}
break;
default:
/* No helpers needed! */ ;
}
PyGSL_TRANSFORM_HELPERS_FREE(helps->helpers);
result = r;
FUNC_MESS_END();
return (PyObject *) result;
fail:
FUNC_MESS("Fail");
PyGSL_add_traceback(module, filename, __FUNCTION__, line);
PyGSL_TRANSFORM_HELPERS_FREE(helps->helpers);
Py_XDECREF(r); r = NULL;
FUNC_MESS("Fail End");
return NULL;
}
/*
* Local Variables:
* mode: C
* c-file-style: "python"
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1