Functions Functions

While one can accomplish almost anything with the tools that have been discussed previously, one finds that if this is all he has, then things get convoluted quickly. MOSES has a concept called "functions" which can be used to organize data more effectively. This concept is based on the true mathematical definition of a function. Suppose that A and B are two sets, and for each element of A there is associated an element of B. This association of elements is called a function from A to B. The set A is called the domain of the function, the set B is called the range of the function, and the elements in B are called the values of the function. What we are going to discuss here are functions who's domain is either the set of positive integers or a "variable" and the range of these functions is a set of strings.

In this sense, a "variable" is not a simple global or local variable. It is, in fact, a set of names, and a name is a string of up to eight characters. The variable itself has a name which is a string of up to twenty four characters. The name must be of the form

     <DBFILE>VAR_NAME

Here DBFILE is the name of the database file where the variable will be stored. Now,we could spend a good bit of time talking about this, but lets just say that there are two that are always available: MACDBF and SYSDBF, so you should use one of these (preferably MACDBF). VAR_NAME is simply the name of the variable. To create a variable, one uses the internal command:


     &VARIABLE, VAR_NAME, -ADD NAME

Which adds the name "NAME" to the variable VAR_NAME. Now, once a variable has names, you can find out what they are with the string function


     &VARIABLE(-WHILE VAR_NAME SEL WHAT )

extracts all the names in "VAR_NAME" that match SEL and sets the (normal global or local) variable WHAT to the value of the name. It also returns a string .FALSE. if there are more names to be output or .TRUE. if it is finished.

Let's look at an example:

     &VARIABLE <MACDBF>COWS -ADD JERSEY
     &VARIABLE <MACDBF>COWS -ADD HOLSTEIN
     &VARIABLE <MACDBF>COWS -ADD ANGUS

Will build a variable <MACDBF>COWS which has three names in it: JERSEY, HOLSTEIN, and ANGUS. Here we will be using the command &LOOP without any entries. This advanced method of using &LOOP creates an infinite loop. Now,

     &LOCAL LIST  =
     &LOOP
     &EXIT &VARIABLE(-WHILE  <MACDBF>COWS @  A_COW)
     &SET LIST   = %LIST %A_COW
     &ENDLOOP

will produce the local variable "LIST" which contains the three names of cows. Finally, there is the string function


     &NUMVAR(VAR_NAME)

that returns the number of names in the variable "VAR_NAME"; e.g.

     &NUMVAR(<MACDBF>COWS)

will return 3.

Often one wishes to "while" items which are in the database. This can be accomplished with

     &LOOP N ( &NAMES(NODES) )
     &ENDLOOP

Unfortunately, for large models, this will produce a "buffer overflow". When this happens you need to change the above to

     &SET NOD_VAR = &NAMES(NODES -V)
     &LOOP
     &EXIT &VARIABLE(-WHILE  %NODE_VAR    @  A_COW)
     &ENDLOOP

The first line above uses the &NAMES string function and the option -V to get the names that MOSES uses to store the data which allows you to use the MOSES data directly.

As mentioned above, "functions" are build on top of variables. Before one can add values to a function, he must first "define" it with the internal command:


     &DEFINE, FUNNAM, -OPTIONS

Here, FUNNAM is the name of the function, and the available options are:



     -DOMAIN, DOMNAM,

     -MEMORY

Here FUNNAM is the name of the function and it follows the same rules as those for a variable name. DOMNAM define the domain of the function. If the option -DOMAIN is omitted, then the domain of the function will be the set of positive integers otherwise it is the variable DOMNAM. The option -MEMORY instructs MOSES that the primary residence for values of the function will be in memory rather than on a file. If omitted, the primary residence will be on the database file. Normally, memory resident functions are accessed more quickly, but not always.

Once a function has been defined you should define its values. This is accomplished with the internal command:


     &FVPUT, FUNNAM, VAR, STRING

Here, FUNNAM is the name of the function, VAR is the value (name) in the variable DOMAIN associated with STRING. For example:

     &DEFINE <MACDBF>COW_DATA -DOMAIN <MACDBF>COWS
     &FVPUT <MACDBF>COW_DATA JERSEY Milk
     &FVPUT <MACDBF>COW_DATA HOLSTEIN Milk
     &FVPUT <MACDBF>COW_DATA ANGUS Beef

defines the function <MACDBF>COW_DATA and associates data for three types of cows. To get the values from a function, one uses the string function


     &FVGET(FUNNAM, VAR)

The following

     &LOOP
     &EXIT &VARIABLE(-WHILE  <MACDBF>COWS @  A_COW)
     &TYPE The %A_COW cow is a &FVGET(<MACDBF>COW_DATA %A_COW).
     &ENDLOOP

Will type a line defining the class for each type of cow.

Functions are similar to files. You open and close files but you &READY and &SUSPEND functions. The internal command


     &READY, FUNNAM

makes the function FUNNAM available for extracting values. When you are through with a function, you can use the internal command:


     &SUSPEND, FUNNAM, -OPTIONS

The options must be either: -DISCARD, -SAVE, or -CLOSE. If the function is discarded when it is suspended, all data for the function is deleted from memory. If the -SAVE option is used, all data for the function will be written to the data base file if it has changed and the function will remain active. If the -CLOSE option is used, then the function will first be saved and then discarded. In both the subroutine call and the internal command, FUNNAM can include wild characters. Thus, one can suspend more than one function with one command.

One thing to know is that at the end of an INMODEL, MOSES closes all function (yours included). Thus you may need to &READY you functions. Actually MOSES function are more general that what we have discussed, but this is all that is available from the command interface.