mailmath_fns c code


Others Months | Index by Date | Thread Index
>>   [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Header


Content

Posted by Gary S. Thompson on April 06, 2006 - 11:24:
The main problem here was that you were getting copies of nump arrays(numpy_values, numpy_sd, numpy_relax_times, numpy_scaling_matrix) that you own from PyArray_ContiguousFromObject and never decrefing them, so their reference counts never reached zero... However, if you Py_DECREF these objects at the end of setup they will be collected and the double arrays values, sd, relax_time, scaling_matrix which you still have references to will no longer be allocated to these objects and will contain junk if the memory allocator has reallocated stuff where they were. So I have set it up so that you keep both numpy_values, numpy_sd, numpy_relax_times, numpy_scaling_matrix and values, sd, relax_time, scaling_matrix in global varaibles and only call Py_DECREF at the start of setup to junk them just before you reallocate them (actually I call Py_XDECREF as they will be null the first time the setup function is called).


So here are the patched files c math_fns which cure the memeory leaks Ed. The changes I have made are as follows


1. for c_chi2 and exponential I have made them both into proper functions with no references to any globals
2. for the relax_fit.c file I have basically done the following
a. I have removed the global visibilty of numpy_params and made sure that i call Py_DECREF in each function where you call PyArray_ContiguousFromObject
b. I have made sure that there are numpy_values, numpy_sd, numpy_relax_times, numpy_scaling_matrix.
c. I call Py_XDECREF for each of numpy_values, numpy_sd, numpy_relax_times, numpy_scaling_matrix so that we don't orphan them when we call PyArray_ContiguousFromObject but ignore null objects the first time we are called.


3. note dfunc has a rather funny return ;-)
/* Test code (convert aaa to a Numeric array */
/* aaa_numpy = (PyArrayObject *) PyArray_FromDimsAndData(1, num_params, PyArray_DOUBLE, aaa_pointer); */
/*aaa_numpy = (PyArrayObject *) PyArray_FromDims(1, &num_params, PyArray_DOUBLE);
aaa_pointer = (double *) aaa_numpy->data;*/


  /* Fill the Numeric array */
  /*for (i = 0; i < 2; i++)
      aaa_pointer[i] = aaa[i];*/

  Py_DECREF(numpy_params);
  return NULL;
  return PyArray_Return(aaa_numpy);
which may cause some more careful compilers to choke (but not g77 ;-)

4. Other comments (more things i could also sort at some point)
a this should really be an object, as it has state and a lifetime. If I get time I will convert it...
b. MAXTIMES shouldn't really exist, data arrays should be allocated on the fly I guess


regards
gary

--
-------------------------------------------------------------------
Dr Gary Thompson
Astbury Centre for Structural Molecular Biology,
University of Leeds, Astbury Building,
Leeds, LS2 9JT, West-Yorkshire, UK             Tel. +44-113-3433024
email: garyt@xxxxxxxxxxxxxxx                   Fax  +44-113-2331407
-------------------------------------------------------------------


/*
 * Copyright (C) 2003, 2006 Edward d'Auvergne
 *
 * This file is part of the program relax.
 *
 * relax is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * relax is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with relax; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <stdio.h>
#include <math.h>

#define square(x) (x)*(x)


double chi2(double *values, double *sd, double *back_calc, int num_times) {
        /* Function to calculate the chi-squared value.

        The chi-sqared equation
        ~~~~~~~~~~~~~~~~~~~~~~~
                  _n_
                  \    (yi - yi()) ** 2
        Chi2()  =  >   ----------------
                  /__    sigma_i ** 2
                  i=1

        where:
                yi are the values of the measured data set.
                yi() are the values of the back calculated data set.
                sigma_i are the values of the error set.

        The chi-squared value is returned.
        */

        int i;
        double chi2 = 0.0;

    /* Loop over the time points and sum the chi-squared components */
        for (i = 0; i < num_times; ++i) {
                chi2 = chi2 + square((values[i] - back_calc[i]) / sd[i]);
        }

        return chi2;
}
/*
 * Copyright (C) 2006 Edward d'Auvergne
 *
 * This file is part of the program relax.
 *
 * relax is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * relax is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with relax; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifndef RELAX_C_CHI2 
#define RELAX_C_CHI2

double chi2(double *values, double *sd, double *back_calc, int num_times);

#endif
/*
 * Copyright (C) 2006 Edward d'Auvergne
 *
 * This file is part of the program relax.
 *
 * relax is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * relax is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with relax; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */


/* This include must come first */
#include <Python.h>

