<commit_before>/**
 * @file   amici_interface_matlab.cpp
 * @brief  core routines for mex interface
 *
 * This file defines the fuction mexFunction which is executed upon calling the
 * mex file from matlab
 */

#include "include/amici_interface_matlab.h"
#include "include/amici_model.h"
#include "include/edata.h"
#include "include/returndata_matlab.h"
#include "include/udata.h"

#include <assert.h>
#include <blas.h>
#include <cstring>

/** MS definition of PI and other constants */
#define _USE_MATH_DEFINES
#include <cmath>
#ifndef M_PI 
/** define PI if we still have no definition */
#define M_PI 3.14159265358979323846
#endif

/**
 * @brief The mexFunctionArguments enum takes care of the ordering of mex file arguments (indexing in prhs)
 */
enum mexRhsArguments {
    RHS_TIMEPOINTS,
    RHS_PARAMETERS,
    RHS_CONSTANTS,
    RHS_OPTIONS,
    RHS_PLIST,
    RHS_PBAR,
    RHS_XSCALE_UNUSED,
    RHS_INITIALIZATION,
    RHS_DATA,
    RHS_NUMARGS_REQUIRED = RHS_DATA,
    RHS_NUMARGS
};

/**
 * @ brief extract information from a property of a matlab class (scalar)
 * @ param OPTION name of the property
 * @ param TYPE class to which the information should be cast
 */
