Wash, rinse, repeat is an English language idiom that might imply "do it again," or humorously imply an infinite loop. Repetition of a function or a set of steps in the context of scripting is called iteration or looping. Iteration is a very important scripting technique. Below is the logic diagram and corresponding JSL code of a simple For loop.
Once a novice scripter learns the syntax of a basic For loop, frequently, they ask "How do I":
- Iterate when the number of iterations is unknown
- Stop a loop early once n events have been counted
- Skip running the block of steps for certain conditions, but continue looping, etc.
Below is an excerpt from chapter 4, section "Conditional Functions", "Iterate" of JSL Companion, Applications of the JMP Scripting Language, Second Edition that presents the basics and tackles these questions. Attached is that section’s example script. As stated in the book’s preface "The example scripts contain ... much more information than we could pack into this book."
Iterate
JSL has several functions that loop or iterate. The basic structure of an iteration loop includes the following:
- Start or initial condition
- Test or while condition
- Increment, step size, or iteration sequence
- Body or block of JSL code to be executed
The body of JSL is executed as long as the test condition is true. The remainder of this blog and script 4_Iterating.jsl provide examples and descriptions of JMP iterating functions.
For Each Row and Set Each Value
For Each Row and Set Each Value are special iteration messages for data tables, where the initial condition is Row( ) = 1, the first row of the source data table. The end condition is the last row. The increment is 1: Row( ) = Row( ) + 1. The test condition can be considered a while condition: Row( ) <= N Row(dt). The first three structural components (initial, while and increment) are built-in.
The syntax is For Each Row ( <dt>, body ).
Summation and Product Functions
The Summation and Product functions are special. In these functions, the main task is built into its name. The three arguments are initial value typically assigned to a variable, end value (i <= 6), where an increment of 1 is implied, and the third argument or body includes what is summed or multiplied.
six_evens = Summation(i=1,6,2*i); // 42 Sum of 1st 6 even integers
six_odds = Summation(i=1,6,2*i-1); // 36 Sum of 1st 6 odd integers
power3to5 = Product(i=1,5,3); // 3*3*3*3*3 = 3^5 = 243
a = 2; b = 4; d = (b - a)/10; //d is step size for 10 intervals
integration_approx = Summation( i=1, 10, d*( a + ( i-.5 )*d)^2);
// 18.66 Integral(x^2) = (x^3)/3 = 64/3 – 8/3 = 56/3
show(six_evens, six_odds, power3to5, integration_approx);
For and While Functions
For and While are traditional programming iteration functions. Typically, For is used when counting, and when the step size is consistent or the number of iterations can be computed. While is most commonly used when the test or while condition requires more complex logic or the increment is conditional. Every For( ) block of code can be written as a While( ) block of code, but the reverse might not be true.
Example
Using the previous integration_approx example, create an iteration loop to get successively better approximations. Start with 10 intervals, and each successive iteration will double the number of intervals. This first example stops after five iterations.
a = 2; b = 4; lastVal = 1000;
integration_approx = 0;
For( k = 1, k <= 5, k++,
If( k == 1,
n = 10,
n = 2 * n
);
lastVal = integration_approx; //needed to check convergence
d = (b - 2) / n;
integration_approx = Summation( i = 1, n, d * (a + (i - .5) * d) ^ 2 );
//-- show convergence
Show (k, n, d, integration_approx, integration_approx - lastVal);
); //end For
Suppose that a specific convergence criterion is wanted. The 4_Iterating.jsl script contains several options to do this. The previous code snippet already has the necessary logic: lastVal and integration_approx have starting values. The script stops when the absolute successive difference is smaller than the convergence criterion.
One variation of this script uses the convergence criterion as an expression in the test argument of the For loop. The following script uses a Break( ) to stop. This example demonstrates that each of the For loop arguments can be a block of code, initiating multiple variables, incrementing multiple variables, or performing other tasks. Recall that semicolons bind the JSL statements together to define the block of code to be executed.
//Uses Break() to stop looping, an early stop when convergence is met
//Note n *= 2 is equivalent to n = 2*n
a = 2; b = 4;
For( k = 1; lastVal = 1000; integration_approx = 0; n = 10 , //multiple initial values
k < 100, //test
k++; n *= 2 , //increment
lastVal = integration_approx; //body...
d = (b - a) / n;
integration_approx = Summation( i = 1, n, d * (a + (i - .5) * d) ^ 2 );
If (Abs( integration_approx - lastVal ) < 1e-5, Break() );
);
Show (k, n, d, integration_approx, integration_approx - lastVal);
If you are new to For loops, review the values of k and n in the Log window for each variation of this script. After the initial loop, JMP executes the increment block of code before it executes the test block of code. Programmers call that incrementing at the bottom of loop. For the previous code snippet, when k=7 and n=640, the convergence criterion is met, and Break( ) stops the For loop before the increment block of code is run. In the full script (which is not shown here), one variation has the convergence criterion as an expression in the test block of code. So, the increment block is run first, k=8 and n=1280, and then the test block stops the For loop.
Without proper checks, For and While loops can iterate indefinitely, which is called an infinite loop. This is usually a problem. In the previous code, the added condition k < 100 ensures that the loop will terminate after 99 iterations, as long as k is incrementing by 1 each time. Most infinite loops are caused by a lack of boundary checks and by destroying boundary variables. For example, if the JSL statement k++ was deleted, and the approximation diverged, the For loop would iterate indefinitely or until it created a JMP exception. There are rare instances where an intentional infinite loop is useful. Typically, they are used to check on a service or object state and they include a break or a termination statement. They are beyond the scope of this blog [book].
There might be instances where the body of code cannot or should not be executed. Consider the JMP sample data set Semiconductor Capability.jmp. Columns P1 and M1 have only one unique value — a control chart or distribution plot is a waste of graphic space. Scenarios where values are all missing or where a user-defined column list includes a non-numeric column should be found and ignored. This scenario is a good case for a Continue function. In this case, inform the user, send a message with a Caption, write a note to the Log window or add a text box to the journal files, and continue analyzing the remaining columns in the list. There might be instances where you want to get out of the loop, but you also want to continue the program. And, in more severe instances, you might want to stop the entire program. Table 4.1 describes the behavior of functions to stop iterating.
Table 4.1 Functions Used to Stop Iterating
Function
|
Result
|
Continue( )
|
Stops the current iteration of a loop at the Continue statement, and begins the loop at the start of the next iteration.
|
Break( )
|
Stops running the loop at the Break statement, and starts executing again at the first statement outside the loop.
|
Throw( )
|
Throw(msg) writes a message to the Log window and aborts script execution. This function is often used with Try( ) or If( ) to catch the problem, create a good error message, perform steps to exit safely, and then throw a message.
|
Continue and Break can be used in the body of the For, While, and For Each Row functions. Throw can be used almost anywhere. Note Stop( ) immediately stops the script that is running.
Extra Example
The 4_Iterating.jsl script includes a block of code that has many extra features, using techniques from previous chapters (such as Open, Sort, Summary, lists, and functions) and future chapters. This code snippet is an example of the Continue function:
//Create a custom chart for each response with a non-constant value
For( i=1, i <= nitems(cList), i++,
if( Col Std Dev( column( cList[i] ) ) == 0,
tmpStr = cList[i] || " has no variation, no charts created";
Caption( tmpStr ); //caption
VListBox( Outline Box(tmpStr) ) << journal; //journal
show( tmpStr ); //Log window
Wait( 5 ); Caption( Remove );
Continue()
//go to the bottom of the loop, skip remaining "body" of code
); // end if
cc = lot_sumry_dt << Control Chart(
Sample Label( :lot_id ),
KSigma( 3 ),
Chart Col( eval(cList[i]), Levey Jennings )
); //end control chart
report(cc)[OutlineBox(2)]<<journal;
wait(0);
cc << close window;
); //end for i
The content of this blog post was condensed from an excerpt of our book, JSL Companion: Applications of the JMP Scripting Language, Second Edition, where you will find more techniques and examples of working with the JMP Scripting Language.