💾 Archived View for tranarchy.fish › ~autumn › apl2 › chapter5.gmi captured on 2023-04-26 at 13:25:13. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-04-19)

-=-=-=-=-=-=-

<- Back to APL2 at a Glance

Chapter 5: Working with Arrays

<div class="chapter-rule">

<hr class="chapter-long">

<p>Chapter</p>

<hr class="chapter-short">

<div>

<div>

5

</div>

</div>

</div>

<h2>Working with Arrays</h2>

<p>In the previous chapters, you worked only with scalar and vector data. <span class="small-caps">APL2</span> allows you to represent data organized in other ways. This chapter shows different ways of arranging data in arrays and discusses functions that create, measure, and manipulate arrays.</p>

<p>Before continuing with this chapter, remember to <code>)LOAD</code> your <code>LEARN</code> workspace so you’ll have access to the work you’ve done in the first four chapters. When you are finished, be sure to <code>)SAVE LEARN</code> before exiting <span class="small-caps">APL2</span>.</p>

<h3 id="section-5.1-properties-of-arrays">Section 5.1 — Properties of Arrays<a href="#section-5.1-properties-of-arrays" class="section-link">§</a></h3>

<p><span class="small-caps">APL2</span> has two types of data: numbers and characters. A collection of data is an <em>array</em>. An array is a rectangular arrangement of data called the <em>items</em> of the array. Each item is a number, a character, or another array. The number of items in an array is the <em>count</em> of the array.</p>

<p>An array that has rows and columns is sometimes called a <em>matrix</em> or a <em>table</em>, A matrix can be pictured as a rectangle:</p>

<center>

<img src="images/matrix_rectangle.png">

</center>

<p>Notice that in this rectangle, all the rows have the same length, and all the columns have the same length.</p>

<p>It is not the geometry that is important but rather the fact that every row of an array has the same number of items and every column in an array contains the same number of items. That is, the length of a row (or column) is the same for all rows (or columns). The term <em>rectangular</em> is, then, extended to collections of data organized along any number of independent directions.</p>

<p>The directions along which data in an array is arranged are the <em>axes</em> of the array. The number of directions is the <em>rank</em> of the array. Thus a table having rows and columns has two axes and a rank of 2. A vector (such as <code>1 2 3</code>) has one axis and a rank of 1. A single number (such as <code>3</code>) is not arranged along any axes and so has rank 0. Ranks higher than 2 are allowed up to some implementation limit (typically 64).</p>

<p><span class="small-caps">APL2</span> has special names for arrays that have rank 0, 1, or 2:</p>

<ul>

<li>Rank 0 — Scalar</li>

<li>Rank 1 — Vector</li>

<li>Rank 2 — Matrix</li>

</ul>

<p>You should attach no other significance to these words. Scalar means only rank 0. A single number or character must be called a simple scalar because it is possible to have a scalar whose item is a non-scalar array. Vector means only rank 1. You don’t need to know vector algebra to understand <span class="small-caps">APL2</span> vectors (although a vector in algebra is closely related to an <span class="small-caps">APL2</span> simple numeric vector).</p>

<p>Because arrays are rectangular, a simple vector of integers gives the lengths of each axis. This vector is the <em>shape</em> of the array. It is this vector that is returned as the result of the <strong>shape</strong> (<code>⍴</code>) function introduced in <a href="chapter2.html">Chapter 2</a>.</p>

<p>Arrays also have a property called <em>depth</em>. Depth is best understood by looking at a few examples.</p>

<p>Simple scalars are depth-zero arrays. Here are two depth-zero Arrays:</p>

<pre> 2.345

'A'</pre>

<p>Any other array that contains only items of depth 0 has a depth of 1. These two arrays have depth 1:</p>

<pre> 2 3 4

'ABC'</pre>

<p>An array that contains an item of depth 1 and no item of greater depth has depth 2. Here are two depth-2 arrays:</p>

<pre> (2 3) (4 5) (6 7)

'AB' 'CD' 'XYZ'</pre>

<p>In general, an array that contains an item of depth <math><mi>n</mi></math> and no item of greater depth, has depth <math><mi>n</mi><mo>+</mo><mn>1</mn></math> (for <math><mi>n</mi></math> not less than 0). Here’s a vector of depth <code>4</code>:</p>

<pre> (((2 3 4) (5 6 7)) (2 3 4)) 5</pre>

<p>Arrays have two classifications according to depth that this book uses in later discussions:</p>

<ul>

<li>Simple array — Array of depth 0 or 1</li>

<li>Nested array — Array of depth 2 or more</li>

</ul>

<h4 id="exercises-for-section-5.1">Exercises for Section 5.1<sup class="answers-note">[<a href="answers.html#section-5.1-properties-of-arrays">Answers</a>]</sup><a href="#exercises-for-section-5.1" class="section-link">§</a></h4>

<ol>

<li>Classify the following arrays as scalar or vector:

<ol type="a">

<li><code>'ABC'</code></li>

<li><code>'A' 'B' 'C'</code></li>

<li><code>'A' 'B'</code></li>

<li><code>'A'</code></li>

<li><code>2.3</code></li>

<li><code>2 3</code></li>

</ol></li>

<li>Classify the following arrays as simple or nested. State the shape and the depth of each:

<ol type="a">

<li><code>'A' 'B' 'C'</code></li>

<li><code>'A' 'B'</code></li>

<li><code>'A'</code></li>

<li><code>'A' 'B' 'C' 2.3</code></li>

<li><code>'ABC' 2.3</code></li>

<li><code>('ABC' 2.3) 'D'</code></li>

<li><code>((⍳3)(2.3 'ABC'))4</code></li>

</ol></li>

<li>Can a scalar be an empty array?</li>

<li>Is there such a thing as a scalar that contains no data?</li>

</ol>

<h3 id="section-5.2-building-and-displaying-arrays">Section 5.2 — Building and Displaying Arrays<a href="#section-5.2-building-and-displaying-arrays" class="section-link">§</a></h3>

<p>Using vector notation, you can construct any vector of length two or longer as long as its items are scalars or vectors of length two or longer. You cannot use vector notation to construct a one-item vector, a zero-item vector, or a matrix.</p>

<p>The function <strong>reshape</strong> (<code>⍴</code>), together with vector notation, can form any array. This section introduces that function and discusses the rules governing the display of arrays.</p>

<h4 id="reshape">Reshape<a href="#reshape" class="section-link">§</a></h4>

<p>The function <strong>reshape</strong> (<code>⍴</code>) takes the items from its right argument and forms them in the shape specified by the left argument. For example, the following expression arranges the numbers from <code>1</code> through <code>24</code> in a matrix (rank 2):</p>

<pre> A← 4 6⍴⍳24

A

1 2 3 4 5 6

7 8 9 10 11 12

13 14 15 16 17 18

19 20 21 22 23 24

DISPLAY A

.→----------------.

↓ 1 2 3 4 5 6|

| 7 8 9 10 11 12|

|13 14 15 16 17 18|

|19 20 21 22 23 24|

'∼----------------'</pre>

<p>This array has four rows and six columns. When given a matrix, <code>DISPLAY</code> puts arrows on the left edge and the top edge.</p>

<p>The examples use <strong>interval</strong> (<code>⍳</code>) as a convenient means of generating data, but the right argument could be any array containing any data and the discussion of <strong>reshape</strong> would remain the same. Just remember that the left argument of <strong>reshape</strong> is the shape of the desired array and the right argument is the set of values that become the items of the desired array.</p>

<p>The rank of the result of <strong>reshape</strong> is the length of the left argument. In the preceding example, the left argument has two integers, and so the resulting array has rank 2.</p>

<p>You can use <strong>reshape</strong> to form the same data into other structures as well. In the following example, <strong>reshape</strong> produces a rank-3 structure:</p>

<pre> B←2 3 4⍴⍳24

B

1 2 3 4

5 6 7 8

9 10 11 12

13 14 15 16

17 18 19 20

21 22 23 24</pre>

<p>The array <code>B</code> has two planes, three rows, and four columns. Notice that the rank-3 display is composed of two rank-2 displays which are separated by a blank row. The arrangement and spacing gives you a visual hint that the array is a rank-3 array. The result of applying <code>DISPLAY</code> to a rank-3 array has two left edges each marked with an arrow:</p>

<pre> DISPLAY B

..→----------.

↓↓ 1 2 3 4|

|| 5 6 7 8|

|| 9 10 11 12|

||13 14 15 16|

||17 18 19 20|

||21 22 23 24|

''∼----------'</pre>

<p>The right argument of <strong>reshape</strong> need not be a vector. <span class="small-caps">APL2</span> ignores the structure of the right argument and uses its items in <em>row-major order</em> (that is, all items from row 1 are used before any items from row 2, and so on). Thus, <code>B</code> could have been defined from <code>A</code> as follows:</p>

<pre> B←2 3 4⍴A</pre>

<p>You form higher-rank arrays in exactly the same way. Here is the construction of a rank-4 array:</p>

<pre> C←2 3 4 5⍴⍳120

C

1 2 3 4 5 ---. ---. ---.

6 7 8 9 10 | rank 2 | |

11 12 13 14 15 | | |

16 17 18 19 20 ---' | |

| |

21 22 23 24 25 ---. | |

26 27 28 29 30 | rank 2 | rank 3 |

31 32 33 34 35 | | |

36 37 38 39 40 ---' | |

| |

41 42 43 44 45 ---. | |

46 47 48 49 50 | rank 2 | |

51 52 53 54 55 | | |

56 57 58 59 60 ---' ---' |

| rank 4

|

61 62 63 64 65 ---. ---. |

66 67 68 69 70 | rank 2 | |

71 72 73 74 75 | | |

76 77 78 79 80 ---' | |

| |

81 82 83 84 85 ---. | |

86 87 88 89 90 | rank 2 | rank 3 |

91 92 93 94 95 | | |

96 97 98 99 100 ---' | |

| |

101 102 103 104 105 ---. | |

106 107 108 109 110 | rank 2 | |

111 112 113 114 115 | | |

116 117 118 119 120 ---' ---' ---'</pre>

<p>Notice that the rank-4 array appears as two rank-3 arrays separated by two blank lines. Each rank-3 array appears as three rank-2 arrays separated by a blank line.</p>

<p>In general, in a rank-<math><mi>n</mi></math> array, its rank <math><mi>n</mi><mo>-</mo><mn>1</mn></math> parts are displayed separated by <math><mi>n</mi><mo>-</mo><mn>2</mn></math> blank lines (for <math><mi>n</mi></math> greater than 1).</p>

<p>In higher-rank arrays, like <code>C</code> above, the rightmost axis is called <em>columns</em>, the second from the rightmost axis is called <em>rows</em>, and the third from the right is usually called <em>planes</em>. The other axes are not normally given names but are sometimes collectively called <em>hyper-planes</em>.</p>

<p>It is not necessary to use all the items from the right argument in producing the result of <strong>reshape</strong>. The following expression uses only the first six items from the right argument:</p>

<pre> D←2 3⍴A

D

1 2 3

4 5 6</pre>

<p>If the right argument does not have enough items to define every item in the result, the items are used over and over again as necessary as in this example:</p>

<pre> E←3 3⍴ 1 0 0 0

E

1 0 0

0 1 0

0 0 1</pre>

<p>The 1 is used three times, and each zero is used twice.</p>

<p>If the right argument has only one item, it is used to define every item of the result:</p>

<pre> F←3 3⍴0

F

0 0 0

0 0 0

0 0 0</pre>

<p>Since <strong>reshape</strong> can use items repeatedly, you can use it to easily produce vectors of repeating values:</p>

<pre> 9⍴ 1 2 3

1 2 3 1 2 3 1 2 3</pre>

<p>All the examples of <strong>reshape</strong> so far have used numbers in the right argument. In fact, the right argument could contain anything and the result would be a rearrangement of those things. Here’s a hypothetical example (don’t try to enter this):</p>

<pre> G←2 2⍴ (item 1) (item 2) (item 3) (item 4)</pre>

<p><code>G</code> will have two rows and two columns with the four items arranged like this:</p>

<center>

<table>

<tbody>

<tr>

<td class="l t r b" style="text-align: center;">item 1</td>

<td class="l t r b" style="text-align: center;">item 2</td>

</tr>

<tr>

<td class="l t r b" style="text-align: center;">item 3</td>

<td class="l t r b" style="text-align: center;">item 4</td>

</tr>

</tbody>

</table>

</center>

<p>Each item in the matrix is any array at all.</p>

<p>Here’s an example that is suitable for entry:</p>

<pre> G←2 2⍴ A 'TWO' F (3 4)

G

1 2 3 4 5 6 TWO

7 8 9 10 11 12

13 14 15 16 17 18

19 20 21 22 23 24

0 0 0 3 4

0 0 0

0 0 0

DISPLAY G

.→--------------------------.

↓ .→----------------. .→--. |

| ↓ 1 2 3 4 5 6| |TWO| |

| | 7 8 9 10 11 12| '---' |

| |13 14 15 16 17 18| |

| |19 20 21 22 23 24| |

| '∼----------------' |

| .→----. .→--. |

| ↓0 0 0| |3 4| |

| |0 0 0| '∼--' |