/* The Numeric array object header file, must come second */
#include <Numeric/arrayobject.h>

/* The header for all functions which will be called */
#include "relax_fit.h"



void exponential(double *params, double *relax_times, double *back_calc, int 
num_times) {
        /* Function to back calculate the peak intensities.
        */

    /* Declarations */
    double Rx, I0;
    int i;


    /* Loop over the time points */
    /* for (i = 0; i < num_times; i++) { */
    for (i = 0; i < num_times; i++) {
        /* Zero Rx value */
        if (params[0] == 0.0)
            back_calc[i] = 0.0;

        /* Back calculate */
        else
            back_calc[i] = params[1] * exp(-relax_times[i] * params[0]);

    }
}
/*
 * Copyright (C) 2006 Edward d'Auvergne
 *
 * This file is part of the program relax.
 *
 * relax is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * relax is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with relax; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#ifndef RELAX_EXPONENTIAL 
#define RELAX_EXPONENTIAL

void exponential(double *params, double *relax_times, double *back_calc, int 
num_times);

#endif
/*
 * Copyright (C) 2006 Edward d'Auvergne
 *
 * This file is part of the program relax.
 *
 * relax is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * relax is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with relax; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/* This include must come first */
#include <Python.h>

/* The Numeric array object header file, must come second */
#include <Numeric/arrayobject.h>

/* The header for all functions which will be called */
#include "relax_fit.h"

/* functions for chi2 and exponential */
#include "c_chi2.h"
#include "exponential.h"

static PyObject *
setup(PyObject *self, PyObject *args, PyObject *keywords) {
    /* Python declarations */
    PyObject *values_arg, *sd_arg, *relax_times_arg, *scaling_matrix_arg;
    extern PyArrayObject *numpy_values, *numpy_sd, *numpy_relax_times, 
*numpy_scaling_matrix;

    /* Normal declarations */
    extern double *values, *sd, *relax_times, *scaling_matrix;
    extern double relax_time_array;
    extern int num_params, num_times;
            
    /* The keyword list */
    static char *keyword_list[] = {"num_params", "num_times", "values", "sd", 
"relax_times", "scaling_matrix", NULL};

    /* Parse the function arguments */
    if (!PyArg_ParseTupleAndKeywords(args, keywords, "iiOOOO", keyword_list, 
&num_params, &num_times, &values_arg, &sd_arg, &relax_times_arg, 
&scaling_matrix_arg))
        return NULL;
    

        
    Py_XDECREF(numpy_values);    
    Py_XDECREF(numpy_sd);
    Py_XDECREF(numpy_relax_times);
    Py_XDECREF(numpy_scaling_matrix);
             
    /* Make the Numeric arrays contiguous */
    numpy_values = (PyArrayObject *) PyArray_ContiguousFromObject(values_arg, 
PyArray_DOUBLE, 1, 1);
    numpy_sd = (PyArrayObject *) PyArray_ContiguousFromObject(sd_arg, 
PyArray_DOUBLE, 1, 1);
    numpy_relax_times = (PyArrayObject *) 
PyArray_ContiguousFromObject(relax_times_arg, PyArray_DOUBLE, 1, 1);
    numpy_scaling_matrix = (PyArrayObject *) 
PyArray_ContiguousFromObject(scaling_matrix_arg, PyArray_DOUBLE, 2, 2);

    /* Pointers to the Numeric arrays */
    values = (double *) numpy_values->data;
    sd = (double *) numpy_sd->data;
    relax_times = (double *) numpy_relax_times->data;
    scaling_matrix = (double *) numpy_scaling_matrix->data;

    /* Return nothing */
    Py_INCREF(Py_None);
    return Py_None;
}


static PyObject *
func(PyObject *self, PyObject *args) {
    /* Function for calculating and returning the chi-squared value.
     *
     * Firstly the back calculated intensities are generated, then the 
chi-squared statistic is
     * calculated
     */

    /* Declarations */
    PyObject *arg1;
    PyArrayObject *numpy_params;
    double* params;


    /* Parse the function arguments, the only argument should be the 
parameter array */
    if (!PyArg_ParseTuple(args, "O", &arg1))
        return NULL;

    /* Convert the Numeric array to be contiguous */
    numpy_params = (PyArrayObject *) PyArray_ContiguousFromObject(arg1, 
PyArray_DOUBLE, 1, 1);

    /* Pointers to the Numeric arrays */
    params = (double *) numpy_params->data;

    /* Back calculated the peak intensities */
    exponential(params, relax_times, back_calc, num_times);

    Py_DECREF(numpy_params);
    /* Calculate and return the chi-squared value */
    return Py_BuildValue("f", chi2(values,sd,back_calc,num_times));
}


