diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4247d6d..e1f376d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,14 @@ In the first instance, it lists the changes between consecutive releases of this
However, because this book is a rework of the first edition by Bernard Legrand,
this changelog also marks with [n] content that is new in this rework.
+## 0.4.4
+
+ - Improve exercise presentation:
+ - provide an admonition for exercises with auto-numbering;
+ - provide an admonition for solutions;
+ - link solutions to corresponding exercises;
+ - Improve phrasing of several exercises and provide more concrete instructions.
+
## 0.4.3.1
- Use local APL385 font when possible.
diff --git a/Data-and-Variables.ipynb b/Data-and-Variables.ipynb
index 0b5e58e..0347349 100644
--- a/Data-and-Variables.ipynb
+++ b/Data-and-Variables.ipynb
@@ -5566,15 +5566,18 @@
" > *For this reason, we suggest that you try to answer them on a sheet of paper, not on your computer. When you are sure of your answer, you can test it on the computer.*\n",
"\n",
"\n",
+ "\n",
"**Exercise 1**:\n",
"\n",
- "Given a scalar `s`, can you transform it into a vector containing one single item? Or the opposite: can you transform a one-item vector `v` into a scalar?"
+ "Given a scalar `s`, can you transform it into a vector containing one single item? What about the opposite: can you transform a one-item vector `v` into a scalar?\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 2**:\n",
"\n",
"Define `x` so that this interactive session becomes possible:\n",
@@ -5585,74 +5588,64 @@
" ⍴x\n",
"8\n",
"```\n",
- "\n",
- "**Exercise 3**:\n",
- "\n",
- "Find the result of this expression: `'LE CHAT'[7 5 2 3 4 6 7]`. This amusing example was first given in \"*Informatique par telephone*\" of Philip S. Abrams and Gérard Lacourly, Editions Herman, Paris 1972."
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "**Exercise 4**:\n",
+ "\n",
+ "**Exercise 3**:\n",
"\n",
- "The variable `tab` is created like this:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 230,
- "metadata": {},
- "outputs": [],
- "source": [
- "tab ← 2 5 ⍴ 9 1 4 3 6 7 4 3 8 2"
+ "Find the result of this expression: `'LE CHAT'[7 5 2 3 4 6 7]`. This amusing example was first given in \"*Informatique par telephone*\" of Philip S. Abrams and Gérard Lacourly, Editions Herman, Paris 1972.\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "How could you replace the values `9 6 7 2` in this variable by `21 45 78 11` respectively?"
+ "\n",
+ "**Exercise 4**:\n",
+ "\n",
+ "The variable `tab` is created like this:\n",
+ "\n",
+ "```APL\n",
+ "tab ← 2 5 ⍴ 9 1 4 3 6 7 4 3 8 2\n",
+ "```\n",
+ "\n",
+ "How could you replace the values `9 6 7 2` in this variable by `21 45 78 11` respectively?\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "**Exercise 5**:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 231,
- "metadata": {},
- "outputs": [],
- "source": [
+ "\n",
+ "**Exercise 5**:\n",
+ "\n",
+ "Consider the following assignments:\n",
+ "\n",
+ "```APL\n",
"x ← 1 2 9 11 3 7 8\n",
- "x[3 5] ← x[4 1]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "What do you think is the new value of `x`? And what happens if you now execute:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 232,
- "metadata": {},
- "outputs": [],
- "source": [
- "x[4 6] ← x[6 4]"
+ "x[3 5] ← x[4 1]\n",
+ "```\n",
+ "\n",
+ "What do you think is the new value of `x`? And what happens if you now execute\n",
+ "\n",
+ "```APL\n",
+ "x[4 6] ← x[6 4]\n",
+ "```\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 6**:\n",
"\n",
"A vector of six items named `mystery` is indexed like this:\n",
@@ -5663,7 +5656,14 @@
"```\n",
"\n",
"What is the value of `mystery`?\n",
- "\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
"**Exercise 7**:\n",
"\n",
"One creates a vector, and selects some items from it, as shown:\n",
@@ -5675,119 +5675,88 @@
"```\n",
"\n",
"Could you guess the value of `findMe`?\n",
- "\n",
- "**Exercise 8**:\n",
- "\n",
- "One creates a vector, and a set of indices:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 233,
- "metadata": {},
- "outputs": [],
- "source": [
- "source ← 10 4 13 3 9 0 7 6 2 13 8 1 5\n",
- "set ← 3 3 ⍴ source[2 4 8 5 12 13 7 4]"
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "Then one uses it to index the original vector:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 234,
- "metadata": {},
- "outputs": [],
- "source": [
- "result ← source[set]"
+ "\n",
+ "**Exercise 8**:\n",
+ "\n",
+ "One creates a vector, and a set of indices:\n",
+ "\n",
+ "```APL\n",
+ "source ← 10 4 13 3 9 0 7 6 2 13 8 1 5\n",
+ "set ← 3 3 ⍴ source[2 4 8 5 12 13 7 4]\n",
+ "```\n",
+ "\n",
+ "Then one uses it to index the original vector:\n",
+ "\n",
+ "```APL\n",
+ "result ← source[set]\n",
+ "```\n",
+ "\n",
+ "What is the shape of `result`? Can you find its value?\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "What is the shape of `result`? Can you find its value?\n",
- "\n",
+ "\n",
"**Exercise 9**:\n",
"\n",
- "Is there a difference between the following two vectors?"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 235,
- "metadata": {},
- "outputs": [],
- "source": [
+ "Is there a difference between the following two vectors?\n",
+ "\n",
+ "```APL\n",
"v1 ← 'p' 'o' 't'\n",
- "v2 ← 'pot'"
+ "v2 ← 'pot'\n",
+ "```\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 10**:\n",
"\n",
- "Is there a difference between the following two vectors?"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 236,
- "metadata": {},
- "outputs": [],
- "source": [
+ "Is there a difference between the following two vectors?\n",
+ "\n",
+ "```APL\n",
"v3 ← 15 48 'Y' 'e' 's' 52\n",
- "v4 ← 15 48 'Yes' 52"
+ "v4 ← 15 48 'Yes' 52\n",
+ "```\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 11**:\n",
"\n",
- "Here is a very simple variable:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 237,
- "metadata": {},
- "outputs": [],
- "source": [
- "two ← 2"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "We use it in the following expression:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 238,
- "metadata": {},
- "outputs": [],
- "source": [
- "foolish ← two two ⍴ 2 two '⍴' 'two'"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
+ "Here is a very simple variable:\n",
+ "\n",
+ "```APL\n",
+ "two ← 2\n",
+ "```\n",
+ "\n",
+ "We use it in the following expression:\n",
+ "\n",
+ "```APL\n",
+ "foolish ← two two ⍴ 2 two '⍴' 'two'\n",
+ "```\n",
+ "\n",
"What is the shape of `foolish`? Can you find its value?\n",
+ "\n",
"\n",
- "Proposed solutions to the exercises can be found at the [end of this chapter](#Solutions)."
+ "Proposed solutions to the exercises can be found in [this section](#Solutions)."
]
},
{
@@ -6724,6 +6693,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 1**:\n",
"\n",
"The dyadic use of `⍴` is _reshape_, so that is what we are going to do to turn a scalar"
@@ -6862,6 +6832,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 2**:\n",
"\n",
"If we define `x` by just copying the numerical values, then we are defining a vector with 4 elements:"
@@ -6978,6 +6949,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 3**:\n",
"\n",
"There is no easier way to confirm your answer than to actually run the code:"
@@ -7008,6 +6980,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 4**:\n",
"\n",
"The first thing to do would be to understand how to access the values we want to modify, and then use the appropriate assignment. Notice that `tab` is a matrix with 2 rows and 5 columns and we are after the values in the corners, or in the first and last columns:"
@@ -7112,6 +7085,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 5**:\n",
"\n",
"When we write"
@@ -7203,6 +7177,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 6**:\n",
"\n",
"To solve this, just notice that if `mystery[3 1 6 5 2 4]` gives `8 11 3 9 2 15` then the 3rd item of `mystery` is 8, the 1st is 11, and so on. So `mystery` is actually:"
@@ -7234,6 +7209,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 7**:\n",
"\n",
"This exercise is similar to the one above. We start with the vector"
@@ -7281,6 +7257,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 8**:\n",
"\n",
"The result of indexing a vector is always equal to the shape of the index. Hence the shape of `result` is equal to the shape of `set`, which is `3 3`:"
@@ -7395,6 +7372,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 9**:\n",
"\n",
"There is _no_ difference between the two vectors. Both are 3-item simple character vectors."
@@ -7404,6 +7382,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 10**:\n",
"\n",
"`v3` is a 6-item vector. Some items are numeric, some are characters; it is a _mixed_ vector."
@@ -7529,6 +7508,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 11**:\n",
"\n",
"Replacing `two` (not `'two'`) by `2` (the value of the variable), one obtains `2 2 ⍴ 2 2 '⍴' 'two'`. This gives away that `foolish` is a 2 by 2 matrix:"
@@ -7612,7 +7592,7 @@
"toc_cell": false,
"toc_position": {},
"toc_section_display": true,
- "toc_window_display": false
+ "toc_window_display": true
}
},
"nbformat": 4,
diff --git a/Nested-Arrays-Continued.ipynb b/Nested-Arrays-Continued.ipynb
index 034320f..4c922cb 100644
--- a/Nested-Arrays-Continued.ipynb
+++ b/Nested-Arrays-Continued.ipynb
@@ -3527,13 +3527,17 @@
"source": [
"Now, the line is exactly where we want it and the numbers are nicely formatted.\n",
"\n",
- "**Exercise 1**: try to deduce the results of the following 3 expressions (depth, rank, shape), and then verify your solutions on the computer:\n",
+ "\n",
+ "**Exercise 1**:\n",
+ "\n",
+ "Deduce the results of the following 3 expressions (depth, rank, shape), and then verify your solutions on the computer:\n",
"\n",
"```APL\n",
"(⊂cm) (⊂nm)\n",
"(⊂cm),(⊂nm)\n",
"cm,⊂nm\n",
- "```"
+ "```\n",
+ ""
]
},
{
@@ -4183,8 +4187,6 @@
"source": [
"## Intermission Exercises\n",
"\n",
- "**Exercise 2**:\n",
- "\n",
"You are given three numeric vectors:"
]
},
@@ -4205,6 +4207,9 @@
"id": "olympic-absolute",
"metadata": {},
"source": [
+ "\n",
+ "**Exercise 2**:\n",
+ "\n",
"Try to predict the results given by the following expressions in terms of depth, rank, and shape.\n",
"Then check your results using `]display`, or the appropriate primitives.\n",
"\n",
@@ -4213,7 +4218,9 @@
" 1. `(10 20),a b`\n",
" 1. `a b 2 × c[2]`\n",
" 1. `10×a 20×b`\n",
+ "\n",
"\n",
+ "\n",
"**Exercise 3**:\n",
"\n",
"Same question for the following expressions:\n",
@@ -4225,15 +4232,18 @@
" 1. `1 10 3 ∊ a`\n",
" 1. `(⊂1 0 1)/¨a b c`\n",
" 1. `1 10 3 ∊ a b c`\n",
+ "\n",
"\n",
+ "\n",
"**Exercise 4**:\n",
"\n",
- "Consider the following nested array:"
+ "What are the results of `+/na` and `,/na` for the vector `na` shown below?\n",
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 80,
+ "execution_count": 2,
"id": "robust-actor",
"metadata": {
"scrolled": true
@@ -4249,7 +4259,7 @@
""
]
},
- "execution_count": 80,
+ "execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
@@ -4258,14 +4268,6 @@
"⎕← na ← 1 2 (2 2⍴3 4 5 6)7 8"
]
},
- {
- "cell_type": "markdown",
- "id": "worst-bookmark",
- "metadata": {},
- "source": [
- "What are the results of `+/na` and `,/na`?"
- ]
- },
{
"cell_type": "markdown",
"id": "collaborative-table",
@@ -7851,18 +7853,21 @@
"source": [
"## Exercises\n",
"\n",
+ "\n",
"**Exercise 5**:\n",
"\n",
"You are given two vectors.\n",
"The first contains the reference codes for some items in a warehouse.\n",
"Identical codes are grouped, but not necessarily in ascending order.\n",
"The second vector contains the quantities of each item sold during the day or the week.\n",
- "For example:"
+ "\n",
+ "Write a dyadic function `QuantitiesSold` that accepts these two vectors as arguments and calculates how many items of each reference code have been sold. Preferably, use a partitioning function.\n",
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 230,
+ "execution_count": 6,
"id": "emotional-renewal",
"metadata": {},
"outputs": [],
@@ -7872,24 +7877,55 @@
]
},
{
- "cell_type": "markdown",
- "id": "furnished-cursor",
- "metadata": {},
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "younger-incentive",
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "13 39 10 152 19\n",
+ ""
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "Can you calculate how many items of each reference code have been sold?\n",
- "Preferably, use a partitioning function."
+ "ref QuantitiesSold qty"
]
},
{
"cell_type": "code",
- "execution_count": 231,
- "id": "younger-incentive",
- "metadata": {},
- "outputs": [],
+ "execution_count": 10,
+ "id": "provincial-interference",
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "1\n",
+ ""
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "QuantitiesSold ← {}\n",
- "ref QuantitiesSold qty\n",
- "⍝ 13 39 10 152 19"
+ "13 39 10 152 19 ≡ ref QuantitiesSold qty"
]
},
{
@@ -7897,6 +7933,7 @@
"id": "valid-trance",
"metadata": {},
"source": [
+ "\n",
"**Exercise 6**:\n",
"\n",
"You are given two character matrices with the same number of columns.\n",
@@ -7908,13 +7945,12 @@
"Currently, _index of_ `⍳` works on matrices, but this hasn't always been the case.\n",
"Thus, can you solve this exercise without using _index of_ on matrices?\n",
"(Using _index of_ on vectors is still allowed!)\n",
- "\n",
- "You can use these two matrices to test your solution:"
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 232,
+ "execution_count": 11,
"id": "voluntary-communications",
"metadata": {},
"outputs": [
@@ -7929,7 +7965,7 @@
""
]
},
- "execution_count": 232,
+ "execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
@@ -7940,7 +7976,7 @@
},
{
"cell_type": "code",
- "execution_count": 233,
+ "execution_count": 12,
"id": "strong-situation",
"metadata": {},
"outputs": [
@@ -7954,7 +7990,7 @@
""
]
},
- "execution_count": 233,
+ "execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
@@ -7973,7 +8009,7 @@
},
{
"cell_type": "code",
- "execution_count": 364,
+ "execution_count": 13,
"id": "exposed-gibson",
"metadata": {},
"outputs": [
@@ -7984,7 +8020,7 @@
""
]
},
- "execution_count": 364,
+ "execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
@@ -7998,41 +8034,11 @@
"id": "minute-mongolia",
"metadata": {},
"source": [
+ "\n",
"**Exercise 7**:\n",
"\n",
- "A _partitioned enclose_ with a single zero as the left argument returns an empty vector:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 236,
- "id": "adopted-summit",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "\n",
- "\n",
- "\n",
- ""
- ]
- },
- "execution_count": 236,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "0⊂'Partition'"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "interior-background",
- "metadata": {},
- "source": [
- "As you know already, not all empty vectors are the same.\n",
+ "A _partitioned enclose_ with a single zero as the left argument returns an empty vector.\n",
+ "However, as you know already, not all empty vectors are the same.\n",
"When working with empty vectors, we also work with prototypes, because an empty vector knows what it would contain if it were not empty.\n",
"\n",
"Go over the expressions that follow and build the empty vector that _matches_ the result of the empty _partitioned enclose_:\n",
@@ -8045,17 +8051,16 @@
" - `0⊂(1 2 3)(4 5 6)(7 8 9)`\n",
" - `0⊂('cat')('dog')(7 8 9)`\n",
" - `0⊂(14 'cat' 8)('a' 2 'c' 4)(1 2 3)`\n",
+ "\n",
"\n",
"The first one is already solved:"
]
},
{
"cell_type": "code",
- "execution_count": 237,
- "id": "suited-bottom",
- "metadata": {
- "scrolled": true
- },
+ "execution_count": 15,
+ "id": "potential-trace",
+ "metadata": {},
"outputs": [
{
"data": {
@@ -8064,7 +8069,7 @@
""
]
},
- "execution_count": 237,
+ "execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
@@ -8079,40 +8084,89 @@
"id": "accurate-george",
"metadata": {},
"source": [
+ "\n",
"**Exercise 8**:\n",
"\n",
- "Given a word or a list of words, return a Boolean vector where 1 indicates a word that starts and ends with the same letter. Each word will have at least one letter and will consist entirely of either uppercase (A–Z) or lowercase (a–z) letters. Words consisting of a single letter can be scalars and **are** considered to start and end with the same letter."
+ "Write a monadic function `StartAndEnd` that, given a word or a list of words, returns a Boolean vector where 1 indicates a word that starts and ends with the same letter. Each word will have at least one letter and will consist entirely of either uppercase (A–Z) or lowercase (a–z) letters. Words consisting of a single letter can be scalars and **are** considered to start and end with the same letter.\n",
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 470,
+ "execution_count": 21,
"id": "scheduled-springfield",
- "metadata": {},
- "outputs": [],
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "1 0 1\n",
+ ""
+ ]
+ },
+ "execution_count": 21,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "StartAndEnd ← {}\n",
- "StartAndEnd 'area' 'banana' 'shoes' ⍝ 1 0 1"
+ "StartAndEnd 'area' 'banana' 'shoes'"
]
},
{
"cell_type": "code",
- "execution_count": 472,
+ "execution_count": 22,
"id": "pretty-samoa",
- "metadata": {},
- "outputs": [],
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "0\n",
+ ""
+ ]
+ },
+ "execution_count": 22,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "StartAndEnd 'cape' ⍝ 0"
+ "StartAndEnd 'cape'"
]
},
{
"cell_type": "code",
- "execution_count": 473,
+ "execution_count": 23,
"id": "bigger-sheet",
- "metadata": {},
- "outputs": [],
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "1\n",
+ ""
+ ]
+ },
+ "execution_count": 23,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "StartAndEnd 'z' ⍝ 1"
+ "StartAndEnd 'z'"
]
},
{
@@ -8120,27 +8174,67 @@
"id": "described-eligibility",
"metadata": {},
"source": [
+ "\n",
"**Exercise 9**:\n",
"\n",
- "You are given a long character vector, called `text`.\n",
- "We would like to extract a part of it as a _simple_ character vector.\n",
- "The extract is defined as a number of sub-vectors, each being five characters long, and starting at the positions given by the vector `start`.\n",
- "\n",
- "For example:"
+ "Write a dyadic function `Extract` that accepts a character vector left argument (let us call it `text`) and an integer vector right argument (let us call it `start`).\n",
+ "We would like to extract a part of `text` as a _simple_ character vector.\n",
+ "The extract is defined as a number of sub-vectors, each being five characters long, and starting at the positions given by `start`.\n",
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 242,
+ "execution_count": 26,
"id": "exotic-living",
- "metadata": {},
- "outputs": [],
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "borintypedxperi\n",
+ ""
+ ]
+ },
+ "execution_count": 26,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"text ← 'This boring text has been typed just for a little experiment.'\n",
"start ← 6 27 52\n",
- "Extract ← {}\n",
- "text Extract start\n",
- "⍝ 'borintypedxperi'"
+ "text Extract start"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "id": "american-three",
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "1\n",
+ ""
+ ]
+ },
+ "execution_count": 27,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "'borintypedxperi' ≡ text Extract start"
]
},
{
@@ -8148,23 +8242,66 @@
"id": "historic-shepherd",
"metadata": {},
"source": [
+ "\n",
"**Exercise 10**:\n",
"\n",
"This exercise is the same as the previous one, but instead of extracting five characters each time, you are asked to extract a variable number of characters specified by the variable `long`.\n",
- "You can use the same example as above, plus this additional variable:"
+ "\n",
+ "\n",
+ "You can use the same example as above plus the additional variable `length`:"
]
},
{
"cell_type": "code",
- "execution_count": 243,
+ "execution_count": 30,
"id": "phantom-realtor",
- "metadata": {},
- "outputs": [],
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "bortyped juxper\n",
+ ""
+ ]
+ },
+ "execution_count": 30,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"length ← 3 8 4\n",
- "ExtractL ← {}\n",
- "text ExtractL start length\n",
- "⍝ 'bortyped juxper'"
+ "text ExtractL start length"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 31,
+ "id": "renewable-annex",
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "1\n",
+ ""
+ ]
+ },
+ "execution_count": 31,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "'bortyped juxper' ≡ text ExtractL start length"
]
},
{
@@ -9284,6 +9421,7 @@
"id": "cardiac-messaging",
"metadata": {},
"source": [
+ "\n",
"**Exercise 1**:\n",
"\n",
"A very reasonable thing to do first is figure out the depth, rank, and shape, of the two arrays we are working with:"
@@ -9557,6 +9695,7 @@
"id": "automotive-venezuela",
"metadata": {},
"source": [
+ "\n",
"**Exercise 2**:\n",
"\n",
"Let's take the three vectors we need and work with them:"
@@ -9817,6 +9956,7 @@
"id": "applicable-marsh",
"metadata": {},
"source": [
+ "\n",
"**Exercise 3**:\n",
"\n",
"We continue our work:\n",
@@ -10144,6 +10284,7 @@
"id": "portable-village",
"metadata": {},
"source": [
+ "\n",
"**Exercise 4**:\n",
"\n",
"We want to know what `+/na` and `,/na` evaluate to, given `na`:"
@@ -10288,6 +10429,7 @@
"id": "incorporate-script",
"metadata": {},
"source": [
+ "\n",
"**Exercise 5**:\n",
"\n",
"We have the two vectors here:"
@@ -10597,6 +10739,7 @@
"id": "advised-phase",
"metadata": {},
"source": [
+ "\n",
"**Exercise 6**:\n",
"\n",
"In order to be able to look the rows of a matrix up on the rows of another matrix, we just need to use _split_ to turn both matrices into vectors of rows:"
@@ -10680,6 +10823,7 @@
"id": "early-thirty",
"metadata": {},
"source": [
+ "\n",
"**Exercise 7**:\n",
"\n",
"In order to understand the results of the empty _partitioned encloses_, it is helpful to think about what the result would be if it were a \"normal\" _partitioned enclose_.\n",
@@ -11179,6 +11323,7 @@
"id": "dangerous-trial",
"metadata": {},
"source": [
+ "\n",
"**Exercise 8**:\n",
"\n",
"To check if a word starts and ends with the same character, we can take a character from the front, one from the back, and compare those:"
@@ -11391,6 +11536,7 @@
"id": "special-teaching",
"metadata": {},
"source": [
+ "\n",
"**Exercise 9**:\n",
"\n",
"In order to extract the sub-vectors from the big character vector, we need to take the starting indices and count five indices starting from there:"
@@ -11498,6 +11644,7 @@
"id": "institutional-locator",
"metadata": {},
"source": [
+ "\n",
"**Exercise 10**:\n",
"\n",
"This exercise is very similar to the previous one, except that now we don't extract sub-vectors of fixed length, the lengths depend on the right argument.\n",
@@ -11550,17 +11697,10 @@
"text ExtractL start length\n",
"⍝ 'bortyped juxper'"
]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "nearby-plant",
- "metadata": {},
- "outputs": [],
- "source": []
}
],
"metadata": {
+ "celltoolbar": "Tags",
"kernelspec": {
"display_name": "Dyalog APL",
"language": "apl",
diff --git a/Some-Primitive-Functions.ipynb b/Some-Primitive-Functions.ipynb
index 741e079..c5445b4 100644
--- a/Some-Primitive-Functions.ipynb
+++ b/Some-Primitive-Functions.ipynb
@@ -4262,10 +4262,10 @@
"source": [
"so, we get the maximum `45`. And so on for other functions we put to the left of `/`.\n",
"\n",
- "\n",
+ "\n",
"***Exercise***:\n",
"\n",
- " > Try to evaluate the following expression in your head or with pen and paper: `23⌈ ⌈ ⌈/ 17.81 21.41 9.34 16.53`\n",
+ "Try to evaluate the following expression in your head or with pen and paper: `23⌈ ⌈ ⌈/ 17.81 21.41 9.34 16.53`\n",
"\n",
"\n",
"Don't panic! Remember to evaluate it symbol by symbol, from right to left."
@@ -11072,8 +11072,14 @@
" > *The following exercises are designed to train **you**, not the computer.*\n",
" >\n",
" > *For this reason, we suggest that you try to answer them on a sheet of paper, not on your computer. When you are sure of your answer, you can test it on the computer.*\n",
- "\n",
- "\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "\n",
"**Exercise 1**:\n",
"\n",
"Can you evaluate the following expressions?\n",
@@ -11088,13 +11094,15 @@
"1 ⊢ 2 ⊣ 3 ⊢ 4 ⊣ 5 ⊢ 6 ⊣ 7\n",
"1 ⊣ 2 ⊢ 3 ⊣ 4 ⊢ 5 ⊣ 6 ⊢ 7\n",
"1 2 3 ⊢ 4 5 6\n",
- "```"
+ "```\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 2**:\n",
"\n",
"Try to evaluate the following expressions. *Be careful*: they are not as simple as might first appear!\n",
@@ -11104,13 +11112,15 @@
"2+2 2+2\n",
"2+2,2+2\n",
"2,2+2,2\n",
- "```"
+ "```\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 3**:\n",
"\n",
"Given the vector `a ← 8 2 7 5`, compare the results obtained from the following sets of expressions:\n",
@@ -11126,13 +11136,15 @@
"1+⍳⍴a\n",
"⍳¯1+⍴a\n",
"⍳⍴a-1\n",
- "```"
+ "```\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 4**:\n",
"\n",
"Using your knowledge of the order of evaluation in APL, re-write the following expressions without using parentheses.\n",
@@ -11141,84 +11153,79 @@
"((⍳4)-1)⌈3\n",
"7⌊(⍳9)⌈3\n",
"1+((⍳5)=1 4 3 2 5)×5\n",
- "```"
+ "```\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 5**:\n",
"\n",
- "Given a variable `a`, find an expression which returns the answer 1 if `a` is a scalar, and 0 if it is not."
+ "Given a variable `a`, find an expression which returns the answer 1 if `a` is a scalar, and 0 if it is not.\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 6**:\n",
"\n",
- "Given two scalars `a` and `b`, write an expressions which gives 7 if `a` is greater than or equal to `b` and 3 if `a` is smaller than `b`."
+ "Given two scalars `a` and `b`, write an expressions which gives 7 if `a` is greater than or equal to `b` and 3 if `a` is smaller than `b`.\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 7**:\n",
"\n",
"Given two scalars `a` and `b`, find an expression which returns:\n",
" - an empty vector, if `a` is zero, whatever the value of `b`;\n",
" - 0, if `b` is zero, but `a` is not;\n",
- " - 3, if neither `a` nor `b` are zero."
+ " - 3, if neither `a` nor `b` are zero.\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 8**:\n",
"\n",
"Unfortunately, your keyboard has been damaged and your `∧` and `∨` keys no longer work. Which other symbols could you use to replace them?\n",
"\n",
- "You can test your solutions on these vectors:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 202,
- "metadata": {},
- "outputs": [],
- "source": [
+ "You can test your solutions on the vectors `l` and `r`:\n",
+ "\n",
+ "```APL\n",
"l ← 0 0 1 1\n",
- "r ← 0 1 0 1"
+ "r ← 0 1 0 1\n",
+ "```\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 9**:\n",
"\n",
- "Given these three vectors:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 203,
- "metadata": {},
- "outputs": [],
- "source": [
+ "Given these three vectors:\n",
+ "\n",
+ "```APL\n",
"g ← 1 1 1 0 0 1\n",
"m ← 0 0 1 1 0 1\n",
- "d ← 1 0 1 0 1 0"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
+ "d ← 1 0 1 0 1 0\n",
+ "```\n",
+ "\n",
"Evaluate the following expressions:\n",
"\n",
"```APL\n",
@@ -11230,13 +11237,15 @@
"(~d)∧(~g)\n",
"(m⌈g)=(m⌊d)\n",
"(m⌊g)≠(m⌈d)\n",
- "```"
+ "```\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 10**:\n",
"\n",
"Evaluate the following expressions:\n",
@@ -11246,53 +11255,49 @@
"'sugar' ∊ 'salt'\n",
"11 ≠ '11'\n",
"'14' ⍳ '41'\n",
- "```"
+ "```\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 11**:\n",
"\n",
- "Write an expression to compute the number of times the letter \"e\" appears in a character vector. You can test it with this vector:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 363,
- "metadata": {},
- "outputs": [],
- "source": [
- "text ← 'The silence of the sea'"
+ "Write an expression to compute the number of times the letter \"e\" appears in a character vector. You can test it with this vector:\n",
+ "\n",
+ "```APL\n",
+ "text ← 'The silence of the sea'\n",
+ "```\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 12**:\n",
"\n",
"How many expressions can you write to retrieve the last element of a vector? Can you write one that uses the operator _reduce_ `/`?\n",
"\n",
- "You can test your expressions on these vectors:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 364,
- "metadata": {},
- "outputs": [],
- "source": [
+ "You can test your expressions on these vectors:\n",
+ "\n",
+ "```APL\n",
"vec ← 1 2 3 4 5 6\n",
"vec ← (1 2) 3 (4 5) 6\n",
- "vec ← 0 (5⍴0) (3 4⍴0) (1 2 3⍴0)"
+ "vec ← 0 (5⍴0) (3 4⍴0) (1 2 3⍴0)\n",
+ "```\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 13**:\n",
"\n",
"We have conducted some experiments on a variable `z`:\n",
@@ -11309,13 +11314,15 @@
"0\n",
"```\n",
"\n",
- "What is the value of `z`?"
+ "What is the value of `z`?\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 14**:\n",
"\n",
"We have conducted some experiments on a variable `z`:\n",
@@ -11330,120 +11337,87 @@
"8 7 6 5\n",
"```\n",
"\n",
- "What is the value of `z`?"
+ "What is the value of `z`?\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 15**:\n",
"\n",
- "What are all the **positions** of the letter \"e\" in the character vector specified in exercise 11?"
+ "What are all the **positions** of the letter \"e\" in the character vector specified in exercise 11?\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 16**:\n",
"\n",
"Given a vector `vec` of any size and type (numeric or character or even nested), try to extract the items of `vec` which are in the odd positions (the 1st, the 3rd, the 5th, ...).\n",
"\n",
- "You can test your solution on these vectors:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 365,
- "metadata": {},
- "outputs": [],
- "source": [
+ "You can test your solution on these vectors:\n",
+ "\n",
+ "```APL\n",
"vec ← 1 2 3 4 5 6 7 8 9\n",
"vec ← 'CROANGGARYANTLULLBAPTWIZOSNSSB'\n",
- "vec ← (1 2) (2 3) (4 5 6) (6 9 42 1024)"
+ "vec ← (1 2) (2 3) (4 5 6) (6 9 42 1024)\n",
+ "```\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 17**:\n",
"\n",
- "How many numbers are there in the variable `prod` used in this chapter? Try to answer with and without using _ravel_ (monadic `,`)."
+ "How many numbers are there in the variable `prod` used in this chapter? Try to answer with and without using _ravel_ (monadic `,`).\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 18**:\n",
"\n",
- "How is it possible to remove all the values which do not fall between 20 (inclusive) and 30 (exclusive) from a given vector?"
+ "How is it possible to remove all the values which do not fall between 20 (inclusive) and 30 (exclusive) from a given vector?\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 19**:\n",
"\n",
- "Notice how these two expressions look the same:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 366,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "4\n",
- ""
- ]
- },
- "execution_count": 366,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "≢vec"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 367,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/html": [
- "4\n",
- ""
- ]
- },
- "execution_count": 367,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "⍴vec"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Can you tell if/how they are different?"
+ "Notice how these two expressions look the same:\n",
+ "\n",
+ "```APL\n",
+ " ≢vec\n",
+ "4\n",
+ " ⍴vec\n",
+ "4\n",
+ "```\n",
+ "\n",
+ "Can you tell if/how they are different?\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 20**:\n",
"\n",
"Compute the _depth_ (`≡`) of these arrays:\n",
@@ -11456,22 +11430,26 @@
"(1 2) (3 4 5) (6 7 8 9)\n",
"1 (2 (3 (4 (5 (6 7)))))\n",
"(2 2⍴4) (2 2⍴⍳47) (3 6⍴⍳18)\n",
- "```"
+ "```\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 21**:\n",
"\n",
- "In a vector, we would like to replace all the values that are smaller than 20 by 20, and replace all the values that are greater than 30 by 30. How can we do that? (In other words, how might we clip the values of a vector so that they are between 20 and 30, inclusive?)"
+ "In a vector, we would like to replace all the values that are smaller than 20 by 20, and replace all the values that are greater than 30 by 30. How can we do that? (In other words, how might we clip the values of a vector so that they are between 20 and 30, inclusive?)\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 22**:\n",
"\n",
"The following 6 expressions cannot be executed, but instead generate error messages; can you say why?\n",
@@ -11483,109 +11461,89 @@
"⍴4 5 6+2 3-1\n",
"⍳3-5\n",
"⍸1 0 2 ¯1\n",
- "```"
+ "```\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 23**:\n",
"\n",
- "Write an APL expression which produces a vector of 17 numbers, the first being 23, with each subsequent number being equal to the preceding one plus 11."
+ "Write an APL expression which produces a vector of 17 numbers, the first being 23, with each subsequent number being equal to the preceding one plus 11.\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 24**:\n",
"\n",
- "In a shop, each product is identified by a code. You are given a list of the codes and the corresponding prices:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 204,
- "metadata": {},
- "outputs": [],
- "source": [
+ "In a shop, each product is identified by a code. You are given a list of the codes and the corresponding prices:\n",
+ "\n",
+ "```APL\n",
"pcodes ← 56 66 19 37 44 20 18 23 68 70 82\n",
- "prices ← 9 27 10 15 12 5 8 9 98 7 22"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "A customer gives you a list of items they intend to buy as vector of code/quantity pairs: code, quantity, code, quantity, and so on."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [],
- "source": [
- "wannaBuy ← 37 1 70 20 19 2 82 5 23 10"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
+ "prices ← 9 27 10 15 12 5 8 9 98 7 22\n",
+ "```\n",
+ "\n",
+ "A customer gives you a list of items they intend to buy as vector of code/quantity pairs: code, quantity, code, quantity, and so on.\n",
+ "\n",
+ "```APL\n",
+ "wannaBuy ← 37 1 70 20 19 2 82 5 23 10\n",
+ "```\n",
+ "\n",
"Can you evaluate their bill?\n",
"\n",
"Note that this cannot be done easily in a single (and readable) APL expression, and you will therefore need to write several expressions.\n",
"\n",
- "The correct total should be 375."
+ "The correct total should be 375.\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 25**:\n",
"\n",
- "We have organised a lottery, and we have created five vectors:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 627,
- "metadata": {},
- "outputs": [],
- "source": [
+ "We have organised a lottery, and we have created five vectors:\n",
+ "\n",
+ "```APL\n",
"⎕RL ← 73\n",
"tickets ← ?1000⍴999999\n",
"sold ← tickets[(800+?200)?1000]\n",
"ours ← sold[(?200)?≢sold]\n",
"winners ← tickets[100?1000]\n",
- "prizes ← ?100⍴1000"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
+ "prizes ← ?100⍴1000\n",
+ "```\n",
+ "\n",
+ "These are the meanings of these vectors:\n",
+ "\n",
" - `tickets` has the numbers of all the existing tickets;\n",
" - `sold` has the numbers of the tickets which have been sold;\n",
" - `ours` has the numbers of the tickets we bought ourselves;\n",
" - `winners` has the numbers of the winning tickets, and\n",
" - `prizes` has the prize amount associated with each respective number in `winners` vector.\n",
" \n",
- "And now, try to answer the following 4 questions:\n",
+ "Now, try to answer the following 4 questions:\n",
"\n",
" 1. What are the numbers of the unsold tickets?\n",
" 2. Are there some winning tickets which have not been sold?\n",
" 3. How many winning tickets do **we** have?\n",
- " 4. How much did we win?"
+ " 4. How much did we win?\n",
+ ""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 26**:\n",
"\n",
"Can you calculate all the divisors of a positive integer number `n`?\n",
@@ -11599,7 +11557,8 @@
"| 3 | 1 3 |\n",
"| 24 | 1 2 3 4 6 8 12 24 |\n",
"| 1337 | 1 7 191 1337 |\n",
- "| 1234321 | 1 11 101 121 1111 10201 12221 112211 1234321 |"
+ "| 1234321 | 1 11 101 121 1111 10201 12221 112211 1234321 |\n",
+ ""
]
},
{
@@ -13511,6 +13470,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 1**:\n",
"\n",
"Copy each expression to the APL session and execute them. If you are surprised by an answer, analyse the expression step by step, starting from the right. For example, for the first expression:"
@@ -13800,6 +13760,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 2**:\n",
"\n",
"`2 2+2 2` is the addition of two vectors of size 2:"
@@ -13907,6 +13868,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 3**:"
]
},
@@ -14042,6 +14004,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 4**:\n",
"\n",
" - `((⍳4)-1)⌈3`\n",
@@ -14351,6 +14314,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 5**:\n",
"\n",
"There are a couple of ways to determine if `a` is a scalar or not. For example, we might check if its rank is 0 with `0=≢⍴a`. We might also check if its shape matches the empty numeric vector with `⍬≡⍴a`."
@@ -14360,6 +14324,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 6**:\n",
"\n",
"A possible way to look at this is by realising that the expression we are about to create is supposed to give two different values depending on the value of `a≥b`. If `a≥b` is 1 the expression needs to evaluate to 7 and if not, it needs to evaluate to 3.\n",
@@ -14371,6 +14336,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 7**:\n",
"\n",
"An example expression could be `(a≠0)⍴3×b≠0`. Here's how to get there:\n",
@@ -14390,6 +14356,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 8**:\n",
"\n",
" - replace `∧` with `×` or `⌊`;\n",
@@ -14519,6 +14486,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 9**:"
]
},
@@ -14705,6 +14673,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 10**:"
]
},
@@ -14817,6 +14786,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 11**:\n",
"\n",
"A sensible way to approach this problem is to first compare the string with the character `'e'` and then sum the 1s that show up:"
@@ -14848,6 +14818,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 12**:\n",
"\n",
"You may have come up with expressions that are similar to these ones or maybe completely different! We show *some* possibilities below.\n",
@@ -14952,6 +14923,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 13**:\n",
"\n",
"Notice how `2 ⍴ 7` gives the first 2 elements of `z`, which are 1 and 7.\n",
@@ -15063,6 +15035,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 14**:\n",
"\n",
"```APL\n",
@@ -15183,6 +15156,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 15**:\n",
"\n",
"**Positions** can be retrieved with _where_:"
@@ -15214,6 +15188,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 16**:\n",
"\n",
"There are a couple of different ways to solve this problem. From an indexing perspective, we might want to generate all the odd numbers up to, and including, the length of the vector:"
@@ -15361,6 +15336,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 17**:\n",
"\n",
"*Ravel* will take a 3D array and create a long vector with all its items, so we just have to count them:"
@@ -15434,6 +15410,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 18**:\n",
"\n",
"This is a simple exercise in compressing with a Boolean mask. We just create a mask with all the numbers we want to keep:"
@@ -15513,6 +15490,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 19**:"
]
},
@@ -15618,6 +15596,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 20**:\n",
"\n",
"For this exercise we just have to revisit the rule for how _depth_ works and work our way inside out.\n",
@@ -15818,6 +15797,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 21**:\n",
"\n",
"This task of ensuring all numbers in an array are above a minimum threshold and below a maximum threshold is sometimes called *clipping* and is easy to achieve in APL with the scalar `⌈` and `⌊` functions. We create a dummy matrix to demonstrate:"
@@ -15911,6 +15891,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 22**:\n",
"\n",
"The challenge of this exercise was to spot the error *before* trying to run the expression on the interpreter and reading its error message.\n",
@@ -16109,6 +16090,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 23**:\n",
"\n",
"This \"vector of 17 numbers, the first being 23, with each subsequent number being equal to the preceding one plus 11\" is called an arithmetic progression in mathematics. Generating them is really easy if you use the algorithm we showed earlier.\n",
@@ -16225,6 +16207,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 24**:\n",
"\n",
"The first sensible thing to do is separate the products from the quantities. We can do this by creating a matrix with 2 columns:"
@@ -16328,6 +16311,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 25**:"
]
},
@@ -16591,6 +16575,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 26**:\n",
"\n",
"Computing divisors of a number `n` amounts to finding the numbers `m` for which `m|n` is 0. First we compute the vector of all candidates:"
@@ -16712,7 +16697,7 @@
"width": "352px"
},
"toc_section_display": true,
- "toc_window_display": false
+ "toc_window_display": true
}
},
"nbformat": 4,
diff --git a/User-Defined-Functions.ipynb b/User-Defined-Functions.ipynb
index bb8ef93..846a912 100644
--- a/User-Defined-Functions.ipynb
+++ b/User-Defined-Functions.ipynb
@@ -1249,7 +1249,9 @@
{
"cell_type": "code",
"execution_count": 44,
- "metadata": {},
+ "metadata": {
+ "scrolled": true
+ },
"outputs": [
{
"data": {
@@ -1283,77 +1285,303 @@
"## Exercises on Dfns\n",
"\n",
"You are ready to solve simple problems. We **strongly recommend** that you try to solve all the following exercises before you continue further in this chapter.\n",
+ "Many of the exercises are followed by some examples you can use to check your work.\n",
"\n",
+ "\n",
"**Exercise 1**:\n",
"\n",
- "Write a dyadic function `Extract` which returns the first `⍺` items of any given vector `⍵`."
+ "Write a dyadic function `Extract` which returns the first `⍺` items of any given vector `⍵`.\n",
+ "\n",
+ "\n",
+ "Here are some examples:"
]
},
{
"cell_type": "code",
- "execution_count": 45,
- "metadata": {},
- "outputs": [],
+ "execution_count": 6,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "45 86 31\n",
+ ""
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "Extract ← {}\n",
- "3 Extract 45 86 31 20 75 62 18 ⍝ 45 86 31\n",
- "6 Extract 'can you do it?' ⍝ 'can yo'"
+ "3 Extract 45 86 31 20 75 62 18"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "1\n",
+ ""
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "45 86 31 ≡ 3 Extract 45 86 31 20 75 62 18"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "can yo\n",
+ ""
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "6 Extract 'can you do it?'"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "1\n",
+ ""
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "'can yo' ≡ 6 Extract 'can you do it?'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 2**:\n",
"\n",
- "Write a dyadic function which ignores the first `⍺` items of any given vector `⍵` and only returns the remainder:"
+ "Write a dyadic function `Ignore` which ignores the first `⍺` items of any given vector `⍵` and only returns the remainder.\n",
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 46,
- "metadata": {},
- "outputs": [],
+ "execution_count": 9,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "20 75 62 18\n",
+ ""
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "3 Ignore 45 86 31 20 75 62 18"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "1\n",
+ ""
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "20 75 62 18 ≡ 3 Ignore 45 86 31 20 75 62 18"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "u do it?\n",
+ ""
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "6 Ignore 'can you do it?'"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "1\n",
+ ""
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "Ignore ← {}\n",
- "3 Ignore 45 86 31 20 75 62 18 ⍝ 20 75 62 18\n",
- "6 Ignore 'can you do it?' ⍝ 'u do it?'"
+ "'u do it?' ≡ 6 Ignore 'can you do it?'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 3**:\n",
"\n",
- "Write a monadic function which returns the items of a vector in reverse order:"
+ "Write a monadic function `Reverse` which returns the items of a vector in reverse order.\n",
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 45,
- "metadata": {},
- "outputs": [],
+ "execution_count": 8,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "congratulations\n",
+ ""
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "Reverse ← {}\n",
- "Reverse 'snoitalutargnoc' ⍝ 'congratulations'\n",
- "Reverse '!ti did uoY' ⍝ 'You did it!'"
+ "Reverse 'snoitalutargnoc'"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "You did it!\n",
+ ""
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "Reverse '!ti did uoY'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 4**:\n",
"\n",
- "Write a monadic function which appends row and column totals to a numeric matrix.\n",
- "\n",
- "For example, if `mat` is the matrix"
+ "Write a monadic function `Totalise` which appends row and column totals to a numeric matrix.\n",
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 46,
+ "execution_count": 10,
"metadata": {},
"outputs": [
{
@@ -1365,7 +1593,7 @@
""
]
},
- "execution_count": 46,
+ "execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
@@ -1374,17 +1602,15 @@
"⊢mat ← 3 4⍴75 14 86 20 31 16 40 51 22 64 31 28"
]
},
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Then `Totalise mat` should give"
- ]
- },
{
"cell_type": "code",
- "execution_count": 47,
- "metadata": {},
+ "execution_count": 12,
+ "metadata": {
+ "scrolled": false,
+ "tags": [
+ "skip-execution"
+ ]
+ },
"outputs": [
{
"data": {
@@ -1396,13 +1622,13 @@
""
]
},
- "execution_count": 47,
+ "execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "⊢totMat ← 4 5⍴75 14 86 20 195 31 16 40 51 138 22 64 31 28 145 128 94 157 99 478"
+ "⊢totMat ← Totalise mat"
]
},
{
@@ -1414,8 +1640,12 @@
},
{
"cell_type": "code",
- "execution_count": 48,
- "metadata": {},
+ "execution_count": 13,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
"outputs": [
{
"data": {
@@ -1427,7 +1657,7 @@
""
]
},
- "execution_count": 48,
+ "execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
@@ -1440,98 +1670,178 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 5**:\n",
"\n",
- "Write a monadic function which returns the lengths of the words contained in a text vector:"
+ "Write a monadic function `Lengths` which returns the lengths of the words contained in a text vector.\n",
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 49,
- "metadata": {},
- "outputs": [],
+ "execution_count": 16,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "4 5 2 2 1 4 8\n",
+ ""
+ ]
+ },
+ "execution_count": 16,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "Lengths 'This seems to be a good solution'"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "1\n",
+ ""
+ ]
+ },
+ "execution_count": 18,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "Lengths ← {}\n",
- "Lengths 'This seems to be a good solution' ⍝ 4 5 2 2 1 4 8"
+ "4 5 2 2 1 4 8 ≡ Lengths 'This seems to be a good solution'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 6**:\n",
"\n",
- "Write a dyadic function which produces the series of integer values between the limits given by its two arguments:"
+ "Write a dyadic function `To` which produces the series of integer values between the limits given by its two arguments.\n",
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 50,
- "metadata": {},
- "outputs": [],
+ "execution_count": 24,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "17 18 19 20 21 22 23 24 25 26 27 28 29\n",
+ ""
+ ]
+ },
+ "execution_count": 24,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "To ← {}\n",
- "17 To 29 ⍝ 17 18 19 20 21 22 23 24 25 26 27 28 29"
+ "17 To 29"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 7**:\n",
"\n",
- "Develop a monadic function which puts a frame around a text matrix. For the first version, just concatenate minus signs above and under the matrix, and vertical bars down both sides. Then, update the function to replace the four corners by four `+` signs. For example, with"
+ "Develop a monadic function `Frame` which puts a frame around a text matrix. For the first version, just concatenate minus signs above and under the matrix, and vertical bars down both sides. Then, update the function to replace the four corners by four `+` signs.\n",
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 51,
+ "execution_count": 29,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
- "Canberra \n",
- "Paris \n",
- "Washington\n",
- "Moscow \n",
- "Martigues \n",
- "Mexico \n",
+ "Canberra \n",
+ "Paris \n",
+ "Washington\n",
+ "Moscow \n",
+ "Martigues \n",
+ "Mexico \n",
+ ""
+ ]
+ },
+ "execution_count": 29,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "⊢towns ← 6 10⍴'Canberra Paris WashingtonMoscow Martigues Mexico '"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 31,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "+----------+\n",
+ "|Canberra |\n",
+ "|Paris |\n",
+ "|Washington|\n",
+ "|Moscow |\n",
+ "|Martigues |\n",
+ "|Mexico |\n",
+ "+----------+\n",
""
]
},
- "execution_count": 51,
+ "execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "⊢towns ← 6 10⍴'Canberra Paris WashingtonMoscow Martigues Mexico '"
+ "Frame towns"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
- "we want to have `Frame towns` return\n",
- "\n",
- "```\n",
- "+----------+\n",
- "|Canberra |\n",
- "|Paris |\n",
- "|Washington|\n",
- "|Moscow |\n",
- "|Martigues |\n",
- "|Mexico |\n",
- "+----------+\n",
- "```\n",
- "\n",
- "Finally, you can improve the appearance of the result by changing the function to use line-drawing symbols. You enter line-drawing symbols by using `⎕UCS`, a *system function* that converts characters to integers and vice-versa: the horizontal and vertical lines are"
+ "Finally, you can improve the appearance of the result by changing the function to use line-drawing symbols. You enter line-drawing symbols by using `⎕UCS`, a *system function* that converts characters to integers and vice-versa:"
]
},
{
"cell_type": "code",
- "execution_count": 54,
+ "execution_count": 33,
"metadata": {},
"outputs": [
{
@@ -1541,7 +1851,7 @@
""
]
},
- "execution_count": 54,
+ "execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
@@ -1550,16 +1860,9 @@
"⎕UCS 9472 9474"
]
},
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "and the four corners are"
- ]
- },
{
"cell_type": "code",
- "execution_count": 55,
+ "execution_count": 34,
"metadata": {},
"outputs": [
{
@@ -1569,7 +1872,7 @@
""
]
},
- "execution_count": 55,
+ "execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
@@ -1587,7 +1890,7 @@
},
{
"cell_type": "code",
- "execution_count": 1,
+ "execution_count": 35,
"metadata": {},
"outputs": [
{
@@ -1597,7 +1900,7 @@
""
]
},
- "execution_count": 1,
+ "execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
@@ -1610,85 +1913,150 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "The final result, using the line-drawing symbols, should look like"
+ "After improving your function, the result should look like this:"
]
},
{
"cell_type": "code",
- "execution_count": 54,
- "metadata": {},
- "outputs": [],
+ "execution_count": 27,
+ "metadata": {
+ "scrolled": true,
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "┌──────────┐\n",
+ "│Canberra │\n",
+ "│Paris │\n",
+ "│Washington│\n",
+ "│Moscow │\n",
+ "│Martigues │\n",
+ "│Mexico │\n",
+ "└──────────┘\n",
+ ""
+ ]
+ },
+ "execution_count": 27,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "⍝ ┌──────────┐\n",
- "⍝ │Canberra │\n",
- "⍝ │Paris │\n",
- "⍝ │Washington│\n",
- "⍝ │Moscow │\n",
- "⍝ │Martigues │\n",
- "⍝ │Mexico │\n",
- "⍝ └──────────┘"
+ "Frame towns"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 8**:\n",
"\n",
"It is very likely that the function you wrote for the previous exercise works on matrices but not on vectors. Can you make it work on both?\n",
- "\n",
- "For example, `Frame 'We are not out of the wood'` should give"
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 55,
- "metadata": {},
- "outputs": [],
+ "execution_count": 37,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "┌──────────────────────────┐\n",
+ "│We are not out of the wood│\n",
+ "└──────────────────────────┘\n",
+ ""
+ ]
+ },
+ "execution_count": 37,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "⍝ ┌──────────────────────────┐\n",
- "⍝ │We are not out of the wood│\n",
- "⍝ └──────────────────────────┘"
+ "Frame 'We are not out of the wood'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 9**:\n",
"\n",
- "Write a function which replaces a given letter by another one in a text vector. The letter to replace is given first; the replacing letter is given second, like this:"
+ "Write a function `Switch` which replaces a given letter by another one in a text vector. The letter to replace is given first; the replacing letter is given second.\n",
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 56,
- "metadata": {},
- "outputs": [],
+ "execution_count": 115,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "A bird in che hand is worch cwo in che bush\n",
+ ""
+ ]
+ },
+ "execution_count": 115,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "Switch1 ← {}\n",
- "'tc' Switch1 'A bird in the hand is worth two in the bush'\n",
- "⍝ A bird in che hand is worch cwo in che bush"
+ "'tc' Switch 'A bird in the hand is worth two in the bush'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 10**:\n",
"\n",
- "Modify the previous function so that it commutes the two letters:"
+ "Modify the previous function so that it commutes the two letters.\n",
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 57,
- "metadata": {},
- "outputs": [],
+ "execution_count": 53,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "A berd en thi hand es worth two en thi bush\n",
+ ""
+ ]
+ },
+ "execution_count": 53,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "Switch2 ← {}\n",
- "'ei' Switch2 'A bird in the hand is worth two in the bush'\n",
- "⍝ A berd en thi hand es worth two en thi bush"
+ "'ei' Swap 'A bird in the hand is worth two in the bush'"
]
},
{
@@ -2431,7 +2799,7 @@
},
{
"cell_type": "code",
- "execution_count": 25,
+ "execution_count": 57,
"metadata": {},
"outputs": [
{
@@ -2444,7 +2812,7 @@
""
]
},
- "execution_count": 25,
+ "execution_count": 57,
"metadata": {},
"output_type": "execute_result"
}
@@ -2456,7 +2824,7 @@
},
{
"cell_type": "code",
- "execution_count": 26,
+ "execution_count": 58,
"metadata": {},
"outputs": [
{
@@ -2469,7 +2837,7 @@
""
]
},
- "execution_count": 26,
+ "execution_count": 58,
"metadata": {},
"output_type": "execute_result"
}
@@ -8741,35 +9109,67 @@
"source": [
"## Exercises on Tradfns\n",
"\n",
+ "\n",
"**Exercise 11**:\n",
"\n",
- "Write a function which displays the greatest value in a numeric matrix, along with its position (row and column) in the matrix, for example:"
+ "Write a function which displays the greatest value in a numeric matrix, along with its position (row and column) in the matrix.\n",
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 347,
+ "execution_count": 116,
"metadata": {},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ " 89 166 420 508 12 23\n",
+ "111 453 177 365 284 352\n",
+ "349 192 329 115 515 374\n",
+ "160 467 234 519 485 283\n",
+ ""
+ ]
+ },
+ "execution_count": 116,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "∇ msg ← MaxPlace matrix\n",
- "∇"
+ "actual"
]
},
{
"cell_type": "code",
- "execution_count": 348,
- "metadata": {},
- "outputs": [],
+ "execution_count": 60,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "The greatest value: 519 in row 4, column 4\n",
+ ""
+ ]
+ },
+ "execution_count": 60,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "MaxPlace actual\n",
- "⍝ The greatest value: 519, is in row 4, column 4"
+ "MaxPlace actual"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 12**:\n",
"\n",
"Conversions from Celsius to Fahrenheit degrees and back can be done using the following formulas:\n",
@@ -8777,132 +9177,230 @@
" - `F ← 32+9×C÷5` converts from Celsius to Fahrenheit;\n",
" - `C ← 5×(F-32)÷9` converts from Fahrenheit to Celsius.\n",
" \n",
- " Can you program a function that makes the conversion `C→F` or `F→C` according to its right argument?"
+ "Program a function `Convert` that makes the conversion `C→F` or `F→C` according to its right argument.\n",
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 349,
- "metadata": {},
- "outputs": [],
+ "execution_count": 64,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "30 0 100\n",
+ ""
+ ]
+ },
+ "execution_count": 64,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "∇ converted ← temps Convert conversion\n",
- "∇"
+ "86 32 212 Convert 'F-C'"
]
},
{
"cell_type": "code",
- "execution_count": 350,
- "metadata": {},
- "outputs": [],
+ "execution_count": 65,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "1\n",
+ ""
+ ]
+ },
+ "execution_count": 65,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "86 32 212 Convert 'F-C' ⍝ 30 0 100\n",
- "7 15 25 Convert 'C-F' ⍝ 44.6 59 7"
+ "30 0 100 ≡ 86 32 212 Convert 'F-C'"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 66,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "44.6 59 77\n",
+ ""
+ ]
+ },
+ "execution_count": 66,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "7 15 25 Convert 'C-F'"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 67,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "1\n",
+ ""
+ ]
+ },
+ "execution_count": 67,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "44.6 59 77 ≡ 7 15 25 Convert 'C-F'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 13**:\n",
"\n",
- "Summing the items of a vector is so simple in APL (`+/vec`) that one cannot understand why this simple problem needs a loop in traditional languages! Just for fun, can you program such a loop in APL? Use control structures."
+ "Summing the items of a vector is so simple in APL (`+/vec`) that one cannot understand why this simple problem needs a loop in traditional languages! Just for fun, can you program such a loop in APL? Use control structures.\n",
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 351,
+ "execution_count": 72,
"metadata": {
- "scrolled": true
+ "tags": [
+ "skip-execution"
+ ]
},
"outputs": [
{
"data": {
"text/html": [
- "260\n",
+ "1\n",
""
]
},
- "execution_count": 351,
+ "execution_count": 72,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "+/ 31 37 44 19 27 60 42"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 352,
- "metadata": {},
- "outputs": [],
- "source": [
- "∇ sum ← LoopSum vec\n",
- "∇"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 353,
- "metadata": {},
- "outputs": [],
- "source": [
- "LoopSum 31 37 44 19 27 60 42 ⍝ 260"
+ "260 ≡ LoopSum 31 37 44 19 27 60 42"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 14:**\n",
"\n",
- "In exercise 3 you were asked to reverse the order of a vector of items. Even if it is a strange idea, can you do the same operation using a loop, moving letter after letter?"
+ "In [exercise 3](ex-reverse) you were asked to reverse the order of a vector of items. Even if it is a strange idea, can you do the same operation using a loop, moving letter after letter?\n",
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 354,
- "metadata": {},
- "outputs": [],
+ "execution_count": 80,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "retteb hcum saw pool tuohtiw noitulos ehT\n",
+ ""
+ ]
+ },
+ "execution_count": 80,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "∇ reversed ← ReverLoop vec\n",
- "∇"
+ "ReverLoop 'The solution without loop was much better'"
]
},
{
"cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
+ "execution_count": 81,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "1\n",
+ ""
+ ]
+ },
+ "execution_count": 81,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "ReverLoop 'The solution without loop was much better'\n",
- "⍝ retteb hcum saw pool tuohtiw noitulos ehT"
+ "'retteb hcum saw pool tuohtiw noitulos ehT' ≡ ReverLoop 'The solution without loop was much better'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 15**:\n",
"\n",
"In a given numeric matrix with $n$ columns, we would like to insert subtotals after each group of $g$ columns (where $g$ is a divisor of $n$).\n",
"\n",
- "Try to write a function to do that, following these 3 steps:\n",
+ "Try to write a function `SubSum` to do that, following these 3 steps:\n",
"\n",
" 1. reshape the matrix so that it fits in $g$ columns only, with the necessary number of rows to contain all the values;\n",
" 2. catenate, on the right, the totals of each row; and\n",
" 3. reshape again that new matrix to obtain the final result.\n",
- " \n",
+ "\n",
+ "\n",
"In the examples below, the original matrix appears in black and the subtotals appear in grey:"
]
},
{
"cell_type": "code",
- "execution_count": 10,
- "metadata": {
- "scrolled": true
- },
+ "execution_count": 96,
+ "metadata": {},
"outputs": [
{
"data": {
@@ -8914,7 +9412,7 @@
""
]
},
- "execution_count": 10,
+ "execution_count": 96,
"metadata": {},
"output_type": "execute_result"
}
@@ -8951,44 +9449,113 @@
]
},
{
- "cell_type": "markdown",
- "metadata": {},
+ "cell_type": "code",
+ "execution_count": 102,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "1\n",
+ ""
+ ]
+ },
+ "execution_count": 102,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "**Exercise 16**:\n",
- "\n",
- "This is a very classic problem: we want to partition a text vector each time a given separator is found and make a matrix from these pieces. Please bear in mind that is exercise is very manageable if you let yourself use a couple of control flow structures. However, solving this exercise with a dfn requires you to make an ingenious use of a primitive we have covered previously."
+ "r ← 89 166 420 675 508 12 23 543\n",
+ "r ← r,111 453 177 741 365 284 352 1001\n",
+ "r ← r,349 192 329 870 115 515 374 1004\n",
+ "r ← r,160 467 234 861 519 485 283 1287\n",
+ "(4 8⍴r) ≡ 3 SubSum actual"
]
},
{
"cell_type": "code",
- "execution_count": 106,
+ "execution_count": 103,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "1\n",
+ ""
+ ]
+ },
+ "execution_count": 103,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "r ← 89 166 255 420 508 928 12 23 35\n",
+ "r ← r,111 453 564 177 365 542 284 352 636\n",
+ "r ← r,349 192 541 329 115 444 515 374 889\n",
+ "r ← r,160 467 627 234 519 753 485 283 768\n",
+ "(4 9⍴r) ≡ 2 SubSum actual"
+ ]
+ },
+ {
+ "cell_type": "markdown",
"metadata": {},
- "outputs": [],
"source": [
- "∇ mat ← sep Sorry string\n",
- "∇"
+ "\n",
+ "**Exercise 16**:\n",
+ "\n",
+ "This is a very classic problem: we want to partition a text vector each time a given separator is found and make a matrix from these pieces.\n",
+ "Implement this functionality in a monadic function `Separate`.\n",
+ "\n",
+ "\n",
+ "Please bear in mind that is exercise is very manageable if you let yourself use a couple of control flow structures. \n",
+ "However, solving this exercise with a dfn requires you to make an ingenious use of a primitive we have covered previously."
]
},
{
"cell_type": "code",
- "execution_count": 107,
- "metadata": {},
- "outputs": [],
+ "execution_count": 105,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "You \n",
+ "will \n",
+ "need a \n",
+ "loop \n",
+ "to solve\n",
+ "this \n",
+ ""
+ ]
+ },
+ "execution_count": 105,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "'/' Sorry 'You/will/need a/loop/to solve/this/exercise'\n",
- "⍝ You\n",
- "⍝ will\n",
- "⍝ need a\n",
- "⍝ loop\n",
- "⍝ to solve\n",
- "⍝ this\n",
- "⍝ exercise"
+ "'/' Separate 'You/will/need a/loop/to solve/this/exercise'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 17**:\n",
"\n",
"Remember when we talked about the [\"Collatz Conjecture\"](https://en.wikipedia.org/wiki/Collatz_conjecture) earlier on? Don't worry if you don't. Now, you will implement a function that takes a positive integer `n` and creates a vector of numbers by successively taking the most recent number and then creating the next value according to a couple of rules:\n",
@@ -8996,30 +9563,107 @@
" - if the most recent number is **even**, the next value will be half of it;\n",
" - if the most recent number is **odd**, the next value will be 1 more than the triple of it; and\n",
" - you stop when you reach 1.\n",
- " \n",
- "For example, starting with `5` you get `5 16 8 4 2 1`.\n",
- "\n",
- "It is believed that no matter what initial positive integer `n` you give it, this process always stops at 1."
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 108,
- "metadata": {},
- "outputs": [],
+ "execution_count": 109,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "5 16 8 4 2 1\n",
+ ""
+ ]
+ },
+ "execution_count": 109,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "∇ path ← CollatzPath n\n",
- "∇"
+ "CollatzPath 5"
]
},
{
"cell_type": "code",
- "execution_count": 109,
- "metadata": {},
- "outputs": [],
+ "execution_count": 111,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "1\n",
+ ""
+ ]
+ },
+ "execution_count": 111,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "5 16 8 4 2 1 ≡ CollatzPath 5"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 110,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "37 112 56 28 14 7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1\n",
+ ""
+ ]
+ },
+ "execution_count": 110,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "CollatzPath 37"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 112,
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "1\n",
+ ""
+ ]
+ },
+ "execution_count": 112,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "CollatzPath 37\n",
- "⍝ 37 112 56 28 14 7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1"
+ "37 112 56 28 14 7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1 ≡ CollatzPath 37"
]
},
{
@@ -10654,6 +11298,7 @@
"source": [
"## Solutions\n",
"\n",
+ "\n",
"**Exercise 1**:\n",
"\n",
"If `⍵` is the vector argument, we can use `⍵[...]` to index into `⍵` and then we can use the _index generator_ primitive to generate the indices we need, which should be the integers from `1` to `⍺`... Except that if `⍺` is too big, we cannot generate indices larger than the length of the vector, so we also find the minimum between `⍺` and `≢⍵`. If we don't, we get a `INDEX ERROR` when indexing. Here is a possible implementation:"
@@ -10738,6 +11383,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 2**:\n",
"\n",
"We can use a reasoning similar to that of the first exercise, except now we want to start the indices at `⍺+1` and go up until `≢⍵`. For this to happen, we first need to find out how many numbers we need. If a vector has `≢⍵` elements and we are going to drop `⍺` of them, we are going to be left with `(≢⍵)-⍺`. This means `⍳(≢⍵)-⍺` will generate the correct amount of indices, but they will be starting at `1` and should start at `⍺+1`, so we just need to add `⍺` to that.\n",
@@ -10824,6 +11470,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 3**:\n",
"\n",
"This is another exercise on index arithmetic. Here is what we want to happen with a vector argument of length 10:\n",
@@ -10920,6 +11567,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 4**:\n",
"\n",
"This exercise can be solved by using the operator _reduce_ to sum: `+/`. Then we need to specify the axis we care about with `[1]` and `[2]`.\n",
@@ -11043,6 +11691,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 5**:\n",
"\n",
"When reading this exercise, one should immediately realise that we are going to need to find _where_ the blank spaces are:"
@@ -11314,6 +11963,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 6**:\n",
"\n",
"We have seen in [a previous section](./Some-Primitive-Functions.ipynb#Basic-Usage) how to create any arithmetic sequence of integers. This is just a special case of the algorithm given, with `Step ← 1`:"
@@ -11356,6 +12006,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 7**:\n",
"\n",
"This exercise is easier than it might look because the primitives to catenate vertically and horizontally, `⍪` and `,`, know how to deal with a matrix and a single scalar:"
@@ -11363,7 +12014,7 @@
},
{
"cell_type": "code",
- "execution_count": 63,
+ "execution_count": 114,
"metadata": {},
"outputs": [
{
@@ -11378,7 +12029,7 @@
""
]
},
- "execution_count": 63,
+ "execution_count": 114,
"metadata": {},
"output_type": "execute_result"
}
@@ -11548,6 +12199,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 8**:\n",
"\n",
"Well, what if the solution we wrote actually works for vectors? Let's give it a try:"
@@ -11720,6 +12372,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 9**:\n",
"\n",
"The logic to solving this task resembles what we did in the first exercises. First we will find *Where* the first letter is, and then we will use indexing to put the second letter in those positions:"
@@ -11727,12 +12380,12 @@
},
{
"cell_type": "code",
- "execution_count": 85,
+ "execution_count": 83,
"metadata": {},
"outputs": [],
"source": [
"]dinput\n",
- "Switch1 ← {\n",
+ "Switch ← {\n",
" r ← ⍵\n",
" r[⍸⍺[1]=⍵] ← ⍺[2]\n",
" r\n",
@@ -11741,7 +12394,7 @@
},
{
"cell_type": "code",
- "execution_count": 86,
+ "execution_count": 84,
"metadata": {},
"outputs": [
{
@@ -11751,13 +12404,13 @@
""
]
},
- "execution_count": 86,
+ "execution_count": 84,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "'tc' Switch1 'A bird in the hand is worth two in the bush'"
+ "'tc' Switch 'A bird in the hand is worth two in the bush'"
]
},
{
@@ -11771,6 +12424,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 10**:\n",
"\n",
"A very obvious modification of the function above is to write"
@@ -11778,12 +12432,12 @@
},
{
"cell_type": "code",
- "execution_count": 87,
+ "execution_count": 85,
"metadata": {},
"outputs": [],
"source": [
"]dinput\n",
- "Switch2 ← {\n",
+ "Swap ← {\n",
" r ← ⍵\n",
" r[⍸⍺[1]=⍵] ← ⍺[2]\n",
" r[⍸⍺[2]=⍵] ← ⍺[1]\n",
@@ -11793,7 +12447,7 @@
},
{
"cell_type": "code",
- "execution_count": 88,
+ "execution_count": 87,
"metadata": {},
"outputs": [
{
@@ -11803,13 +12457,13 @@
""
]
},
- "execution_count": 88,
+ "execution_count": 87,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "'ei' Switch2 'A bird in the hand is worth two in the bush'"
+ "'ei' Swap 'A bird in the hand is worth two in the bush'"
]
},
{
@@ -11821,12 +12475,12 @@
},
{
"cell_type": "code",
- "execution_count": 89,
+ "execution_count": 88,
"metadata": {},
"outputs": [],
"source": [
"]dinput\n",
- "Switch2 ← {\n",
+ "Swap ← {\n",
" pos ← (⍺,⍵)⍳⍵\n",
" (⍺[2 1],⍵)[pos]\n",
"}"
@@ -11850,7 +12504,7 @@
}
],
"source": [
- "'ei' Switch2 'A bird in the hand is worth two in the bush'"
+ "'ei' Swap 'A bird in the hand is worth two in the bush'"
]
},
{
@@ -11868,7 +12522,7 @@
"\n",
"For every character, we first look for it in the first line, stopping as soon as we find it (that is what `⍳` does) and then we swap it with the corresponding character in the line below.\n",
"\n",
- "We can thus re-implement `Switch2` with more intermediate steps, to make this more obvious:"
+ "We can thus re-implement `Swap` with more intermediate steps, to make this more obvious:"
]
},
{
@@ -11878,7 +12532,7 @@
"outputs": [],
"source": [
"]dinput\n",
- "Switch2 ← {\n",
+ "Swap ← {\n",
" ⎕← initialSet ← ⍺,⍵\n",
" pos ← initialSet⍳⍵\n",
" ⎕← finalSet ← ⍺[2 1],⍵\n",
@@ -11908,13 +12562,14 @@
}
],
"source": [
- "'ei' Switch2 'A bird in the hand is worth two in the bush'"
+ "'ei' Swap 'A bird in the hand is worth two in the bush'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 11**:\n",
"\n",
"If you are thinking about doing this exercise with a double `:For` loop then you are thinking it wrong, because APL has two primitives that are particularly well-suited for this job: the primitive _index of_, that you learned about in [here](./Some-Primitive-Functions.ipynb#Position-Index-Of), and the primitive _where_, that you learned about in [here](./Some-Primitive-Functions.ipynb#Where).\n",
@@ -11924,7 +12579,7 @@
},
{
"cell_type": "code",
- "execution_count": 93,
+ "execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
@@ -12134,6 +12789,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 12**:\n",
"\n",
"A straightforward solution to this exercise would involve a tradfn with an `:If` statement to select which formula to use:"
@@ -12336,6 +12992,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 13**:\n",
"\n",
"Solving this exercise is a straightforward application of what you learned in the section about control structures:"
@@ -12387,6 +13044,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 14**:\n",
"\n",
"Once again, solving this exercise is a straightforward application of what you learned in the section on control structures:"
@@ -12394,38 +13052,37 @@
},
{
"cell_type": "code",
- "execution_count": 113,
+ "execution_count": 94,
"metadata": {},
"outputs": [],
"source": [
"∇ reversed ← ReverLoop vec; item\n",
" reversed ← ⍬\n",
" :For item :In vec\n",
- " reversed ← reversed,item\n",
+ " reversed ← item,reversed\n",
" :EndFor\n",
"∇"
]
},
{
"cell_type": "code",
- "execution_count": 114,
+ "execution_count": 95,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
- "The solution without loop was much better\n",
+ "retteb hcum saw pool tuohtiw noitulos ehT\n",
""
]
},
- "execution_count": 114,
+ "execution_count": 95,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "ReverLoop 'The solution without loop was much better'\n",
- "⍝ retteb hcum saw pool tuohtiw noitulos ehT"
+ "ReverLoop 'The solution without loop was much better'"
]
},
{
@@ -12439,6 +13096,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 15**:\n",
"\n",
"This exercise has a very helpful hint that should greatly simplify it.\n",
@@ -12519,6 +13177,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 16**:\n",
"\n",
"The main difficulty of this exercise is in managing the lengths of all the rows of the final character matrix. As we loop over the different \"slices\" of the input vector, we need to append them to the final character matrix while making sure all rows have the appropriate size, as dictated by the longest slice.\n",
@@ -12768,7 +13427,7 @@
},
{
"cell_type": "code",
- "execution_count": 126,
+ "execution_count": 106,
"metadata": {},
"outputs": [
{
@@ -12784,14 +13443,14 @@
""
]
},
- "execution_count": 126,
+ "execution_count": 106,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "Sorry ← {↑⍵⊆⍨⍺≠⍵}\n",
- "'/' Sorry 'You/will/need a/loop/to solve/this/exercise'"
+ "Separate ← {↑⍵⊆⍨⍺≠⍵}\n",
+ "'/' Separate 'You/will/need a/loop/to solve/this/exercise'"
]
},
{
@@ -12805,7 +13464,7 @@
},
{
"cell_type": "code",
- "execution_count": 127,
+ "execution_count": 107,
"metadata": {},
"outputs": [
{
@@ -12821,14 +13480,14 @@
""
]
},
- "execution_count": 127,
+ "execution_count": 107,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "Sorry ← ↑≠⊆⊢\n",
- "'/' Sorry 'You/will/need a/loop/to solve/this/exercise'"
+ "Separate ← ↑≠⊆⊢\n",
+ "'/' Separate 'You/will/need a/loop/to solve/this/exercise'"
]
},
{
@@ -12844,6 +13503,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "\n",
"**Exercise 17**:\n",
"\n",
"This was already done when we introduced `:While` loops in [the section about control flow](#Top-Controlled-Loop-(:While/:EndWhile)), and the implementation there did not make use of an `:If... :Else` statement to decide which of the two branching options we should choose:"
@@ -13078,6 +13738,7 @@
}
],
"metadata": {
+ "celltoolbar": "Tags",
"kernelspec": {
"display_name": "Dyalog APL",
"language": "apl",
diff --git a/Working-on-Data-Shape.ipynb b/Working-on-Data-Shape.ipynb
index f197199..bf5251d 100644
--- a/Working-on-Data-Shape.ipynb
+++ b/Working-on-Data-Shape.ipynb
@@ -4280,14 +4280,32 @@
"source": [
"## Exercises\n",
"\n",
+ "\n",
"**Exercise 1**:\n",
"\n",
- "You are given this matrix:"
+ "Given the matrix `xg1` below, try to produce each of the three following matrices; first using only _take_, and then only _drop_.\n",
+ "\n",
+ "```APL\n",
+ "5 3 6\n",
+ "8 2 3\n",
+ "```\n",
+ "\n",
+ "```APL\n",
+ "5 4 8 2\n",
+ "7 7 6 2\n",
+ "```\n",
+ "\n",
+ "```APL\n",
+ "9 5 3\n",
+ "4 8 2\n",
+ "7 6 2\n",
+ "```\n",
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 134,
+ "execution_count": 1,
"id": "tropical-jenny",
"metadata": {},
"outputs": [
@@ -4300,7 +4318,7 @@
""
]
},
- "execution_count": 134,
+ "execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
@@ -4309,35 +4327,12 @@
"⎕← xg1 ← 3 5⍴1 9 5 3 6 5 4 8 2 3 7 7 6 2 6"
]
},
- {
- "cell_type": "markdown",
- "id": "serious-appendix",
- "metadata": {},
- "source": [
- "Try to produce each of the three following matrices, using first only _take_, and then only _drop_:\n",
- "\n",
- "```APL\n",
- "5 3 6\n",
- "8 2 3\n",
- "```\n",
- "\n",
- "```APL\n",
- "5 4 8 2\n",
- "7 7 6 2\n",
- "```\n",
- "\n",
- "```APL\n",
- "9 5 3\n",
- "4 8 2\n",
- "7 6 2\n",
- "```"
- ]
- },
{
"cell_type": "markdown",
"id": "composite-columbus",
"metadata": {},
"source": [
+ "\n",
"**Exercise 2**:\n",
"\n",
"With `xg1` again, how could you produce this:\n",
@@ -4347,63 +4342,75 @@
"5 4 8 2 3 0\n",
"7 7 6 2 6 0\n",
"0 0 0 0 0 0\n",
- "```"
+ "```\n",
+ ""
]
},
{
"cell_type": "markdown",
- "id": "tight-meter",
+ "id": "hazardous-terminology",
"metadata": {},
"source": [
+ "\n",
"**Exercise 3**:\n",
"\n",
- "Write a dyadic function `TakeShape` that computes the _shape_ of the result of doing `ns↑array`.\n",
- "The left argument to `TakeShape` will be `ns` and the right argument will be `⍴array`.\n",
+ "Write two dyadic functions `TakeShape` and `DropShape`.\n",
+ "`TakeShape` computes `⍴ns↑array` and `DropShape` computes `⍴ns↓array`.\n",
+ "The left argument to both functions will be `ns` and the right argument will be `⍴array`.\n",
"You can assume that the left argument and right arguments are valid and make sense together.\n",
- "\n",
- "Also implement `DropShape`, that does the same thing as `TakeShape`, but for _drop_ instead of for _take_."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 135,
- "id": "posted-heritage",
- "metadata": {},
- "outputs": [],
- "source": [
- "TakeShape ← {}"
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 136,
+ "execution_count": 7,
"id": "daily-colonial",
- "metadata": {},
- "outputs": [],
- "source": [
- "2 ¯3 TakeShape 1 5 10\n",
- "⍝ 2 3 10"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 137,
- "id": "eight-peninsula",
- "metadata": {},
- "outputs": [],
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "2 3 10\n",
+ ""
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "DropShape ← {}"
+ "2 ¯3 TakeShape 1 5 10"
]
},
{
"cell_type": "code",
- "execution_count": 138,
+ "execution_count": 8,
"id": "recovered-northwest",
- "metadata": {},
- "outputs": [],
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "0 6 7\n",
+ ""
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "15 4 ¯3 DropShape 10 10 10\n",
- "⍝ 0 6 7"
+ "15 4 ¯3 DropShape 10 10 10"
]
},
{
@@ -4411,11 +4418,14 @@
"id": "controlling-thickness",
"metadata": {},
"source": [
+ "\n",
"**Exercise 4**:\n",
"\n",
"Write two dyadic functions, `TakeAsDrop` and `DropAsTake`, that take an array on the right and a vector on the left.\n",
"`r ← v TakeAsDrop a` is such that `(r↓a)≡v↑a` whenever possible, and conversely for `DropAsTake`: `r ← v DropAsTake` is such that `(r↑a)≡v↓a` whenever possible.\n",
- "Test your functions with your solutions to exercise 1."
+ "\n",
+ "\n",
+ "Test your functions with your solutions to the first exercise."
]
},
{
@@ -4423,31 +4433,38 @@
"id": "round-arbitration",
"metadata": {},
"source": [
+ "\n",
"**Exercise 5**:\n",
"\n",
- "Write a function which \"highlights\" all the vowels of a given character vector by placing an arrow under them:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 139,
- "id": "collect-appreciation",
- "metadata": {},
- "outputs": [],
- "source": [
- "ShowVowels ← {}"
+ "Write a function which \"highlights\" all the vowels of a given character vector by placing an arrow under them.\n",
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 140,
+ "execution_count": 12,
"id": "naval-asset",
- "metadata": {},
- "outputs": [],
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "This function works properly\n",
+ " ↑ ↑ ↑↑ ↑ ↑ ↑ ↑\n",
+ ""
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "ShowVowels 'This function works properly'\n",
- "⍝ This function works properly\n",
- "⍝ ↑ ↑ ↑↑ ↑ ↑ ↑ ↑"
+ "ShowVowels 'This function works properly'"
]
},
{
@@ -4455,14 +4472,21 @@
"id": "collective-screen",
"metadata": {},
"source": [
+ "\n",
"**Exercise 6**:\n",
"\n",
- "Some matrices are mainly filled with zeroes, like the matrix `xg4` shown below:"
+ "Write two monadic functions:\n",
+ "\n",
+ " - `Contract` takes a sparse matrix and returns a more compact representation of the same matrix; and\n",
+ " - `Restore` takes a compact representation of a sparse matrix and builds the full matrix.\n",
+ "\n",
+ "\n",
+ "For reference, a sparse matrix is a matrix that contains mostly zeroes, like the matrix `xg6` shown below:"
]
},
{
"cell_type": "code",
- "execution_count": 141,
+ "execution_count": 14,
"id": "forty-optimum",
"metadata": {},
"outputs": [
@@ -4476,7 +4500,7 @@
""
]
},
- "execution_count": 141,
+ "execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
@@ -4492,10 +4516,9 @@
"id": "lyric-malta",
"metadata": {},
"source": [
- "These are called _sparse matrices_.\n",
- "\n",
"A large sparse matrix may occupy a lot of memory.\n",
- "To reduce the memory consumption, we can ravel the matrix,"
+ "To reduce the memory consumption, we can consider an alternative, more compact representation.\n",
+ "For example, we can start by ravelling the matrix:"
]
},
{
@@ -4525,18 +4548,18 @@
"id": "mechanical-karma",
"metadata": {},
"source": [
- "retaining only the positive values together with their position in the ravel:"
+ "Then, we retain only the non-zero values together with their position in the ravel:"
]
},
{
"cell_type": "code",
- "execution_count": 143,
+ "execution_count": 16,
"id": "vertical-ratio",
"metadata": {},
"outputs": [],
"source": [
- "positiveValues ← 8 3 7 6 2 1 4\n",
- "positions ← 3 6 9 15 17 21 26"
+ "values ← 8 3 7 6 2 1 4\n",
+ "positions ← 3 6 9 15 17 21 26"
]
},
{
@@ -4544,50 +4567,104 @@
"id": "failing-bunny",
"metadata": {},
"source": [
- "If now we add the shape of the matrix on the left, we have all the necessary information to restore the original matrix when required:\n",
+ "Now, if we add the shape of the matrix on the left, we have all the necessary information to restore the original matrix when required:\n",
"\n",
"```APL\n",
- " 4 8 3 7 6 2 1 4\n",
- " 7 3 6 9 15 17 21 26\n",
- "⍝↑ shape of the original matrix\n",
- "```\n",
- "\n",
- "Can you write\n",
- "\n",
- " - a function which creates this compact form (let us call the function `Contraction`); and\n",
- " - a function `Restore` which retrieves the original matrix from its compact form?"
+ " 4 8 3 7 6 2 1 4 ⍝ values\n",
+ " 7 3 6 9 15 17 21 26 ⍝ positions\n",
+ "⍝ ^ shape of the original matrix\n",
+ "```"
]
},
{
- "cell_type": "markdown",
- "id": "european-fluid",
- "metadata": {},
+ "cell_type": "code",
+ "execution_count": 19,
+ "id": "single-waterproof",
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "4 8 3 7 6 2 1 4\n",
+ "7 3 6 9 15 17 21 26\n",
+ ""
+ ]
+ },
+ "execution_count": 19,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "**Exercise 7**:\n",
- "\n",
- "In a given character vector, we would like to replace all the occurrences of a given letter with blanks:"
+ "Contract xg6"
]
},
{
"cell_type": "code",
- "execution_count": 144,
- "id": "arabic-parent",
+ "execution_count": 21,
+ "id": "adjusted-short",
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "1\n",
+ ""
+ ]
+ },
+ "execution_count": 21,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "xg6 ≡ Restore Contract xg6"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "european-fluid",
"metadata": {},
- "outputs": [],
"source": [
- "sentence ← 'Panama is a canal between Atlantic and Pacific'\n",
- "Whiten ← {}"
+ "\n",
+ "**Exercise 7**:\n",
+ "\n",
+ "Write a dyadic function `Whiten` that replaces all occurrences of the character scalar left argument in the character vector right argument with blanks.\n",
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 145,
+ "execution_count": 24,
"id": "changed-party",
- "metadata": {},
- "outputs": [],
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "P n m is c n l between Atl ntic nd P cific\n",
+ ""
+ ]
+ },
+ "execution_count": 24,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "'a' Whiten sentence\n",
- "⍝ P n m is c n l between Atl ntic nd P cific"
+ "'a' Whiten 'Panama is a canal between Atlantic and Pacific'"
]
},
{
@@ -4595,7 +4672,7 @@
"id": "constitutional-stretch",
"metadata": {},
"source": [
- "Find a solution using _expand_."
+ "Can you find a solution that uses the function _expand_?"
]
},
{
@@ -4603,37 +4680,55 @@
"id": "variable-flavor",
"metadata": {},
"source": [
+ "\n",
"**Exercise 8**:\n",
"\n",
- "Write a dyadic function to centre a title above a character matrix, like this:"
+ "Write a dyadic function `OnTop` to centre a title above a character matrix.\n",
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 146,
+ "execution_count": 32,
"id": "informational-breast",
"metadata": {},
"outputs": [],
"source": [
- "OnTop ← {}"
+ "monMat ← 6 8⍴'January FebruaryMarch April May June '"
]
},
{
"cell_type": "code",
- "execution_count": 147,
+ "execution_count": 33,
"id": "perfect-chaos",
- "metadata": {},
- "outputs": [],
+ "metadata": {
+ "scrolled": true,
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ " 2022 \n",
+ "--------\n",
+ "January \n",
+ "February\n",
+ "March \n",
+ "April \n",
+ "May \n",
+ "June \n",
+ ""
+ ]
+ },
+ "execution_count": 33,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "'2007' OnTop monMat\n",
- "⍝ 2007\n",
- "⍝ --------\n",
- "⍝ January\n",
- "⍝ February\n",
- "⍝ March\n",
- "⍝ April\n",
- "⍝ May\n",
- "⍝ June"
+ "'2022' OnTop monMat"
]
},
{
@@ -4641,14 +4736,16 @@
"id": "detected-voltage",
"metadata": {},
"source": [
+ "\n",
"**Exercise 9**:\n",
"\n",
- "You are given this matrix:"
+ "Determine the result of the expression `¯3 ¯1 3⌽(-2 1 0 1 0 2 1 2 0)⊖xg9` for the matrix `xg9` given below.\n",
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 148,
+ "execution_count": 34,
"id": "understanding-array",
"metadata": {},
"outputs": [
@@ -4661,7 +4758,7 @@
""
]
},
- "execution_count": 148,
+ "execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
@@ -4670,98 +4767,170 @@
"⎕← xg9 ← 3 9⍴'oeornlhtu n siduothf uogYti'"
]
},
- {
- "cell_type": "markdown",
- "id": "bronze-september",
- "metadata": {},
- "source": [
- "What is the result of the expression `¯3 ¯1 3⌽(-2 1 0 1 0 2 1 2 0)⊖xg9`?"
- ]
- },
{
"cell_type": "markdown",
"id": "lined-response",
"metadata": {},
"source": [
+ "\n",
"**Exercise 10**:\n",
"\n",
- "You are given a Boolean vector like the following:"
+ "Write a dyadic function `Free` which looks for a sequence of contiguous zeroes in a Boolean vector.\n",
+ "The right argument is the Boolean vector in which to look for the sequence of zeroes and the left argument is the integer that specifies the sequence length to look for.\n",
+ "The function should return the position of the first zero of the first such sequence and, if no such sequence exists, it should return `0`.\n",
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 149,
+ "execution_count": 38,
"id": "emotional-mississippi",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
- "1 0 0 1 1 1 0 1 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 0 0\n",
+ "1 0 0 1 1 1 0 0 1 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 0 0\n",
""
]
},
- "execution_count": 149,
+ "execution_count": 38,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "⎕← xg10 ← 1 0 0 1 1 1 0 1 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 0 0"
+ "⎕← xg10 ← 1 0 0 1 1 1 0 0 1 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 1 0 0"
]
},
{
- "cell_type": "markdown",
- "id": "respected-logging",
- "metadata": {},
+ "cell_type": "code",
+ "execution_count": 41,
+ "id": "smaller-plenty",
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "0\n",
+ ""
+ ]
+ },
+ "execution_count": 41,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "We would like to find a list of `n` contiguous zeroes in this vector.\n",
- "Write a function which gives the position of the first zero of the first such list found.\n",
- "If there is no list of `n` zeroes, the function is supposed to return 0.\n",
- "Loops are (of course) strictly forbidden!"
+ "1 Free xg10"
]
},
{
"cell_type": "code",
- "execution_count": 150,
- "id": "alpha-lending",
- "metadata": {},
- "outputs": [],
+ "execution_count": 42,
+ "id": "acute-association",
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "2\n",
+ ""
+ ]
+ },
+ "execution_count": 42,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "Free ← {}"
+ "2 Free xg10"
]
},
{
"cell_type": "code",
- "execution_count": 151,
+ "execution_count": 43,
"id": "cultural-court",
- "metadata": {},
- "outputs": [],
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "10\n",
+ ""
+ ]
+ },
+ "execution_count": 43,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "3 Free xg10\n",
- "⍝ 9"
+ "3 Free xg10"
]
},
{
"cell_type": "code",
- "execution_count": 152,
- "id": "cardiovascular-tanzania",
- "metadata": {},
- "outputs": [],
+ "execution_count": 44,
+ "id": "physical-census",
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "15\n",
+ ""
+ ]
+ },
+ "execution_count": 44,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "6 Free xg10\n",
- "⍝ 0"
+ "4 Free xg10"
]
},
{
"cell_type": "code",
- "execution_count": 153,
- "id": "continued-faculty",
- "metadata": {},
- "outputs": [],
+ "execution_count": 45,
+ "id": "ordered-spectrum",
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "0\n",
+ ""
+ ]
+ },
+ "execution_count": 45,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "4 Free xg10\n",
- "⍝ 14"
+ "6 Free xg10"
]
},
{
@@ -4769,14 +4938,17 @@
"id": "reduced-benefit",
"metadata": {},
"source": [
+ "\n",
"**Exercise 11**:\n",
"\n",
- "The following is a long matrix of names:"
+ "Write a dyadic function `ToColumns` that takes an integer scalar left argument and a character matrix right argument.\n",
+ "The function should split the matrix into as many columns as the left argument specifies. Columns should be separated by, at least, a blank.\n",
+ ""
]
},
{
"cell_type": "code",
- "execution_count": 154,
+ "execution_count": 46,
"id": "introductory-thirty",
"metadata": {},
"outputs": [
@@ -4797,7 +4969,7 @@
""
]
},
- "execution_count": 154,
+ "execution_count": 46,
"metadata": {},
"output_type": "execute_result"
}
@@ -4806,44 +4978,33 @@
"⎕← xg11 ← 11 8⍴'Emily Luciano Paul Oxana Thor Carmen VeronicaWilliam VladimirMonica Colette '"
]
},
- {
- "cell_type": "markdown",
- "id": "joined-essay",
- "metadata": {},
- "source": [
- "Write a function to split this matrix into slices, and position these slices one next to the other, like this:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 155,
- "id": "adaptive-train",
- "metadata": {},
- "outputs": [],
- "source": [
- "Split ← {}"
- ]
- },
{
"cell_type": "code",
- "execution_count": 156,
+ "execution_count": 49,
"id": "distinct-partner",
- "metadata": {},
- "outputs": [],
- "source": [
- "3 Split xg11\n",
- "⍝ Emily Thor Vladimir\n",
- "⍝ Luciano Carmen Monica\n",
- "⍝ Paul Veronica Colette\n",
- "⍝ Oxana William"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "threatened-count",
- "metadata": {},
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "Emily Thor Vladimir\n",
+ "Luciano Carmen Monica \n",
+ "Paul Veronica Colette \n",
+ "Oxana William \n",
+ ""
+ ]
+ },
+ "execution_count": 49,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "The number of slices is passed as the left argument and a blank is inserted between the slices."
+ "3 ToColumns xg11"
]
},
{
@@ -4851,14 +5012,19 @@
"id": "spread-hayes",
"metadata": {},
"source": [
+ "\n",
"**Exercise 12**:\n",
"\n",
- "You are given a numeric vector:"
+ "Write a dyadic function `ShowCodes` that takes a numeric vector left argument and a character matrix right argument.\n",
+ "The function should display the numerical codes on the left of the rows of the argument matrix, but with a blank row every time the code changes.\n",
+ "\n",
+ "\n",
+ "Notice that, in the example below, the vector `xg12` with the codes has length equal to the number of rows in `xg11`."
]
},
{
"cell_type": "code",
- "execution_count": 157,
+ "execution_count": 51,
"id": "mighty-turtle",
"metadata": {},
"outputs": [],
@@ -4866,50 +5032,44 @@
"xg12 ← 22 22 74 74 74 74 30 65 65 65 19"
]
},
- {
- "cell_type": "markdown",
- "id": "binding-symposium",
- "metadata": {},
- "source": [
- "It has the same number of items as there are names in the variable `xg9` from the previous exercise.\n",
- "It is composed of groups of identical codes.\n",
- "\n",
- "Write a function which displays side by side this vector of codes and the associated matrix of names, with an empty line inserted each time the code changes, like this:"
- ]
- },
{
"cell_type": "code",
- "execution_count": 158,
- "id": "experimental-letter",
- "metadata": {},
- "outputs": [],
- "source": [
- "Expand ← {}"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 159,
+ "execution_count": 69,
"id": "material-simon",
- "metadata": {},
- "outputs": [],
+ "metadata": {
+ "tags": [
+ "skip-execution"
+ ]
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "22 Emily \n",
+ "22 Luciano \n",
+ " \n",
+ "74 Paul \n",
+ "74 Oxana \n",
+ "74 Thor \n",
+ "74 Carmen \n",
+ " \n",
+ "30 Veronica\n",
+ " \n",
+ "65 William \n",
+ "65 Vladimir\n",
+ "65 Monica \n",
+ " \n",
+ "19 Colette \n",
+ ""
+ ]
+ },
+ "execution_count": 69,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "xg12 Expand xg11\n",
- "⍝ 22 Emily\n",
- "⍝ 22 Luciano\n",
- "⍝\n",
- "⍝ 74 Paul\n",
- "⍝ 74 Oxana\n",
- "⍝ 74 Thor\n",
- "⍝ 74 Carmen\n",
- "⍝\n",
- "⍝ 30 Veronica\n",
- "⍝\n",
- "⍝ 65 William\n",
- "⍝ 65 Vladimir\n",
- "⍝ 65 Monica\n",
- "⍝\n",
- "⍝ 19 Colette"
+ "xg12 ShowCodes xg11"
]
},
{
@@ -5452,6 +5612,7 @@
"\n",
"We advise you to try and solve the exercises before reading the solutions!\n",
"\n",
+ "\n",
"**Exercise 1**:\n",
"\n",
"Starting from `xg1`,"
@@ -5708,6 +5869,7 @@
"id": "identical-sacramento",
"metadata": {},
"source": [
+ "\n",
"**Exercise 2**:\n",
"\n",
"We want to produce the matrix\n",
@@ -5753,6 +5915,7 @@
"id": "objective-pierce",
"metadata": {},
"source": [
+ "\n",
"**Exercise 3**:\n",
"\n",
"Let us start with `TakeShape`, that is supposed to compute the _shape_ of the result of doing `ns↑array`.\n",
@@ -5872,6 +6035,7 @@
"id": "systematic-pressing",
"metadata": {},
"source": [
+ "\n",
"**Exercise 4**:\n",
"\n",
"This exercise wants us to convert left arguments of _take_ into left arguments of _drop_ and vice-versa, and doing so means we need to understand the lengths of the resulting dimensions, but that is what we have been doing in the previous exercises.\n",
@@ -6066,7 +6230,7 @@
"metadata": {},
"source": [
"The simplest way to fix this is by shortening `⍵` to match the length of `⍺`.\n",
- "This works, because the trailing dimensions that are not covered by the left argument to _take_ can also be omitted in the left argument to _drop_:"
+ "This works because the trailing dimensions that are not covered by the left argument to _take_ can also be omitted in the left argument to _drop_:"
]
},
{
@@ -6105,6 +6269,7 @@
"id": "ordinary-tourist",
"metadata": {},
"source": [
+ "\n",
"**Exercise 5**:\n",
"\n",
"It is clear that an integral part of this exercise will be finding the vowels in the given character vector, and we can use the _membership_ primitive for that:"
@@ -6200,14 +6365,9 @@
"id": "loose-weekend",
"metadata": {},
"source": [
- "**Exercise 6**:"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "funky-given",
- "metadata": {},
- "source": [
+ "\n",
+ "**Exercise 6**:\n",
+ "\n",
"Let's work with the following matrix:"
]
},
@@ -6341,13 +6501,13 @@
},
{
"cell_type": "code",
- "execution_count": 203,
+ "execution_count": 54,
"id": "subjective-reggae",
"metadata": {},
"outputs": [],
"source": [
"]dinput\n",
- "Contraction ← {\n",
+ "Contract ← {\n",
" r ← ,⍵\n",
" (⍴⍵),(r≠0)/r,[.5]⍳≢r\n",
"}"
@@ -6355,7 +6515,7 @@
},
{
"cell_type": "code",
- "execution_count": 204,
+ "execution_count": 55,
"id": "adapted-jersey",
"metadata": {},
"outputs": [
@@ -6367,13 +6527,13 @@
""
]
},
- "execution_count": 204,
+ "execution_count": 55,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "Contraction xg6"
+ "Contract xg6"
]
},
{
@@ -6403,7 +6563,7 @@
},
{
"cell_type": "code",
- "execution_count": 206,
+ "execution_count": 56,
"id": "serial-hello",
"metadata": {},
"outputs": [
@@ -6417,13 +6577,13 @@
""
]
},
- "execution_count": 206,
+ "execution_count": 56,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "Restore Contraction xg6"
+ "Restore Contract xg6"
]
},
{
@@ -6431,6 +6591,7 @@
"id": "accurate-bedroom",
"metadata": {},
"source": [
+ "\n",
"**Exercise 7**:\n",
"\n",
"When the problem statement mentions blanks and _expand_, it hints at the fact that the blank space is the fill element for character vectors, and we know that _expand_ inserts fill elements when it finds zeroes.\n",
@@ -6533,6 +6694,7 @@
"id": "talented-enhancement",
"metadata": {},
"source": [
+ "\n",
"**Exercise 8**:\n",
"\n",
"If we want to centre something, that means we will need to rotate it to the correct place.\n",
@@ -6648,14 +6810,14 @@
},
{
"cell_type": "code",
- "execution_count": 216,
+ "execution_count": 57,
"id": "efficient-forum",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
- " 2007 \n",
+ " 2022 \n",
"--------\n",
"January \n",
"February\n",
@@ -6666,13 +6828,13 @@
""
]
},
- "execution_count": 216,
+ "execution_count": 57,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "'2007' OnTop monMat"
+ "'2022' OnTop monMat"
]
},
{
@@ -6717,6 +6879,7 @@
"id": "different-orientation",
"metadata": {},
"source": [
+ "\n",
"**Exercise 9**:\n",
"\n",
"Best way to check if your solution is correct is by actually running the code:"
@@ -6775,6 +6938,7 @@
"id": "alone-flexibility",
"metadata": {},
"source": [
+ "\n",
"**Exercise 10**:\n",
"\n",
"Let us prototype our solution with the vector that follows, and let us assume we want to find a run of 4 zeroes."
@@ -7452,6 +7616,7 @@
"id": "solved-anatomy",
"metadata": {},
"source": [
+ "\n",
"**Exercise 11**:\n",
"\n",
"We start with our matrix of names:"
@@ -7459,7 +7624,7 @@
},
{
"cell_type": "code",
- "execution_count": 243,
+ "execution_count": 73,
"id": "entertaining-stadium",
"metadata": {},
"outputs": [
@@ -7480,7 +7645,7 @@
""
]
},
- "execution_count": 243,
+ "execution_count": 73,
"metadata": {},
"output_type": "execute_result"
}
@@ -7494,12 +7659,12 @@
"id": "medieval-production",
"metadata": {},
"source": [
- "Let us also assume we want to make `n ← 3` slices:"
+ "Let us also assume we want to make `n ← 3` columns:"
]
},
{
"cell_type": "code",
- "execution_count": 244,
+ "execution_count": 74,
"id": "vocational-polish",
"metadata": {},
"outputs": [],
@@ -7521,15 +7686,15 @@
" 2. then we want to go down along the column of names,\n",
" 3. and then we want to go right along the columns of names.\n",
"\n",
- "This hints at the fact that we should reshape our data to have 3 dimensions, where one dimension holds the slices, another holds all the names, and the last one holds the characters that compose a name.\n",
+ "This hints at the fact that we should reshape our data to have 3 dimensions, where one dimension holds the columns, another holds all the names, and the last one holds the characters that compose a name.\n",
"\n",
"The first thing that we need to do, in order to break up the matrix with the names, into an array with 3 dimensions, is figure out the length of each dimension.\n",
- "`n ← 3` indicates that we want 3 slices, but how many names are there in each slice?"
+ "`n ← 3` indicates that we want 3 columns, but how many names are there in each slice?"
]
},
{
"cell_type": "code",
- "execution_count": 245,
+ "execution_count": 75,
"id": "numerous-pizza",
"metadata": {},
"outputs": [
@@ -7540,7 +7705,7 @@
""
]
},
- "execution_count": 245,
+ "execution_count": 75,
"metadata": {},
"output_type": "execute_result"
}
@@ -7555,12 +7720,12 @@
"id": "aquatic-recording",
"metadata": {},
"source": [
- "This doesn't divide evenly, so we use the _ceiling_ primitive to round up, and then we use _take_ to create empty names to pad the slice:"
+ "This doesn't divide evenly, so we use the _ceiling_ primitive to round up, and then we use _take_ to create empty names to pad the column:"
]
},
{
"cell_type": "code",
- "execution_count": 246,
+ "execution_count": 76,
"id": "together-maple",
"metadata": {},
"outputs": [
@@ -7582,14 +7747,14 @@
""
]
},
- "execution_count": 246,
+ "execution_count": 76,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "sliceSize ← ⌈height÷n\n",
- "⎕← names ← (sliceSize×n)↑xg11"
+ "colSize ← ⌈height÷n\n",
+ "⎕← names ← (colSize×n)↑xg11"
]
},
{
@@ -7603,7 +7768,7 @@
},
{
"cell_type": "code",
- "execution_count": 247,
+ "execution_count": 77,
"id": "developed-checkout",
"metadata": {},
"outputs": [
@@ -7614,12 +7779,12 @@
"Luciano \n",
"Paul \n",
"Oxana \n",
- " \n",
+ "\n",
"Thor \n",
"Carmen \n",
"Veronica\n",
"William \n",
- " \n",
+ "\n",
"Vladimir\n",
"Monica \n",
"Colette \n",
@@ -7627,13 +7792,13 @@
""
]
},
- "execution_count": 247,
+ "execution_count": 77,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "⎕← slices ← n sliceSize width ⍴ names"
+ "⎕← columns ← n colSize width ⍴ names"
]
},
{
@@ -7648,7 +7813,7 @@
},
{
"cell_type": "code",
- "execution_count": 248,
+ "execution_count": 78,
"id": "aquatic-cable",
"metadata": {},
"outputs": [
@@ -7658,28 +7823,28 @@
"Emily \n",
"Thor \n",
"Vladimir\n",
- " \n",
+ "\n",
"Luciano \n",
"Carmen \n",
"Monica \n",
- " \n",
+ "\n",
"Paul \n",
"Veronica\n",
"Colette \n",
- " \n",
+ "\n",
"Oxana \n",
"William \n",
" \n",
""
]
},
- "execution_count": 248,
+ "execution_count": 78,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "2 1 3⍉slices"
+ "2 1 3⍉columns"
]
},
{
@@ -7692,7 +7857,7 @@
},
{
"cell_type": "code",
- "execution_count": 249,
+ "execution_count": 79,
"id": "attempted-middle",
"metadata": {},
"outputs": [
@@ -7706,13 +7871,13 @@
""
]
},
- "execution_count": 249,
+ "execution_count": 79,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "sliceSize (n×width)⍴2 1 3⍉slices"
+ "colSize (n×width)⍴2 1 3⍉columns"
]
},
{
@@ -7720,13 +7885,13 @@
"id": "initial-diagram",
"metadata": {},
"source": [
- "This is almost perfect, we just need to add blanks between all the slices.\n",
+ "This is almost perfect, we just need to add blanks between all the columns.\n",
"In order to do so, we can catenate a blank space at the end of the array (making it one character wider) and then dropping the last column of superfluous blanks:"
]
},
{
"cell_type": "code",
- "execution_count": 250,
+ "execution_count": 80,
"id": "ecological-cameroon",
"metadata": {},
"outputs": [
@@ -7740,13 +7905,13 @@
""
]
},
- "execution_count": 250,
+ "execution_count": 80,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "0 ¯1↓sliceSize (n×width+1)⍴2 1 3⍉slices,' '"
+ "0 ¯1↓colSize (n×width+1)⍴2 1 3⍉columns,' '"
]
},
{
@@ -7759,24 +7924,24 @@
},
{
"cell_type": "code",
- "execution_count": 251,
+ "execution_count": 82,
"id": "retained-absolute",
"metadata": {},
"outputs": [],
"source": [
"]dinput\n",
- "Split ← {\n",
+ "ToColumns ← {\n",
" (h w) ← ⍴⍵\n",
" nh ← ⌈h÷⍺\n",
" names ← (nh×⍺)↑⍵\n",
- " slices ← ⍺ nh w⍴names\n",
- " 0 ¯1↓nh (⍺×w+1)⍴2 1 3⍉slices,' '\n",
+ " columns ← ⍺ nh w⍴names\n",
+ " 0 ¯1↓nh (⍺×w+1)⍴2 1 3⍉columns,' '\n",
"}"
]
},
{
"cell_type": "code",
- "execution_count": 252,
+ "execution_count": 83,
"id": "sought-flesh",
"metadata": {
"scrolled": true
@@ -7792,13 +7957,13 @@
""
]
},
- "execution_count": 252,
+ "execution_count": 83,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "3 Split xg11"
+ "3 ToColumns xg11"
]
},
{
@@ -7812,22 +7977,22 @@
},
{
"cell_type": "code",
- "execution_count": 253,
+ "execution_count": 64,
"id": "brazilian-potential",
"metadata": {},
"outputs": [],
"source": [
"]dinput\n",
- "SplitWrong ← {\n",
+ "ToColumnsWrong ← {\n",
" (h w) ← ⍴⍵\n",
" nh ← ⌈h÷⍺\n",
- " 0 ¯1↓nh(n×w+1)⍴(n×nh×w+1)↑,xg11,' '\n",
+ " 0 ¯1↓nh(⍺×w+1)⍴(⍺×nh×w+1)↑,xg11,' '\n",
"}"
]
},
{
"cell_type": "code",
- "execution_count": 254,
+ "execution_count": 65,
"id": "occupied-affect",
"metadata": {},
"outputs": [
@@ -7841,13 +8006,13 @@
""
]
},
- "execution_count": 254,
+ "execution_count": 65,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "3 SplitWrong xg11"
+ "3 ToColumnsWrong xg11"
]
},
{
@@ -7855,6 +8020,7 @@
"id": "compliant-agriculture",
"metadata": {},
"source": [
+ "\n",
"**Exercise 12**:\n",
"\n",
"For this exercise, we are given an extra vector `xg12`:"
@@ -8127,13 +8293,13 @@
},
{
"cell_type": "code",
- "execution_count": 271,
+ "execution_count": 66,
"id": "spiritual-typing",
"metadata": {},
"outputs": [],
"source": [
"]dinput\n",
- "Expand ← {\n",
+ "ShowCodes ← {\n",
" labeled ← ⍕⍺,' ',⍵\n",
" indices ← ⍸(¯1↓⍺)≠1↓⍺\n",
" exp ← ~(⍳(≢indices)+≢xg12)∊indices+⍳≢indices\n",
@@ -8143,7 +8309,7 @@
},
{
"cell_type": "code",
- "execution_count": 272,
+ "execution_count": 67,
"id": "advance-collectible",
"metadata": {},
"outputs": [
@@ -8168,17 +8334,18 @@
""
]
},
- "execution_count": 272,
+ "execution_count": 67,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "xg12 Expand xg11"
+ "xg12 ShowCodes xg11"
]
}
],
"metadata": {
+ "celltoolbar": "Tags",
"kernelspec": {
"display_name": "Dyalog APL",
"language": "apl",
diff --git a/book/_config.yml b/book/_config.yml
index 84e8c5f..e20817b 100644
--- a/book/_config.yml
+++ b/book/_config.yml
@@ -26,3 +26,5 @@ launch_buttons:
sphinx:
config:
html_show_copyright: false
+ extra_extensions:
+ - sphinx_exercise
diff --git a/book/_static/custom.css b/book/_static/custom.css
index cdb010e..9f5723e 100644
--- a/book/_static/custom.css
+++ b/book/_static/custom.css
@@ -22,3 +22,7 @@
.table td p, .table th p {
margin: 0;
}
+
+.solution.admonition {
+ padding-bottom: 0 !important;
+}
diff --git a/requirements.txt b/requirements.txt
index 49f26a3..3878d05 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,2 +1,3 @@
jupyter-book
-ghp-import
\ No newline at end of file
+ghp-import
+sphinx-exercise
diff --git a/scripts/preprocess.py b/scripts/preprocess.py
index 2c33deb..aed2d51 100644
--- a/scripts/preprocess.py
+++ b/scripts/preprocess.py
@@ -12,7 +12,6 @@
import json
import os
import re
-import shutil
import sys
from pathlib import Path
from ruamel import yaml
@@ -26,7 +25,7 @@
"exercise": "hint",
"remark": "tip",
"rule": "tip",
- "rules" : "tip",
+ "rules": "tip",
}
def safe_hyphenate(string):
@@ -150,6 +149,60 @@ def replacer_function(match):
return lines
+
+def create_exercises(filename, lines):
+ """Convert an exercise section to the sphinx-exercise syntax."""
+
+ i = 0
+ while i < len(lines):
+ m = re.match(r"", lines[i])
+ if m:
+ label = m.group(1)
+ end_match = "\n"
+ try:
+ matching_line = lines.index(end_match)
+ except ValueError:
+ if lines[-1] == end_match[:-1]:
+ matching_line = len(lines) - 1
+ else:
+ print(f"Exercise has no closing 'end' in file {filename}, line {i}.")
+ sys.exit(1)
+ content_lines = lines[i+3:matching_line]
+ # How deep must the admonition nesting be?
+ backtick_nesting = max(
+ map(len, re.findall(r"`+", "\n".join(content_lines))),
+ default=0,
+ )
+ backticks = "`" * max(3, 1 + backtick_nesting)
+ lines[i:matching_line + 1] = (
+ [f"{backticks}{{exercise}}\n", f":label: {label}\n"] +
+ content_lines +
+ [f"{backticks}\n"]
+ )
+ # after doing the maths, this is exactly where we want to resume processing:
+ i = matching_line
+ else:
+ i += 1
+
+ return lines
+
+
+def create_solutions(lines):
+ """ Convert a solution section to the sphinx-exercise syntax."""
+
+ i = 0
+ while i < len(lines):
+ m = re.match(r"", lines[i])
+ if m:
+ label = m.group(1)
+ lines[i:i+2] = [f"```{{solution}} {label}\n", "```\n"]
+ i += 2
+ else:
+ i += 1
+
+ return lines
+
+
def create_admonitions(filename, lines):
"""Convert an admonition section into a MyST admonition.
@@ -161,7 +214,7 @@ def create_admonitions(filename, lines):
and end with . The sections can optionally be completely offset
with " > " to produce a blockquote that gives a visual cue for readers of
the plain notebooks.
-
+
Inside those sections, we look for code blocks or other formatting done with
backticks (`), to ensure that the outer admonition is nested correctly.
@@ -243,6 +296,8 @@ def parse_lines(filename, lines):
lines = generate_figure_references(lines)
lines = image_to_figure(lines)
lines = create_admonitions(filename, lines)
+ lines = create_exercises(filename, lines)
+ lines = create_solutions(lines)
return lines
if __name__ == "__main__":