| |0 0 0| |

| '∼----' |

'∊--------------------------'</pre>

<p>The right argument is a four-item vector. The first and third items come from the variables <code>A</code> and <code>F</code> defined in earlier examples. The second and fourth items are the vectors shown. Remember that writing four arrays next to each other produces a four-item vector.</p>

<p>The same result could have been computed without using the variables <code>A</code> and <code>F</code> as follows:</p>

<pre> G←2 2⍴ (4 6⍴⍳24) 'TWO' (3 3⍴0) (3 4)</pre>

<p>Because you can use <strong>reshape</strong> itself to form any item in the right argument of another <strong>reshape</strong>, you can construct every possible <span class="small-caps">APL2</span> array using the function <strong>reshape</strong> together with vector notation.</p>

<p><strong>Reshape</strong> produces arrays of any rank, while vector notation can produce only arrays of rank 1. <strong>Reshape</strong> can also produce rank-1 arrays including those that vector notation cannot express—namely, vectors of length less than 2.</p>

<pre> 1⍴5

5</pre>

<p>This is not the scalar 5 even though it is printed the same way. It is a one-item vector containing 5 as its only item:</p>

<pre> DISPLAY 1⍴5

.→.

|5|

'∼'</pre>

<p><strong>Reshape</strong> can produce a vector with no items at all:</p>

<pre> 0⍴5</pre>

<p>This result is an empty vector. It is displayed on one line with no data.</p>

<p>An empty array may be an item of a non-empty array:</p>

<pre> H← 2 3⍴(2 3)(⍳0)(0 5⍴0)(4 5) '' 'ABC'

H

2 3

4 5 ABC </pre>

<p>Notice that the empty arrays yield spaces in the result.</p>

<p><code>DISPLAY</code> puts <code>⌽</code> on the left edge if a matrix has zero rows, and <code>⊖</code> on the top edge if the matrix has zero columns:</p>

<pre> DISPLAY H

.→----------------------.

↓ .→--. .⊖. .→--------. |

| |2 3| |0| ⌽0 0 0 0 0| |

| '∼--' '∼' '∼--------' |

| .→--. .⊖. .→--. |

| |4 5| | | |ABC| |

| '∼--' '-' '---' |

'∊----------------------'</pre>

<h4 id="default-display-of-arrays">Default Display of Arrays<a href="#default-display-of-arrays" class="section-link">§</a></h4>

<p>You’ve seen several examples of the presentation of arrays on an output device. Basically, these presentations are rectangular arrangements of the items. Knowing the rules that govern these displays can help you interpret what you see. The rules may vary somewhat on different implementations, so check the documentation for your implementation to be sure. Here is the set of rules for the <span class="small-caps">IBM</span> <span class="small-caps">APL2</span> implementation and some examples.</p>

<ol>

<li><p>The width of a column depends only on the data in the column. Each column is only as wide as necessary. Here’s a simple array of numbers:</p>

<pre> 1 1 1 1 1 1 1 1

2 4 8 16 32 64 128 256

3 9 27 81 243 729 2187 6561

4 16 64 256 1024 4096 16384 65536</pre></li>

<li><p>At least one blank separates any column containing a number from adjacent columns. Numbers are right-justified in a column on the decimal point. There is no separation between adjacent columns that contain only scalar characters. Here’s a simple 3 by 5 array where columns 1, 2, and 3 are numbers, columns 4, 5, and 6 are characters, and column 7 is a mixture of numbers and characters:</p>

<pre> 1 2 3 DOG 5

8 19 10 CAT 7

8 7 6 MAN D</pre></li>

<li><p>If a column contains only character vectors or scalars, the characters are left-justified. Here’s a two-column array where column 1 has character vectors and column 2 has single numbers:</p>

<pre> YEAR 1988

MONTH 2

DAY 23</pre></li>

<li><p>If a column contains character vectors and numbers, the character vectors are right-justified. Here’s an array where each item in row 1 is a four-item character vector and every other item is a number:</p>

<pre>COL1 COL2 COL3 COL4 COLS COL6 COL7 COL8

1 1 1 1 1 1 1 1

2 4 8 16 32 64 128 256

3 9 27 81 243 729 2187 6561

4 16 64 256 1024 4096 16384 65536</pre></li>

<li><p>Other nested items are displayed with a leading and trailing blank for each level of nesting (depth). Here’s an example you’ve seen before:</p>

<pre>1 2 3 4 TWO

5 6 7 8

9 10 11 12

0 0 0 3 4

0 0 0 </pre>

<p>Three blanks separate the columns: one is the trailing blank for the nested items in column 1; one is the blank separating non-character columns; and one is the leading blank for the nested items in column 2.</p></li>

<li><p>Arrays that are wider than the output device are truncated near the right margin, then continued on subsequent lines indented six spaces. Here is a five-by-eleven numeric matrix presented on an output device 40 characters wide:</p>

<pre>1 1 1 1 1 1 1 1

2 4 8 16 32 64 128 256

3 9 27 81 243 729 2187 6561

4 16 64 256 1024 4096 16384 65536

5 25 125 625 3125 15625 78125 390625

1 1 1

512 1024 2048

19683 59049 177147

262144 1048576 4194304

1953125 9765625 48828125</pre></li>

</ol>

<p>Does knowing the rules for output allow you to always unambiguously deduce the properties of an array, given its display? Here’s an output. Can you determine what array it represents?</p>

<pre>1 2 3</pre>

<p>Did you guess a three-item vector of the integers 1, 2, and 3? It does look like that and it’s a good guess, but here are some expressions that produce the same output:</p>

<pre>1 '2' 3

1 3⍴ 1 2 3

'1 2 3'</pre>

<p>In general, you cannot be sure what you’re looking at. <span class="small-caps">APL2</span> displays data without explicit indication of its type or structure. <span class="small-caps">APL2</span> output is designed to display data in a pleasing form. If you need to know exactly what the value, type, and structure of an array are, you must apply functions to the data. <a href="#section-5.3-measuring-arrays">Section 5.3</a> discusses the functions you use to determine this information about an array.</p>

<h4 id="applying-the-display-function-to-arrays">Applying the <code>DISPLAY</code> Function to Arrays<a href="#applying-the-display-function-to-arrays" class="section-link">§</a></h4>

<p>You have seen examples of <code>DISPLAY</code> applied to all types of arrays, The following table summarizes the symbols the <code>DISPLAY</code> function uses:</p>

<center>

<table>

<caption>Table 5.1 Summary of <code>DISPLAY</code> Symbols</caption>

<thead>

<tr class="header">

<th class="r b"></th>

<th class="l t r b" style="text-align: center;">Placement</th>

<th class="l t r b" style="text-align: center;">Meaning</th>

</tr>

</thead>

<tbody>

<tr>

<td class="l t r"><code>_</code></td>

<td class="l t r">beneath a character</td>

<td class="l t r">scalar character</td>

</tr>

<tr>

<td class="l r"><code>→</code></td>

<td class="l r">top edge of box</td>

<td class="l r">vector or higher-rank array</td>

</tr>

<tr>

<td class="l r"><code>∼</code></td>

<td class="l r">lower edge of box</td>

<td class="l r">numeric data</td>

</tr>

<tr>

<td class="l r"><code>+</code></td>

<td class="l r">lower edge of box</td>

<td class="l r">mixed data</td>

</tr>

<tr>

<td class="l r"><code>⊖</code></td>

<td class="l r">top edge of box</td>

<td class="l r">empty vector or higher-rank array</td>

</tr>

<tr>

<td class="l r"><code>↓</code></td>

<td class="l r">left edge of box</td>

<td class="l r">matrix or higher-rank array</td>

</tr>

<tr>

<td class="l r"><code>⌽</code></td>

<td class="l r">left edge of box</td>

<td class="l r">empty matrix or higher-rank array</td>

</tr>

<tr>

<td class="l r b"><code>∊</code></td>

<td class="l r b">lower edge of box</td>

<td class="l r b">nested array</td>

</tr>

</tbody>

</table>

</center>

<h4 id="exercises-for-section-5.2">Exercises for Section 5.2<sup class="answers-note">[<a href="answers.html#section-5.2-building-and-displaying-arrays">Answers</a>]</sup><a href="#exercises-for-section-5.2" class="section-link">§</a></h4>

<ol>

<li><p>State the shape and result of the following expressions:</p>

<ol type="a">

<li><code>4⍴'ABCD'</code></li>

<li><code>6⍴'ABCD'</code></li>

<li><code>3⍴'ABCD'</code></li>

<li><code>3⍴'AB' 'CD'</code></li>

<li><code>4 1⍴ 'ABCD'</code></li>

<li><code>2 3⍴ 'AB' 5</code></li>

<li><code>2 2⍴ 'BUILT' 25 'SHIPPED' 20</code></li>

</ol></li>

<li><p>Write an expression whose value displays as five blank lines.</p></li>

<li><p>Create a defined function to produce <code>N</code> blank lines.</p></li>

<li><p>Given the following variables:</p>

<pre> D ← 5 10 15 20 1 3 6 12

A ← 3 2

R ← 4

C ← 3</pre>

<p>Write a general expression to build an array from <code>D</code> to reflect each of the following specifications:</p>

<ol type="a">

<li>An array with as many rows as the value of <code>R</code> and as many columns as the value of <code>C</code>.</li>

<li>An array with as many rows as <code>D</code> has items and three columns.</li>

<li>An array with as many rows as 3 times the number of items in <code>D</code> and as many columns as the product of <code>R</code> and <code>C</code>.</li>

</ol></li>

<li><p>An identity matrix is a matrix in which every item is zero except those along the main diagonal, which are <code>1</code>’s. Here is a 3-by-3 identity matrix:</p>

<pre> 1 0 0

0 1 0

0 0 1</pre>

<p>Given <code>N</code>, a nonnegative scalar integer, write an expression using <strong>reshape</strong> and <strong>catenate</strong> to produce an <code>N</code>-by-<code>N</code> identity matrix.</p></li>

<li><p>Write an expression to produce a 2-by-3 array that contains no data.</p></li>

<li><p>Given non-empty array <code>AR</code>, write an expression using only <strong>reshape</strong> and vector notation to produce the following arrays:</p>

<ol type="a">

<li>A five-item vector with each item being <code>AR</code>.</li>

<li>A vector whose items are the items of <code>AR</code>.</li>

<li>A scalar whose only item is <code>AR</code>.</li>

</ol></li>

</ol>

<h3 id="section-5.3-measuring-arrays">Section 5.3 — Measuring Arrays<a href="#section-5.3-measuring-arrays" class="section-link">§</a></h3>

<p>This section discusses the main functions used to compute the properties of arrays: <strong>shape</strong>, <strong>rank</strong>, <strong>count</strong>, and <strong>depth</strong>.</p>

<h4 id="shape">Shape<a href="#shape" class="section-link">§</a></h4>

<p>You have seen <strong>shape</strong> applied to vectors and scalars. It applies to any array and returns as its result an integer vector representing the shape of the array. Here are the shapes of some of the arrays used in the examples of <strong>reshape</strong>:</p>

<pre> A←4 6⍴⍳24

⍴A

4 6

B←2 3 4⍴⍳24

⍴B

2 3 4

C←2 3 4 5⍴⍳120

⍴C

2 3 4 5</pre>

<p><strong>Shape</strong> applied to an empty array produces a vector containing at least one zero:</p>

<pre> ⍴⍳0

0

⍴ 0 5⍴0

0 5</pre>

<p>The functions <strong>shape</strong> and <strong>reshape</strong> are related by the following identity:</p>

<pre> A &lt;--&gt; (⍴A)⍴A for any array A</pre>

<p>This identity says that if you reshape <code>A</code> to the shape it already has, you get the same <code>A</code> as the result.</p>

<h4 id="rank">Rank<a href="#rank" class="section-link">§</a></h4>

<p><strong>Shape</strong> also measures the rank of an array. Because <strong>shape</strong> measures any array, it can measure the result of the application of <strong>shape</strong> itself. Thus, in the expression <code>⍴⍴A</code>, the rightmost <code>⍴</code> produces a vector containing the length of each axis. The second <code>⍴</code> counts the number of items in the length vector, and so computes the rank of an array:</p>

<pre> ⍴⍴A

2

⍴⍴B

3

⍴⍴C

4</pre>

<p>Remember that <strong>shape</strong> always returns a vector. Therefore, the numbers produced are one-item vectors, not simple scalars:</p>

<pre> DISPLAY ⍴⍴A

.→.

|2|

'∼'</pre>

<h4 id="count">Count<a href="#count" class="section-link">§</a></h4>

<p>You can compute the number of items in an array from its shape. Clearly an array of shape <code>2 3 5</code> has <code>2×3×5</code> items. A <strong>multiplication-reduction</strong> (<code>×/</code>) computes the count of an array:</p>

<pre> ×/⍴A

24

×/⍴B

24

×/⍴C

120</pre>

<p>In a nested array, the items of the items do not contribute to the count. Thus, the count of a two-item vector is <code>2</code> no matter how much data is in each item:</p>

<pre> ×/⍴(1 2)(2 5⍴⍳10)

2</pre>

<p>You use <strong>each</strong> to measure the count of each item in an array:</p>

