Apr 27, 1996 - New built-in functions acting upon whole arrays, array sections, and ... We introduce symmetric indexing of arrays and argue its bene ts over.
Proceedings of MASPLAS '96 The Mid-Atlantic Student Workshop on Programming Languages and Systems SUNY at New Paltz April 27, 1996
Symmetric Indexing of Arrays 1 George Becker
Neil V. Murray
Department of Computer Science University at Albany - SUNY, Albany, NY 12222
Abstract
Fortran 90 oered an alternative to conventional arrays and their one element at a time processing. New built-in functions acting upon whole arrays, array sections, and array expressions streamline programs by avoiding excessive coding details. Such monolithic array programs are easier to develop and more likely to be correct. We introduce symmetric indexing of arrays and argue its bene ts over arrays with asymmetric axes, particularly in case of monolithic array programming. We also discuss implementation of symmetric arrays, as well as parallelism and performance issues.
1 Introduction In this section, we will rst review conventional arrays and point out some of their limitations. Then we will introduce the concept of monolithic arrays, and the idea of symmetry of array axes. Finally, we will discuss parallelism. In Section 2, we compare our work with array theories. In Section 3, we review traditional array indexing concepts. In Section 4, the symmetric indexing approach is presented. The symmetric indexing is closely tied to linear transformations, which are discussed in Section 5. Implementation, application, parallelism, and performance issues are discussed in Sections 6 and 7.
1.1 Conventional Programming with Arrays Conventional programming languages (such as C/C++ [4], Pascal, Modula-2 [3], Fortran-77) manipulate arrays one element at a time. With few exceptions (e.g., copying of a whole array by one assignment statement in Pascal), useful array calculations are expressed through operations on individual array elements. When an array is created anew, it is only natural to store its elements contiguously in memory. Under this assumption of array contiguity, compilers often map array indices into memory addresses by a formula that is closely related to Horner's formula for evaluation of polynomials. Though optimizing compilers may use other mapping formulas, the above assumption of array contiguity has become an automatic assumption in designs of virtually all languages and, in case of standardized languages, in language standards. Therefore, on one hand, it is possible, e.g., in C/C++, to extract one row from a matrix (alternatively, we can extract a column from a Fortran 77 matrix). On the other hand, it is not possible to directly extract a column from a C/C++ matrix, as such a column within the matrix constitutes a noncontiguous vector. The same problem arises when extracting a row from a Fortran 77 matrix. In addition, the assumption of array contiguity and the use of a Horner-like index-to-memory mapping formula results in a xed ordering of array axes. Regardless of whether a language uses row-major or column-major ordering of array elements, one of the axes is always treated as a primary axis, one as a 1 Supported in part by NSF Grant CCR-9404338.
4.1
secondary axis, and so on. For example, in C/C++, Pascal, Modula-2, the rst array index corresponds to this primary axis. On the other hand, in Fortran, it is the last array index that corresponds to the primary axis. When array axes are distinguished as primary, secondary, etc., we call them asymmetric axes.
1.2 Monolithic Arrays and Operations In the area of numeric and scienti c computing, the modern version of Fortran (i.e. Fortran 90 [6]) presents new ways of dealing with arrays. The fundamental idea is to treat arrays as entities on their own, rather than view them only as containers of elements such as scalar numbers. Following the ideas of the APL programming language [2], Fortran 90 extended many originally scalar operations (e.g., +, {, *) to array operands. Fortran 90 also introduced new built-in functions acting upon whole arrays rather than operating separately on individual array elements. We now prefer to think in terms of arrays and sub-arrays (e.g., matrices, rows, columns), and in terms of monolithic operations on these arrays and sub-arrays. Array expressions constructed using monolithic array operators and built-in functions are preferable over conventional programming with arrays. Array expressions represent mathematical formulations of user applications and their algorithms more clearly and directly. By avoiding excessive coding details, programs with array expressions are easier to develop and more likely to be correct. Fortran 90 also introduced array sections. Similarly to array slices in the Ada programming language [1], array sections allow us to select parts of arrays by specifying subranges for individual axes. Array sections are intended primarily for array expressions. However, array sections are still not treated as rst class data. In particular, they cannot be indexed, and no further sectioning can be applied to them. Moreover, when array sections are assigned or are passed as actual arguments to functions or subroutines, all their elements must be copied. We wish to make it possible to treat array sections as rst class data. Many array operations, e.g., array addition, create arrays whose elements in general do not exist in their array operands. Such operations, though often fundamental for array expressions, are not of interest in our work. We are interested in array operations, such as array sections, matrix transpositions (and permutations of axes in general), axis splitting (e.g., transforming a matrix into a three-dimensional array), and array spreading, where arrays resulting from these operations can only contain element values that already exist in array operands of these operations. Essentially, the arrays resulting from these operations can be simply obtained by viewing the array operands from a dierent perspective, rather than rearranging data. Such re-mappings naturally lead to noncontiguous arrays. Contiguity of arrays can be always restored by copying of data, but we wish to re-map arrays instead of copying them.
1.3 Arrays with Symmetric Axes We believe that the Horner-like formula for index-to-memory mapping of arrays is a limiting factor, particularly with respect to monolithic array operations. We wish to show that a weighted sum of indices formula (including an additive oset) can make monolithic array programming more exible, as well as ecient. The concept of a weighted sum of indices is not really new, since it was used in the past particularly in connection with code optimization [9]. However, we use this formula in a much broader context. The weighted sum of indices formula makes it possible to treat array sections as rst class data. In addition, other important monolithic array operations (e.g., matrix transposition, axis splitting, array spreading), mostly with one array operand, can be implemented by constructing only a mapping formula for the resulting array, and thus avoiding the need to copy all of the elements in the array. The resulting arrays can be freely indexed and sectioning can be applied. Further, array sections can be passed as actual arguments to functions or subroutines without the need to construct new array objects. Matrix transposition, for example, can be achieved by mere swapping of the multiplicative coecients. 4.2
1.4 Arrays and Parallelism
Array expressions, as pure functional constructs, can be used both within imperative and functional paradigms. For our presentation, we assume an imperative language, namely Fortran 90. The applicability of these ideas in the context of functional paradigm is discussed in Section 6. In addition to extending many originally scalar operators to array operands, Fortran 90 also introduced a number of new built-in functions that act upon whole array arguments. In both cases, the resulting array expressions lend themselves to parallel evaluation. In the Fortran literature, this kind of implied dataparallelism is called array parallelism. In addition to the parallelism of array expressions in Fortran 90, High Performance Fortran (HPF) [7] and Fortran 95 provide an explicitly data-parallel construct called FORALL. The symmetric indexing of arrays can make it possible to obtain the performance bene ts of both implied and explicit parallelism without incurring unnecessary costs from data copying.
2 Comparison with Array Theories In the past, various formalizations of array operations have been developed, e.g., [12]. These theories attempt to provide a complete set of primitive array operations. Thus, most other array operations could be expressed by these primitives. Array theories are formal mathematical systems dealing with arrays as abstract mathematical values. These theories themselves do not deal directly with computer systems and their memories. The issue of mapping arrays into computer memories arises only in implementations of these theories. Here, strict assumptions of arrays being contiguous in memory are coupled with one xed way of mapping array elements into memory cells. In addition, array axes are in a strictly xed order (a primary axis, a secondary axis, etc.). Various array operations are then de ned with respect to speci c axes in this xed order. Thus, individual axes are dependent on axes preceding them in the xed order. Implementations of these theories strive to generate optimized code. This code implements assignment statements where whole complex array expressions are evaluated and assigned to array variables. In general, these array expressions have multiple array operands. The objective is to optimize access to array elements for run-time eciency. Towards this purpose, whole array expressions are transformed by applying various reductions. In general, such transformations are non-linear. These implementations are based on a crucial assumption of memory storage equivalence between multi-dimensional arrays and vectors. However, certain programming issues, such as passing arrays to procedures and functions, are not issues in implementations of array theories. Also, neither full nor partial aliasing of array variables is considered. Still other array theories express array operations in a dimension-independent way (irrespective of array rank), further equating scalars with zero-dimensional arrays. In other words, the number of dimensions of an array is not a part of its data-type. Rather than being a formal theory, our work is about realization of non-contiguous arrays. We take advantage of array non-contiguity to implement a sub-class of (monolithic) array operations. We achieve high eciency by merely re-mapping given arrays. In this re-mapping, no array elements are ever accessed. Thus, there are never any computations with array elements themselves. Our approach is focussed on array operations where the array resulting from these operations can be simply obtained by viewing the array operands from a dierent perspective, rather than rearranging or copying array elements. Such re-mappings naturally lead to non-contiguous arrays. Our objective here is to avoid copying data. Thus, array operations in our scope may have only one array operand. In addition, only linear transformations of array indices can be accommodated by our approach. In our approach, we strive for programming versatility and exibility, rather than optimal performance of computations. Actually, from the perspective of memory caching, our approach might appear nonoptimal or even inecient due to its use of non-unit stride arrays. 4.3
In general, our approach deals with programming issues, such as passing arrays to procedures and functions, as well as aliasing of array variables. Though our weighted sum of indices formula could be used in other approaches as well, we use this formula in a much more general context. Because there is no xed ordering of array axes in our approach, array axes are symmetric and independent of each other. Thus, we can readily deal with array operations aecting only one axis, or any subset of axes. No array assignment and no array element copying is either needed or used in our approach. Actually, it is our objective to avoid either whole or partial array copying. We do not combine individual array operations. Instead, we preserve the structure of original array expressions, and deal with array operations one at a time, rather than with the entire expression. We strictly follow the Fortran approach, with array rank being a part of the array data-type (i.e. rank is a static array attribute). This approach is related to those Fortran library routines that accept array strides as explicit arguments. Our vector of our multiplicative coecients is distinct from the shape of arrays (there is no particular relationship here). Our work concentrates on array mappings and re-mappings, but does not deal with array shapes and is in no sense a formalization of array operations. In fact, it is inherently incomplete with respect to any array algebra. Our non-contiguous arrays exhibit no memory storage equivalence between multi-dimensional arrays and vectors.
3 Review of Array Concepts Arrays are repetitive data aggregates that can contain a number of elements of the same data-type. Array elements can themselves be data aggregates (e.g., arrays, lists, data structures). In this paper, without loss of generality, we only consider arrays with scalar elements. (Our ideas apply equally well to arrays with aggregate elements, as long as these elements have the same size.) Sometimes, ragged (i.e. irregular) arrays (e.g., a matrix whose rows dier in their length) are discussed in the computer science literature. In this work, however, we deal only with regular arrays. As usual, valid indices for individual axes of arrays form nite intervals of integer numbers (i.e. ranges of integer numbers from certain lower bounds up to corresponding upper bounds). For a multi-dimensional array, its index set, i.e. the set of all valid index tuples (sequences), is a Cartesian product of integer intervals corresponding to the individual axes of the array. We can then de ne, e.g., an array of real numbers, as a mathematical mapping from the array's index set into the set of real numbers. As usual in programming, both element data-type and the number of dimensions are treated as components of array data-type. Extents of arrays along individual axes are considered dynamic attributes of arrays. This treatment is consistent with modern array argument passing and new array declarations in Fortran 90. Most of the programming languages used for teaching and/or computing with arrays are either languages derived from Algol 60, e.g., Pascal, Modula-2, Ada, and C/C++, or belong to the Fortran family of languages. On uniprocessor machines, as well as on parallel machines with shared memory, arrays are implemented by mapping their multi-dimensional index spaces into one-dimensional memory addresses. Consider an n-dimensional array with lower bounds `0 ; `1; : : : ; `n?1 and upper bounds u0 ; u1; : : : ; un?1. Then the mapping [10] from an index sequence i0 ; i1; : : : ; in?1 into a memory address is as follows: Address = (: : : ((i0 ? `0 ) (u1 ? `1 + 1) + (i1 ? `1 )) + (in?1 ? `n?1 )) ElemSize + Base (1) For the purposes of our work, lower bounds will always be equal to zero. This treatment, in addition to its theoretical advantages, is also consistent with the C/C++ programming languages. Considering this assumption that `0 = 0, `1 = 0, . . . , `n?1 = 0, and de ning extents along individual axes as s0 = u0 + 1, s1 = u1 +1, . . . , sn?1 = un?1 +1, we obtain a simpli ed formula for the index to memory address mapping: Address = (: : : (i0 s1 + i1 ) + in?1 ) ElemSize + Base (2) 4.4
Please note that the above formulas correspond to the row-major element ordering of Algol-like languages. We can obtain the column-major element ordering of the Fortran language family by simply reversing the ordering of array lower/upper bounds, as well as array indices, in the above formulas.
4 Symmetric Approach to Arrays We wish to treat array sections as rst class data. Thus, we need to be able to extract either one row or one column from a matrix without copying of matrix elements. In addition, we should be able to perform any permutations of array axes (e.g., matrix transposition), as well as splitting of one or more array axes without aecting the remaining axes. Even in Fortran 90, these operations may not be feasible. Programs in conventional languages map array indices into memory addresses using complex formulas such as those discussed in Section 3. We believe that the structure of these formulas causes in exibility and limitations, particularly with respect to monolithic array operations. The major obstacle is that array axes are treated strictly asymmetrically (i.e. a primary axis, a secondary axis, etc.). We propose a fully symmetric formula for mapping of an index sequence i0 ; i1; : : : ; in?1 into a memory address:
0 ?1 1 X Address = @ ( ) + OsetA ElemSize + Base n j
=0
cj
ij
(3)
In the above formula, the coecients c0 ; c1; : : : ; cn?1 are in general determined by the upper and lower bounds of an array. The additive constant Oset provides for mapping, e.g., of array sections that skip initial elements of an array along one or more axes. Considering our assumption that `0 = 0, `1 = 0, . . . , `n?1 = 0, and de ning extents along individual axes as s0 = u0 + 1, s1 = u1 + 1, . . . , sn?1 = un?1 + 1, we can, though only for contiguous arrays, obtain a formula for all cj , where 0 j < n: cj
=
?1 Y
n
= +1
sk
(4)
k j
In order to map individual index tuples into corresponding memory addresses, we only need the values of multiplicative coecients c0; c1; : : : ; cn?1 (in addition to values of Oset, ElemSize, and Base). However, for monolithic array operations, as well as for out-of-bounds index checking, we also need the values of upper bounds (provided that all lower bounds have zero values). Thus, the number of values needed for mapping and processing of symmetric arrays is essentially the same as the number of values needed in programming languages that allow lower bounds to be speci ed at will, rather than xing their values. In principle, a monolithic array operation can re-map only one array operand. Thus, in this paper we deal only with array operations having only one array operand. Some operations, such as Fortran 90's array spreading, can also have scalar (e.g., integer) operands. We note that scalars are always considered distinct from arrays. The purpose of symmetric arrays is their ability to realize results of certain array operations by re-mapping an argument of the operation. However, our work does not treat array operations themselves (i.e. transformations of values of array elements). We deal with a sub-class of array operations that is inherently incomplete in respect to any algebra or other formal system. Many monolithic array operations can thus be very eciently implemented by only constructing a new mapping formula for the resulting array without the need to copy all of the elements of the array. The resulting arrays can be again freely indexed and sectioning can be applied on them. Further, array sections can be passed as actual arguments to functions and subroutines without the need to construct intermediate array objects. Constructing new symmetric mapping formulas for arrays can be compared to deriving virtual tables (views) in relational database systems [5]. Analogous to views in databases, any symmetric mapping formulas can be again used for construction of new array mappings. 4.5
When an array operation is realized by re-mapping its argument, a particular form of aliasing results. The same aliasing arises, e.g., in Fortran 90. The language standard for Fortran 90 stipulates the semantics of an assignment statement under aliasing as though a temporary array were used. Thus, Mat = transpose(Mat) is equivalent to Temp = transpose(Mat); Mat = Temp. Therefore, the aliasing issue is related to the semantics of the assignment statement, or of other operations with side eects. As an example, consider transposition of a matrix. In order to avoid copying all matrix elements, the transposition can be achieved by constructing only a new re-mapping formula. Then each element of the matrix is mapped into through two dierent indices, except for elements on the main diagonal.
5 Linear Transformations We know from linear algebra [8] that our symmetric formula (3) can express any linear mapping of array indices into memory addresses. Consider array Array1 (indexed by the tuple Index1 ) with linear index-tomemory mapping M1: Address = M1 (Index1 ) (5) Assume that a monolithic array operation is applied to Array1 , yielding second array Array2 (indexed by the tuple Index2 ) with index-to-memory mapping M2: Address = M2 (Index2 ) (6) We are interested in realizing the second array by re-mapping the rst array (by reusing memory cells at the same addresses). Thus the following condition needs to be satis ed: M1 (Index1 ) = M2 (Index2 ) (7) Linear transformations [11] play an important role in our work. In particular, for some important monolithic array operations, there exists a linear transformation T of array indices: Index1 = T (Index2 ) (8) From the above equations, we can obtain index-to-memory mapping M2 for the second array by composing mapping M1 of the rst array with transformation T : Address = M1 (Index1) = M1(T (Index2 )) = (M1 T )(Index2) = M2(Index2 ) (9) Since any composition of linear mappings is a linear mapping, index-to-memory mapping M2 for the second array is also a linear mapping and can be therefore expressed by our symmetric formula. The index-to-memory mapping formulas represent linear mappings. Array sections of Fortran 90, matrix transpositions and other permutations of axes, axis splitting, and array spreading correspond to linear transformations of array indices. Since composition of linear mappings is also a linear mapping, our symmetric formula can express all possible array sections of Fortran 90. Moreover, our symmetric formula can easily express matrix transpositions, as well as any permutation of axes of multi-dimensional arrays. We can also split one or more array axes without aecting the remaining axes. Finally, we can realize the intrinsic function spread of Fortran 90. As an example, we will apply Fortran 90 array section to Array1 , and assign the result to Array2: Array2 = Array1 (Start : Stop : Stride) The above array section can be realized by re-mapping as follows: Index1 = Start + Stride Index2 4.6
Though this linear index-to-index mapping formula does not contain the Stop value, this value is used to determine the upper bound for Array2 . Realization of matrix transposition is indeed trivial. We just need to swap the multiplicative coecients associated with row and column indices, and to swap the upper bounds of the matrix. The index-to-index linear transformation can be expressed by 2-by-2 matrix T2 : " # 0 1 T2 = 1 0 Of course, this can be easily generalized to arbitrary permutations of array axes. We only need to carry out the given permutation on the sequence of multiplicative coecients, as well as on the sequences of array upper bounds. To transpose a three-dimensional array, the transformation matrix T3 is as follows: 3 2 0 0 1 6 1 0 75 T3 = 4 0 1 0 0 As an example for axis splitting, consider, e.g., a vector with 24 elements. Assume that the vector is noncontiguous, with adjacent vector elements having a distance of ve memory cells, and that a cell holds one vector element. There is only one multiplicative coecient c0 = 5 for memory mapping of the vector. We can transform this vector into a 4-by-6 matrix. There are two possible values for 1-by-2 transformation matrix T4 that maps the matrix indices onto a vector index: 0 00 T4 = [ 6 1] T4 = [ 1 4] Therefore, there are two corresponding values for the matrix multiplicative coecients d0; d1 for matrix mapping into memory: [ d00 d01 ] = c0 T40 = 5 [ 6 1 ] = [ 30 5 ] [ d000 d001 ] = c0 T400 = 5 [ 1 4 ] = [ 5 20 ] In addition to transforming a vector, axis splitting can be applied to any axis of a multi-dimensional array independently of the remaining axes. Consider a three-dimensional array whose middle axis has extent of 24, i.e. same as the above vector. Then the 3-by-4 transformation matrix T5 can have two values: 3 3 2 2 1 0 0 0 1 0 0 0 00 6 0 6 1 4 0 75 6 1 0 75 T5 = 4 0 T5 = 4 0 0 0 0 1 0 0 0 1 We de ne array spreading the same way as Fortran 90 intrinsic function spread. In addition to a single array argument, this function takes two integer arguments. One integer argument speci es a new axis, and the other integer argument speci es an extent along the new axis. The application of spread function increases the number of array dimensions by one through \insertion" of a new axis into the sequence of existing axes. Realization of array spreading is trivial. We insert a new entry into both the sequence of multiplicative multipliers, as well as into the sequence of array upper bounds. By setting the new multiplicative coecient to zero, the corresponding index is eectively ignored. This achieves the intended eect of apparent replication of the given array. Of course, the upper bound for the new axis is set using the second integer argument (i.e. extent along the new axis). As an example, consider a matrix spreading into a three-dimensional array by adding a third axis. Regardless of the extent for this third axis, 2-by-3 transformation matrix T6 will be: " # 1 0 0 T6 = 0 1 0 4.7
Our work concentrates on mappings of non-contiguous arrays. Array operations other than remappings, as well as any transformations of array expressions, are outside the scope of our work. We deal with linear transformations of array indices rather than transformations of array element values. Consequently, array operations that transform values of array elements are irrelevant to this work.
6 Implementation and Application Conventional programming languages implement arrays with asymmetric axes. Aside from designing and implementing a new programming language, we could implement symmetric arrays using a preprocessor for a conventional programming language. However, programs for such a preprocessor would need to avoid making assumptions (i.e. no tricks) about storage layout of arrays. We note that this is already recommended for Fortran 90 and HPF programs. Though programs before preprocessing would use multidimensional arrays, the preprocessor would generate programs with only one-dimensional arrays. Array expressions, as pure functional constructs, can be used both within imperative and functional paradigms. Application of re-mapped arrays in imperative languages would be essentially equivalent to native language constructs; e.g., array slices in Ada, array sections in Fortran 90. Operations on re-mapped arrays correspond to those Fortran library routines that accept explicit array stride arguments. However, in the case of language statements with side eects, particularly the assignment statement, the aliasing issue may become important. The Fortran family of languages, as well as Ada, have aliasing rules that prohibit modifying a variable that is aliased at the time of such a modi cation. However, these alising rules of Fortran and Ada put all the responsibility for the management of aliasing on the programmer, since in general compilers cannot assume this task. Thus we are interested in applying array re-mapping in the more disciplined context of functional paradigm. By excluding side eects, compilers of functional languages can avoid aliasing diculties.
7 Parallelism and Performance Fortran 90 extended many originally scalar operators to array arguments. Fortran 90 also introduced new intrinsic functions that operate on whole arrays. These operations and functions give rise to the so called array parallelism. The extended operators and these new intrinsic functions are often used to construct array expressions. As in scalar expressions, intermediate values in array expressions are used only once. Thus, it is advantageous to realize intermediate arrays by re-mapping. With symmetric indexing of arrays, many monolithic array operations can be implemented by constructing new mapping formulas only for the resulting arrays, and thus copying all the elements in the array is avoided. This way, we can utilize data-parallelism without incurring time and space costs associated with extensive copying of array elements. In addition to these monolithic array operations of Fortran 90, the proposals for High Performance Fortran and Fortran 95 introduce an explicit data-parallel construct FORALL. In order to guarantee the correct semantics of FORALL constructs, substantial copying may be needed. We believe that our symmetric array indexing can contribute to both exibility and performance of explicit data-parallel constructs. This is an area of further research. Conventional arrays are contiguous. Such contiguity is a default for arrays with symmetric indexing. However, some operations can create noncontiguous arrays. For example, an array section that selects every fth element from a vector creates a noncontiguous array unless we copy all the speci ed elements. Most computer systems rely on fast cache memories to mitigate lower speed of large main memories. The cache memories are most ecient with contiguous arrays. If arrays are noncontiguous, cache memories cannot generally improve performance. We note that during evaluation of array expressions, all intermediate 4.8
values are used only once. If an intermediate array is a result of linear transformation of array indices, the symmetric array indexing makes the construction of a new array unnecessary. If we created a contiguous array for such an intermediate value, we would reference noncontiguous data anyway. Thus, copying of data to achieve contiguity would be futile.
8 Summary Array expressions constructed using monolithic array operators and intrinsic functions are preferable over conventional programming with arrays (i.e. one element at a time). Array expressions represent mathematical formulations of user applications and their algorithms more clearly and directly. By avoiding excessive coding details, programs with array expressions are easier to develop and more likely to be correct. We present our symmetric indexing of arrays in an attempt to make monolithic array programming more exible as well as more ecient. The concept of a weighted sum of indices is not really new (it was used in the past as an optimization technique in compiler implementations). However, we argue that the fully general use of this method is superior since various array operations and intrinsic functions of Fortran 90 can be implemented more eciently. Our motivation is to increase programming exibility by avoiding mutual axis dependencies in conventional arrays. The symmetric indexing makes it possible to treat array sections of Fortran 90 as rst class data. In addition, many monolithic array operations (e.g., array sections, matrix transposition, axis splitting, array spreading) can be implemented highly eciently without the need to copy all elements of an array. For example, matrix transposition can be achieved by mere swapping of multiplicative coecients associated with row and column indices. Further, array sections (e.g., one row or one column of a matrix) can be passed as actual arguments of functions or subroutines without the need to construct new array objects. In addition to the monolithic array expressions, the proposed symmetric indexing of arrays meshes well with both implied parallelism of array expressions, as well as with explicitly data-parallel constructs, such as FORALL in High Performance Fortran (HPF) and Fortran 95.
Acknowledgments We express our sincere thanks to Richard E. Stearns for helpful discussions on this paper.
4.9
References [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12]
D. W. Gonzales: Ada Programmer's Handbook, Benjamin/Cummings, 1991 Kenneth E. Iverson: A Programming Language, Wiley, 1962, New York Niklaus Wirth: Programming in Modula-2, Springer-Verlag, 1982 Bjarne Stroustrup: The C++ Programming Language, 2-nd edition, Addison-Wesley, 1991 R. Elmasri, S. B. Navathe: Fundamentals of Database Systems, Addison-Wesley, 1994 J. C. Adams, W. S. Brainerd, J. T. Martin, B. T. Smith and J. L. Wagener: Fortran 90 Handbook, McGraw-Hill, 1992, New York C. H. Koelbel, D. B. Loveman, R. S. Schreiber, G. L. Steele and M. E. Zosel: The High Performance Fortran Handbook, MIT Press, 1994 J. B. Fraleigh, R. A. Beauregard: Linear Algebra, Addison-Wesley, 1995 Richard E. Stearns: Personal communication, 1996 A. V. Aho, R. Sethi, J. D. Ullman: Compilers: Principles, Techniques, and Tools, Addison-Wesley, 1986 Paul R. Halmos: Finite-Dimensional Vector Spaces, Springer-Verlag, 1974 L. R. Mullin, Thom McMahon: \Parallel Algorithm Derivation and Program Transformation in a Preprocessing Compiler for Scienti c Languages: The Psi Project and HPF", Submitted to Journal of Scienti c Programming, 1996
4.10