\documentclass{article} \usepackage[utf8]{inputenc} \input apl.tex \begin{document} \begin{verbatim} Simple Arrays Outline 1. Introduction 2. Creating Test Arrays The primitive functions illustrated in this section are: Reshape: Dyadic ⍴ Interval: Monadic ⍳ Roll and Deal: Monadic and Dyadic ? Assignment: Dyadic ← 3. Characteristics of Arrays The primitive functions illustrated in this section are: Shape: Monadic ⍴ Indexing: [;⍳;] Count and Choose: Monadic and Dyadic # Type: Monadic ∨ 4. Scalar Functions 5. Structural Functions and the Items of Arrays The primitive functions illustrated in this section are: Take and Drop: Dyadic ↑ and ↓ Replicate and Expand: Dyadic / and \ Reverse and Rotate:Monadic and Dyadic ⌽ Catenate: Dyadic , Laminate: Dyadic ∼ 6. Reduction and Scan 7. Frames and Cells 7a. The Primitive Functions Member Of and Index Of 7b. The Rank Operator 8. Idioms and Phrases 8a. A To B 8b. Bar Graph 8c. Remove Duplicate Items 8d. Append 8e. Eliminate Leading Blanks from a Vector 8f. Eliminate Trailing Blanks from a Vector 8g. Eliminate Multiple Blanks from a Vector 8h. Left Justify a Character Vector 8i. Left Justify the Rows of a Character Matrix (preparation) 8j. Left Justify the Rows of a Character Matrix Using the Rank Operator 1. Introduction These tutorials are designed not only to familiarize you with the A+ language, but to help you adopt the attitude that much can be learned about A+ from experimentation. As you work on your programming assignments you will undoubtedly encounter A+ expressions, indeed entire functions, where you have no clue as to how they work. Often it is not necessary to know how they work, since you will only have to use them as is. And often you will be too busy to figure them out at the moment. Even so, you should get in the habit of reserving time to work your way through such functions. What you will learn are new ways to say things succinctly, new ways to say things in computationally efficient ways, and - this is rare, of course - some things not to do. In that spirit, this tutorial begins with a section on creating test data. The test data created here is fairly simple, because we aren't looking at very specific things. In order to understand real applications, it's worthwhile to generate realistic test data, although it may be difficult, and you may learn something new while doing it. Following the section on test data, there are several illustrating various things about various A+ primitives. The last section presents a series of basic A+ phrases, some sample test data, and some exercises to work through as you figure out what the expressions do and how they do it. Feel free to create your own test data and explore the boundaries - shape, type, and values - of where the expressions work and where they don't work. With one exception, the A+ primitives discussed in this chapter correspond to APL\360, which is the common part of all commercial APL systems. Thus, if you have an APL background, this chapter will show you where A+ differs from what you already know about APL\360, although most times the comparisons are left to you to make. If you do not have an APL background, the material in this chapter is a good place to start. The exception referred above is the rank operator, which replaces the axis operator in APL\360, but is much more general in its application and much more effective. This tutorial is not meant to be self-contained. You may have to look things up in the A+ Reference Manual, particularly in the later sections. Also, while many of the test expressions can be executed using F2, as described in the Getting Started tutorial, others must be typed in directly. Moreover, you must type in any test expressions of your own design, and any expressions that create your own test data. Consequently, you should have a printout of the A+ keyboard showing how to type the special graphic characters (see Chapter 2 and Appendix B of the A+ Reference Manual). 2. Creating Test Arrays The primitive functions illustrated in this section are: Reshape: Dyadic ⍴ Interval: Monadic ⍳ Roll and Deal: Monadic and Dyadic ? Specification: Dyadic ← In order to experiment with expressions in A+ it is very helpful to know how to produce test data, and the primitive functions illustrated in this section are the basic tools for doing it. Examples Execute each of the following: 10 20 3 ¯2 ⍝ A 4-element vector of 10, 20, 3, and minus 2. 2 2⍴10 20 3 ¯2 ⍝ 10, 20, 3, minus 2 arranged 2-by-2. 10⍴25 ⍝ A vector of 10 copies of 25. ?10⍴25 ⍝ 10 random numbers between 0 and 24. ⍳5 12 ⍝ The integers 0 through 59 arranged 5-by-12. 3 9⍴100 ⍝ A 3-by-9 matrix of 27 copies of 100. ?3 9⍴100 ⍝ 27 random numbers between 0 and 99 arranged ⍝ 3-by-9. 20?100 ⍝ 20 distinct random numbers between 0 and 99. 100+5×⍳2 3 ⍝ 100, 105, ..., 125 arranged 2-by-3. 3 5⍴10 2 31 107 ⍝ A 3-by-5 matrix filled with 10, 2, 31, and ⍝ 107, repeated as necessary. 'abcdefgh' ⍝ A vector of 8 characters. 4 2⍴'abcef' ⍝ A 4-by-2 matrix filled with a, b, c, e, and ⍝ f, repeated as necessary. 12.012 ¯10e5 ⍝ A vector of two floating point numbers. ⍳5 7 3 ⍝ The integers 0 through 104 arranged ⍝ 5-by-7-by-3. a←⍳5 12 ⍝ The variable a now has the array value of ⍝ the expression on the right of the arrow. a ⍝ Enter the name alone and its value is ⍝ displayed. 3. Characteristics of Arrays The primitive functions illustrated in this section are: Shape: Monadic ⍴ Indexing: [;⍳;] Count and Choose: Monadic and Dyadic # Type: Monadic ∨ Some A+ Primitives deal with the most basic properties of arrays. Arrays have: shape, e.g. the number of rows and columns of a matrix; count, e.g. the number of rows of a matrix; type, this is, whether the elements are characters, integers, etc. Not only can the shape of arrays be determined, arrays can reshaped into any shape (see the examples of dyadic ⍴ in the preceding section.) And, finally, their elements can be extracted, either one at a time, or in contiguous blocks called subarrays. Examples Execute each of the following: ⍴?10⍴25 ∨?10⍴25 ⍴⍳5 12 ∨⍳5 12 ⍴'abcdefgh' ∨'abcdefgh' ⍴12.012 ¯10e5 ∨12.012 ¯10e5 c←'abcdefgh' ⍝ Make a character vector c. c[0] ⍝ The first element in c. 0#c c[7] ⍝ The last element in c. 7#c c[0 7 2 1] ⍝ 4 elements of c in a 4-element vector. 0 7 2 1#c c[2 3⍴ 7 2 3 3 1 5] ⍝ 6 elements of c arranged 2-by-3, with ⍝ element 3 repeated. #c (2 3⍴ 7 2 3 3 1 5)#c xy←?4 6⍴75 ⍝ Make an integer matrix xy. xy[2;3] ⍝ The element at row 2, column 3. (2;3)#xy xy[2;3 0 4] ⍝ The elements at row 2, columns 3, 0 and 4. (2;3 0 4)#xy xy[1 2 0;3] ⍝ The elements at rows 1, 2 and 0, column 3. (1 2 0;3)#xy xy[0 2;0 2 1] ⍝ The cross-section of rows 0 and 2 and ⍝ columns 0, 2 and 1. (0 2;0 2 1)#xy xy[0 2 0;] ⍝ Rows 0, 2 and 0 again. (0 2 0;)#xy xy[;4 1] ⍝ Columns 4 and 1. (;4 1)#xy xy[0 2 1] ⍝ Rows 0, 2 and 1. 0 2 1#xy The shape of an array x, as evaluated by ⍴x, is a vector. It therefore has a shape of its own, which is ⍴⍴x. ⍴⍴x is called the rank of x. The rank of x is the number of axes of x. Execute each of the following: ⍴⍴xy ⍴⍴⍳4 5 ⍴⍴'abcdeftg' ⍴⍴1 2 ¯6 10 ⍴⍴4 The last example illustrates an array of rank 0, which is called a scalar. A scalar has no axes, and therefore can't be indexed with bracket indexing. The shape of a scalar is an empty vector. For example, execute: ⍴4 and nothing prints out in your A+ session (there is a "new line", however, which puts the next prompt two lines down instead of one.) 4. Scalar Functions This tutorial assumes that you are familiar with the idea of scalar functions and how they apply to arrays (see the A+ Reference Manual or the Scalar Functions tutorial). 5. Structural Functions and the Items of Arrays The primitive functions illustrated in this section are: Take and Drop: ↑ and ↓ Replicate and Expand: / and \ Reverse and Rotate: ⌽ Catenate: , Laminate: ∼ The complementary notions of leading axis and items are important in understanding how many of the structural functions in A+ work (a structural function is one that rearranges the elements of arrays, but does not change their values. For example, 10×x is not a structural function because it multiplies the values of the elements of x by 10.) The leading axis of an array in the first one indexed. For example, in a[i;j;k] the leading axis is the one indexed by i; in b[n;m] it is the one indexed by n; in c[v] it is the only axis. The items of an array are the subarrays obtained by indexing the array with an index expression having the following properties: the leading axis is indexed with a single, scalar value; all other axes are indexed with null. For example, all the following index expressions produce items. Execute them: m←⍳3 5 m[0;] m[2;] a←⍳5 2 7 a[3;;] a[1;;] v←⍳10 v[1] v[8] In fact, items are such an important idea in A+ that there is a special, bracket notation for producing them, no matter what their rank. Repeating the above examples: m[0] m[2] a[3] a[1] v[1] v[8] Most A+ structural primitive functions apply along the leading axes of their right arguments and rearrange the items of that argument. The following are good test values to see how items are rearranged by these primitive functions. Bring them into the A+ session with F2. Examples v←⍳10 m←⍳10 10 Ex 1. ↑ denotes the dyadic primitive function called take. For a positive left argument n, the result is the first n items of the right argument. For example, execute: 3↑v Since ↑ is defined in terms of the items of the right argument, what do expect 3↑m to be? Confirm your guess by evaluating the expression. Ex 2. Experiment with n↑v and n↑m when n is greater than 10. Describe what you see in terms of items. Will this be true for character arrays too? What is true for character arrays? Ex 3. When n is negative, n↑a is the last -n items of a. For example, try ¯4↑v What do you expect ¯4↑m to be? Ex 4. Repeat Ex 2 when n is negative and less that ¯10. Ex 5. 0↑a is an empty array, and consequently you cannot learn much by looking at it. Still, 0↑a is consistent with n↑a for nonzero n, relative to its type and shape. Use the above test data and create some of your own to compare ∨0↑a and ∨a, as well as ⍴0↑a and ⍴a. Describe what you see, and in particular describe ⍴0↑a in terms of the shape of the items of a. Ex 6. ↓ denotes the dyadic primitive function called drop. For a positive left argument n, the result is all but first n items of the right argument. Both its symbol and definition suggest that it is a complementary function to take. Rephrase Ex 1 - Ex 4 for drop and then do them. Ex 7. Ex 5 deals with 0↑a. Without testing it, describe what you think 0↓a is. Now test it. Fill in the indicated expression below: 0↑a equals ( )↓a ∧ What goes here? Ex 8. More generally, for n≥0 fill in the indicated expression: n↑a equals ( )↓a ∧ What goes here? Ex 9. Fill in the expression in Ex 8 so that it works for both negative integers n as well. Ex 10. Look up the definitions of replicate and expand, rotate and reverse. Be sure you understand how they apply to the items of their right arguments (or, in the case of reverse, to its only argument.) Ex 11. Repeat Ex 10 for catenate. Note that catenate has an interesting special case when one argument has rank one less than that of the other one: the argument of lesser rank must have the same shape as the items of the other argument. For example, suppose that the argument of smaller rank is a. Then the definitions of both a,b and b,a are reduced to the equal rank case by replacing a with (1,⍴a)⍴a. Ex 12. The primitive function called laminate, which is denoted by ∼, is an interesting variation in the way it uses the concept of items. Namely, it is dyadic and applies to arrays with the same shape. It produces an array with two items, which are identical to the two arguments. For example: 1 2 3 ∼ 4 5 6 When one of the arguments is a scalar, that argument is reshaped to the shape of the other. For example: 1 2 3 ∼ 4 and 3 ∼ 4 5 6 Test this primitive with other arrays. Try to answer the following little puzzle: for which arrays x and y are the results x,y and x∼y identical? When you find the answer, you will have found the case where the general definition of catenate based on items breaks down. It is a useful special case, but one you must watch out for in expressions that apply catenate to arrays of varying rank. 6. Reduction and Scan Reduction is an example of a mathematical entity called an operator, and it is called an operator in A+ as well. The operator is denoted by /, and it applies to certain scalar functions to produce a new function, called a derived function. For example, +/ is the derived function for + and is called + reduction, or summation. If v is a numeric vector then +/v sums the items of v. E.g., +/3 5 7 is 15. That is: +/v equals v[0]+v[1]+⍳+v[¯1+#v] This definition holds for v of any rank because v[i] denotes the ith item of v, no matter what the rank. Scan is also an operator. For example, +\ is the derived function for + and is called partial sums. If v is a numeric vector then +\v is the partial sums of the items of v. E.g., +/3 5 7 is 3 8 15. See the Scalar Functions tutorial for an introduction to these operators. Ex 13. Make sure you understand that reduction and scan apply to the items of arrays. Test your understanding with matrices and arrays of rank two and three (e.g., ⍳3 5 and ⍳3 5 2.) 7. Frames and Cells Frames and cells are a more general way of partitioning arrays than leading axis and items. For example, consider: a←⍳3 8 4 The array a has three axes. In an index expression of the form a[i;j;k] ⍝ This expression is not executable unless ⍝ i, j, and k are given values. The axis indexed by i is called the leading axis. If i is a scalar, the subarrays a[i;;], or equivalently a[i], are the items of a. In terms of frames and cells, the leading axis is the frame of rank 1 and the items are the cells of rank 2. Similarly, the first two axes are the frame of rank 2. If both i and j are scalars then the subarrays a[i;j;], or equivalently a[i;j], are the cells of rank 1. To complete the picture: the three axes of a are the frame of rank 3 and the scalar elements are the cells of rank 0; the empty set of axes is the frame of rank 0 and the array a itself is the cell of rank 3. The rank of the frame plus the rank of the cells within that frame equals the rank of the array. Instead of always referring explicitly to the rank of the frame and the rank of the cells, it is sometimes convenient to refer to "the frame for the cells of rank n", or the "the cells within the frame of rank k." The concepts of frame and cells are useful in explaining several A+ primitives. We will look at these primitives before the main topic of this section, which is the rank operator. 7a. The Primitive Functions Called Member Of and Index Of In its simplest form, where the arguments are scalars or vectors, the result of Member Of is a boolean vector where 1's mark the elements of the left argument that appear in the right. For example: 1 ¯5 4 10 9 ∈ 9 7 ¯5 0 1 0 0 1 More generally, the definition of the function y∈x is this: let N denote the rank of the items of the right argument x, and let S denote their shape. Then the left argument y must have rank at least N, and the N cells of y must have shape S. If so, y∈x is defined and is a boolean array; its shape equals the shape of the frame for the cells of rank N; and an element of the result is 1 if the corresponding cell is identical to at least one item of the right argument x, and 0 otherwise. Ex 14. Let's see if we understand the definition of Member Of. Define x←⍳3 4 y←6 4 ⍴ ¯1 10 5 2 8 9 10 11 17 0 1 ¯9 5 4 6 7 0 1 2 3 7 9 ¯1 0 and look at these arrays by executing the following: x y Since the rank of y equals the rank of x, the cells of y that are relevant to y∈x are just the items of y. Before evaluating y∈x, can you predict the rank of the result? The shape? The value? Evaluate y∈x to check your answer. Ex 15. Replace y in the Ex 13 as follows: y←3 2 4⍴y Now, what is the rank of the cells of y that are relevant to y∈x. What is rank of the frame that holds these cells? What is the shape of the frame? What is the rank and shape of the result y∈x? What is the value? Evaluate y∈x to check your answer. Ex 16. Replace y in the Ex 14 as follows: y←8 9 10 11 Repeat Ex 14. Ex 17. Index of is similar to Member Of. It is denoted y⍳x. There are two basic differences in the definitions. One, the roles of the left argument and right argument are interchanged from those of Member Of. That is, in Member Of, cells of the left argument are compared to items of the right. In Index Of, however, cells of the right argument are compared to items of the left. The second difference is that the value of Index Of is an array of integers: if a cell of the right argument is identical to an item of the left argument, the corresponding element of the result is the index of that item; if it matches more than one item, the element is the smallest index among those it matches; if there is no match, the element is the number of items in the left argument. Here's a simple example: 'mxaz' ⍳ 'O1zAx' 4 4 3 4 1 Make sure you understand this result. Ex 18. Form x and y as in Ex 13. Describe the result of x⍳y in terms of the items of x and the appropriate cells of y. Ex 19. Form y as in Ex 14, and then describe the result of x⍳y in terms of the items of x and the appropriate cells of y. Ex 20. Form y as in Ex 15, and then describe the result of x⍳y in terms of the items of x and the appropriate cells of y. 7b. The Rank Operator By now you should appreciate the uniformity with which many of the A+ primitive functions apply to the items of their arguments. You may also be wondering whether or not this is too restrictive. For example, what does one do to catenate one matrix to another row-by-row, instead of itemwise? Well, the answer to this question lies in another operator, called the rank operator and denoted by @. The definition of the rank operator is based on the concepts of frames and cells, which were just introduced. In effect, the rank operator specifies the rank of the cells to which a monadic function is to be applied, or the ranks in the case of a dyadic function. Ex 21. One of the easiest ways to see how the rank operator applies is with reduction. For example, execute: ⍴+/⍳3 5 8 The result shows that the leading axis disappears; it is the axis over which the reduction took place. Now execute: ⍴(+/@ 1)⍳3 5 8 The expression +/@ 1 means that reduction will be applied to cells of rank 1 of the array ⍳3 5 8. (The parentheses around +/@ 1 in the above expression are not necessary, but have been included for emphasis.) The cells of rank 1 are vectors along the last axis. The last result shows that the last axis is the one over which the reduction took place. Now here is the challenge: execute the following and explain what you what see: ⍴(+/@ 2)⍳3 5 8 Hint: Answer the following questions. What are cells of ⍳3 5 8 to which the reduction is applied? What is the result when ordinary reduction is applied to those cells? Here are two more challenges: compare ⍳3 5 8 and (+/@ 0)⍳3 5 8 and explain what you see; compare +/⍳3 5 8 and (+/@ 3)⍳3 5 8 and explain what you see. Ex 22. In the rank operator we specify the function to be applied and the rank(s) of the cells to which it applies. For example: a←3 4⍴'abcdefghujkl' b←3⍴'ABC' The expression a(,@1 0) b expresses the catenation of the rank 1 cells of a to the rank 0 cells of b. That is, each row of a is catenated to the corresponding element of b. Evaluate this expression and make sure that you understand what you see. The rule of frames is: When the Rank operator is applied dyadically, the shape of the corresponding frames must be equal, if they are of the same rank, and otherwise the shape of the frame of lower rank, say r, must equal the last r dimensions of the shape of the other frame. Define c←'zyxwvut' Evaluate a(,@1 1)c and explain what you see in terms of the rule of frames. Ex 23. For each of the following expressions explain what you think the result should be. Test your understanding by evaluating the expressions: a(@,2 2) b a(@,0 0) b a(,@1 0)'MNO' a(,@0 1)'MNO' a(,@2 0)'MNO' Consult the A+ Reference Manual regarding 3-element data operands and negative elements of data operands. 8. Idioms and Phrases The purpose of this section is to illustrate the expressiveness of A+ and to help you get in the habit of experimenting with the A+ expressions you come across in order to understand them. Most topics begin with one or more A+ expressions, followed by test data in a subsection called Example(s). Use F2 to first bring in the test data, and then go back to the expressions themselves and apply F2 to them to see what they do. 8a. A To B Make a vector of integers from a to b, where a is less than or equal b. a+⍳1+b-a Example a←10 b←17 Ex 24. Modify this expression using max (⌈) and min (⌊) to work whether a is less or equal b, or vice versa. Ex 25. Repeat using absolute value (monadic ∣) and signum (monadic ×) in place of ⌈ and ⌊. 8b. Bar Graph This example uses the outer product operator (denoted by ∘.). For example, ∘.+ is the outer product of +. It is a dyadic function. x∘.+y forms an array consisting of the sums of all pairs of elements consisting of one from x and one from y. See the Scalar Functions tutorial for an introduction to the outer product operator. Here is a use of another outer product: ' ⎕'[v∘.≥⍳⌈/v] or ' ⎕'[(⍳⌈/v)∘.≥v] Example v←?20⍴20 Ex 26. Execute the above expressions for the test data and explain what you see. In particular, what role does ⍳⌈/v play? 8c. Remove Duplicate Items ((v⍳v)=⍳#v)/v Example v←?30⍴10 Ex 27. The sample data is guaranteed to have duplicates. Why? Ex 28. The key here is the expression (v⍳v)=⍳#v. To understand what's going on, execute v⍳v and ⍳#v separately so that their elements line up. Explain how duplicates can be identified by examining these two rows. (If the elements do not line up, execute (v⍳v)∼⍳#v Why does this work)? Ex 29. Try the above expression on matrices: v←(3 5⍴'abcdefghijklmno')[?8⍴3] Explain what you see. 8d. Append d←(1#⍴a)⌈#b (d(↑@0 1)a),d↑b Example a←'abcdfgeh'[?4 5⍴8] b←'ABCDEFGHIJK' Ex 30. Experiment with d↑a vs. d(↑@0 1)a. Describe the differences. The symbol @ denotes the Rank operator. The notation ↑@0 1 signifies "the rank of ↑ applied to scalar (rank 0) items on the left and vector (rank 1) items on the right." Ex 31. Modify the expressions in this section to apply to a matrix b? 8e. Eliminate Leading Blanks from a Vector ((v≠' ')⍳1)↓v or (∨\v≠' ')/v or (+/∧\v=' ')↓v Example v←' abc de f' Ex 32. Experiment with the expression (v≠' ')⍳1 and describe its behavior. Ex 33. Experiment with the boolean expression ∨\v≠' ' and describe its behavior. Ex 34. Experiment with the boolean expression ∧\v=' ' and describe its behavior. 8f. Eliminate Trailing Blanks from a Vector You will write the expressions in this exercise. Example v←'std sqz dabc ' Ex 35. Use rotate (monadic ⌽) to modify the expression (∨\v≠' ')/v so that trailing blanks are removed. Ex 36. Use rotate (monadic ⌽) and anything else to modify the expression (∨\v≠' ')/v so that trailing blanks are removed. Ex 37. Repeat the last exercise for (+/∧\v=' ')↓v. 8g. Eliminate Multiple Blanks from a Vector ((1↓z)∨¯1↓z←1,' '≠w)/w Example w←' srt 5cp qrsx ' Ex 38. Examine the boolean expression (1↓z)∨¯1↓z by first evaluating 1↓z and then ¯1↓z. Their elements should line up in the display, so that you can compare them quite easily. Explain how this expression removes duplicate blanks. Ex 39. What is role is played by the catenation by 1 in 1,' '≠w? Suppose the 1 is replaced with 0. How does this change things? 8h. Left Justify a Character Vector ((v≠' ')⍳1)⌽v or (+/∧\v=' ')⌽v Example v←' abc de f' Ex 40. Compare these expressions to the ones used for eliminating leading blanks. Explain the difference between the effect of eliminating leading blanks and left justifying. Hint: in left justification, where do the blanks go? 8i. Left Justify the Rows of a Character Matrix (preparation) (m≠' ')⍳1 or +/∧\m=' ' Example m←3 5⍴' abcd e f ghij' m Display m for reference below. abc d e f ghij Ex 41. Test these expressions for the sample data. If the expression executes successfully, explain whether it applies to the rows or columns of m. Ex 42. If an expression applies to the columns of m, modify the expression using monadic transpose (⍉) (see the A+ Reference Manual) so that it applies to the rows. 8j. Left Justify the Rows of a Character Matrix Using the Rank Operator f{x}:((x≠' ')⍳1)⌽x (f@1) m Example m←3 5⍴' abcd e f ghij' Ex 43. Explain (f@1) m. Ex 44. Use the rank operator in the same way to extend the other expression for left justifying vectors to one that applies to matrices. Ex 45. Here is a challenge for using the rank operator. Instead of defining the function f above and applying the rank operator to it, figure out how to apply the rank operator to the primitive functions in the expression ((m≠' ')⍳1)⌽m, so that the result justifies the rows of a matrix. \end{verbatim} \end{document}