<pre> ×/¨⍴¨(1 2)(2 5⍴⍳10)

2 10</pre>

<p>A scalar has one item:</p>

<pre> ×/⍴2.345

1</pre>

<h4 id="depth">Depth<a href="#depth" class="section-link">§</a></h4>

<p>The monadic function <strong>depth</strong> (<code>≡</code>) measures the depth of an array. Applied to a simple scalar, <strong>depth</strong> returns a zero:</p>

<pre> ≡5

0

≡'X'

0</pre>

<p>Unlike <strong>shape</strong> (<code>⍴</code>), <strong>depth</strong> (<code>≡</code>) returns a simple scalar:</p>

<pre> DISPLAY ≡5

0</pre>

<p>The depth of other arrays containing only simple scalars is 1:</p>

<pre> ≡A

1

≡C

1</pre>

<p>The depth of an array that contains at least one depth-1 array and no array of greater depth has depth 2:</p>

<pre> ≡G

2</pre>

<p>The depth of an array is easy to determine from the <code>DISPLAY</code> function output. If you draw a line from outside the display to some simple scalar, just count <code>1</code> for every box you enter and <code>¯1</code> for every box you exit. The resulting number is the depth of that scalar. The largest number you get by doing this to every simple scalar in the array is the depth of the array.</p>

<p>Here is the <code>DISPLAY</code> of a depth-4 array:</p>

<pre> T←(2 2⍴'ABC' 'DE' ((1↑5)(⍳2)) 10) 'ABC'

DISPLAY T

.→-----------------------------.

| .→-------------------. .→--. |

| ↓ .→--. .→-. | |ABC| |

| | |ABC| |DE| | '---' |

| | '---' '--' | |

| | .→----------. | |

| | | .→. .→--. | 10 | |

| | | |5| |1 2&lt;---------------------------------------

| | | '∼' '∼--' | | |

| | '∊----------' | |

| '∊-------------------' |

'∊-----------------------------'</pre>

<p>You can see that drawing a line to the number <code>1</code> or <code>2</code> from the right (or to the number <code>5</code> from the left) will cross the most lines (four) so the array is a depth-4 array.</p>

<p>Note that <strong>depth</strong> (<code>≡</code>) tells you nothing about the shape or contents of an array—only the maximum depth of nesting.</p>

<h4 id="exercises-for-section-5.3">Exercises for Section 5.3<sup class="answers-note">[<a href="answers.html#section-5.3-measuring-arrays">Answers</a>]</sup><a href="#exercises-for-section-5.3" class="section-link">§</a></h4>

<ol>

<li><p>Give the shape, rank, count, and depth of the following arrays. Write a one-item vector <code>N</code> as <code>1⍴N</code> to distinguish it in your response from a scalar.</p>

<ol type="a">

<li><code>2</code></li>

<li><code>3 4</code></li>

<li><code>'ABC'</code></li>

<li><code>'AB'</code></li>

<li><code>'A'</code></li>

<li><code>'A' 'B' 'C'</code></li>

<li><code>'A' 'B' 'C' 2.3</code></li>

<li><code>(1 2 3)(4 5)</code></li>

<li><code>'ABC' 2.3</code></li>

<li><code>('ABC' 2.3) 'D'</code></li>

<li><code>((⍳3)('ABC' 2.3)) 4</code></li>

</ol></li>

<li><p>Write an expression that describes the result of <strong>shape-each</strong> (<code>⍴¨</code>) applied to each expression in exercise 1. For example, for the array <code>(1 2 3) (4 5) 6</code> write <code>(1⍴3) (1⍴2) (⍳0)</code>.</p></li>

<li><p>Create for your toolbox a monadic function <code>DISP</code> that produces the following output:</p>

<pre> DISP ⍳¨⍳3

SHAPE: 3 DEPTH: 2 COUNT: 3

.→------------------.

| .→. .→--. .→----. |

| |1| |1 2| |1 2 3| |

| '∼' '∼--' '∼----' |

'∊------------------'</pre></li>

<li><p>Apply <code>DISP</code> of the previous problem to the output of the <code>DISPLAY</code> function applied to a nested array as in this example:</p>

<pre> DISP DISPLAY ⍳¨⍳4</pre></li>

<li><p>Given the following variables:</p>

<pre> A←2 3⍴⍳6

B←5

C←'APL2'

D←A B C

E←A B</pre>

<p>State the value, shape, and depth of the result of each of these expressions:</p>

<ol type="a">

<li><code>D</code></li>

<li><code>A 8</code></li>

<li><code>A 8−2</code></li>

<li><code>A (8−2)</code></li>

<li><code>A A+100</code></li>

<li><code>A (A+100)</code></li>

<li><code>C</code></li>

<li><code>'A' 'P' 'L'</code></li>

<li><code>'APL'</code></li>

<li><code>'A' 'P''L'</code></li>

<li><code>'AP' 'L'</code></li>

<li><code>A B × 10 A</code></li>

<li><code>1 (2 3)+(1 2 3) 4</code></li>

<li><code>(D)(≡D)</code></li>

<li><code>A(10 (20 30))</code></li>

<li><code>B+0 1 2</code></li>

<li><code>B (B+1)(B+2)</code></li>

<li><code>B(B+1)B+2</code></li>

<li><code>B B+1 (B+2)</code></li>

<li><code>B B+1 B+2</code></li>

</ol></li>

</ol>

<h3 id="section-5.4-unshaping-and-nested-shaping-of-arrays">Section 5.4 — Unshaping and Nested Shaping of Arrays<a href="#section-5.4-unshaping-and-nested-shaping-of-arrays" class="section-link">§</a></h3>

<p><strong>Ravel</strong> and <strong>enlist</strong> are functions that ignore structure and rearrange their arguments into vectors. <strong>Enclose</strong> and <strong>disclose</strong> are functions that change the depth of arrays.</p>

<h4 id="ravel">Ravel<a href="#ravel" class="section-link">§</a></h4>

<p>The monadic function <strong>ravel</strong> might be compared to unraveling a ball of string. The items of its argument are simply arranged in a vector. Because all the items of the arguments are kept intact, the result of <strong>ravel</strong> preserves the count of the argument. Except when applied to a scalar, <strong>ravel</strong> also preserves depth. The rank of the result is always 1. Here is an example:</p>

<pre> B←2 3 4⍴⍳24

,B

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

20 21 22 23 24

⍴,B

24

G←2 2⍴ (4 6⍴⍳24) 'TWO' (3 3⍴0) (3 4)

,G

1 2 3 4 5 6 TWO 0 0 0 3 4

7 8 9 10 11 12 0 0 0

13 14 15 16 17 18 0 0 0

13 20 21 22 23 24

⍴,G

4

⍴⍴,G

1</pre>

<p><strong>Ravel</strong> does not drop or add items to an array—it merely rearranges items into a vector. If an item of the argument is empty, it appears empty in the result:</p>

<pre> H← 2 3⍴(2 3)(⍳0)(0 5⍴0)(4 5) '' 'ABC'

,H

2 3 4 5 ABC

DISPLAY ,H

.→--------------------------------------.

| .→--. .⊖. .→--------. .→--. .⊖. .→--. |

| |2 3| |0| ⌽0 0 0 0 0| |4 5| | | |ABC| |

| '∼--' '∼' '∼--------' '∼--' '-' '---' |

'∊--------------------------------------'</pre>

<p><strong>Ravel</strong> is related to <strong>reshape</strong> by the following identity:</p>

<pre> ,A &lt;--&gt; (×/⍴A)⍴A for any array A</pre>

<p>Recall that <code>×/⍴A</code> computes the count of items in an array. A single number as the left argument of <strong>reshape</strong> specifies the creation of a vector of that length. <strong>Ravel</strong>, like <strong>reshape</strong>, is often used to overcome a limitation of vector notation. Vector notation cannot express a vector of length less than 2. Whereas <code>2 3</code> is a two-item vector, <code>2</code> is not a one-item vector. It is a simple scalar. To produce a one-item vector from a simple scalar, you can enter either of the following equivalent expressions:</p>

<pre> ,2

2

1⍴2

2</pre>

<h4 id="enlist">Enlist<a href="#enlist" class="section-link">§</a></h4>

<p>The monadic function <strong>enlist</strong> (<code>∊</code>) produces a vector but does not preserve any of the array’s properties—rank, rank, shape, depth, or count. <strong>Enlist</strong> always returns a simple vector that contains every simple scalar contained anywhere in the array. Here’s an example:</p>

<pre> G←2 2⍴ (4 6⍴⍳24) 'TWO' (3 3⍴0) (3 4)

∊G

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

20 21 22 23 24 TWO 0 0 0 0 0 0 0 0 0 3 4

⍴∊G

38</pre>

<p>Notice that items in the result are selected in row-major order. Every simple scalar in the first item is listed before any scalar in the following items.</p>

<p>If the argument to <strong>enlist</strong> contains empty items, they do not contribute to the result:</p>

<pre> H← 2 3⍴(2 3)(⍳0)(0 5⍴0)(4 5) '' 'ABC'

∊H

2 3 4 5 ABC

⍴∊H

7

DISPLAY ∊H

.→----------.

|2 3 4 5 ABC|

'+----------'</pre>

<p>If the argument to <strong>enlist</strong> is a simple array, the result is the same as <strong>ravel</strong>:</p>

<pre> ,S &lt;--&gt; ∊S for simple array S</pre>

<h4 id="nested-reshaping-of-an-array-enclose">Nested Reshaping of an Array: Enclose<a href="#nested-reshaping-of-an-array-enclose" class="section-link">§</a></h4>

<p><strong>Reshape</strong> (<code>⍴</code>) merely rearranges the items of its argument, possibly repeating some of them. Depth is only increased when a scalar is reshaped into a non-scalar. If not all the items from the right argument are used in the result, the depth of the result might be less than the depth of the argument:</p>

<pre> ≡ 1 2 'ABC'

2

≡ 2⍴1 2 'ABC'

1</pre>

<p>The monadic function <strong>enclose</strong> (<code>⊂</code>), like <strong>reshape</strong>, only rearranges data in an array; but, except for simple scalars, it does produce a result whose depth is one greater than the depth of its argument. The <strong>enclose</strong> of a simple scalar is the simple scalar. Its depth does not change.</p>

<p><strong>Enclose</strong> has only one purpose: the production of scalars. Given an array, <strong>enclose</strong> produces the scalar that contains that array as its only item. Whenever you see the <strong>enclose</strong> function, think of scalars.</p>

<p>The rank of the result of <strong>enclose</strong> is always zero—that is. <strong>enclose</strong> always produces a scalar. The following identity expresses this fact:</p>

<pre> ,0 &lt;--&gt; ⍴⍴⊂A for all A</pre>

<p>Whenever you are not interested in the array’s structure, you can use <strong>enclose</strong> to turn that array into a scalar. For example, if you are writing an application that deals with people’s names, the fact that the name <em>Shakespeare</em> contains 11 characters may be of no interest.</p>

<pre> ⍴'SHAKESPEARE'

11</pre>

<p>By enclosing the 11-character vector, you may treat the resulting scalar as a unit of data within the application.</p>

<pre> ⍴⊂'SHAKESPEARE'

&lt;---(empty vector)</pre>

<p>In <a href="chapter2.html">Chapter 2</a>, you saw that the following expression catenates three new names onto a vector of names:</p>

<pre>WHAT←⍳0

WHAT←WHAT,'LPS' 'TAPES' 'CDS'</pre>

<p>This expression added three items onto <code>WHAT</code> because the right argument of <strong>catenate</strong> is a three-item vector. Suppose you want to append one more item to the vector: the character string <code>'VIDEOTAPE'</code>. You might be tempted to write the following (don’t do it):</p>

<pre> WHAT←WHAT,'VIDEOTAPES'</pre>

<p>If you wrote that expression, the right argument to <strong>catenate</strong> would be a ten-item vector and you would append ten letters—not what you want to do. You really want to append one name. Use <strong>enclose</strong> to make the nine-item vector into a scalar with one item:</p>

<pre> WHAT←WHAT,⊂'VIDEOTAPES'</pre>

<p>Now you’ve appended one name to the list <code>WHAT</code>:</p>

<pre> WHAT

LPS TAPES CDS VIDEOTAPES</pre>

<p>Note: <span class="small-caps">IBM</span>’s <span class="small-caps">APL2</span> Release 3 adds a dyadic function <strong>partition</strong>, which is related to <strong>enclose</strong>. For information on this new function, see <a href="appendixF.html">Appendix F</a>.</p>

<h4 id="nested-reshaping-of-an-array-disclose">Nested Reshaping of an Array: Disclose<a href="#nested-reshaping-of-an-array-disclose" class="section-link">§</a></h4>

<p>The monadic function <strong>disclose</strong> in its simplest form undoes what <strong>enclose</strong> does. Given a scalar argument, <strong>disclose</strong> produces the array that is the only item of the scalar:</p>

<pre> SX←⊂2 3⍴⍳6

⊃SX

1 2 3

4 5 6</pre>

<p>The following relationship is always true between <strong>enclose</strong> and <strong>disclose</strong>:</p>

<pre> A &lt;--&gt; ⊃⊂A</pre>

