Control parameters
Topics covered in this chapter:
- Example
- Structures for passing information
- Services related to parameters
- Functions for handling parameters
- Module vs. package
Control parameters may be used to direct and modify the behaviour of modules or to obtain status information from a module. A module may provide such parameters as read-only, for information purposes. But much more frequently the control parameters will be write-enabled, giving the user the possibility to modify their value.
Example
We want to add two parameters to the module defining a task structure that was presented in the previous chapter: the maximum length of name strings used for reading in tasks (tasknamelength, an integer value) and a time limit value (taskmaxtime, a real). These parameters might be used as follows in a model (assuming t is an array of tasks):
if(getparam("tasknamelength")<10) then setparam("tasknamelength",20) end-if t(3):=task("three",getparam("taskmaxtime"))
Structures for passing information
The introduction of parameters necessitates several additions to the lists that are passed to Mosel via the interface structure.
List of subroutines
In the list of subroutines, the following two lines are new (they must be added at the beginning of the list and in the order shown here):
static XPRMdsofct tabfct[]= { {"", XPRM_FCT_GETPAR, XPRM_TYP_NOT, 0, NULL, task_getpar}, {"", XPRM_FCT_SETPAR, XPRM_TYP_NOT, 0, NULL, task_setpar}, ... }
These two subroutines do not take any names (first parameter). The macros XPRM_FCT_GETPAR and XPRM_FCT_SETPAR identify them as implementations of Mosel's getparam and setparam subroutines for this module.
List of services
We have also got two new services:
static XPRMdsoserv tabserv[]= { {XPRM_SRV_RESET, (void *)task_reset}, {XPRM_SRV_PARAM, (void *)task_findparam}, {XPRM_SRV_PARLST, (void *)task_nextparam} };
Module context
The user is free to store the control parameters in any way that is convenient for him. There is no predefined format for this list since it is not passed as such to Mosel. In our example we have chosen the following structure for storing parameters (their names — always in lower case only, types and access rights, and descriptions):
static struct { char *name; int type; char *desc; } taskparams[]={ {"taskmaxtime", XPRM_TYP_REAL|XPRM_CPAR_READ|XPRM_CPAR_WRITE, "a time limit value"}, {"tasknamelength", XPRM_TYP_INT|XPRM_CPAR_READ|XPRM_CPAR_WRITE, "maximum length of task names"} };
The current values of the parameters are stored in the context of the module since they may be modified (these values must be initialized when the context is created):
typedef struct { s_task *firsttask; int maxname; double maxtime; } s_taskctx;
Services related to parameters
Whenever a module defines control parameters, it needs to provide the service to retrieve a parameter number by a name. If the corresponding parameter is not found in the module, this function returns -1. Otherwise, if the parameter belongs to the module, its reference number (here: index in the list of parameters defined by the module) must be returned, together with information about its type (second argument of the function).
static int task_findparam(const char *name, int *type) { int n; int notfound; n=0; do { if((notfound=strcmp(name, taskparams[n].name))==0) break; n++; } while(taskparams[n].name!=NULL); if(!notfound) { *type=taskparams[n].type; return n; } else return -1; }
The findparam service function is only used during the compilation of a model to convert the name of a parameter to a module-internal identification number. This number is used by the subroutines setparam and getparam during the execution of the model (see Section Functions for handling parameters).
The second service that we are defining is optional: it provides a possibility of enumerating the parameters of the module (e.g. this is used when module information is displayed with the examine command).
static void *task_nextparam(void *ref, const char **name, const char **desc, int *type) { long cst; cst=(long)ref; if((cst<0)||(cst>=TASK_NUMPARAM)) return NULL; else { *name=taskparams[cst].name; *type=taskparams[cst].type; *desc=taskparams[cst].desc; return (void *)(cst+1); } }
Mosel calls this function repeatedly until it returns NULL. At the first call the value of the argument ref is NULL, while at any subsequent calls it corresponds to the return value of the immediately preceding execution of this function. The other arguments need to be filled with the information for a parameter (name and type are required, the descriptive text is optional). The constant TASK_NUMPARAM is the number of parameters that we have defined in this module.
Functions for handling parameters
In a Mosel program, parameters are accessed with the two subroutines setparam and getparam. The module must implement these two subroutines for its parameters.
The function that enables the user to set the parameters of our module is the following:
static int task_setpar(XPRMcontext ctx, void *libctx) { s_taskctx *taskctx; int n; taskctx=libctx; n=XPRM_POP_INT(ctx); switch(n) { case 0: taskctx->maxname=XPRM_POP_INT(ctx); break; case 1: taskctx->maxtime=XPRM_POP_REAL(ctx); break; default: mm->dispmsg(ctx, "Task: Wrong control parameter number.\n"); return XPRM_RT_ERROR; } return XPRM_RT_OK; }
Via its stack, Mosel provides the number of the parameter (value returned by the findparam service function) and its new value to the module.
The parameters of our module are accessed via the following function:
static int task_getpar(XPRMcontext ctx, void *libctx) { s_taskctx *taskctx; int n; taskctx=libctx; n=XPRM_POP_INT(ctx); switch(n) { case 0: XPRM_PUSH_INT(ctx, taskctx->maxname); break; case 1: XPRM_PUSH_REAL(ctx, taskctx->maxtime); break; default: mm->dispmsg(ctx, "Task: Wrong control parameter number.\n"); return XPRM_RT_ERROR; } return XPRM_RT_OK; }
The complete task module is part of the module examples provided with the Mosel distribution and on the Xpress website.
Module vs. package
Since Mosel 5.0 packages offer similar functionality as modules for the implementation of parameters. The parameter names and types are specified in the parameters block of the package:
parameters "p1":real "p2":integer "p3":string "p4":boolean end-parameters
The access routines for the four parameter types have a fixed format, namely packagename∼get[r|i|s|b]param and packagename∼set[r|i|s|b]param. The access routines must be defined according to the parameter types implemented by a package as shown in the code extract below—the complete example can be found in the Chapter 'Packages' of the Mosel User Guide.
declarations myp1: real ! Entity for storing the current parameter value end-declarations myp1:=0.25 ! Set the default value for the parameter ! Get value of a real parameter public function parpkg~getrparam(p:string):real case p of "p1": returned:=myp1 end-case end-function ! Set value for real parameters public procedure parpkg~setparam(p:string,v:real) case p of "p1": myp1:=v end-case end-procedure
A model using the package will access the package parameters via Mosel's standard getparam and setparam routines.
© 2001-2024 Fair Isaac Corporation. All rights reserved. This documentation is the property of Fair Isaac Corporation (“FICO”). Receipt or possession of this documentation does not convey rights to disclose, reproduce, make derivative works, use, or allow others to use it except solely for internal evaluation purposes to determine whether to purchase a license to the software described in this documentation, or as otherwise set forth in a written software license agreement between you and FICO (or a FICO affiliate). Use of this documentation and the software described in it must conform strictly to the foregoing permitted uses, and no other use is permitted.