Lesson 35: Modules
Modules are basically subroutines. A module can just be a structure that groups a set of commands executed at once, or it can be a subroutine that passes parameters, or it can be a function, which is used in an assignment statement that returns one (matrix) value.
Consider matrices
X={1 1, 2 2, 3
3};
Y={"A", "B", "C"};
Z={1 2 3, 2 3 4, 3 5 9};
X1=X[,1];
X2=X1+5;
Modules provide a means of saving and reusing code. They can take three forms, a simple module without parameters, a subroutine module that passes parameters, and a function.
Simple module. The name is XPX. X and XPRIMEX are global variables. This type of module depends on having the correctly named matrices available in the program, and having the program accept the matrices it creates as global variables.
start xpx;
xprimex=x`*x;
print xprimex "Inside Module";
finish;
That just creates the module, nothing runs. So then run it and show the XPRIMEX exists outside the module.
run xpx;
print xprimex "Outside Module";
Errors inside modules can do strange things. A module may be created even if it has errors. If this happens and you run it, it might go into pause mode. This means that it is waiting for your input. In this case you can submit commands and it continues to wait. To get out of the module, you can issue a "stop" command. You can also use a "stop" command inside the module in programming statements, such as in if-then conditionals. If the condition is met, the module will stop, but IML keeps running. There is also an "abort" command that you can use in programming statements which will exit out of IML under program control. You can also pause a module with programming statements so that it waits for your input. If you put a "quit" statement inside a module, IML will exit immediately and the module will not be created.
Subroutine module. This type of module accepts parameters when it is called and can pass parameters back. Put parameters next to the module name in parentheses. The parameters will have local symbol table values, even if they have the same names as variables in the global symbol table. The second print command will not work.
start xpx2(X);
xprimex=x`*x;
print xprimex "Inside Module";
finish;
run xpx2(Z);
print xprimex "Outside Module";
You can pass parameters back out: This time the second print works, because the value of xprimex has been passed back out to the global variable Y. Here the global Z value is passed into the module's local symbol table where it becomes X.
start
xpx2(X,xprimex);
xprimex=x`*x;
print xprimex "Inside Module";
finish;
run xpx2(Z,Y);
print Y "Outside Module";
Function module. This kind of module returns a single value and is used in assignment statements like any function. The print statements inside the module would not normally be there, this is just to show what happens inside the module.
module
upsquare(X);
print X "Incoming value of X";
n=min(nrow(X),ncol(X));
X=X[1:n,1:n];
print X "Processed value of X";
return(X);
finish;
Z=upsquare(X);
print Z;
Storing modules and matrices. If you want to save all your matrices and modules, a simple store command will do it. It will, by default, go to the current user library (work if you haven't changed it). There is some difficulty in keeping track of when the library goes into effect, so the best thing to do is to have a permanent library defined, then use
reset storage=library.imlstor;
store;
Where library is your library name. You can give it a different name but IMLSTOR is the default name of the IML catalog which is a single file that holds all the matrices and modules. You can then call everything back into memory with a load command.
load;
But you can store and load individual matrices and modules too. For matrices just give the name, for modules, say "module=name".
save X Y
module=XPX;
load X;
Setting a user libname while IML is running may not change the default library. It is not entirely clear to me how this works. You can define the libname user before starting IML, and then the default module storage will go there. You can save matrices by saying "store matrixname;" and you can bring them back with "load matrixname;" Modules need the syntax "store module=modulename;" You can also use the load and store commands without any options (names) and you will load or store all matrices and modules that are available.
IMLstore is the default name of the catalog in which matrices and modules are stored. A catalog is a single file that stores multiple objects. If you don't have a user library defined this will go into work. Otherwise it will save it in the specified user library.
There is another way to do this though. You can use an option in the reset command, like
libname stat510 "C: \Stat510";
reset storage=stat510.imlstore;
You can use other names instead of imlstore but it is probably best to keep the default name.
Exercises:
1. Write a subroutine without parameters that finds the average value of each column in a matrix, then subtracts that value from each element in the corresponding column (this is called "centering" in regression).
2. Write a subroutine module that takes two parameters, a constant and a square matrix, adds the constant value to every element of the diagonal of the matrix, and passes the result back in a new parameter (this is related to "ridge regression").
3. Write a function module that will return one of three identically sized input matrices that has the largest determinant (you decide what to do about ties). The function should check that the matrices are square and all the same size, and print an error message if not.
Copyright reserved by Dr. Dwight Galster, 2006. Please request permission for reprints (other than for personal use) from dwight.galster@sdstate.edu . "SAS" is a registered trade name of SAS Institute, Cary North Carolina. All other trade names mentioned are the property of their respective owners. This document is a work in progress and comments are welcome. Please send an email if you find it useful or if your site links to it.