Test whether a sequence is increasing

3

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:

  1. 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.
  2. 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.
  3. 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.
  4. 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;
Share

About Author

Rick Wicklin

Distinguished Researcher in Computational Statistics

Rick Wicklin, PhD, is a distinguished researcher in computational statistics at SAS and is a principal developer of PROC IML and SAS/IML Studio. His areas of expertise include computational statistics, simulation, statistical graphics, and modern methods in statistical data analysis. Rick is author of the books Statistical Programming with SAS/IML Software and Simulating Data with SAS.

3 Comments

  1. 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.

  2. Pingback: Testing for equality of sets - The DO Loop

Leave A Reply

Back to Top