The SAS/IML language supports both row vectors and column vectors. This is useful for performing linear algebra, but it can cause headaches when you are writing a SAS/IML module. I want my modules to be able to handle both row vectors and column vectors. I don't want the user to have to know that my module requires, say, a row vector, and I don't want my module to fail if it is called with a column vector. This article shows two quick tips for handling row vectors and column vectors in a uniform manner.
Row vectors versus column vectors: Which are which?
The NCOL and NROW functions are useful for determining the dimensions of a vector. If x is a row vector, then nrow(x)=1 and ncol(x) is the number of elements in x. Conversely, if x is a column vector, then nrow(x) is the number of elements in x. This shows why it is unwieldy to write a module that handles both row and column vectors: there is no function that returns the number of elements in a vector independent of the shape of the vector.
Two useful helper functions
Of course, it is trivial to write such a function. The following function returns the number of elements in a vector, regardless of the vector's shape:
start NumElements(x); return( nrow(x)*ncol(x) ); finish;
In fact, the same function also returns the number of elements in any nxp matrix.
A related useful function is one that returns the last element in a vector:
start Last(x); return( x[nrow(x)*ncol(x)] ); finish;
I like to use Last(x) to get the last element of a function, rather than the more obscure x[ncol(x)] or x[nrow(x)], which assume a particular shape for the vector.
The ROWVEC and COLVEC modules
Another technique that I use is calling the ROWVEC or COLVEC module to physically copy the argument of a module into a vector that has a known shape. For example, the following module converts the module argument into a row vector, which means that there are ncol(x) elements in x:
start MyModule(_x); x = rowvec(_x); /* x is a row vector. Continue computations. */ finish;
Why did I create a new variable instead of reusing the argument variable? Because the SAS/IML language uses a pass-by-reference scheme to send variables into functions. This means that any modifications to the variable in the module also affect the variable that is passed to the module. If I were to write _x = rowvec(_x), the code would change the shape of the matrix that is passed to the MyModule function.