static PyObject *
dfunc(PyObject *self, PyObject *args) {
    /* Function for calculating and returning the chi-squared gradient. */

    /* Declarations */
    PyObject *arg1;
    PyArrayObject *numpy_params;

    /* Temp Declarations */
    PyArrayObject *aaa_numpy;
    double aaa[MAXPARAMS] = {1.0, 2.0};
    double *aaa_pointer;
    int i;
    double* params; 

    /* Parse the function arguments, the only argument should be the 
parameter array */
    if (!PyArg_ParseTuple(args, "O", &arg1))
        return NULL;

    /* Convert the Numeric array to be contiguous */
    numpy_params = (PyArrayObject *) PyArray_ContiguousFromObject(arg1, 
PyArray_DOUBLE, 1, 1);

    /* Pointers to the Numeric arrays */
    params = (double *) numpy_params->data;

    /* Back calculated the peak intensities */
    exponential(params, relax_times, back_calc, num_times);


    /* Test code (convert aaa to a Numeric array */
    /* aaa_numpy = (PyArrayObject *) PyArray_FromDimsAndData(1, num_params, 
PyArray_DOUBLE, aaa_pointer); */
    /*aaa_numpy = (PyArrayObject *) PyArray_FromDims(1, &num_params, 
PyArray_DOUBLE);
    aaa_pointer = (double *) aaa_numpy->data;*/

    /* Fill the Numeric array */
    /*for (i = 0; i < 2; i++)
        aaa_pointer[i] = aaa[i];*/

    Py_DECREF(numpy_params);
    return NULL;
    return PyArray_Return(aaa_numpy);
}

static PyObject *
d2func(PyObject *self, PyObject *args) {
    /* Function for calculating and returning the chi-squared Hessian. */
    return Py_BuildValue("f", 0.0);
}


static PyObject *
back_calc_I(PyObject *self, PyObject *args) {
    /* Function for returning as a Numeric array the back calculated peak 
intensities */

    /* Declarations */
    extern double back_calc[];
    extern int num_times;
    int i;

    PyObject *back_calc_py = PyList_New(num_times);
    assert(PyList_Check(back_calc_py));

    /* Copy the values out of the C array into the Python array */
    for (i = 0; i < num_times; i++)
        PyList_SetItem(back_calc_py, i, Py_BuildValue("f", back_calc[i]));

    /* Return the Numeric array */
    return back_calc_py;
}


/* The method table for the functions called by Python */
static PyMethodDef relax_fit_methods[] = {
    {"setup", (PyCFunction)setup, METH_VARARGS | METH_KEYWORDS, "The main 
relaxation curve fitting setup function."},
    {"func", func, METH_VARARGS},
    {"dfunc", dfunc, METH_VARARGS},
    {"d2func", d2func, METH_VARARGS},
    {"back_calc_I", back_calc_I, METH_VARARGS},
    {NULL, NULL, 0, NULL}        /* Sentinel */
};


/* Initialise as a Python module */
PyMODINIT_FUNC
initrelax_fit(void)
{
    (void) Py_InitModule("relax_fit", relax_fit_methods);

    /* Import the Numeric array module.  This is essential. */
    import_array();
}
/*
 * Copyright (C) 2006 Edward d'Auvergne
 *
 * This file is part of the program relax.
 *
 * relax is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * relax is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with relax; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */


/* Required for the Python/C API??? */

#define PY_ARRAY_UNIQUE_SYMBOL numarray


/* The maximum number of parameters for this function */
#define MAXPARAMS 3

/* The maximum number of spectral time points */
#define MAXTIMES 30


/****************************************/
/* External, hence permanent, variables */
/****************************************/

/* Variables sent to the setup function to be stored for later use */
PyArrayObject *numpy_values, *numpy_sd, *numpy_relax_times, 
*numpy_scaling_matrix;
int num_params, num_times;
double *sd;

/* Variables sent to 'func', 'dfunc', and 'd2func' during optimisation */
/*PyArrayObject *numpy_params;*/

/* Pointers to contiguous PyArrayObjects */
double *values, *sd, *relax_times, *scaling_matrix;
/*double *params;*/


/* Variables used for storage during the function calls of optimisation */
double back_calc[MAXTIMES];


Related Messages


Powered by MHonArc, Updated Fri Apr 07 06:20:27 2006