#define readOptionScalar(OPTION, TYPE)                                         \
    if (mxGetProperty(prhs[RHS_OPTIONS], 0, #OPTION)) {                                  \
        udata->OPTION = (TYPE)mxGetScalar(mxGetProperty(prhs[RHS_OPTIONS], 0, #OPTION)); \
    } else {                                                                   \
        warnMsgIdAndTxt("AMICI:mex:OPTION",                                    \
                        "Provided options do not have field " #OPTION "!");    \
        goto freturn;                                                          \
    }

/**
 * @ brief extract information from a property of a matlab class (matrix)
 * @ param OPTION name of the property
 */
#define readOptionData(OPTION)                                                 \
    if (mxGetProperty(prhs[RHS_OPTIONS], 0, #OPTION)) {                                  \
        mxArray *a = mxGetProperty(prhs[RHS_OPTIONS], 0, #OPTION);                       \
        int len = (int)mxGetM(a) * mxGetN(a);                                  \
        udata->OPTION = new double[len];                                       \
        memcpy(udata->OPTION, mxGetData(a), sizeof(double) * len);             \
    } else {                                                                   \
        warnMsgIdAndTxt("AMICI:mex:OPTION",                                    \
                        "Provided options do not have field " #OPTION "!");    \
        goto freturn;                                                          \
    }

/*!
 * mexFunction is the main interface function for the MATLAB interface. It reads in input data (udata and edata) and 
 * creates output data compound (rdata) and then calls the AMICI simulation routine to carry out numerical integration.
 *
 * @param[in] nlhs number of output arguments of the matlab call @type int
 * @param[out] plhs pointer to the array of output arguments @type mxArray
 * @param[in] nrhs number of input arguments of the matlab call @type int
 * @param[in] prhs pointer to the array of input arguments @type mxArray
 * @return void
 */
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    // use matlab error reporting
    warnMsgIdAndTxt = &mexWarnMsgIdAndTxt;
    errMsgIdAndTxt = &mexErrMsgIdAndTxt;

    /* ensures that plhs[0] is available */
    if (nlhs != 1) {
        errMsgIdAndTxt("AMICI:mex",
                       "Incorrect number of output arguments (must be 1)!");
        return;
    }

    Model *model = getModel();

    const UserData *udata = userDataFromMatlabCall(prhs, nrhs, model);

    ReturnDataMatlab *rdata = new ReturnDataMatlab(udata, model);
    plhs[0] = rdata->matlabSolutionStruct;
    if (*(rdata->status) != AMICI_SUCCESS)
        return;

    ExpData *edata = NULL;
    if (nrhs >= 8) {
        edata = expDataFromMatlabCall(prhs, udata, model);
    }

    if (udata) {
        if (model->nx > 0) {
            *(rdata->status) =
                (double)runAmiciSimulation(udata, edata, rdata, model);
        }
    }

    delete model;

    if (udata)
        delete udata;
    if (rdata)
        delete rdata;
    if (edata)
        delete edata;
}

/*!
 * userDataFromMatlabCall parses the input from the matlab call and writes it to an UserData class object
 *
 * @param[in] nrhs number of input arguments of the matlab call @type int
 * @param[in] prhs pointer to the array of input arguments @type mxArray
 * @param[in] model pointer to the model object, this is necessary to perform dimension checks @type Model
 * @return udata pointer to user data object @type UserData
 */
UserData *userDataFromMatlabCall(const mxArray *prhs[], int nrhs,
                                 Model *model) {
    if (nrhs < RHS_NUMARGS_REQUIRED) {
        errMsgIdAndTxt(
            "AMICI:mex",
            "Incorrect number of input arguments (must be at least 7)!");
        return nullptr;
    };

    UserData *udata = new UserData(model->np, model->nk, model->nx);

    /* time */
    if (prhs[RHS_TIMEPOINTS] && mxGetM(prhs[RHS_TIMEPOINTS]) * mxGetN(prhs[RHS_TIMEPOINTS]) > 0) {
        udata->setTimepoints(mxGetPr(prhs[RHS_TIMEPOINTS]), (int) mxGetM(prhs[RHS_TIMEPOINTS]) * mxGetN(prhs[RHS_TIMEPOINTS]));
    } else {<commit_msg>Fix potential memleaks in mexFunction<commit_after>/**
 * @file   amici_interface_matlab.cpp
 * @brief  core routines for mex interface
 *
 * This file defines the fuction mexFunction which is executed upon calling the
 * mex file from matlab
 */

#include "include/amici_interface_matlab.h"
#include "include/amici_model.h"
#include "include/edata.h"
#include "include/returndata_matlab.h"
#include "include/udata.h"

#include <assert.h>
#include <blas.h>
#include <cstring>

/** MS definition of PI and other constants */
#define _USE_MATH_DEFINES
#include <cmath>
#ifndef M_PI 
/** define PI if we still have no definition */
#define M_PI 3.14159265358979323846
#endif

/**
 * @brief The mexFunctionArguments enum takes care of the ordering of mex file arguments (indexing in prhs)
 */
enum mexRhsArguments {
    RHS_TIMEPOINTS,
    RHS_PARAMETERS,
    RHS_CONSTANTS,
    RHS_OPTIONS,
    RHS_PLIST,
    RHS_PBAR,
    RHS_XSCALE_UNUSED,
    RHS_INITIALIZATION,
    RHS_DATA,
    RHS_NUMARGS_REQUIRED = RHS_DATA,
    RHS_NUMARGS
};

/**
 * @ brief extract information from a property of a matlab class (scalar)
 * @ param OPTION name of the property
 * @ param TYPE class to which the information should be cast
 */
#define readOptionScalar(OPTION, TYPE)                                         \
    if (mxGetProperty(prhs[RHS_OPTIONS], 0, #OPTION)) {                                  \
        udata->OPTION = (TYPE)mxGetScalar(mxGetProperty(prhs[RHS_OPTIONS], 0, #OPTION)); \
    } else {                                                                   \
        warnMsgIdAndTxt("AMICI:mex:OPTION",                                    \
                        "Provided options do not have field " #OPTION "!");    \
        goto freturn;                                                          \
    }

/**
 * @ brief extract information from a property of a matlab class (matrix)
 * @ param OPTION name of the property
 */
#define readOptionData(OPTION)                                                 \
    if (mxGetProperty(prhs[RHS_OPTIONS], 0, #OPTION)) {                                  \
        mxArray *a = mxGetProperty(prhs[RHS_OPTIONS], 0, #OPTION);                       \
        int len = (int)mxGetM(a) * mxGetN(a);                                  \
        udata->OPTION = new double[len];                                       \
        memcpy(udata->OPTION, mxGetData(a), sizeof(double) * len);             \
    } else {                                                                   \
        warnMsgIdAndTxt("AMICI:mex:OPTION",                                    \
                        "Provided options do not have field " #OPTION "!");    \
        goto freturn;                                                          \
    }

/*!
 * mexFunction is the main interface function for the MATLAB interface. It reads in input data (udata and edata) and 
 * creates output data compound (rdata) and then calls the AMICI simulation routine to carry out numerical integration.
 *
 * @param[in] nlhs number of output arguments of the matlab call @type int
 * @param[out] plhs pointer to the array of output arguments @type mxArray
 * @param[in] nrhs number of input arguments of the matlab call @type int
 * @param[in] prhs pointer to the array of input arguments @type mxArray
 * @return void
 */
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    // use matlab error reporting
    warnMsgIdAndTxt = &mexWarnMsgIdAndTxt;
    errMsgIdAndTxt = &mexErrMsgIdAndTxt;

    /* ensures that plhs[0] is available */
    if (nlhs != 1) {
        errMsgIdAndTxt("AMICI:mex",
                       "Incorrect number of output arguments (must be 1)!");
        return;
    }

    Model *model = getModel();
    if(!model) {
        return;
    }
    if(model->nx <= 1) {
        delete model;
        return;
    }

    const UserData *udata = userDataFromMatlabCall(prhs, nrhs, model);
    if(!udata) {
        delete model;
        return;
    }

    ReturnDataMatlab *rdata = new ReturnDataMatlab(udata, model);   
    if (!rdata || *(rdata->status) != AMICI_SUCCESS) {
        delete model;
        delete rdata;
        return;
    }
    plhs[0] = rdata->matlabSolutionStruct;

    ExpData *edata = nullptr;
    if (nrhs >= RHS_DATA) {
        edata = expDataFromMatlabCall(prhs, udata, model);
        if(!edata) {
            delete model;
            delete rdata;
            return;
        }
    }

    *(rdata->status) =
            (double)runAmiciSimulation(udata, edata, rdata, model);

    delete model;
    delete udata;
    delete rdata;

    if (edata)
        delete edata;
}

/*!
 * userDataFromMatlabCall parses the input from the matlab call and writes it to an UserData class object
 *
 * @param[in] nrhs number of input arguments of the matlab call @type int
 * @param[in] prhs pointer to the array of input arguments @type mxArray
 * @param[in] model pointer to the model object, this is necessary to perform dimension checks @type Model
 * @return udata pointer to user data object @type UserData
 */
UserData *userDataFromMatlabCall(const mxArray *prhs[], int nrhs,
                                 Model *model) {
    if (nrhs < RHS_NUMARGS_REQUIRED) {
        errMsgIdAndTxt(
            "AMICI:mex",
            "Incorrect number of input arguments (must be at least 7)!");
        return nullptr;
    };

    UserData *udata = new UserData(model->np, model->nk, model->nx);

    /* time */
    if (prhs[RHS_TIMEPOINTS] && mxGetM(prhs[RHS_TIMEPOINTS]) * mxGetN(prhs[RHS_TIMEPOINTS]) > 0) {
        udata->setTimepoints(mxGetPr(prhs[RHS_TIMEPOINTS]), (int) mxGetM(prhs[RHS_TIMEPOINTS]) * mxGetN(prhs[RHS_TIMEPOINTS]));
    } else {
{'fraction_non_alphanumeric': 0.09639309048599302, 'fraction_numerical': 0.00581759599033384, 'mean_word_length': 2.02, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 38, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 34, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2205890', 'n_tokens_mistral': 3387, 'n_tokens_neox': 3386, 'n_words': 967}