<p>But <strong>disclose</strong> does more than undo the result of <strong>enclose</strong>. For example, <strong>disclose</strong> can turn a nested vector into a matrix, with one row per product and one column per type of information.</p>

<p>Earlier you worked with this vector:</p>

<pre> PRD←('LPS' 6.95)('TAPES' 7.95)('CDS' 12.95)

PRD

LPS 6.95 TAPES 7.95 CDS 12.95</pre>

<p>This structure is a depth-3 array that contains one item per product. Each product item contains two fields: one for the product name and one for product cost. <strong>Disclose</strong> turns this vector into a matrix with each item providing data for one row:</p>

<pre> PRDTBL←⊃PRD

PRDTBL

LPS 6.95

TAPES 7.95

CDS 12.95</pre>

<p>This result is a depth-2 array with one row per product:</p>

<pre> ⍴PRDTBL

3 2</pre>

<h4 id="exercises-for-section-5.4">Exercises for Section 5.4<sup class="answers-note">[<a href="answers.html#section-5.4-unshaping-and-nested-shaping-of-arrays">Answers</a>]</sup><a href="#exercises-for-section-5.4" class="section-link">§</a></h4>

<ol>

<li><p>State the shape and depth of the results of following expressions:</p>

<ol type="a">

<li><code>,2 3⍴⍳6</code></li>

<li><code>∊2 3⍴⍳6</code></li>

<li><code>,2 2⍴ 'ABC:' 5 'XY:' 6</code></li>

<li><code>∊2 2⍴ '"ABC:' 5 'XY:' 6</code></li>

</ol></li>

<li><p>Given the variables:</p>

<pre> A← 3 4⍴⍳12

B← 3

C← 'APL'

D← A B C</pre>

<p>State the shape and depth of the result of each of the following expressions:</p>

<ol type="a">

<li><code>B C</code></li>

<li><code>D</code></li>

<li><code>⊂D</code></li>

<li><code>⊂⊂D</code></li>

<li><code>⊂B C</code></li>

<li><code>⊃B C</code></li>

<li><code>⊃⊂A</code></li>

<li><code>⊃ B (B×5) (B×10)</code></li>

<li><code>⊃ A (A×10)</code></li>

</ol></li>

<li><p>Write a three-item vector whose enlist is empty.</p></li>

<li><p>Write an expression to construct a 2-by-3 matrix. Each item should be the name <code>'RAY'</code>.</p></li>

<li><p>Given a simple vector of non-negative integers, write an expression to produce a horizontal bar chart. For example, from <code>V←4 1 3 0 2</code>, the expression should produce the following simple character matrix:</p>

<pre>⎕⎕⎕⎕

⎕⎕⎕

⎕⎕</pre></li>

<li><p>Write an expression that replaces the second item of the vector <code>V</code> with the matrix <code>M</code>.</p></li>

<li><p>Let <code>VV</code> be a vector of words like the following:</p>

<pre> VV←'DISTRIBUTION' 'OF' 'SCORES'</pre>

<p>Write an expression that returns a simple character vector containing the words separated by a single blank. For the example <code>VV</code>, this result is</p>

<pre> 'DISTRIBUTION OF SCORES '</pre></li>

</ol>

<h3 id="section-5.5-manipulating-an-array-along-an-axis">Section 5.5 — Manipulating an Array along an Axis<a href="#section-5.5-manipulating-an-array-along-an-axis" class="section-link">§</a></h3>

<p>One source of <span class="small-caps">APL2</span>’s power is the fact that the primitive operations apply to whole arrays at one time. Sometimes it is useful to think of arrays as split apart in some organized way so you can apply a function to each of the pieces. For example, a matrix can be split up in the following two ways. You can split the matrix into vectors along axis 1:</p>

<center>

<img src="images/splitting_axis_1.png">

</center>

<p>You can split the matrix into vectors along axis 2:</p>

<center>

<img src="images/splitting_axis_2.png">

</center>

<p>Similarly, a rank-3 array can be split into vectors three ways: along each of its three axes.</p>

<p>Many <span class="small-caps">APL2</span> primitives allow specification of an axis to indicate the type of split. The axis is specified in square brackets on the right of the function. For example, <code>↑[1]</code> indicates a <strong>take</strong> along the first axis.</p>

<p>Some dyadic functions with axis split both of their arguments, while others split only one of their arguments.</p>

<p>Here is a general outline of how functions with axis form their result:</p>

<ol>

<li>Split the appropriate arguments along the axis specified.</li>

<li>Apply the function (as defined without an axis) to each piece.</li>

<li>Put the resulting pieces back together again in some appropriate way.</li>

</ol>

<p>The description of the function will tell you which arguments are split and how the pieces are put back together.</p>

<p>The best way to understand how functions with axis operate is to understand the relationship between the shape of the arguments and the shape of the result. The shape of the result is the same as the shape of an argument, with the exception of the axes specified. Those axes may be longer or shorter than the corresponding axes in the argument. The specified axes may not appear in the result at all or new axes may appear.</p>

<p>If you don’t specify an axis for a primitive, one of three defaults applies:</p>

<ul>

<li>Function applies along the rightmost axis.</li>

<li>Function applies along the leftmost axis.</li>

<li>Function applies to all axes.</li>

</ul>

<p>The default taken is also part of the description of each function.</p>

<p>The following sections discuss seven operations that allow an axis specification:</p>

<ul>

<li><strong>take</strong></li>

<li><strong>drop</strong></li>

<li><strong>catenate</strong></li>

<li><strong>ravel</strong></li>

<li><strong>reduction</strong></li>

<li><strong>enclose</strong></li>

<li><strong>disclose</strong></li>

</ul>

<p>You have worked with these operations before, so the discussions concentrate on their use with axis specification.</p>

<h4 id="take-and-drop-with-axis">Take and Drop with Axis<a href="#take-and-drop-with-axis" class="section-link">§</a></h4>

<p>You apply <strong>take</strong> and <strong>drop</strong> to arrays of rank 2 or greater by specifying the axis along which the vector definition is to apply. Here is an example:</p>

<pre> A← 4 6⍴⍳24

A

1 2 3 4 5 6

7 8 9 10 11 12

13 14 15 16 17 18

19 20 21 22 23 24

3↑[1] A

1 2 3 4 5 6

7 8 9 10 11 12

13 14 15 16 17 18</pre>

<p>Here is the analysis of this example using the general outline for functions with axis specification. Given the original four-by-six array:</p>

<center>

<img src="images/split_example_0.png">

</center>

<ul>

<li><p>Split the appropriate arguments along the axis specified.</p>

<p><strong>Take</strong> splits the right argument as shown here:</p>

<center>

<img src="images/split_example_1.png">

</center>

<p>(Note that these pictures are not using the <code>DISPLAY</code> function.) The four-by-six matrix is split into six four-item vectors. The vectors are drawn vertically to show the orientation of the axis that was split.</p></li>

<li><p>Apply the function without an axis to each piece:</p>

<center>

<img src="images/split_example_2.png">

</center>

<p>The vector definition of <strong>take</strong> is applied to each of the four-item vectors, producing a set of three-item vectors.</p></li>

<li><p>Put the resulting pieces back together again in some appropriate way:</p>

<center>

<img src="images/split_example_3.png">

</center>

<p>The six three-item vectors are reassembled into a three-by-six matrix.</p></li>

</ul>

<p>Notice that axis 2 (the one not specified in square brackets) has the same length as before. Axis 1 (the one specified in square brackets) is shorter.</p>

<p>You should be able to apply the same analysis to the following example:</p>

<pre> 3↓[2] A

4 5 6

10 11 12

16 17 18

22 23 24</pre>

<p>Notice again, the axis specified in brackets changes length and the axis not specified stays the same length.</p>

<p>If more than one axis is specified, <span class="small-caps">APL2</span> applies the function independently along each axis:</p>

<pre> W←3 4 2⍴⍳24

2 3↑[1 2] W

1 2

3 4

5 6

9 10

11 12

13 14</pre>

<p>Because <span class="small-caps">APL2</span> applies the function independently along each axis, the following is an equivalent expression:</p>

<pre> 2↑[1] 3↑[2] W

1 2

3 4

5 6

9 10

11 12

13 14</pre>

<p>If no axis is specified, all axes are implied and the left argument must have as many items as there are axes in the right argument:</p>

<pre> A←4 6⍴⍳24

2 3↑A

1 2 3

7 8 9</pre>

<p><strong>Take</strong> and <strong>drop</strong> allow no scalar extension on the left argument.</p>

<h4 id="catenate-with-axis">Catenate with Axis<a href="#catenate-with-axis" class="section-link">§</a></h4>

<p><strong>Catenate</strong> can be used to join data to an array much as it attaches data to a vector. With <strong>catenate</strong>, the axis mentioned is one that will get longer as a result of the operation. For example, here’s a - <strong>catenate with axis</strong> that joins two matrices along the first axis.</p>

<pre> A← 2 3⍴⍳6

B←4 3⍴−⍳12

A,[1]B

1 2 3

4 5 6

¯1 ¯2 ¯3

¯4 ¯5 ¯6

¯7 ¯8 ¯9

¯10 ¯11 ¯12

⍴A,[1]B

6 3</pre>

<p>Notice that axis 2 (the one not specified in square brackets) has the same length as before. Axis 1 (the one specified in square brackets) is longer.</p>

<p>When both arguments have the same rank, <strong>catenate</strong> splits both arguments along the specified axis, joins corresponding vectors together, and reassembles the result. Even when the arguments are higher-rank arrays, the splitting of the arguments ends up with vectors which are joined by <strong>catenate</strong>.</p>

<p>You may also join an array with another array whose rank is one less. When the ranks of the arguments differ by one, <strong>catenate</strong> splits the argument of higher-rank and each vector so formed is joined with the corresponding scalar from the lower-rank argument. For example, here’s a <strong>catenate</strong> that adds a new row to the top of the <code>PRDTBL</code> matrix:</p>

<pre> PRDTBL

LPS 6.95

TAPES 7.95

CDS 12.95

PRDTBL←'PRODUCT' 'COST',[1] PRDTBL

PRDTBL

PRODUCT COST

LPS 6.95

TAPES 7.95

CDS 12.95</pre>

<p>In this case, the axis specified is one longer in the result.</p>

<p>If the music store decides that it should keep track of a third piece of information, it can add another column to the matrix. Suppose that, in addition to product name and cost, the store wants to keep track of the number of each item in its stock. The following expression adds this third column to the matrix:</p>

<pre> PRDTBL←PRDTBL,[2] 'STOCK' 1250 1375 495

PRDTBL

PRODUCT COST STOCK

LPS 6.95 1250

TAPES 7.95 1375

CDS 12.95 495</pre>

<p>If no axis is specified, <strong>catenate</strong> applies along the rightmost axis and, in the case of a matrix, adds new columns. If an axis is specified, it can contain only one number.</p>

<p>If one argument to catenate is a scalar, the non-scalar array is split along the specified axis, and the scalar is joined to each vector so formed:</p>

<pre> (3 4⍴⍳12),1000

1 2 3 4 1000

5 6 7 8 1000

9 10 11 12 1000</pre>

<p>Unlike most other functions with axis, <strong>catenate</strong> allows a fractional axis to indicate creation of a new axis of length 2. <strong>Catenate</strong>, when written with a fractional axis, is called <strong>laminate</strong>. For example, two vectors may be catenated as follows to form the rows or columns of a matrix:</p>

<pre> 'ABCD',[.5] 1 2 3 4

A B C D

1 2 3 4

'ABCD',[1.5] 1 2 3 4

A 1

B 2

C 3

D 4</pre>

<p>In the first case, a new axis of length 2 is inserted before axis 1 of the vector, giving a 2 4 array. In the second case, the new axis is added after axis 1, giving a 4 2 array.</p>

<p><strong>Laminate</strong> can build a matrix from a set of equal length vectors. For example, suppose you have the following three vectors:</p>

<pre> WHAT←'LPS' 'TAPES' 'CDS'

DISCOUNT←.9 .9 1

RETAIL←6.95 7.95 12.95</pre>

<p>They describe the names of various possible purchases, applicable discounts, and retail prices. To keep this data under one name, use <strong>laminate</strong>:</p>

<pre> PURCHASES← WHAT,DISCOUNT,[1.5]RETAIL

PURCHASES

LPS .9 6.95

TAPES .9 7.95

CDS 1 12.95</pre>

<p>The rightmost axis is fractional, causing the two vectors <code>DISCOUNT</code> and <code>RETAIL</code> to be joined into a two-column matrix. Then <code>WHAT</code> is attached as a new column, giving a three-column matrix.</p>

<p>Keeping the data as a matrix is, in fact, a better representation than keeping three separate variables. By using a matrix, you have only one name to keep track of instead of three, and there is no chance that the values can get out of sync (some longer than others). For instance, if you ever discovered that <code>WHAT</code> had five items but <code>RETAIL</code> had six items, you wouldn’t know how to line up the corresponding items. In a matrix, it is impossible for one column to be shorter than the others.</p>

<p>Instead of catenating new values to each of three variables, you can catenate a new row to the matrix:</p>

<pre> PURCHASES←PURCHASES,[1] 'VIDEODISCS' 1 19

