This commit is contained in:
jverzani
2025-01-24 11:04:54 -05:00
parent ff0f8a060d
commit 92f4cba496
28 changed files with 1070 additions and 124 deletions

View File

@@ -207,6 +207,7 @@ The authors note in a supplement to their paper that over 15,700 species and sub
(3.02 * 10^15 + 1.34*10^15) * 100 / 22
```
The answer is in *scientific notation$ and reads as $1.89\dots \cdot 10^16$.
Shifting the decimal point, this gives a value rounded to $20\cdot 10^{15}$ ants.
The authors used a value for the *dry weight* of an average (and representative) single ant. What was that value? (Which they indicate is perhaps unreliable,
@@ -216,7 +217,7 @@ as, for example, small-bodied ants may be much more abundant than large-bodied a
(12 * 1_000_000 * 1_000 * 1_000) / 20_000_000_000_000_000
```
Which translates to an *average* dry *carbon* weight of $0.6/1000$ grams, that is $0.6$ milligrams ($0.62$ mg C was actually used).
Which translates to an *average* dry *carbon* weight of $0.6/1000$ grams, that is $0.6$ milligrams ($0.62$ mg C was actually used). The underscores in `20_000_000_000_000_000` are *ignored* when parsed and are only for readability. This is a readable alternate to scientific notation for large numbers.
The authors write that insects are generally considered to have a dry weight of 30% wet weight, and a carbon weight of 50% dry weight, so the weight in grams of an *average* living ant would be multiplied by $2$ and then $10/3$:
@@ -228,8 +229,6 @@ That is 4 milligrams, or 250 ants per gram on average.
Numeric combinations, as above, will be easier to check for correctness when variable names are assigned to the respective values.
Using the underscore, as above, to separate groups of digits, is helpful, as an alternate to scientific notation, when working with large numbers.
@@ -326,7 +325,7 @@ $$
\frac{1 + 2}{3 + 4}?
$$
It would have to be computed through $(1 + 2) / (3 + 4)$. This is because unlike `/`, the implied order of operation in the mathematical notation with the *horizontal division symbol* (the [vincula](http://tinyurl.com/y9tj6udl)) is to compute the top and the bottom and then divide. That is, the vincula is a grouping notation like parentheses, only implicitly so. Thus the above expression really represents the more verbose:
It would have to be computed through $(1 + 2) / (3 + 4)$. This is because unlike `/`, the implied order of operation in the mathematical notation with the *horizontal division symbol* (the [vinculum](http://tinyurl.com/y9tj6udl)) is to compute the top and the bottom and then divide. That is, the vincula is a grouping notation like parentheses, only implicitly so. Thus the above expression really represents the more verbose:
$$
@@ -368,7 +367,7 @@ In `Julia` many infix operations can be done using a prefix manner. For example
## Constants
The Google calculator has two built in constants, `e` and `π`. Julia provides these as well, though not quite as easily. First, `π` is just `pi`:
The Google calculator has two built in constants, `e` and `π`. Julia provides these as well, though not quite as easily, as they have names and not dedicated buttons. First, `π` is just `pi`:
```{julia}
@@ -407,7 +406,7 @@ In most cases. There are occasional (basically rare) spots where using `pi` by i
### Numeric literals
For some special cases, Julia parses *multiplication* without a multiplication symbol. This is when the value on the left is a number, as in `2pi`, which has an equivalent value to `2*pi`. *However* the two are not equivalent, in that multiplication with *numeric literals* does not have the same precedence as regular multiplication - it is higher. This has practical importance when used in division or powers. For instance, these two are **not** the same:
For some special cases, Julia parses *multiplication* without a multiplication symbol. One case is when the value on the left is a number, as in `2pi`, which has an equivalent value to `2*pi`. *However* the two are not equivalent, in that multiplication with *numeric literals* does not have the same precedence as regular multiplication - it is higher. This has practical importance when used in division or powers. For instance, these two expressions are **not** the same:
```{julia}
@@ -485,7 +484,9 @@ Using a function is very straightforward. A function is called using parentheses
sqrt(4), sqrt(5)
```
The function is referred to by name (`sqrt`) and called with parentheses. Any arguments are passed into the function using commas to separate values, should there be more than one. When there are numerous values for a function, the arguments may need to be given in a specific order or may possibly be specified with *keywords*. (A semicolon can be used instead of a comma to separate keyword arguments.)
The function is referred to by name (`sqrt`) and called with parentheses.
Any arguments are passed into the function using commas to separate values, should there be more than one. When there are numerous values for a function, the arguments may need to be given in a specific order or may possibly be specified with *keywords*. (A semicolon can be used instead of a comma to separate keyword arguments from positional arguments.)
Some more examples:

View File

@@ -129,7 +129,7 @@ x = -40
y = 5/9 * (x - 32)
```
will evaluate the right-hand side with the value of `x` bound at the time of assignment to `y`, whereas assignment to a function
will evaluate the expression on the right-hand side with the value of `x` bound at the time of assignment to `y`, whereas assignment to a function
```{julia}
@@ -144,7 +144,7 @@ will create a function object with a value of `x` determined at a later time - t
Within `Julia`, we make note of the distinction between a function object versus a function call. In the definition `f(x)=cos(x)`, the variable `f` refers to a function object, whereas the expression `f(pi)` is a function call. This mirrors the math notation where an $f$ is used when properties of a function are being emphasized (such as $f \circ g$ for composition) and $f(x)$ is used when the values related to the function are being emphasized (such as saying "the plot of the equation $y=f(x)$).
Distinguishing these three related but different concepts (equations, function objects, and function calls) is important when modeling on the computer.
Distinguishing these three related but different concepts -- equations and expressions, function objects, and function calls -- is important when modeling mathematics on the computer.
### Cases
@@ -548,6 +548,13 @@ v0, theta
The *big* advantage of bundling parameters into a container is consistency the function is always called in an identical manner regardless of the number of parameters (or variables).
::: {.callout-note}
## Avoid global variables
Referring to a global parameter is common in math, but has a significant performance impact in `Julia`. Save for the simplest usage, it is much better to pass parameters to the function through one of several means that too rely on the value of the global state.
:::
## Multiple dispatch
@@ -576,7 +583,7 @@ Multiple dispatch is very common in mathematics. For example, we learn different
:::
`Julia` is similarly structured. `Julia` terminology would be to call the operation "`+`" a *generic function* and the different implementations *methods* of "`+`". This allows the user to just need to know a smaller collection of generic concepts yet still have the power of detail-specific implementations. To see how many different methods are defined in the base `Julia` language for the `+` operator, we can use the command `methods(+)`. As there are so many ($\approx 200$) and that number is growing, we illustrate how many different logarithm methods are implemented for "numbers:"
`Julia` is similarly structured. `Julia` terminology would be to call the operation "`+`" a *generic function* and the different implementations *methods* of "`+`". This allows the user to just need to know a smaller collection of generic concepts yet still have the power of detail-specific implementations. To see how many different methods are defined in the base `Julia` language for the `+` operator, we can use the command `methods(+)`. As there are so many (well over $200$ when `Julia` is started), we illustrate how many different logarithm methods are implemented for "numbers:"
```{julia}
@@ -599,7 +606,7 @@ twotox(x::Complex) = (2.0 + 0.0im)^x
This is for illustration purposes -- the latter two are actually already done through `Julia`'s *promotion* mechanism -- but we see that `twotox` will return a rational number when `x` is an integer unlike `Julia` which, when `x` is non-negative will return an integer and will otherwise will error or return a float (when `x` is a numeric literal, like `2^(-3)`).
The key to reading the above is the type annotation acts like a gatekeeper allowing in only variables of that type.
The key to reading the above is the type annotation acts like a gatekeeper allowing in only variables of that type or a subtype of that type.
For example, the number `2` is parsed as a 64-bit integer (typically) and has concrete type `Int64` which is a subtype of `Integer`. So `twotox(2)` will use the first definition, and return a rational number. Whereas, the number `2.0` is parsed as a floating point number with concrete type `Float64` which is a subtype of `Real`, not `Integer`, so `twotox(2.0)` will use the second method defined above.
@@ -1283,6 +1290,82 @@ radioq(choices, answ)
###### Question
Nasa has some learning materials on [stars](https://spacemath.gsfc.nasa.gov/stars.html) including one that describes how to count the number of stars brighter than some level. This formula is from [https://spacemath.gsfc.nasa.gov/stars/6Page103.pdf](https://spacemath.gsfc.nasa.gov/stars/6Page103.pdf):
$$
\log_{10}(N(m)) = -0.0003 m^3 + 0.0019 m^2 + 0.484 m -3.82, \quad 4.0 \leq m \leq 25.0.
$$
Where $N(m)$ counts the number of stars brighter than magnitude $m$ *per* square degree of space.
A [square degree](https://en.wikipedia.org/wiki/Square_degree) is a unit of a solid angle. An entire sphere has a solid angle of $4\pi$ and $4\pi \cdot (180/\pi)^2$ square degrees.
With this we can answer agequestions, such as:
> How many stars can we see in the sky?
Star [magnitude](https://en.wikipedia.org/wiki/Magnitude_(astronomy)) measures the brightness of celestial objects, with the sun on a log scale so that a magnitude $1$ star is $100$ times brighter than a magnitude $6$ star. The sun has a value around $-27$, Sirius (the brightest visible star) around $-1.46), Venus around $-5$. We will take a magnitude of $6$ or brighter for visibility. (magnitudes less than $6$). The value of $N(6)$ is then
```{julia}
q(m) = -0.0003*m^3 + 0.0019*m^2 + 0.484*m - 3.82
N(m) = 10.0^(q(m))
n_6 = N(6)
```
The number of square degrees in the sky is
```{julia}
total_square_degrees = 4pi * (180/pi)^2
```
So the formula estimates this many visible stars in the entire sky:
```{julia}
n_6 * total_square_degrees
```
With a telescope, it is estimated that stars with brightness at magnitude $10.0$ can be seen. How many stars are visible in the sky with such a telescope?
```{julia}
#| echo: false
val = N(10) * total_square_degrees
atol = 10
numericq(val, atol)
```
A photograph is taken of a faint star cluster covering 5 square-degrees of space. The cluster contains stars of magnitude between $11.0$ and $15.0$. The stars seen in the photograph number $5237$. The astronomer estimates there are $5237$ *minus* the expected number of stars in this cluster. What did she estimate?
```{julia}
#| echo: false
expected_count = (N(15.0) - N(11.0)) * 5
actual_count = 5237
cluster = actual_count - expected_count
atol = 2
hint = """
The total expected number of stars in the one degree is `N(15.0) - N(11.0)`.
The count is then `5237 - 5*(N(15.0) - N(11.0))`.
"""
numericq(cluster, atol; hint)
```
If a star of magnitude $5$ difference is $100$ times brighter, what is the scale of the logarithm?
```{julia}
#| echo: false
explanation = raw"""
The base $a$ solve $\log_a(x + 5) / \log_a(x) = 100$. The logs can be combined and then $a$ can be solved for.
"""
choices = [raw"$5$",raw"$\sqrt[5]{100}$", raw"$\sqrt{100}$"]
answer = 2
buttonq(choices, answer; explanation)
```
###### Question
Identifying the range of a function can be a difficult task. We see in this question that in some cases, a package can be of assistance.

View File

@@ -18,7 +18,7 @@ plotly()
A (univariate) mathematical function relates or associates values of $x$ to values $y$ using the notation $y=f(x)$. A key point is a given $x$ is associated with just one $y$ value, though a given $y$ value may be associated with several different $x$ values. (Graphically, this is the vertical line test.)
We may conceptualize such a relation in many ways: through an algebraic rule; through the graph of $f;$ through a description of what $f$ does; or through a table of paired values, say. For the moment, let's consider a function as rule that takes in a value of $x$ and outputs a value $y$. If a rule is given defining the function, the computation of $y$ is straightforward. A different question is not so easy: for a given value $y$ what value - or *values* - of $x$ (if any) produce an output of $y$? That is, what $x$ value(s) satisfy $f(x)=y$?
We may conceptualize such a relation in many ways: through an algebraic rule; through the graph of $f;$ through a description of what $f$ does; or through a table of paired values, say. For the moment, let's consider a function as a rule that takes in a value of $x$ and outputs a value $y$. If a rule is given defining the function, the computation of $y$ is straightforward. A different question is not so easy: for a given value $y$ what value - or *values* - of $x$ (if any) produce an output of $y$? That is, what $x$ value(s) satisfy $f(x)=y$?
*If* for each $y$ in some set of values there is just one $x$ value, then this operation associates to each value $y$ a single value $x$, so it too is a function. When that is the case we call this an *inverse* function.

View File

@@ -19,7 +19,7 @@ The [`Julia`](http://www.julialang.org) programming language is well suited as a
`Julia` is an *open source* project which allows anyone with a supported computer to use it free of charge.
To install locally, the [downloads](https://julialang.org/downloads/) page has directions to use the `Juliaup` utility for managing an installation. There are also links to several different binaries for manual installation. Additionally, the downloads page contains a link to a docker image. `Julia` can also be compiled from source.
To install locally, the [downloads](https://julialang.org/downloads/) page has directions to use the `juliaup` utility for managing an installation. There are also links to several different binaries for manual installation. Additionally, the downloads page contains a link to a docker image. `Julia` can also be compiled from source.
`Julia` can also be run through the web.
@@ -280,7 +280,7 @@ Values will be promoted to a common type (or type `Any` if none exists). For exa
(Vectors are used as a return type from some functions, as such, some familiarity is needed.)
Other common container types are variables of vectors (higher-dimensional arrarys, offset arrays, etc.) tuples (for heterogeneous, immutable, indexed values); named tuples (which add a name to each value in a tuple); and dictionaries (for associative relationships between a key and a value).
Other common container types are variations of vectors (higher-dimensional arrarys, offset arrays, etc.) tuples (for heterogeneous, immutable, indexed values); named tuples (which add a name to each value in a tuple); and dictionaries (for associative relationships between a key and a value).
Regular arithmetic sequences can be defined by either:

View File

@@ -174,12 +174,12 @@ You can discover more about the range of floating point values provided by calli
* `typemax(0.0)` gives the largest value for the type (`Inf` in this case).
* `prevfloat(Inf)` gives the largest finite one, in general `prevfloat` is the next smallest floating point value.
:::
* `nextfloat(-Inf)`, similarly, gives the smallest finite floating point value, and in general returns the next largest floating point value.
* `nextfloat(0.0)` gives the closest positive value to 0.
* `eps()` gives the distance to the next floating point number bigger than `1.0`. This is sometimes referred to as machine precision.
:::
#### Scientific notation
@@ -298,7 +298,7 @@ That is adding `1/10` and `2/10` is not exactly `3/10`, as expected mathematical
1/10 + (2/10 + 3/10) == (1/10 + 2/10) + 3/10
```
* Mathematically, or real numbers, subtraction of similar-sized numbers is not exceptional, for example $1 - \cos(x)$ is positive if $0 < x < \pi/2$, say. This will not be the case for floating point values. If $x$ is close enough to $0$, then $\cos(x)$ and $1$ will be so close, that they will be represented by the same floating point value, `1.0`, so the difference will be zero:
* Mathematically, for real numbers, subtraction of similar-sized numbers is not exceptional, for example $1 - \cos(x)$ is positive if $0 < x < \pi/2$, say. This will not be the case for floating point values. If $x$ is close enough to $0$, then $\cos(x)$ and $1$ will be so close, that they will be represented by the same floating point value, `1.0`, so the difference will be zero:
```{julia}

View File

@@ -439,7 +439,7 @@ plot!(zero, label="zero")
(The job of `zero` is to return "$0$" in the appropriate type. There is also a similar `one` function in base `Julia`.)
The `plot!` call adds a layer. We could still specify the limits for the plot, though as this can be computed from the figure, to plot `zero` we let `Plots` do it.
The `plot!` call adds a layer. We could still specify the limits for the plot, though, as this can be computed from the figure, to plot `zero` we let `Plots` do it.
For another example, suppose we wish to plot the function $f(x)=x\cdot(x-1)$ over the interval $[-1,2]$ and emphasize with points the fact that $0$ and $1$ are zeros. We can do this with three layers: the first to graph the function, the second to emphasize the $x$ axis, the third to graph the points.
@@ -492,6 +492,8 @@ For plotting points with `scatter`, or `scatter!` the markers can be adjusted vi
Of course, zero, one, or more of these can be used on any given call to `plot`, `plot!`, `scatter`, or `scatter!`.
There are also several *shorthands* in `Plots` that allows several related attributes to be specified to a single argument that is disambiguated using the type of the value. (Eg. `line=(5, 0.25, "blue")` will specify the line have widht `5`, color `blue`, and alpha-transparency `0.25`.)
#### Example: Bresenham's algorithm

View File

@@ -1,6 +1,9 @@
# Polynomials
Now that basic properties of functions have been discussed, we move to various types of related functions beginning with polynomial functions.
{{< include ../_common_code.qmd >}}
In this section we use the following add-on packages:
@@ -22,6 +25,7 @@ nothing
---
Polynomials are a particular class of expressions that are simple enough to have many properties that can be analyzed. In particular, the key concepts of calculus: limits, continuity, derivatives, and integrals are all relatively trivial for polynomial functions. However, polynomials are flexible enough that they can be used to approximate a wide variety of functions. Indeed, though we don't pursue this, we mention that `Julia`'s `ApproxFun` package exploits this to great advantage.
@@ -128,7 +132,7 @@ Symbolic math programs include well-known ones like the commercial programs Math
The [Symbolics](https://github.com/JuliaSymbolics/Symbolics.jl) package for `Julia` provides a "fast and modern CAS for fast and modern language." It is described further in [Symbolics.jl](../alternatives/symbolics.qmd).
As `SymPy` has some features not yet implemented in `Symbolics`, we use that here. The `PyCall` and `PythonCall` packages are available to glue `Julia` to Python in a seamless manner. These allow the `Julia` package `SymPy` to provide functionality from SymPy within `Julia`.
As `SymPy` has some features not yet implemented in `Symbolics`, we use `SymPy` in these notes. The `PyCall` and `PythonCall` packages are available to glue `Julia` to Python in a seamless manner. These allow the `Julia` package `SymPy` (or `SymPyPythonCall`) to provide functionality from SymPy within `Julia`.
:::{.callout-note}

View File

@@ -140,11 +140,11 @@ Floating point roundoff leads to the last value *exceeding* `0.6`, so should it
Enter the base function `range` which solves this seemingly simple - but not really - task. It can use `a`, `b`, and `n`. Like the range operation, this function returns a generator which can be collected to realize the values.
The number of points is specified with keyword arguments, as in:
The number of points is specified as a third argument (though keyword arguments can be given):
```{julia}
xs = range(-1, 1, length=9) # or simply range(-1, 1, 9) as of v"1.7"
xs = range(-1, 1,9)
```
and

View File

@@ -160,7 +160,7 @@ This basic fact can be manipulated many ways. For example, dividing through by $
[cos(theta) for theta in [0, pi/6, pi/4, pi/3, pi/2]]
```
To compute $\sin^2(\theta)$, the power is applied to the value of $\sin(\theta)$ and not the `sin` function. (Think of $\sin^2(\theta)$ as $(sin(\theta))^2$:
To compute $\sin^2(\theta)$, the power is applied to the value of $\sin(\theta)$ and not the `sin` function. (Think of $\sin^2(\theta)$ as $(\sin(\theta))^2$:
```{julia}
theta = pi/8
@@ -982,6 +982,18 @@ answ = 1
radioq(choices, answ, keep_order=true)
```
###### Question
The function `f(x) = x * tanh(exp(x))` has a shape akin to `max(0,x)` but is smoooth. Graphically finds its smallest $y$ value.
```{julia}
#| echo: false
f(x) = x * tanh(exp(x))
val = -0.35328577784821125
numericq(val, 1e-1)
```
###### Question
@@ -1016,3 +1028,4 @@ Is this identical to the pattern for the regular sine function?
#| echo: false
yesnoq(false)
```

View File

@@ -111,6 +111,26 @@ a = v0 * cosd(theta)
By defining a new variable `a` to represent a value that is repeated a few times in the expression, the last command is greatly simplified. Doing so makes it much easier to check for accuracy against the expression to compute.
##### Example
A common expression in mathematics is a polynomial expression, for example $-16s^2 + 32s - 12$. Translating this to `Julia` at $s =3$ we might have:
```{julia}
s = 3
-16*s^2 + 32*s - 12
```
This looks nearly identical to the mathematical expression, but we inserted `*` to indicate multiplication between the constant and the variable. In fact, this step is not needed as Julia allows numeric literals to have an implied multiplication:
```{julia}
-16s^2 + 32s - 12
```
##### Example
A [grass swale](https://stormwater.pca.state.mn.us/index.php?title=Design_criteria_for_dry_swale_(grass_swale)) is a design to manage surface water flow resulting from a storm. Swales detain, filter, and infiltrate runoff limiting erosion in the process.
@@ -158,25 +178,6 @@ R = A / P
Q = R^(2/3) * S^(1/2) / n * A
```
##### Example
A common expression in mathematics is a polynomial expression, for example $-16s^2 + 32s - 12$. Translating this to `Julia` at $s =3$ we might have:
```{julia}
s = 3
-16*s^2 + 32*s - 12
```
This looks nearly identical to the mathematical expression, but we inserted `*` to indicate multiplication between the constant and the variable. In fact, this step is not needed as Julia allows numeric literals to have an implied multiplication:
```{julia}
-16s^2 + 32s - 12
```
## Where math and computer notations diverge
@@ -243,7 +244,7 @@ The `varinfo` function will list the variables currently defined in the main wor
:::{.callout-warning}
## Warning
**Shooting oneselves in the foot.** `Julia` allows us to locally redefine variables that are built in, such as the value for `pi` or the function object assigned to `sin`. This is called shadowing. For example, this is a perfectly valid command `sin=3`. However, it will overwrite the typical value of `sin` so that `sin(3)` will be an error. At the terminal, the binding to `sin` occurs in the `Main` module. This shadows that value of `sin` bound in the `Base` module. Even if redefined in `Main`, the value in base can be used by fully qualifying the name, as in `Base.sin(pi)`. This uses the notation `module_name.variable_name` to look up a binding in a module.
**Shooting oneselves in the foot.** `Julia` allows us to locally redefine variables that are built in, such as the value for `pi` or the function object assigned to `sin`. This is called shadowing. For example, this is a perfectly valid command `x + y = 3`. However, it doesn't specify an equation, rather it *redefines* addition. At the terminal, this binding to `+` occurs in the `Main` module. This shadows that value of `+` bound in the `Base` module. Even if redefined in `Main`, the value in base can be used by fully qualifying the name, as in `Base.:+(2, 3)`. This uses the notation `module_name.variable_name` to look up a binding in a module.
:::
@@ -265,7 +266,7 @@ __private = 2 # a convention
### Unicode names
Julia allows variable names to use Unicode identifiers. Such names allow `julia` notation to mirror that of many mathematical texts. For example, in calculus the variable $\epsilon$ is often used to represent some small number. We can assign to a symbol that looks like $\epsilon$ using `Julia`'s LaTeX input mode. Typing `\epsilon[tab]` will replace the text with the symbol within `IJulia` or the command line.
`Julia` allows variable names to use Unicode identifiers. Such names allow `julia` notation to mirror that of many mathematical texts. For example, in calculus the variable $\epsilon$ is often used to represent some small number. We can assign to a symbol that looks like $\epsilon$ using `Julia`'s LaTeX input mode. Typing `\epsilon[tab]` will replace the text with the symbol within `IJulia` or the command line.
```{julia}

View File

@@ -359,9 +359,12 @@ fibs = [1, 1, 2, 3, 5, 8, 13]
Later we will discuss different ways to modify the values of a vector to create new ones, similar to how scalar multiplication does.
As mentioned, vectors in `Julia` are comprised of elements of a similar type, but the type is not limited to numeric values. Some examples:,
As mentioned, vectors in `Julia` are comprised of elements of a similar type, but the type is not limited to numeric values. Some examples:
* a vector of strings might be useful for text processing, For example, the `WordTokenizers.jl` package takes text and produces tokens from the words.
* a vector of Boolean values can naturally arise and is widely used within Julia's `DataFrames.jl` package.
* some applications are even naturally represented in terms of vectors of vectors (such as happens when plotting a collection points).
@@ -378,7 +381,7 @@ Look at the output of these two vectors, in particular how the underlying type o
Finally, we mention that if `Julia` has values of different types it will promote them to a common type if possible. Here we combine three types of numbers, and see that each is promoted to `Float64`:
Finally, we mention that if `Julia` has values of different types it will promote them to a common type, as possible. Here we combine three types of numbers, and see that each is promoted to `Float64`:
```{julia}
@@ -415,6 +418,8 @@ vs[2]
The last value of a vector is usually denoted by $v_n$. In `Julia`, the `length` function will return $n$, the number of items in the container. So `v[length(v)]` will refer to the last component. However, the special keyword `end` will do so as well, when put into the context of indexing. So `v[end]` is more idiomatic. (Similarly, there is a `begin` keyword that is useful when the vector is not $1$-based, as is typical but not mandatory.)
The functions `first` and `last` refer to the first and last components of a collection. An additional argument can be specified to take the first (or last) $n$ components. The function `only` will return the only component of a vector, if it has length $1$ and error otherwise.
:::{.callout-note}
## More on indexing
@@ -837,7 +842,7 @@ d["two"]
Named tuples are associative arrays where the keys are restricted to symbols. There are other types of associative arrays, specialized cases of the `AbstractDict` type with performance benefits for specific use cases. In these notes, dictionaries appear as output in some function calls.
Unlike vectors and tuples, named tuples and dictionaries are not currently supported by broadcasting. This causes no loss in usefulness, as the values can easily be iterated over, but the convenience of the dot notation is lost.
Unlike vectors and tuples, dictionaries are not currently supported by broadcasting. This causes no loss in usefulness, as the values can easily be iterated over, but the convenience of the dot notation is lost.