The other day I needed to check that a sequence of numerical values was in strictly increasing order. My first thought was to sort the values and compare the sorted and original values, but I quickly discarded that approach because it does not detect duplicate values in a montonic (nondecreasing) sequence.

Instead, I decided to use the UNIQUE function in the SAS/IML language, which returns a sorted vector of the input values and removes duplicate values. The following PROC IML statements define a module that
tests whether the row vector `x` contains strictly increasing values:

proc iml; /** Test whether the row vector, x, is strictly increasing **/ start TestIncreasing(x); u = unique(x); if ncol(u) ^= ncol(x) then return( 0 ); if any(u ^= x) then return( 0 ); return( 1 ); finish; |

The module consists of the following steps:

- Use the UNIQUE function to create a sorted increasing list of the unique values of
`x`. The remainder of the module tests whether`u`and`x`contain the same values in the same order. - If the number of columns in
`u`is different than the number of columns of`x`, then there must have been a repeated value in`x`that was removed by the UNIQUE function. Return`0`(failure) in this case. - Do an elementwise comparison of the value in
`u`and`x`. If any of the values are different (as determined by the ANY function), return`0`. (In the second chapter (p. 38-39) of my book,*Statistical Programming with SAS/IML Software*, I explain why you need to use the ANY function in this case.) Notice that you do not need to write a loop in order to test every value. - If the vector
`x`passes both of those tests, it is in increasing order. Return`1`for success.

You can test the module on a few examples. Only the first example is an increasing sequence:

inc1 = TestIncreasing( 1:10 ); inc2 = TestIncreasing( {0 1 1 2 } ); inc3 = TestIncreasing( {0 1 2 -1} ); print inc1 inc2 inc3; |

### Generalizing the Module

I try to write modules that are robust to the shape of the input argument. The module `TestIncreasing` works correctly for row vectors, but Step 2 (the first IF-THEN statement) will return `0` (failure) if the input argument is not a row vector.

There is an easy way to accomodate input arguments that are not necessarily row vectors: use the ROWVEC function module, which part of the IMLMLIB module library.

Change the beginning of the module to the following statements:

start TestIncreasing(_x); x = rowvec(_x); /** ...continue with the module definition... **/ |

With that small change, the module can be used to detect whether a column vector has values in increasing order, and even whether a matrix of values (considered in row-major order) is in increasing order:

inc4 = TestIncreasing( {0,4,6,9} ); inc5 = TestIncreasing( {0 1, 3 4, 7 9} ); print inc4 inc5; |

### An easier method

*Update 14AUG2014*: I'm not sure why I wrote such a complicated module. Here's an easier approach that uses the DIF function, which was introduced in SAS/IML 9.22:

start TestIncreasing(x); d = dif(shape(x,0,1)); return( all(d[2:nrow(d)]> 0) ); finish; |

## 3 Comments

May I ask why you chose to use an underscore (‘_x’) in the final module?

An excellent question! As I discuss in Chapter 3 of my book, the SAS/IML language passes arguments by reference, rather than by making a copy of the values. Therefore, "any change made to an argument in a module also changes the matrix that is passed into the module." (Programming Tip 3.4.4)

A programmer should be careful to not change the input data, unless that is the stated purpose of the module. Because I do not want to reshape the matrix that the user passes in, I made a copy of the matrix in the shape that I need.

Pingback: Testing for equality of sets - The DO Loop