PURCHASES

LPS .9 6.95

TAPES .9 7.95

CDS 1 12.95

VIDEODISCS 1 19</pre>

<p>In writing an application to maintain the matrix, you would initialize the matrix to have zero rows but three columns:</p>

<pre> PURCHASES←0 3⍴0</pre>

<p>This makes <code>PURCHASES</code> a 0-by-3 matrix of numbers. Because there is no data, it doesn’t matter if you make the empty matrix numeric or character. Each time a new product comes along, you catenate the data for it onto the matrix. This <strong>catenate</strong> works even for the first product.</p>

<h4 id="ravel-with-axis">Ravel with Axis<a href="#ravel-with-axis" class="section-link">§</a></h4>

<p>As seen earlier, <strong>ravel</strong> without an axis turns any array into a vector of its items. It combines all the axes from an array to produce one long vector. <strong>Ravel with axis</strong> selects a set of adjacent axes that are combined:</p>

<pre> B← 2 3 4⍴⍳24

,[2 3]B

1 2 3 4 5 6 7 8 9 10 11 12

13 14 15 16 17 18 19 20 21 22 23 24

⍴,[2 3]B

2 12</pre>

<p><strong>Ravel</strong> splits its argument along all the axes specified. In the preceding example, two axes are specified, so <strong>ravel</strong> splits the rank-3 array into matrices. Each matrix is raveled and the resulting vector shape appears in the result shape in place of the whole set of axes.</p>

<p>The following picture shows how the shape of the result for the example is formed:</p>

<center>

<img src="images/ravel_shape.png">

</center>

<p>Thus, the result is a vector if all axes are specified; a matrix if one axis is not specified; a rank-3 array if two axes are not specified; and so forth for higher-rank arrays.</p>

<p>There is a useful special case of <strong>ravel with axis</strong>. If the axis is empty, a new axis of length 1 is appended on the right.</p>

<p>If you have a long vector that is too wide to fit on your display device, you can use <code>,[⍳0]</code> to turn it into a one-column matrix. A one-column matrix displays vertically instead of horizontally:</p>

<pre> NAMES←'JANE' 'JIM' 'EV' 'MIKE'

,[⍳0] NAMES

JANE

JIM

EV

MIKE

⍴,[⍳0] NAMES

4 1</pre>

<p>Like <strong>laminate</strong>, <strong>ravel with axis</strong> can take a fractional axis specification to create a new axis of length 1. For example, a vector can become a matrix with either one row or one column:</p>

<pre> ,[.5] 'RAY' 'SANDY' 'JIM'

RAY SANDY JIM

⍴,[.5] 'RAY' 'SANDY' 'JIM'

1 3

,[1.5] '"RAY' 'SANDY' 'JIM'

RAY

SANDY

JIM

⍴,[1.5] 'RAY' 'SANDY' 'JIM'

3 1</pre>

<h4 id="reduction-with-axis">Reduction with Axis<a href="#reduction-with-axis" class="section-link">§</a></h4>

<p>You’ve seen many applications of <strong>reduction</strong>: adding up a vector of numbers (<code>+/V</code>), computing the number of items in an array (<code>×/⍴A</code>), and so forth. In each of these applications, <strong>reduction</strong> applied to vectors and produced scalars. <strong>Reduction</strong> applies to other arrays as well—with axis specification. Axis specification, when used with <strong>reduction</strong>-derived functions, determines how to split an array into vectors. Given a matrix, the vectors could come from splitting the rows or the columns.</p>

<pre> +/[1] 3 4⍴⍳12

15 18 21 24

⍴+/[1] 3 4⍴⍳12

4

+/[2] 3 4 ⍴⍳12

10 26 42

⍴+/[2] 3 4 ⍴⍳12

3</pre>

<p><strong>Reduction</strong> splits the array along the specified axis and reduces each vector. Since <strong>reduction</strong> of a vector always returns a scalar, each result is a scalar. Reassembling the pieces into the result produces an array with rank one less than the argument. The axes not specified in square brackets appear in the result unchanged; the axis specified does not appear in the result at all.</p>

<p><strong>Reduction</strong> without an axis, by default, applies to the rightmost axis.</p>

<pre> +/3 4⍴⍳12

10 26 42</pre>

<p>If an axis is specified, it can contain only one number.</p>

<p>Instead of specifying <strong>reduction</strong> on the first axis as <code>/[1]</code>, <span class="small-caps">APL2</span> permits the alternative symbol <code>⌿</code>:</p>

<pre> +⌿3 4⍴⍳12

15 18 21 24</pre>

<h4 id="enclose-with-axis">Enclose with Axis<a href="#enclose-with-axis" class="section-link">§</a></h4>

<p>Given a matrix, <strong>enclose with axis</strong> produces a vector whose items come from either the rows or the columns of its argument:</p>

<pre> D←2 3⍴⍳6

D

1 2 3

4 5 6

⊂[2] D

1 2 3 4 5 6

DISPLAY ⊂[2] D

.→----------------.

| .→----. .→----. |

| |1 2 3| |4 5 6| |

| '∼----' '∼----' |

'∊----------------'

⍴⊂[2] D

2</pre>

<p>In the preceding example, each row of the matrix becomes a vector in the result. The 2 which is the row length of <code>D</code> becomes the shape of the items of the result:</p>

<pre> ⍴¨⊂[2] D

3 3</pre>

<p><strong>Enclose with axis</strong> splits its argument along the axes specified just like <strong>ravel with axis</strong> does. Each piece is enclosed, giving a scalar. Just as in <strong>reduction with axis</strong>, reassembling the scalars into the result array gives a result that does not contain the axis specified in the square brackets.</p>

<p><strong>Enclose with axis</strong> applied along axis 1 of a matrix produces a vector whose items come from the columns of the argument array:</p>

<pre> ⊂[1]D

1 4 2 5 3 6

DISPLAY ⊂[1]D

.→------------------.

| .→--. .→--. .→--. |

| |1 4| |2 5| |3 6| |

| '∼--' '∼--' '∼--' |

'∊------------------'

⍴⊂[1]D

3</pre>

<p>You can <strong>enclose</strong> along more than one axis at a time:</p>

<pre> H←2 4 3⍴⍳24

⊂[1 3]H

1 2 3 4 5 6 7 8 9 10 11 12

13 14 15 16 17 18 19 20 21 22 23 24

⍴⊂[1 3]H

4

⍴¨⊂[1 3]H

2 3 2 3 2 3 2 3</pre>

<p><strong>Enclose</strong> along all axes of an array is the same as <strong>enclose</strong> with no axis:</p>

<pre> ⊂[1 2 3]H

1 2 3

4 5 6

7 8 9

10 11 17

13 14 15

16 17 18

19 20 21

22 23 24

⍴⊂[1 2 3]H

</pre>

<p>In most cases, <strong>enclose with axis</strong> produces a result with smaller rank and greater depth that its argument. Only an empty axis specification produces a result with the same rank as the argument:</p>

<pre> ⊂[⍳0] (1 2) (3 4 5)

1 2 3 4 5

⍴⊂[⍳0] (1 2) (3 4 5)

2

≡⊂[⍳0] (1 2) (3 4 5)

3

DISPLAY ⊂[⍳0] (1 2) (3 4 5)

.→----------------------.

| .-------. .---------. |

| | .→--. | | .→----. | |

| | |1 2| | | |3 4 5| | |

| | '∼--' | | '∼----' | |

| '∊------' '∊--------' |

'∊----------------------'</pre>

<p><strong>Enclose</strong> with an empty axis is the same as <strong>enclose-each</strong>.</p>

<h4 id="disclose-with-axis">Disclose with Axis<a href="#disclose-with-axis" class="section-link">§</a></h4>

<p>Given a vector of vectors, <strong>disclose with axis</strong> (<code>⊃[]</code>) produces a matrix whose rows or columns come from the items of the vector. Unlike other functions with axis, the numbers in brackets refer to the result axes, not the argument axes. <strong>Disclose with axis</strong> does not split its argument. It only does the rearranging with the axis specification saying where in the result new axes are inserted. Here is an example:</p>

<pre> ⊃[1] 'FRED' 'JOHN' 'PAUL'

FJP

ROA

EHU

DNL

⍴⊃[1] 'FRED' 'JOHN' 'PAUL'

4 3

⊃[2] 'FRED' 'JOHN' 'PAUL'

FRED

JOHN

PAUL

⍴⊃[2] 'FRED' 'JOHN' 'PAUL'

3 4</pre>

<p>Notice that <strong>disclose</strong> reduces the depth of its argument if the depth is at least 2 to start with:</p>

<pre> ≡ 'FRED' 'JOHN' 'PAUL'

2

≡ ⊃[2]'FRED' 'JOHN' 'PAUL'

1</pre>

<p>The default axis for <strong>disclose</strong> is the rightmost axis, so the second example gives the same result if the <code>[2]</code> is left off:</p>

<pre> ⊃ 'FRED' 'JOHN' 'PAUL'

FRED

JOHN

PAUL</pre>

<p>Unlike <strong>enclose with axis</strong>, <strong>disclose with axis</strong> can cause data to be added to an array. If the items of the argument are not the same length, they are padded on the right to the length of the longest:</p>

<pre> ⊃[2]'FRED' 'RALPH' 'EV'

FRED

RALPH

EV

⍴⊃[2]'FRED' 'RALPH' 'EV'

3 5</pre>

<p>You can’t see the padding blanks but they are there. Here’s an example, using numbers, where the padding with zeros is obvious:</p>

<pre> ⊃[2] (10 20 30 40)(⍳5)(8 7)

10 20 30 40 0

1 2 3 4 5

8 7 0 0 0</pre>

<p>If some items are numeric and others are character, <span class="small-caps">APL2</span> pads the numeric arrays with zeros and the character arrays with blanks:</p>

<pre> ⊃[2] (10 20 30 40)(⍳5) 'AB'

10 20 30 40 0

1 2 3 4 5

A B </pre>

<p>If the rank of each item is 2, then two numbers must be given as axes because two of the result axes come from the shapes of the argument items:</p>

<pre> ⊃[1 3](2 2⍴⍳4) (3 4⍴⍳12)

1 2 0 0

1 2 3 4

3 4 0 0

5 6 7 8

0 0 0 0

9 10 11 12</pre>

<p>The axes numbers determine where in the result shape the shapes from the items are placed:</p>

<pre> ⍴⊃[1 3](2 2⍴⍳4) (3 4⍴⍳12)

3 2 4</pre>

<p>The following picture shows how the shape of the result is constructed:</p>

<center>

<img src="images/disclose_argument_shape.png">

</center>

<p>A scalar item is treated as a one-item array of the proper rank:</p>

<pre> ⊃[2] (10 20 30 40)(5) 'AB'

10 20 30 40

5 0 0 0

A B</pre>

<p>If the wrong number of axes is specified, an <code>AXIS ERROR</code> is generated:</p>

<pre> ⊃[2 3](10 20 30 40)(⍳5)

AXIS ERROR

⊃[2 3](10 20 30 40)(⍳5)

^</pre>

<p>If the items do not have the same rank, a <code>RANK ERROR</code> is generated:</p>

<pre> ⊃[1] (10 20 30 40)(2 3⍴⍳6)

RANK ERROR

⊃[1] (10 20 30 40)(2 3⍴⍳6)

∧</pre>

<p>Recall that the function <strong>disclose</strong> (<code>⊃</code>) is closely related to <strong>enclose</strong>. Whatever <strong>enclose</strong> does, <strong>disclose</strong> undoes it:</p>

<pre> A &lt;--&gt; ⊃⊂A</pre>

<p>The same is true for <strong>enclose with axis</strong> and <strong>disclose with axis</strong>.</p>

<pre> A &lt;--&gt; ⊃[I]⊂[I]A</pre>

<p>Here’s an example:</p>

<pre> A←4 6⍴⍳24

⊃[1]⊂[1] A

1 2 3 4 5 6

7 8 9 10 11 12

13 14 15 16 17 18

19 20 21 22 23 24</pre>

<h4 id="scalar-functions-with-axis">Scalar Functions with Axis<a href="#scalar-functions-with-axis" class="section-link">§</a></h4>

<p>When used with an axis specification, the scalar functions split the array of higher-rank along the specified axes, then apply the whole array of lower rank to each of the pieces. For example, you can add a three-item vector to each row of a four-by-three array as follows:</p>

<pre> 10 20 30 +[2] 4 3⍴⍳6

11 22 33

14 25 36

11 22 33

14 25 36</pre>

<p>The matrix is split along the second axis, giving four three-item vectors which are then added to the three-item vector which is the other argument.</p>

<p>In the same manner, you can add a vector to each column of a matrix:</p>

<pre> 10 20 30 40 +[1] 4 3⍴⍳6

11 12 13

24 25 26

31 32 33

44 45 46</pre>

<p>The number of axes specified matches the difference in their ranks of the arguments. A scalar may be applied to each item of a matrix by specifying both axes:</p>

<pre> 10+[1 2] 4 3⍴⍳6

11 12 13

14 15 16

11 12 13

14 15 16</pre>

<p>Thus in the limiting case of scalars, a scalar function with axis reduces to ordinary scalar extension.</p>

