HELP IN_ARRAY                               David Young, January 1994

This * ________FOR_FORM is used for looping over data in arrays.


         CONTENTS - (Use <ENTER> g to access required sections)

  1   Introduction

  2   Basic use

  3   Additional facilities
      3.1   with_index
      3.2   updating_last
      3.3   in_region
      3.4   of_dimension

  4   One-D equivalence and optimisation

  5   fast_for form


-----------------------------------------------------------------------
1  Introduction
-----------------------------------------------------------------------

The * ________FOR_FORM

    for ... in_array ... do ... endfor

allows looping over the data in arrays (see REF * ______ARRAYS), much as other
forms allow looping over data in lists and vectors.  This can often
replace a number of nested numerical for loops, and provide greater
flexibility in programs that deal with arrays with varying numbers of
dimensions.

The general in_array form includes several components:

    for ____var1, ____var2, ...
        with_index ____ivar
        in_array ______array1, ______array2, ...
        updating_last _n
        in_region ____list
        of_dimension _d
    do
        ...
    endfor

Any of the with_index, updating_last, in_region and of_dimension
components may be omitted.  They may be included in any combination, as
long as they are in the order shown above.

It is also possible to iterate a set of coordinates over an
N-dimensional region using

    for ____ivar in_region ____list do ... endfor

See HELP * in_region for more details of this.


-----------------------------------------------------------------------
2  Basic use
-----------------------------------------------------------------------

The simplest usage is

    for ____var1, ____var2, ... in_array ______array1, ______array2, ... do

Each of the variables ____varN iterates over elements of the corresponding
array ______arrayN.

The arrays must all have the same number of dimensions. If their
boundslists differ, iteration occurs over the elements that they have in
common. E.g., if the boundslists are

    [0 100 1 10] and [50 150 0 5]

then the loop runs over elements whose first index takes values from 50
to 100 and whose second takes values from 1 to 5.

Array elements are processed in order, with the first index increasing
most quickly.

For example, a 2-D array containing pairs, each of which contains its
own indices in the array, can be made with:

    vars array1;
    newarray([1 3 1 2], conspair) -> array1;

Printing out the values of this array with

    vars v1;
    for v1 in_array array1 do
        v1 =>
    endfor;

gives

    ** [1|1]
    ** [2|1]
    ** [3|1]
    ** [1|2]
    ** [2|2]
    ** [3|2]


-----------------------------------------------------------------------
3  Additional facilities
-----------------------------------------------------------------------

The following constructs can be included in any combination, as long as
they are in the order shown at the top of this file.  The examples show
only each one added to the basic format on its own.

3.1  with_index
---------------

The current indices into the arrays can be kept track of using

    for ____var1, ... with_index ____ivar in_array ______array1, ... do

The variable ____ivar is assigned a vector whose length is equal to the
number of dimensions of the arrays.  During execution of the loop, the
contents of the this vector are the current indices into the array.

That is, when ____ivar has the value {__c1, c2 , ...}, the value of ______arrayN(__c1,
__c2, ...) is assigned to ____varN.

The code in the body of the loop should not assign anything to ____ivar, and
should not change the contents of the vector. If it is necessary to save
the indices at some point and continue the loop, the vector must be
copied and not just assigned to another variable.

One way to update an array inside the loop is to use an index variable -
applying destvector to it will give the indices to use for updating the
current array element. However, it is more efficient (and neater) to use
the facility described next, particularly if having an index variable
can then be avoided.

3.2  updating_last
------------------

Updating an array can be done with

    for ____var1, ... ____varp in_array ______array1, ... ______arrayp updating_last do

The value of the last variable ____varp is then used to update the last
array ______arrayp. This happens at the end of the loop, in effect just before
the endfor is reached, but after all the code in the body of the loop
has executed. This variable ____varp is not assigned a value automatically
like the other loop variables; it is up to the code in the body of the
loop to give it a value.

For example, the following code adds 1 to every element in ______array1,
storing the results in ______array2.

    for v1, v2 in array1, array2 updating_last do
        v1 + 1 -> v2
    endfor

