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; }
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); }
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; }
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; }
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; }
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; }