<h4 id="exercises-for-section-5.5">Exercises for Section 5.5<sup class="answers-note">[<a href="answers.html#section-5.5-manipulating-an-array-along-an-axis">Answers</a>]</sup><a href="#exercises-for-section-5.5" class="section-link">§</a></h4>

<p>In problems 1 through 5, assume that <code>I</code>, <code>J</code>, <code>K</code>, <code>L</code>, <code>M</code>, and <code>N</code> are non-negative scalar integers and <code>A</code> is a simple array.</p>

<ol>

<li><p>State the shape, rank, and depth of the results of the following expressions. Also give the shape of the items of the result. Indicate an error if one would occur:</p>

<ol type="a">

<li><code>⊂[1] M N⍴A</code></li>

<li><code>⊂[2] M N⍴A</code></li>

<li><code>⊂[1 2] M N⍴A</code></li>

<li><code>⊂[⍳0] M N⍴A</code></li>

<li><code>⊂[1] M⍴A</code></li>

<li><code>⊂[1 3 5] I J K L M N⍴A</code></li>

<li><code>⊂[5 3 1] I J K L M N⍴A</code></li>

<li><code>⊂[⍳6] I J K L M N⍴A</code></li>

<li><code>⊂[⍳0] I J K L M N⍴A</code></li>

</ol></li>

<li><p>State the shape, rank, and depth of the results of the following expressions. Indicate an error if one would occur:</p>

<ol type="a">

<li><code>⊃[1] M⍴⊂N⍴A</code></li>

<li><code>⊃[2] M⍴⊂N⍴A</code></li>

<li><code>⊃[1 2] M⍴⊂N⍴A</code></li>

<li><code>⊃[2 1] M⍴⊂N⍴A</code></li>

<li><code>⊃[⍳0] M⍴⊂N⍴A</code></li>

<li><code>⊃[1 3 5] I J K⍴⊂ L M N⍴A</code></li>

<li><code>⊃[3 1 5] I J K⍴⊂ L M N⍴A</code></li>

</ol></li>

<li><p>State the shape, rank, and depth of the results of the following expressions. Indicate an error if one would occur:</p>

<ol type="a">

<li><code>(I J⍴A),[1] (I J⍴A)</code></li>

<li><code>(I J⍴A),[2] (I J⍴A)</code></li>

<li><code>(I J⍴A),[1 2] (I J⍴A)</code></li>

<li><code>(I J⍴A),[⍳0] (I J⍴A)</code></li>

<li><code>(I K⍴A),[1] (J K⍴A)</code></li>

<li><code>(I K⍴A),[2] (J K⍴A)</code></li>

<li><code>(I J⍴A),[1] (I K⍴A)</code></li>

<li><code>(I J⍴A),[2] (I K⍴A)</code></li>

<li><code>(I J⍴A),(I J⍴A)</code></li>

</ol></li>

<li><p>State the shape of the result of the following expressions, where <code>F</code> is any dyadic function and <code>A</code> is any array:</p>

<ol type="a">

<li><code>F/I J K⍴A</code></li>

<li><code>F/[1]I J K⍴A</code></li>

<li><code>F/[3]I J K⍴A</code></li>

<li><code>F/[1 2]I J K⍴A</code></li>

<li><code>F/[⍳0]I J K⍴A</code></li>

</ol></li>

<li><p>State the shape of the result of the following expressions:</p>

<ol type="a">

<li><code>,[1 2 3]I J K⍴A</code></li>

<li><code>,[3 2 1]I J K⍴A</code></li>

<li><code>,[2 3]I J K⍴A</code></li>

<li><code>,[3]I J K⍴A</code></li>

<li><code>,[⍳0]I J K⍴A</code></li>

</ol></li>

<li><p>You saw that the following identity is true:</p>

<pre> A &lt;--&gt; ⊃[I] ⊂[I] A</pre>

<p>Give an example that shows that the following identity is <em>not</em> true:</p>

<pre> A &lt;--&gt; ⊂[I] ⊃[I] A</pre></li>

<li><p>Suppose you have the following two arrays:</p>

<pre> M←3 4⍴⍳12

A←3 4 2⍴−⍳24</pre>

<p>Determine the value and shape of the following expressions:</p>

<ol type="a">

<li><code>2 3↑M</code></li>

<li><code>2↑[1]M</code></li>

<li><code>3↑[2]M</code></li>

<li><code>2↑[1]3↑[2]M</code></li>

<li><code>4↑[2]2↑[1]M</code></li>

<li><code>2 3↓M</code></li>

<li><code>2↓[2]M</code></li>

<li><code>2↓[1]M</code></li>

<li><code>4 4↑M</code></li>

<li><code>3 ¯6↑M</code></li>

<li><code>4 5↑M</code></li>

<li><code>4 4↓M</code></li>

<li><code>1 1 1↑A</code></li>

<li><code>1 1 1↓A</code></li>

<li><code>1 ¯2 1↑M</code></li>

<li><code>1 ¯2 1↓A</code></li>

<li><code>¯1 2↑[1 2]A</code></li>

<li><code>¯1 2↑[1 2]A</code></li>

<li><code>¯1 2↑[2 3]A</code></li>

<li><code>¯1 2↑[2 3]A</code></li>

<li><code>¯1 2↑[2 1]A</code></li>

