Exemplo n.º 1
0
static GnmValue *
call_python_function_nodes (GnmFuncEvalInfo *ei,
			    int argc, GnmExprConstPtr const *argv)
{
	GOPluginService *service;
	ServiceLoaderDataFunctionGroup *loader_data;
	PyObject *python_fn;
	GnmFunc const * fndef;
	GnmValue **values;
	gint i;
	GnmValue *ret_value;

	g_return_val_if_fail (ei != NULL, NULL);
	g_return_val_if_fail (ei->func_call != NULL, NULL);

	fndef = ei->func_call->func;
	service = (GOPluginService *) gnm_func_get_user_data (fndef);
	loader_data = g_object_get_data (G_OBJECT (service), "loader_data");
	SWITCH_TO_PLUGIN (go_plugin_service_get_plugin (service));
	python_fn = PyDict_GetItemString (loader_data->python_fn_info_dict,
	                                  (gchar *) gnm_func_get_name (fndef, FALSE));

	values = g_new (GnmValue *, argc);
	for (i = 0; i < argc; i++) {
		values[i] = gnm_expr_eval (argv[i], ei->pos, GNM_EXPR_EVAL_PERMIT_NON_SCALAR);
	}
	ret_value = call_python_function (python_fn, ei->pos, argc,
					  (GnmValue const * const *)values);
	for (i = 0; i < argc; i++) {
		value_release (values[i]);
	}
	g_free (values);

	return ret_value;
}
Exemplo n.º 2
0
static GnmValue *
call_python_function_args (GnmFuncEvalInfo *ei, GnmValue const * const *args)
{
	GOPluginService *service;
	ServiceLoaderDataFunctionGroup *loader_data;
	PyObject *fn_info_tuple;
	PyObject *python_fn;
	GnmFunc const * fndef;

	gint min_n_args, max_n_args, n_args;

	g_return_val_if_fail (ei != NULL, NULL);
	g_return_val_if_fail (ei->func_call != NULL, NULL);
	g_return_val_if_fail (args != NULL, NULL);

	fndef = ei->func_call->func;
	service = (GOPluginService *) gnm_func_get_user_data (fndef);
	loader_data = g_object_get_data (G_OBJECT (service), "loader_data");
	SWITCH_TO_PLUGIN (go_plugin_service_get_plugin (service));
	fn_info_tuple = PyDict_GetItemString (loader_data->python_fn_info_dict,
	                                      (gchar *) gnm_func_get_name (fndef, FALSE));
	g_assert (fn_info_tuple != NULL);
	python_fn = PyTuple_GetItem (fn_info_tuple, 2);
	function_def_count_args (fndef, &min_n_args, &max_n_args);
	for (n_args = min_n_args; n_args < max_n_args && args[n_args] != NULL; n_args++) {
		;
	}
	return call_python_function (python_fn, ei->pos, n_args, args);
}
Exemplo n.º 3
0
LIST *
evaluate_rule(
    char  * rulename,
    FRAME * frame )
{
    LIST          * result = L0;
    RULE          * rule;
    profile_frame   prof[1];
    module_t      * prev_module = frame->module;

    LIST * l;
    {
        LOL arg_context_, * arg_context = &arg_context_;
        if ( !frame->prev )
            lol_init(arg_context);
        else
            arg_context = frame->prev->args;
        l = var_expand( L0, rulename, rulename+strlen(rulename), arg_context, 0 );
    }

    if ( !l )
    {
        backtrace_line( frame->prev );
        printf( "warning: rulename %s expands to empty string\n", rulename );
        backtrace( frame->prev );
        return result;
    }

    rulename = l->string;
    rule = bindrule( l->string, frame->module );

#ifdef HAVE_PYTHON
    if ( rule->python_function )
    {
        /* The below messing with modules is due to the way modules are
         * implemented in Jam. Suppose we are in module M1 now. The global
         * variable map actually holds 'M1' variables, and M1->variables hold
         * global variables.
         *
         * If we call Python right away, Python calls back Jam and then Jam
         * does 'module M1 { }' then Jam will try to swap the current global
         * variables with M1->variables. The result will be that global
         * variables map will hold global variables, and any variable settings
         * we do will go to the global module, not M1.
         *
         * By restoring basic state, where the global variable map holds global
         * variable, we make sure any future 'module M1' entry will work OK.
         */

        LIST * result;
        module_t * m = python_module();

        frame->module = m;

        exit_module( prev_module );
        enter_module( m );

        result = call_python_function( rule, frame );

        exit_module( m );
        enter_module ( prev_module );

        return result;
    }
#endif

    /* Drop the rule name. */
    l = list_pop_front( l );

    /* Tack the rest of the expansion onto the front of the first argument. */
    frame->args->list[0] = list_append( l, lol_get( frame->args, 0 ) );

    if ( DEBUG_COMPILE )
    {
        /* Try hard to indicate in which module the rule is going to execute. */
        if ( rule->module != frame->module
             && rule->procedure != 0 && strcmp( rulename, rule->procedure->rulename ) )
        {
            char buf[256] = "";
            strncat( buf, rule->module->name, sizeof( buf ) - 1 );
            strncat( buf, rule->name, sizeof( buf ) - 1 );
            debug_compile( 1, buf, frame );
        }
        else
        {
            debug_compile( 1, rulename, frame );
        }

        lol_print( frame->args );
        printf( "\n" );
    }

    if ( rule->procedure && rule->module != prev_module )
    {
        /* Propagate current module to nested rule invocations. */
        frame->module = rule->module;

        /* Swap variables. */
        exit_module( prev_module );
        enter_module( rule->module );
    }

    /* Record current rule name in frame. */
    if ( rule->procedure )
    {
        frame->rulename = rulename;
        /* And enter record profile info. */
        if ( DEBUG_PROFILE )
            profile_enter( rule->procedure->rulename, prof );
    }

    /* Check traditional targets $(<) and sources $(>). */
    if ( !rule->actions && !rule->procedure )
    {
        backtrace_line( frame->prev );
        printf( "rule %s unknown in module %s\n", rule->name, frame->module->name );
        backtrace( frame->prev );
        exit( 1 );
    }

    /* If this rule will be executed for updating the targets then construct the
     * action for make().
     */
    if ( rule->actions )
    {
        TARGETS * t;
        ACTION  * action;

        /* The action is associated with this instance of this rule. */
        action = (ACTION *)BJAM_MALLOC( sizeof( ACTION ) );
        memset( (char *)action, '\0', sizeof( *action ) );

        action->rule = rule;
        action->targets = targetlist( (TARGETS *)0, lol_get( frame->args, 0 ) );
        action->sources = targetlist( (TARGETS *)0, lol_get( frame->args, 1 ) );

        /* If we have a group of targets all being built using the same action
         * then we must not allow any of them to be used as sources unless they
         * had all already been built in the first place or their joined action
         * has had a chance to finish its work and build all of them anew.
         *
         * Without this it might be possible, in case of a multi-process build,
         * for their action, triggered by buiding one of the targets, to still
         * be running when another target in the group reports as done in order
         * to avoid triggering the same action again and gets used prematurely.
         *
         * As a quick-fix to achieve this effect we make all the targets list
         * each other as 'included targets'. More precisely, we mark the first
         * listed target as including all the other targets in the list and vice
         * versa. This makes anyone depending on any of those targets implicitly
         * depend on all of them, thus making sure none of those targets can be
         * used as sources until all of them have been built. Note that direct
         * dependencies could not have been used due to the 'circular
         * dependency' issue.
         *
         * TODO: Although the current implementation solves the problem of one
         * of the targets getting used before its action completes its work it
         * also forces the action to run whenever any of the targets in the
         * group is not up to date even though some of them might not actually
         * be used by the targets being built. We should see how we can
         * correctly recognize such cases and use that to avoid running the
         * action if possible and not rebuild targets not actually depending on
         * targets that are not up to date.
         *
         * TODO: Using the 'include' feature might have side-effects due to
         * interaction with the actual 'inclusion scanning' system. This should
         * be checked.
         */
        if ( action->targets )
        {
            TARGET * t0 = action->targets->target;
            for ( t = action->targets->next; t; t = t->next )
            {
                target_include( t->target, t0 );
                target_include( t0, t->target );
            }
        }

        /* Append this action to the actions of each target. */
        for ( t = action->targets; t; t = t->next )
            t->target->actions = actionlist( t->target->actions, action );
    }

    /* Now recursively compile any parse tree associated with this rule.
     * parse_refer()/parse_free() call pair added to ensure rule not freed
     * during use.
     */
    if ( rule->procedure )
    {
        SETTINGS * local_args = collect_arguments( rule, frame );
        PARSE * parse = rule->procedure;
        parse_refer( parse );

        pushsettings( local_args );
        result = parse_evaluate( parse, frame );
        popsettings( local_args );
        freesettings( local_args );

        parse_free( parse );
    }

    if ( frame->module != prev_module )
    {
        exit_module( frame->module );
        enter_module( prev_module );
    }

    if ( DEBUG_PROFILE && rule->procedure )
        profile_exit( prof );

    if ( DEBUG_COMPILE )
        debug_compile( -1, 0, frame);

    return result;
}
Exemplo n.º 4
0
int
ode_jacobian_function(int *n, double *t, double *y, int *ml, int *mu,
                      double *pd, int *nrowpd)
{
    /*
        This is the function called from the Fortran code it should
            -- use call_python_function to get a multiarrayobject result
            -- check for errors and return -1 if any (though this is ignored
                           by calling program).
            -- otherwise place result of calculation in pd
    */

    PyArrayObject *result_array;
    PyObject *arglist, *arg1;

    int ndim, nrows, ncols, dim_error;
    npy_intp *dims;

    /* Append t to argument list */
    if ((arg1 = PyTuple_New(1)) == NULL) {
        *n = -1;
        return -1;
    }
    PyTuple_SET_ITEM(arg1, 0, PyFloat_FromDouble(*t));
    /* arg1 now owns newly created reference */
    if ((arglist = PySequence_Concat(arg1, global_params.extra_arguments)) == NULL) {
        *n = -1;
        Py_DECREF(arg1);
        return -1;
    }
    Py_DECREF(arg1);    /* arglist has reference */

    result_array = (PyArrayObject *)call_python_function(global_params.python_jacobian,
                                                         *n, y, arglist, odepack_error);
    if (result_array == NULL) {
        *n = -1;
        Py_DECREF(arglist);
        return -1;
    }

    ncols = *n;
    if (global_params.jac_type == 4) {
        nrows = *ml + *mu + 1;
    }
    else {
        nrows = *n;
    }

    if (!global_params.jac_transpose) {
        int tmp;
        tmp = nrows;
        nrows = ncols;
        ncols = tmp;
    }

    ndim = PyArray_NDIM(result_array);
    if (ndim > 2) {
        PyErr_Format(PyExc_RuntimeError,
            "The Jacobian array must be two dimensional, but got ndim=%d.",
            ndim);
        *n = -1;
        Py_DECREF(arglist);
        Py_DECREF(result_array);
        return -1;
    }

    dims = PyArray_DIMS(result_array);
    dim_error = 0;
    if (ndim == 0) {
        if ((nrows != 1) || (ncols != 1)) {
            dim_error = 1;
        }
    }
    if (ndim == 1) {
        if ((nrows != 1) || (dims[0] != ncols)) {
            dim_error = 1;
        }
    }
    if (ndim == 2) {
        if ((dims[0] != nrows) || (dims[1] != ncols)) {
            dim_error = 1;
        }
    }
    if (dim_error) {
        char *b = "";
        if (global_params.jac_type == 4) {
            b = "banded ";
        }
        PyErr_Format(PyExc_RuntimeError,
            "Expected a %sJacobian array with shape (%d, %d)",
            b, nrows, ncols);
        *n = -1;
        Py_DECREF(arglist);
        Py_DECREF(result_array);
        return -1;
    }

    /*
     *  global_params.jac_type is either 1 (full Jacobian) or 4 (banded Jacobian).
     *  global_params.jac_transpose is !col_deriv, so if global_params.jac_transpose
     *  is 0, the array created by the user is already in Fortran order, and
     *  a transpose is not needed when it is copied to pd.
     */

    if ((global_params.jac_type == 1) && !global_params.jac_transpose) {
        /* Full Jacobian, no transpose needed, so we can use memcpy. */
        memcpy(pd, PyArray_DATA(result_array), (*n)*(*nrowpd)*sizeof(double));
    }
    else {
        /*
         *  global_params.jac_type == 4 (banded Jacobian), or
         *  global_params.jac_type == 1 and global_params.jac_transpose == 1.
         *
         *  We can't use memcpy when global_params.jac_type is 4 because the leading
         *  dimension of pd doesn't necessarily equal the number of rows of the
         *  matrix.
         */
        int m;  /* Number of rows in the (full or packed banded) Jacobian. */
        if (global_params.jac_type == 4) {
            m = *ml + *mu + 1;
        }
        else {
            m = *n;
        }
        copy_array_to_fortran(pd, *nrowpd, m, *n,
            (double *) PyArray_DATA(result_array),
            !global_params.jac_transpose);
    }

    Py_DECREF(arglist);
    Py_DECREF(result_array);
    return 0;
}
Exemplo n.º 5
0
void
ode_function(int *n, double *t, double *y, double *ydot)
{
    /*
    This is the function called from the Fortran code it should
        -- use call_python_function to get a multiarrayobject result
        -- check for errors and set *n to -1 if any
        -- otherwise place result of calculation in ydot
    */

    PyArrayObject *result_array = NULL;
    PyObject *arg1, *arglist;

    /* Append t to argument list */
    if ((arg1 = PyTuple_New(1)) == NULL) {
        *n = -1;
        return;
    }
    PyTuple_SET_ITEM(arg1, 0, PyFloat_FromDouble(*t));
    /* arg1 now owns newly created reference */
    if ((arglist = PySequence_Concat(arg1, global_params.extra_arguments)) == NULL) {
        *n = -1;
        Py_DECREF(arg1);
        return;
    }
    Py_DECREF(arg1);    /* arglist has reference */

    result_array = (PyArrayObject *)call_python_function(global_params.python_function,
                                                    *n, y, arglist, odepack_error);
    if (result_array == NULL) {
        *n = -1;
        Py_DECREF(arglist);
        return;
    }

    if (PyArray_NDIM(result_array) > 1) {
        *n = -1;
        PyErr_Format(PyExc_RuntimeError,
                "The array return by func must be one-dimensional, but got ndim=%d.",
                PyArray_NDIM(result_array));
        Py_DECREF(arglist);
        Py_DECREF(result_array);
        return;
    }

    if (PyArray_Size((PyObject *)result_array) != *n) {
        PyErr_Format(PyExc_RuntimeError,
            "The size of the array returned by func (%ld) does not match "
            "the size of y0 (%d).",
            PyArray_Size((PyObject *)result_array), *n);
        *n = -1;
        Py_DECREF(arglist);
        Py_DECREF(result_array);
        return;
    }

    memcpy(ydot, PyArray_DATA(result_array), (*n)*sizeof(double));
    Py_DECREF(result_array);
    Py_DECREF(arglist);
    return;
}
Exemplo n.º 6
0
LIST *
evaluate_rule(
    char    *rulename,
    FRAME *frame )
{
    LIST      *result = L0;
    RULE          *rule;
    profile_frame prof[1];
    module_t    *prev_module = frame->module;
    
    LIST      *l;
    {
        LOL arg_context_, *arg_context = &arg_context_;
        if ( !frame->prev )
            lol_init(arg_context);
        else
            arg_context = frame->prev->args;
        
        l = var_expand( L0, rulename, rulename+strlen(rulename), arg_context, 0 );
    }

    if ( !l )
    {
        backtrace_line( frame->prev );
        printf( "warning: rulename %s expands to empty string\n", rulename );
        backtrace( frame->prev );
        return result;
    }

    rulename = l->string;
    rule = bindrule( l->string, frame->module );

#ifdef HAVE_PYTHON
    if (rule->python_function)
    {
        return call_python_function(rule, frame);
    }
#endif

    /* drop the rule name */
    l = list_pop_front( l );

    /* tack the rest of the expansion onto the front of the first argument */
    frame->args->list[0] = list_append( l, lol_get( frame->args, 0 ) );

    if ( DEBUG_COMPILE )
    {
        /* Try hard to indicate in which module the rule is going to execute */
        if ( rule->module != frame->module
             && rule->procedure != 0 && strcmp(rulename, rule->procedure->rulename) )
        {
            char buf[256] = "";
            strncat( buf, rule->module->name, sizeof(buf) - 1 );
            strncat( buf, rule->name, sizeof(buf) - 1 );
            debug_compile( 1, buf, frame);
        }
        else
        {
            debug_compile( 1, rulename, frame);
        }

        lol_print( frame->args );
        printf( "\n" );
    }
    
    if ( rule->procedure && rule->module != prev_module )
    {
        /* propagate current module to nested rule invocations */
        frame->module = rule->module;
        
        /* swap variables */
        exit_module( prev_module );
        enter_module( rule->module );
    }
        
    /* record current rule name in frame */
    if ( rule->procedure )
    {
        frame->rulename = rulename;
        /* and enter record profile info */
        if ( DEBUG_PROFILE )
            profile_enter( rule->procedure->rulename, prof );
    }

    /* Check traditional targets $(<) and sources $(>) */

    if( !rule->actions && !rule->procedure )
    {
        backtrace_line( frame->prev );
        printf( "rule %s unknown in module %s\n", rule->name, frame->module->name );
        backtrace( frame->prev );
        exit(1);
    }

    /* If this rule will be executed for updating the targets */
    /* then construct the action for make(). */

    if( rule->actions )
    {
        TARGETS *t;
        ACTION  *action;

        /* The action is associated with this instance of this rule */

        action = (ACTION *)malloc( sizeof( ACTION ) );
        memset( (char *)action, '\0', sizeof( *action ) );

        action->rule = rule;
        action->targets = targetlist( (TARGETS *)0, lol_get( frame->args, 0 ) );
        action->sources = targetlist( (TARGETS *)0, lol_get( frame->args, 1 ) );

        /* Append this action to the actions of each target */

        for( t = action->targets; t; t = t->next )
            t->target->actions = actionlist( t->target->actions, action );
    }

    /* Now recursively compile any parse tree associated with this rule */
    /* refer/free to ensure rule not freed during use */

    if( rule->procedure )
    {
        SETTINGS *local_args = collect_arguments( rule, frame );
        PARSE *parse = rule->procedure;
        parse_refer( parse );
        
        pushsettings( local_args );
        result = parse_evaluate( parse, frame );
        popsettings( local_args );
        freesettings( local_args );
        
        parse_free( parse );
    }

    if ( frame->module != prev_module )
    {
        exit_module( frame->module );
        enter_module( prev_module );
    }

    if ( DEBUG_PROFILE && rule->procedure )
        profile_exit( prof );

    if( DEBUG_COMPILE )
        debug_compile( -1, 0, frame);

    return result;
}