An array can be specified twice if it is both to supply and receive
values.

An integer _n may be placed after updating_last to specify that the last
_n arrays are to be updated from the last _n variables.

    for ____var1, ... in_array ______array1, ... updating_last _n do

Note that _n must be given as an integer (or a macro that expands to an
integer) in the program, not as an expression or variable.

All the variables can be update variables if the purpose of the loop is
to fill arrays or parts of them with data from some other source.

3.3  in_region
--------------

It is possible to specify explicitly the region of the arrays over which
to iterate, with a list in the form of a *boundslist. The syntax is

    for ____var1, ... in_array ______array1, ... in_region ____list do

The first index into the arrays takes values between the first two
numbers in ____list, inclusive; the second index takes values between the
next two numbers; and so on.

The region specified by ____list can be pictured as rectangular for 2-D
arrays and cuboid for 3-D arrays.

The region must not include any elements which cannot be accessed in all
the arrays.

The form

    for ____ivar in_region ____list do

is also available if only the coordinates are required. This has the
same effect as

    for with_index ____ivar in_array in_region ____list do

would have if it was possible to omit all the arrays from the in_array
form (which it isn't). See HELP * in_region for more details.

3.4  of_dimension
-----------------

If the number of dimensions of the arrays is known in advance (when the
loop is compiled) then of_dimension can be used:

    for ____var1, ... in_array ______array1, ... of_dimension _d do

Here _d must be an integer in the program (or a macro that expands to an
integer), not an expression or variable. The arrays must all have _d
dimensions. The main effects of this are to produce more compact code
and reduce the startup time for the loop.

For most applications, it is not likely to be worth bothering with
of_dimension, even if the dimensionality is known at compile time. It
may be worth including if

    EITHER  the code must be as small as possible;

    OR      the code must run as fast as possible
            AND the dimensionality is 3 or greater
            AND     EITHER the user index (with_index) is used
                    OR the arrays are not all 1-D equivalent (see below)

    OR      the code must run as fast as possible
            AND the arrays or region will be very small
            AND it is possible to use the fast_for form (see below)

Including of_dimension may cause a slight slow-down in the case of 1-D
arrays, or where 1-D optimisation (see below) would otherise get done.
For small regions, this might be balanced by a decrease in start-up
overhead.


-----------------------------------------------------------------------
4  One-D equivalence and optimisation
-----------------------------------------------------------------------

Most programmers can ignore this section, which is provided for
completeness, and to explain the reasons behind the indications for
using of_dimension, given above.

An array is ___1-D __________equivalent with respect to a region if the data
referenced by indices in that region are stored in a contiguous section
of the arrayvector. In addition, the array must be either actually 1-D
or arrayed by row (REF * ______ARRAYS). Thus, for example, all by-row arrays
are 1-D equivalent with respect to their own boundslists.

It is often faster to access a 1-D equivalent array via a single index
into its arrayvector, rather than by applying the array procedure to
multiple indices. The single index also involves fewer
increment-and-test operations in the loop. This can greatly reduce the
loop overhead, at the expense of slightly increased start-up time and
code size.

This optimisation is never done if the number of dimensions has been
specified at compile-time using of_dimension. Otherwise, it is carried
out if ______either the arrays are actually 1-D __or all the arrays are 1-D
equivalent with respect to the processing region, and no index variable
has been specified using with_index. (The processing region is either
the region specified using in_region or the intersection of the
boundslists of the arrays.)


-----------------------------------------------------------------------
5  fast_for form
-----------------------------------------------------------------------

If fast_for is used instead of for, initial checks on the arrays and
region are not carried out.  As usual with fast loop forms, strange
behaviour will result if assumptions are violated, e.g. if the arrays
have different numbers of dimensions, or the region is not within all
the array bounds.

In addition, if in_region is not specified, the boundslist of the first
array is used as the region, rather than the intersection of all the
boundslists.



--- ___________________C.all/help/in_array
--- _________Copyright __________University __of ______Sussex _____1994. ___All ______rights _________reserved.