<li><code>¯1 2↑[2 11A</code></li>

</ol></li>

<li><p>Write an expression to extract the following:</p>

<ol type="a">

<li>The last row of a rank-2 array <code>M</code>.</li>

<li>The first column of a rank-2 array <code>M</code>.</li>

<li>The last plane of a rank-3 array <code>M</code>.</li>

<li>The last row of the last plane of a rank-3 array <code>M</code>.</li>

<li>The first two items in the last row of the last plane of a rank-3 array <code>M</code>.</li>

</ol></li>

<li><p>Let <code>A</code> be defined as follows:</p>

<pre> A←3 4⍴'ABCDEFGHIJKL'</pre>

<p>State the result, shape, and depth of the following expressions:</p>

<ol type="a">

<li><code>⊂A</code></li>

<li><code>⊂[1]A</code></li>

<li><code>⊂[2]A</code></li>

<li><code>⊂[⍳0]A</code></li>

<li><code>⊃[2]⊂[2]A</code></li>

<li><code>⊃⊂A</code></li>

<li><code>⊃[1]⊂[2]A</code></li>

<li><code>⊃⊂[1]A</code></li>

<li><code>⊂[1 2]A</code></li>

</ol></li>

<li><p>Given the following arrays:</p>

<pre> V←10 20 30

M←4 3⍴⍳12

N←3 3⍴⍳9

A←2 4 3 ⍴100×⍳24</pre>

<p>Determine the value and shape of the following expressions:</p>

<ol type="a">

<li><code>N+[1]V</code></li>

<li><code>N+[2]V</code></li>

<li><code>N+V</code></li>

<li><code>A+[3]V</code></li>

<li><code>A+[2 3]M</code></li>

<li><code>M+[2 3]A</code></li>

</ol></li>

<li><p>Given variable <code>M</code>, which is either a character matrix or a vector of character vectors, write an expression to produce a vector of character vectors.</p></li>

<li><p>Given a vector of vectors where each of the items is a vector of the same length:</p>

<pre> D←(2 4 6 8)(10 20 30 40)</pre>

<p>Write an expression to create another vector of vectors where the first item contains the first items of the original vector; the second item contains the second items of the original vector; and so on. With <code>D</code> as just defined, your expression should produce the following:</p>

<pre> (2 10)(4 20)(6 30)(8 40)</pre></li>

<li><p>Given the following variables:</p>

<pre>TITLE←'NAME' 'PRICE' 'QUANTITY'

DATA←3 3⍴'OX' 3.95 35 'ANT' 10 100 'PIG' 45.5 13</pre>

<p>The following expression displays a small report:</p>

<pre> TITLE,[1]DATA

NAME PRICE QUANTITY

0X 3.95 35

ANT 10 100

PIG 45.5 13</pre>

<p>How would you modify the preceding expression if you wanted each column to be at least 10 positions wide?</p></li>

<li><p>Write a function <code>APPEND</code> which, given a matrix, a scalar, and an integer, catenates the scalar onto the matrix on the front of and on the back of the axis indicated by the integer. Here is an example:</p>

<pre> M←2 3 ⍴⍳6

M

1 2 3

4 5 6

APPEND M '|' 2

| 1 2 3 |

| 4 5 6 |</pre></li>

<li><p>Suppose you have a numeric matrix <code>GRADES</code> that reflects the grades a set of students earned on a series of quizzes and examinations:</p>

<pre> GRADES

90 93 89

81 89 90

88 90 89

145 160 150

120 121 125</pre>

<p>You really want to see the data displayed with row and column titles as follows:</p>

<pre> J. SMITH D. BROWN R. WHITE

QUIZ 1 90 93 89

QUIZ 2 81 89 90

MIDTERM 88 90 89

PROJECT 145 160 150

FINAL 120 121 125</pre>

<p>Define a function <code>REPORT</code> that takes as right argument the numeric matrix and as left argument the row and column titles and returns the report (like the one shown) as an explicit result.</p></li>

<li><p>Write an expression to multiply each row of matrix <code>M</code> by the corresponding item in vector <code>V</code>.</p></li>

<li><p>Define a dyadic function <code>CALENDAR</code> to return a matrix that displays like a traditional calendar. Inputs to the function should be as follows:</p>

<ul>

<li>A left argument indicating the starting day of the week (<code>0</code>=Sunday, <code>1</code>=Monday, … <code>6</code>=Saturday).</li>

<li>An integer right argument indicating the number of days in the month.</li>

</ul>

<p>Sample execution:</p>

<pre> 3 CALENDAR 31

S M T W T F S

1 2 3 4

5 6 7 8 9 10 11

12 13 14 15 16 17 18

19 20 21 22 23 24 25

26 27 28 29 30 31</pre></li>

<li><p>Given numeric matrix <code>M</code> and numeric vector <code>V</code>, where <code>(⍴V)=¯1↑⍴M</code>, write an expression that gives the value of <code>M</code> with no value in any column greater than the corresponding item in <code>V</code>.</p></li>

</ol>

<h3 id="section-5.6-other-functions-on-higher-rank-arrays">Section 5.6 — Other Functions on Higher-Rank Arrays<a href="#section-5.6-other-functions-on-higher-rank-arrays" class="section-link">§</a></h3>

<p>Other functions that you’ve seen applied to vectors also apply to higher-rank arrays:</p>

<ul>

<li><strong>first</strong></li>

<li><strong>pick</strong></li>

<li><strong>scalar functions</strong></li>

</ul>

<h4 id="first">First<a href="#first" class="section-link">§</a></h4>

<p>The <strong>first</strong> (<code>↑</code>) function ignores the structure of its argument and selects the leading item. For any array:</p>

<pre> ↑A &lt;--&gt; ↑,A</pre>

<p>Therefore, if you know how <strong>first</strong> works on a vector, you know how it works on any array. Here is an example:</p>

<pre> G←2 2⍴(4 6⍴⍳24) 'TWO' (3 3⍴0) (3 4)

↑G

1 2 3 4 5 6

7 8 9 10 11 12

13 14 15 16 17 18

19 20 21 22 23 24

⍴↑G

4 6

↑↑G

1</pre>

<p><strong>First</strong> applied to an empty array returns an array that identifies the kind of data used in constructing the empty array. Here is an example:</p>

<pre> ↑10

0

NA1←(1 2 3)(4 5 6)(7 8 9)(10 11 12)

↑0⍴NA1

0 0 0</pre>

<p>This result may be a surprise. <code>NA1</code> is a four-item vector of three-item vectors. <code>0⍴NA1</code> is an empty vector. The result of <code>↑0⍴NA1</code> indicates that the empty vector <code>0⍴NA1</code> was constructed from an array whose first item was a three-item numeric vector. If you experiment with various empty arrays, you’ll see that the first item of the non-empty array determines the nature of the result you get from using first on the empty array. This structure of an empty array is called the <em>prototype</em> of the array.</p>

<p>Empty arrays with structure gave rise to the Great Empty Array Joke contest described in <a href="appendixD.html">Appendix D</a>.</p>

<h4 id="pick">Pick<a href="#pick" class="section-link">§</a></h4>

<p>In <a href="chapter2.html">Chapter 2</a>, you saw <strong>pick</strong> applied to vectors. Recall this example from <a href="chapter2.html">Chapter 2</a>:</p>

<pre> PRD←('LPS' 6.95)('TAPES' 7.95)('CDS' 12.95)

1⊃2⊃PRD

TAPES

2 1⊃PRD

TAPES</pre>

<p><strong>Pick</strong> with a left argument of length 2 is like writing two <strong>pick</strong>s with one-item left arguments. Notice the reversal of the numbers.</p>

<p>However, a single number is not enough to identify an item in a higher rank array. For example, for a matrix, two integers are necessary: a row position and a column position. Here is how to select the letter <code>'O'</code> out of the matrix <code>G</code>:</p>

<pre> G←2 2⍴(4 6⍴⍳24) 'TWO' (3 3⍴0) (3 4)

(1 2)3⊃G

O</pre>

<p>Do you see how this result is computed? The left argument of <strong>pick</strong> is a vector. The first item is again a vector of length <code>2</code> and is suitable for selecting from the rank-2 array <code>G</code>. Row 1, column 2, of <code>G</code> contains the three-item vector <code>'TWO'</code>. The second item in the left argument of <strong>pick</strong> is <code>3</code> and selects the third item of the character vector, giving the scalar <code>'O'</code> as a result.</p>

<p>Suppose you want to select <code>'TWO'</code>. You might be tempted to write this:</p>

<pre> 1 2⊃G</pre>

<p>But this is equivalent to this:</p>

<pre> 2⊃ 1⊃G</pre>

<p>Using <strong>pick</strong> in this way won’t work because the <code>1</code> in the left argument is not enough to select from a matrix. You need a left argument that has one item containing two integers. <strong>Enclose</strong> produces just that:</p>

<pre> (⊂1 2)⊃G

TWO</pre>

<p>Why do you need <strong>enclose</strong> in this case when you didn’t need it to select <code>'O'</code>? The answer is that to select from a matrix using <strong>pick</strong>, you always need a nested left argument.</p>

<p>In conjunction with the <strong>each</strong> operator, <strong>pick</strong> can be used to select a set of arrays from arbitrary positions in an array. Here’s how it works:</p>

<pre>If I⊃A gives X

J⊃A gives Y

and K⊃A gives Z

Then I J K⊃¨A A A gives X Y Z</pre>

<p>The right argument shown is a three-item vector whose each item is <code>A</code>. A scalar on the right of any derived function of <strong>each</strong> is extended. So, using <strong>enclose</strong> to create the scalar, the example looks like this:</p>

<pre> I J K⊃¨⊂A</pre>

<h4 id="scalar-functions">Scalar Functions<a href="#scalar-functions" class="section-link">§</a></h4>

<p>The scalar functions extend to arrays of rank 2 or greater in the way you would expect. A monadic scalar function is applied to each item of its argument:</p>

<pre> −2 3⍴⍳6

¯1 ¯2 ¯3

¯4 ¯5 ¯6</pre>

<p>A dyadic scalar function is applied between corresponding items of its two arguments, which conform if they have the same shape:</p>

<pre> (2 3⍴⍳6) + 10 × 2 3⍴⍳6

11 22 33

44 55 66</pre>

<p>With all arrays, the dyadic scalar functions are extended to permit one argument to be a scalar even though the other argument is not a scalar. The array inside the scalar pairs with each item from the non-scalar array:</p>

<pre> 1+10×2 3⍴⍳6

11 21 31

41 51 61

(⊂1 2 3) + 10× 2 3⍴⍳6

11 12 13 21 22 23 31 32 33

41 42 43 51 52 53 61 62 63</pre>

<p>In this last example, the right argument has shape <code>2 3</code>, so the result has shape <code>2 3</code>:</p>

<pre> ⍴(⊂1 2 3) + 10× 2 3⍴⍳6

2 3</pre>

<p>The array inside the scalar is the three-item vector <code>1 2 3</code>. This vector pairs with each of the items from the other argument. Thus, each item of the result is a three-item vector:</p>

<pre> ⍴¨(⊂1 2 3) + 10× 2 3⍴⍳6

3 3 3

3 3 3</pre>

<h4 id="exercises-for-section-5.6">Exercises for Section 5.6<sup class="answers-note">[<a href="answers.html#section-5.6-other-functions-on-higher-rank-arrays">Answers</a>]</sup><a href="#exercises-for-section-5.6" class="section-link">§</a></h4>

<ol>

<li><p>Write three different <span class="small-caps">APL2</span> expressions to produce a simple scalar from a one-item simple vector <code>N</code>.</p></li>

<li><p>Write an <span class="small-caps">APL2</span> expression to produce the number of rows in matrix <code>M</code> as a scalar.</p></li>

<li><p>Given the vector <code>W</code>:</p>

<pre> W←('ABC' 'DE')('XY' 'PQR')('K' 'LMNO')</pre>

<ol type="a">

<li>Evaluate the following expressions:

<ol>

<li><code>⍴W</code></li>

<li><code>≡W</code></li>

<li><code>⍴∊W</code></li>

<li><code>≡∊W</code></li>

<li><code>⍴,/W</code></li>

<li><code>≡,/W</code></li>

<li><code>⍴↑,/W</code></li>

<li><code>≡↑,/W</code></li>

</ol></li>

<li>What does <code>↑</code> do in the expression <code>↑,/W</code>?</li>

</ol></li>

<li><p>Given the array <code>A</code> as follows:</p>

<pre> A←(⍳4)(2 3⍴'ABCDEF')(⊂'XYZ')(6 (7 8))</pre>

<p>Evaluate the following expressions. State the shape and depth of each result:</p>

<ol type="a">

<li><code>A</code></li>

<li><code>↑A</code></li>

<li><code>A[2]</code></li>

<li><code>2⊃A</code></li>

<li><code>2(1 3)⊃A</code></li>

<li><code>4 2 1⊃A</code></li>

<li><code>3⊃A</code></li>

<li><code>3 2⊃A</code></li>

<li><code>3(⍳0)2⊃A</code></li>

</ol></li>

<li><p>Suppose you are given these arrays:</p>

<pre> A← 3 2⍴⍳6

B←10×⍳3

C←'APL2'

D←A B C</pre>

<p>Fill in the blanks in the following expressions so the indicated result is produced:</p>

<ol type="a">

<li><pre>_______⊃D

APL2 </pre></li>

<li><pre>_______⊃D

P</pre></li>

<li><pre>_______⊃⊂D

P</pre></li>

<li><pre>________⊃D

1 2 3 4 5 6</pre></li>

<li><pre>________⊃D

6</pre></li>

<li><pre>________⊃A

6</pre></li>

<li><pre>______________ A

3 4</pre></li>

</ol></li>

<li><p>Evaluate the following expressions:</p>

<ol type="a">

<li><code>3 2⊃¨⊂ D</code></li>

<li><code>((1 (3 2)) 3 2)⊃¨⊂ D</code></li>

</ol></li>

<li><p>Evaluate the following expressions:</p>

<ol type="a">

<li><code>↑0⍴5 'A'</code></li>

<li><code>↑0⍴(5 'A')(⍳3)</code></li>

<li><code>↑0⍴ 'A' 5</code></li>

<li><code>↑0⍴('A' 5)(⍳3)</code></li>

<li><code>3↑('A' 5)(⍳3)</code></li>

<li><code>3↑(5 'A')(⍳3)</code></li>

</ol></li>

</ol>

<h3 id="section-5.7-other-primitive-operators">Section 5.7 — Other Primitive Operators<a href="#section-5.7-other-primitive-operators" class="section-link">§</a></h3>

<p>You’ve already seen the two primitive operators <strong>each</strong> and <strong>reduction</strong>. This section introduces these primitive operators:</p>

<ul>

<li><strong>scan</strong></li>

<li><strong>n-wise reduction</strong></li>

<li><strong>outer product</strong></li>

<li><strong>inner product</strong></li>

</ul>

<h4 id="scan">Scan<a href="#scan" class="section-link">§</a></h4>

<p>The <strong>scan</strong> (<code>\</code>) operator is defined in terms of <strong>reduction</strong> and, like <strong>reduction</strong>, applies to any dyadic function. It is best understood by analyzing an example:</p>

<pre> +\ 1 3 5 7 11 13

1 4 9 16 27 40</pre>

<p>First, notice that the shape of the result matches the shape of the argument of the derived function. The first item of the result matches the first item of the argument; the second item of the result is the <code>+/</code> of the first two items. And, in general, the <code>N</code>th item of the result is <code>+/N↑</code>argument. The last item of the result is the same value as <code>+/</code> of the data.</p>

<p><strong>Scan</strong> can be applied to any dyadic function:</p>

<pre> ,\ (10 20)(30 40)(50 60)

10 20 10 20 30 40 10 20 30 40 50 60

⍴ ,\ (10 20)(30 40)(50 60)

3</pre>

<p><strong>Scan</strong> extends to higher-rank arrays much as <strong>reduction</strong> does: it can be used with an axis; and the symbol <code>⍀</code> implies a <strong>scan</strong> along the first axis:</p>

<pre> A←4 6⍴⍳24

+\[1] A

1 2 3 4 5 6

8 10 12 14 16 18

21 24 27 30 33 36

40 44 48 52 56 60

,\ 3 2⍴'AB' 'CD' 'EF' 'GH'

AB ABCD

ED EFGH

AB ABCD

,⍀ 3 2⍴'AB' 'CD' 'EF' 'GH'

AB CD

ABEF CDGH

ABEFAB CDGHCD</pre>

<h4 id="n-wise-reduction">N-wise Reduction<a href="#n-wise-reduction" class="section-link">§</a></h4>

<p><strong>N-wise reduction</strong> is the dyadic form of the derived function produced by <strong>reduction</strong>. It is best understood by analyzing an example:</p>

<pre> 3 +/ 1 3 5 7 11 13

9 15 23 31</pre>

<p>First, notice that the length of the result is less than the length of the right argument. In general, the length of the result is one plus the difference between the length of the right argument and the value of the left argument.</p>

<p>The first item of the result in the preceding example is <code>+/</code> of the first three items of the right argument. The <code>N</code>th item of the result is <code>+/3↑(N−1)↓</code><em>argument</em>.</p>

<p>The derived function is sometimes called a <strong><em>moving-window reduction</em></strong>. In the preceding example, a window three items wide is moved from left to right across the right argument with a reduction performed at each step.</p>

<p>As an example, suppose that a company has sales figures for the last twelve quarters:</p>

<pre> SALES← 1001 2741 3081 3767 3279 4015 7305

SALES← SALES,7200 7496 9247 5100 7650</pre>

<p>As you can see, there was a big jump in sales during the tenth quarter followed by a big drop in sales in the eleventh quarter. The chief executive officer would like to smooth out these numbers so the monthly fluctuations are not so dramatic. <strong>N-wise reduction</strong> can do the smoothing:</p>

<pre> (1↑SALES),(2+/SALES)÷2

1001 1871 2911 3424 3523 3647 5660 7252.5 7348

8371.5 7173.5 6375</pre>

<p>The expression just shown replaces every item but the first by the average of it and the preceding quarter. Although there are still peaks and valleys in the data, they are not nearly so drastic. Averaging over more than two items at a time smooths the data even more:</p>

<pre> (3↑SALES),(4+/SALES)÷4

1001 2741 3081 2647.5 3217 3535.5 4591.5 5449.75

6504 7812 7260.75 7373.25</pre>

<p>Another interesting <strong>n-wise reduction</strong> uses <strong>catenate</strong> as the operand. As this example shows, <strong>n-wise reduction</strong> with <strong>catenate</strong> applied to a simple vector returns a vector of the sub-vectors implied by the moving window:</p>

<pre> 3 ,/ 'ABCDEFGHI'

ABC BCD CDE DEF EFG FGH GHI</pre>

<p>Here’s an example where the argument is not a simple vector:</p>

<pre> 2 ,/ 'BILLY' 'BOB' 'TOM' 'CAT'

BILLYBOB BOBTOM TOMCAT</pre>

<p>By applying <strong>n-wise reduction</strong> to a vector of scalars instead of a vector of vectors, you can get a vector of pairs of names:</p>

<pre> 2 ,/ ⊂¨'BILLY' 'BOB' 'TOM' 'CAT'

BILLY BOB BOB TOM TOM CAT</pre>

<p><strong>N-wise reduction</strong> extends to higher-rank arrays just as <strong>reduction</strong> and <strong>scan</strong> do and can be used with an axis. The symbol <code>⌿</code> implies an <strong>n-wise reduction</strong> along the first axis:</p>

<pre> A←4 6⍴⍳24

2 +/ A

3 5 7 9 11

15 17 19 21 23

27 29 31 33 35

39 41 43 45 47

3+/A

6 9 12 15

24 27 30 33

42 45 48 51

60 63 66 69

3 2⍴'AB' 'CD' 'EF' 'GH'

AB CD

EF GH

AB CD

2 ,/3 2⍴'AB' 'CD' 'EF' 'GH'

ABCD

EFGH

ABCD

⍴2 ,/3 2⍴'AB' 'CD' 'EF' 'GH'

3 1

2,⌿3 2⍴'AB' 'CD' 'EF' 'GH'

ABEF CDGH

EFAB GHCD</pre>

<h4 id="outer-product">Outer Product<a href="#outer-product" class="section-link">§</a></h4>

<p>The operator <strong>each</strong> applies a function between corresponding items of two arrays. You may also want to apply a function between all pairings of items one from the left argument and one from the right argument. The operator <strong>outer product</strong> (<code>∘.</code>) creates an “all combinations” derived function. The result of combining items from a two-item vector <code>A B</code> in all combinations with items from a three-item vector <code>C D E</code> looks like this:</p>

<center>

<img src="images/outer_product.png">

</center>

<p>Applying <strong>multiplication</strong> (<code>×</code>) between pairs of items in all combinations gives a matrix that looks like an operation table for multiplication on integers:</p>

<pre> (⍳5) ∘.× (⍳10)

1 2 3 4 5 6 7 8 9 10

2 4 6 8 10 12 14 16 18 20

3 6 9 12 15 18 21 24 27 30

4 8 12 16 20 24 28 32 36 40

5 10 15 20 25 30 35 40 45 50</pre>

<p>Any dyadic function can be used with <strong>outer product</strong>. Here’s <strong>outer product</strong> applied to the function <strong>take</strong> (<code>↑</code>):</p>

<pre> 2 3 ¯4 ∘.↑ (5 6 7) 'ABC'

5 6 AB

5 6 7 ABC

0 5 6 7 ABC

DISPLAY 2 3 ¯4 ∘.↑ (5 6 7) 'ABC'

.→-----------------.

↓ .→--. .→-. |

| |5 6| |AB| |

| '∼--' '--' |

| .→----. .→--. |

| |5 6 7| |ABC| |

| '∼----' '---' |

| .→------. .→---. |

| |0 5 6 7| | ABC| |

| '∼------' '----' |

'∊-----------------'</pre>

<p>Because the left argument is a three-item vector and the right argument is a two-item vector, the result is a three-by-two array. It is nested because <strong>take</strong> returned a nonscalar array.</p>

<p>The shape of the result of <strong>outer product</strong> is the shape of the left argument catenated with the shape of the right argument. This is stated more formally as follows:</p>

<pre> ⍴ L ∘.F R &lt;--&gt; (⍴L),(⍴R)</pre>

<h4 id="inner-product">Inner Product<a href="#inner-product" class="section-link">§</a></h4>

<p>The <strong>inner product</strong> operator (<code>.</code>) applies two functions in a uniform way to arrays. The following example illustrates the way <strong>inner product</strong> applies <strong>addition</strong> and <strong>multiplication</strong> to vectors:</p>

<p>Suppose you have a three-item vector of hours, minutes, and seconds that you want to convert to scalar seconds. You can do this with primitives you already know:</p>

<pre> +/3600 60 1 × 2 15 30

8130</pre>

<p>The left argument is the vector giving the number of seconds in an hour, the number of seconds in a minute, and the number of seconds in a second. The <strong>multiplication</strong> converts everything to seconds, and the <strong>reduction</strong> adds them up. You can write this computation as an <strong>inner product</strong> as follows:</p>

<pre> 3600 60 1 +.× 2 15 30

8130</pre>

<p><strong>Inner product</strong> on vectors is defined more formally in terms of <strong>reduction</strong> as follows:</p>

<pre> L F.G R &lt;--&gt; ⊂F/ L G R</pre>

<p>The <strong>enclose</strong> following the <strong>reduction</strong> in the formal definition is not needed if the <strong>reduction</strong> returns a simple scalar as it did in the first example; but if <code>G</code> returns a higher-rank array, the <strong>reduction</strong> would not return a scalar. Here’s an example where the <strong>enclose</strong> is required:</p>

<pre> 3 4,.⍴'ABC'

ABCA BCAB CABC

DISPLAY 3 4,.⍴'ABC'

.--------------------------.

| .→---------------------. |

| | .→---. .→---. .→---. | |

| | |ABCA| |BCAB| |CABC| | |

| | '----' '----' '----' | |

| '∊---------------------' |

'∊-------------------------'</pre>

<p>For matrices and higher-rank arrays, <strong>inner product</strong> is defined in terms of <strong>outer product</strong> and <strong>reduction</strong>. The <strong>inner product</strong> <code>F.G</code> applies <code>G</code> between rows of the left argument and columns of the right argument in all combinations. Then each of those results is reduced by <code>F</code>.</p>

<p>Here are some pictures that describe how <strong>inner product</strong> works on matrices:</p>

<center>

<img src="images/inner_product_1.png">

</center>

<p>The arguments are split along the inner axes—the rightmost axis for the left argument and the leftmost axis for the right argument (this is why the operator is called <strong>inner product</strong>). The resulting vectors are given to <code>G</code> in all combinations, with the result reduced by <code>F</code>:</p>

<center>

<img src="images/inner_product_2.png">

</center>

<p>The shape of the result is the shapes of the arguments catenated, with the inner axes removed. This picture shows the result, with an expression to compute each item:</p>

<center>

<img src="images/inner_product_3.png">

</center>

<p>Here is a small example that you should be able to figure out yourself if you are not at a terminal:</p>

<pre> I←3 3⍴ 14 ¯140 168 ¯40 640 ¯84O 27 ¯540 756

I

14 ¯140 168

¯40 640 ¯840

27 ¯540 756

J←3 3⍴÷⍳9

J

1 0.5 0.33333333

0.25 0.2 0.16666667

0.14285714 0.125 0.11111111

I+.×J

3 0 0

0 3 0

O 0 3</pre>

<p>Depending on the system you are using, the answer could be slightly different from the values shown here. In particular, zero values might be shown as very small numbers (on an <span class="small-caps">IBM</span> 370, in the range of <code>1E¯16</code>). For most numerical computations, that’s close enough to zero compared to the other numbers in the result.</p>

<p>In mathematics, the <code>+.×</code> <strong>inner product</strong> is often called <em>matrix product</em>.</p>

<p>The shape of the result of <strong>inner product</strong> is the shape of the left argument without its rightmost axis joined with the shape of the right argument without its leftmost axis. This can be expressed formally for non-scalar arguments as follows:</p>

<pre> ⍴ L F.G R &lt;--&gt; (¯1↓⍴L),(1↓⍴R)</pre>

<h4 id="exercises-for-section-5.7">Exercises for Section 5.7<sup class="answers-note">[<a href="answers.html#section-5.7-other-primitive-operators">Answers</a>]</sup><a href="#exercises-for-section-5.7" class="section-link">§</a></h4>

<ol>

<li><p>State the shape, depth, and value for each of the following expressions:</p>

<ol type="a">

<li><code>+\⍳5</code></li>

<li><code>+\5</code></li>

<li><code>+\⊂⍳5</code></li>

<li><code>+\(1 2 3)(4 5 6)(7 8 9)</code></li>

<li><code>+\(1 2 3)(4 5 6)(7 8 9) 10</code></li>

<li><code>+\(1 2 3)(4 5 6)(7 8 9) 10 20</code></li>

<li><code>+\(1 2 3)(4 5 6)(7 8 9) (⊂10 20)</code></li>

<li><code>+\¨(1 2 3)(4 5 6)(7 8 9)</code></li>

<li><code>,\⍳5</code></li>

<li><code>&lt;\0 0 1 0 1 1</code></li>

<li><code>≤\1 1 1 0 0 1 0 1</code></li>

<li><code>≠\1 1 1 0 0 1 0 1</code></li>

<li><code>&gt;\(1 0 1 0 1 1 )(1 1 1 0 1 1 )</code></li>

</ol></li>

<li><p>Determine the value, shape, and depth of the following expressions where <code>T</code> is defined as:</p>

<pre> T← 3 4 ⍴ 3 6 9 1 8 2 4 4 9 7 5 3</pre>

<ol type="a">

<li><code>+\T</code></li>

<li><code>−\T</code></li>

<li><code>+\[1]T</code></li>

<li><code>−\[1]T</code></li>

</ol></li>

<li><p>State the shape, depth, and result of each of the following expressions, where</p>

<pre> A←10 5 7 12 4 3</pre>

<ol type="a">

<li><code>2 +/A</code></li>

<li><code>3 +/A</code></li>

<li><code>5 +/A</code></li>

<li><code>6 +/A</code></li>

<li><code>7 +/A</code></li>

<li><code>0 +/A</code></li>

<li><code>0 ⌈/A</code></li>

<li><code>0 ⌊/A</code></li>

<li><code>2 −/A</code></li>

<li><code>¯2 −/A</code></li>

<li><code>3 −/A</code></li>

<li><code>¯3 −/A</code></li>

<li><code>2 +/¨ A (−A)</code></li>

</ol></li>

<li><p>State the shape, depth, and result of each of the following expressions where:</p>

<pre> M←4 4⍴2 4 6 8 1 3 5 7 8 9

N←10×M

T←3 3 3⍴⍳27

S←−T</pre>

<ol type="a">

<li><code>2 +/ M N</code></li>

<li><code>2 +/ M N</code></li>

<li><code>2 +/[1]¨ M N</code></li>

<li><code>+/ T S</code></li>

<li><code>+⌿ T S</code></li>

<li><code>+/¨ T S</code></li>

<li><code>+⌿¨ T S</code></li>

<li><code>+/[2]¨ T S</code></li>

<li><code>2 +/¨ T S</code></li>

<li><code>2 +/[1]¨ T S</code></li>

<li><code>2 +/[2]¨ T S</code></li>

</ol></li>

<li><p>Given a positive integer <code>N</code>, write an expression to generate the following vector:</p>

<pre> 1 ¯1 2 ¯2 3 ¯3 4 ¯4 ... N ¯N</pre></li>

<li><p>Write a function <code>CHECK</code> to produce a Boolean vector with <code>1</code>’s for the rows of numeric matrix <code>M</code> that are in ascending order. Here is an example:</p>

<pre> M

2 3 4 5

3 1 7 8

4 7 9 2

CHECK M

1 0 0</pre></li>

<li><p>Write an expression to produce <code>R</code>, given the result of <code>+\R</code>. For example, given the vector <code>N</code> where <code>N←+\ 2 4 5 7</code>, produce <code>2 4 5 7</code>.</p></li>

<li><p>Write an expression to generate sets of <code>N</code> consecutive integers where the first item is from <code>⍳S</code>. For example, from <code>N←3</code> and <code>S←⍳4</code>, you should get the following result:</p>

<pre> (1 2 3)(2 3 4)(3 4 5)(4 5 6)</pre></li>

<li><p>Write a function <code>MOVING_AVG</code> to produce the average of each successive group of <code>N</code> items from a simple vector of numeric data.</p></li>

<li><p>Write an expression to convert 3 miles, 6 yards, 2 feet, and 7 inches to inches (1 mile is 1760 yards, 1 yard is 3 feet, 1 foot is 12 inches).</p></li>

<li><p>Given the following variables:</p>

<pre> A←2 4 6

5←10 11 12 13

C←(5 10) (1 2 4)</pre>

<p>Evaluate these expressions:</p>

<ol type="a">

<li><code>A∘.+B</code></li>

<li><code>⍴A∘.+B</code></li>

<li><code>A∘.,B</code></li>

<li><code>⍴A∘.,B</code></li>

<li><code>A∘.×C</code></li>

<li><code>⍴A∘.×C</code></li>

</ol></li>

<li><p>State both the value and shape of the following expressions:</p>

<ol type="a">

<li><code>2 5 10 ∘.⋆ 1 2 3</code></li>

<li><code>1 2 3 ∘.⌈ 1 2 3 4</code></li>

<li><code>1 2 3 4 ∘.⌊ 1 2 3</code></li>

<li><code>3 7 8 ∘.⌈ 5 (6 4)</code></li>

<li><code>(3 7)(8 4) ∘.⌈ 5 (6 4)(2 9)</code></li>

<li><code>1 ¯2 2 ∘.↑ 'ABC' (10 20 30 40)</code></li>

<li><code>1 2 3 ∘.⊃ 'ABCD' 'XYZ'</code></li>

<li><code>1 2 3 ∘., 'AB' 'CDE'</code></li>

<li><code>1 2 3 ∘., ⊂¨'AB' 'CDE'</code></li>

</ol></li>

<li><p>Write an expression to produce all nine pairings of the letters <code>ABC</code> (including repetitions).</p></li>

<li><p>Evaluate the following expressions:</p>

<ol type="a">

<li><code>(3 4⍴5↑1) +.× 4 3⍴⍳12</code></li>

<li><code>(3 4⍴5↑1) ,.× 4 3⍴⍳12</code></li>

</ol></li>

<li><p>The risk level for cardiovascular disease involves <code>HDL</code> (high density lipoprotein), <code>LDL</code> (low density lipoprotein), triglycerides, and cholesterol. It is measured as the ratio of <code>LDL</code> over <code>HDL</code>. As the ratio increases, so does the risk and the extent of the treatment:</p>

<ul>

<li>2 or less — Low risk.</li>

<li>2-3 — Moderate risk.</li>

<li>3-5 — Dietary care indicated.</li>

<li>5 or more — Candidate for drug therapy.</li>

</ul>

<p>A regular blood analysis provides measures of <code>HDL</code>, total cholesterol (<code>TC</code>), and triglycerides (<code>TRIG</code>). The following expressions relate <code>LDL</code> to the measured items:</p>

<pre> LDL ← TC − HDL + TRIG ÷ 6

RISK ← LDL ÷ HDL</pre>

<ol type="a">

<li>Calculate the risk ratio for the following values:

<ul>

<li><code>HDL</code>, from 25 to 40 in increments of 5.</li>

<li><code>TRIG</code>, from 120 to 300 in increments of 10.</li>

<li><code>TC</code>, from 175 to 225 in increments of 5.</li>

</ul></li>

<li>Write an expression to produce the values of <code>LDL</code> for each possible combination of the given values of <code>HDL</code>, <code>TRIG</code>, and <code>TC</code>.</li>

<li>Write an expression to compute the risk values.</li>

</ol></li>

</ol>

View this page on the web

View page source