Merge branch 'main' into v0.5

This commit is contained in:
jverzani
2022-08-21 10:16:00 -04:00
4 changed files with 22 additions and 24 deletions

View File

@@ -199,7 +199,7 @@ end
The conditions for the `if` statements are expressions that evaluate to either `true` or `false`, such as generated by the Boolean operators `<`, `<=`, `==`, `!-`, `>=`, and `>`.
If familiar with `if` conditions, they are natural to use. However, for simpler cases of "if-else" `Julia` provides the more convenient *ternary* operator: `cond ? if_true : if_false`. (The name comes from the fact that there are three arguments specified.) The ternary operator checks the condition and if true returns the first expression, whereas if the condition is false the second condition is returned. Both expressions are evaluated. (The [short-circuit](http://julia.readthedocs.org/en/latest/manual/control-flow/#short-circuit-evaluation) operators can be used to avoid both evaluations.)
If familiar with `if` conditions, they are natural to use. However, for simpler cases of "if-else" `Julia` provides the more convenient *ternary* operator: `cond ? if_true : if_false`. (The name comes from the fact that there are three arguments specified.) The ternary operator checks the condition and if true returns the first expression, whereas if the condition is false the second condition is returned. Both expressions are evaluated. (The [short-circuit](https://docs.julialang.org/en/v1/manual/control-flow/#Short-Circuit-Evaluation) operators can be used to avoid both evaluations.)
For example, here is one way to define an absolute value function:
@@ -242,7 +242,7 @@ The `ternary` operator can be used to define an explicit domain. For example, a
```{julia}
h(t) = 0 <= t <= sqrt(10/16) ? 10.0 - 16t^2 : error("t is not in the domain")
h(t) = 0 <= t <= sqrt(10/16) ? 10.0 - 16t^2 : error("t is not in the domain")
```
#### Nesting ternary operators
@@ -252,7 +252,7 @@ The function `s(x)` isn't quite so easy to implement, as there isn't an "otherwi
```{julia}
s(x) = x < 0 ? 1 :
s(x) = x < 0 ? -1 :
x > 0 ? 1 : error("0 is not in the domain")
```
@@ -327,7 +327,7 @@ By using a multi-line function our work is much easier to look over for errors.
This next example, shows how using functions to collect a set of computations for simpler reuse can be very helpful.
An old method for finding a zero of an equation is the [secant method](https://en.wikipedia.org/wiki/Secant_method). We illustrate the method with the function $f(x) = x^2 - 2$. In an upcoming example we saw how to create a function to evaluate the secant line between $(a,f(a))$ and $(b, f(b))$ at any point. In this example, we define a function to compute the $x$ coordinate of where the secant line crosses the $x$ axis. This can be defined as follows:
An old method for finding a zero of an equation is the [secant method](https://en.wikipedia.org/wiki/Secant_method). We illustrate the method with the function $f(x) = x^2 - 2$. In an upcoming example we see how to create a function to evaluate the secant line between $(a,f(a))$ and $(b, f(b))$ at any point. In this example, we define a function to compute the $x$ coordinate of where the secant line crosses the $x$ axis. This can be defined as follows:
```{julia}
@@ -470,10 +470,10 @@ mxb(0)
So the `b` is found from the currently stored value. This fact can be exploited. we can write template-like functions, such as `f(x)=m*x+b` and reuse them just by updating the parameters separately.
How `Julia` resolves what a variable refers to is described in detail in the manual page [Scope of Variables](http://julia.readthedocs.org/en/latest/manual/variables-and-scoping/). In this case, the function definition finds variables in the context of where the function was defined, the main workspace. As seen, this context can be modified after the function definition and prior to the function call. It is only when `b` is needed, that the context is consulted, so the most recent binding is retrieved. Contexts (more formally known as environments) allow the user to repurpose variable names without there being name collision. For example, we typically use `x` as a function argument, and different contexts allow this `x` to refer to different values.
How `Julia` resolves what a variable refers to is described in detail in the manual page [Scope of Variables](https://docs.julialang.org/en/v1/manual/variables-and-scoping/). In this case, the function definition finds variables in the context of where the function was defined, the main workspace. As seen, this context can be modified after the function definition and prior to the function call. It is only when `b` is needed, that the context is consulted, so the most recent binding is retrieved. Contexts (more formally known as environments) allow the user to repurpose variable names without there being name collision. For example, we typically use `x` as a function argument, and different contexts allow this `x` to refer to different values.
Mostly this works as expected, but at times it can be complicated to reason about. In our example, definitions of the parameters can be forgotten, or the same variable name may have been used for some other purpose. The potential issue is with the parameters, the value for `x` is straightforward, as it is passed into the function. However, we can also pass the parameters, such as $m$ and $b$, as arguments. For parameters, we suggest using [keyword](http://julia.readthedocs.org/en/latest/manual/functions/#keyword-arguments) arguments. These allow the specification of parameters, but also give a default value. This can make usage explicit, yet still convenient. For example, here is an alternate way of defining a line with parameters `m` and `b`:
Mostly this works as expected, but at times it can be complicated to reason about. In our example, definitions of the parameters can be forgotten, or the same variable name may have been used for some other purpose. The potential issue is with the parameters, the value for `x` is straightforward, as it is passed into the function. However, we can also pass the parameters, such as $m$ and $b$, as arguments. For parameters, we suggest using [keyword](https://docs.julialang.org/en/v1/manual/functions/#Keyword-Arguments) arguments. These allow the specification of parameters, but also give a default value. This can make usage explicit, yet still convenient. For example, here is an alternate way of defining a line with parameters `m` and `b`:
```{julia}
@@ -527,7 +527,7 @@ For example, here we use a *named tuple* to pass parameters to `f`:
```{julia}
#| hold: true
function trajectory(x ,p)
g,v0, theta, k = p.g, p.v0, p.theta, p.k # unpack parameters
g, v0, theta, k = p.g, p.v0, p.theta, p.k # unpack parameters
a = v0 * cos(theta)
(g/(k*a) + tan(theta))* x + (g/k^2) * log(1 - k/a*x)
@@ -663,7 +663,7 @@ With `Julia` we can represent such operations. The simplest thing would be to do
```{julia}
#| hold: true
f(x) = x^2 - 2x
g(x) = f(x -3)
g(x) = f(x - 3)
```
Then $g$ has the graph of $f$ shifted by 3 units to the right. Now `f` above refers to something in the main workspace, in this example a specific function. Better would be to allow `f` to be an argument of a function, like this:
@@ -731,7 +731,7 @@ To model this in `Julia`, we would want to turn the inputs `f`,`a`, `b` into a f
```{julia}
function secant(f, a, b)
m = (f(b) - f(a)) / (b-a)
m = (f(b) - f(a)) / (b - a)
x -> f(a) + m * (x - a)
end
```
@@ -767,7 +767,7 @@ specific_line(m,b) = x -> mxplusb(x; m=m, b=b)
The returned object will have its parameters (`m` and `b`) fixed when used.
In `Julia`, the functions `Base.Fix1` and `Base.Fix2` are provided to take functions of two variables and create callable objects of just one variable, with the other argument fixed. This partial function application is provided by a some of the logical comparison operators. which can be useful with filtering, say.
In `Julia`, the functions `Base.Fix1` and `Base.Fix2` are provided to take functions of two variables and create callable objects of just one variable, with the other argument fixed. This partial function application is provided by a some of the logical comparison operators, which can be useful with filtering, say.
For example, `<(2)` is a funny looking way of expressing the function `x -> x < 2`. (Think of `x < y` as `<(x,y)` and then "fix" the value of `y` to be `2`.) This is useful with filtering by a predicate function, for example:
@@ -1010,7 +1010,7 @@ A(w, h) = w * h
when called as `A(10, 5)` will use 10 for `w` and `5` for `h`, as the order of `w` and `h` matches that of `10` and `5` in the call.
This is clear enough, but in fact positional arguments can have default values (then called [optional](http://julia.readthedocs.org/en/latest/manual/functions/#optional-arguments)) arguments). For example,
This is clear enough, but in fact positional arguments can have default values (then called [optional](https://docs.julialang.org/en/v1/manual/functions/#Optional-Arguments)) arguments). For example,
```{julia}
@@ -1132,7 +1132,7 @@ radioq(choices, answ, keep_order=true)
###### Question
The [pipe](http://julia.readthedocs.org/en/latest/stdlib/base/#Base.|>) notation `ex |> f` takes the output of `ex` and uses it as the input to the function `f`. That is composition. What is the value of this expression `1 |> sin |> cos`?
The [pipe](https://docs.julialang.org/en/v1/manual/functions/#Function-composition-and-piping) notation `ex |> f` takes the output of `ex` and uses it as the input to the function `f`. That is composition. What is the value of this expression `1 |> sin |> cos`?
```{julia}

View File

@@ -47,7 +47,7 @@ The set of numeric comparisons is nearly the same as the mathematical counterpar
:::{.callout-warning}
## Warning
The use of `==` is necessary, as `=` is used for assignment and mutation.")
The use of `==` is necessary, as `=` is used for assignment and mutation.
:::

View File

@@ -58,8 +58,8 @@ Though there are explicit constructors for these types, these notes avoid them u
:::{.callout-note}
## Warngin
Heads up, the difference between `1` and `1.0` is subtle. Even more so, as `1.` will parse as `1.0`. This means some expressions, such as `2.*3`, are ambigous, as the `.` might be part of the `2` (as in `2. * 3`) or the operation `*` (as in `2 .* 3`).
## Warning
Heads up, the difference between `1` and `1.0` is subtle. Even more so, as `1.` will parse as `1.0`. This means some expressions, such as `2.*3`, are ambiguous, as the `.` might be part of the `2` (as in `2. * 3`) or the operation `*` (as in `2 .* 3`).
:::
@@ -69,7 +69,7 @@ Similarly, each type is printed slightly differently.
The key distinction is between integers and floating points. While floating point values include integers, and so can be used exclusively on the calculator, the difference is that an integer is guaranteed to be an exact value, whereas a floating point value, while often an exact representation of a number is also often just an *approximate* value. This can be an advantage floating point values can model a much wider range of numbers.
Now in nearly all cases the differences are not noticable. Take for instance this simple calculation involving mixed types.
Now in nearly all cases the differences are not noticeable. Take for instance this simple calculation involving mixed types.
```{julia}
@@ -200,14 +200,14 @@ or may be represented in scientific notation:
```{julia}
6.23 * 10.0^23
6.022 * 10.0^23
```
The special coding `aeb` (or if the exponent is negative `ae-b`) is used to represent the number $a \cdot 10^b$ ($1 \leq a < 10$). This notation can be used directly to specify a floating point value:
```{julia}
avagadro = 6.23e23
avogadro = 6.022e23
```
Here `e` is decidedly *not* the Euler number, rather syntax to separate the exponent from the mantissa.

View File

@@ -410,13 +410,11 @@ The last value of a vector is usually denoted by $v_n$. In `Julia`, the `length`
There is [much more](http://julia.readthedocs.org/en/latest/manual/arrays/#indexing) to indexing than just indexing by a single integer value. For example, the following can be used for indexing:
* a scalar integer (as seen)
:::
* a range
* a vector of integers
* a boolean vector
:::
Some add-on packages extend this further.
@@ -541,7 +539,7 @@ sum(v), length(v)
Other desired operations with vectors act differently. Rather than reduce a collection of values using some formula, the goal is to apply some formula to *each* of the values, returning a modified vector. A simple example might be to square each element, or subtract the average value from each element. An example comes from statistics. When computing a variance, we start with data $x_1, x_2, \dots, x_n$ and along the way form the values $(x_1-\bar{x})^2, (x_2-\bar{x})^2, \dots, (x_n-\bar{x})^2$.
Such things can be done in *many* differents ways. Here we describe two, but will primarily utilize the first.
Such things can be done in *many* different ways. Here we describe two, but will primarily utilize the first.
### Broadcasting a function call
@@ -678,7 +676,7 @@ The first task is to create the data. We will soon see more convenient ways to g
```{julia}
a,b, n = -1, 1, 7
a, b, n = -1, 1, 7
d = (b-a) // (n-1)
𝐱s = [a, a+d, a+2d, a+3d, a+4d, a+5d, a+6d] # 7 points
```
@@ -712,7 +710,7 @@ The style generally employed here is to use plural variable names for a collecti
## Other container types
Vectors in `Julia` are a container, one of many different types. Another useful type for programming purposes are *tuples*. If a vector is formed by placing comma-separated values within a `[]` pair (e.g., `[1,2,3]`), a tuple is formed by placing comma-separated values withing a `()` pair. A tuple of length $1$ uses a convention of a trailing comma to distinguish it from a parethesized expression (e.g. `(1,)` is a tuple, `(1)` is just the value `1`).
Vectors in `Julia` are a container, one of many different types. Another useful type for programming purposes are *tuples*. If a vector is formed by placing comma-separated values within a `[]` pair (e.g., `[1,2,3]`), a tuple is formed by placing comma-separated values withing a `()` pair. A tuple of length $1$ uses a convention of a trailing comma to distinguish it from a parenthesized expression (e.g. `(1,)` is a tuple, `(1)` is just the value `1`).
Tuples are used in programming, as they don't typically require allocated memory to be used so they can be faster. Internal usages are for function arguments and function return types. Unlike vectors, tuples can be heterogeneous collections. (When commas are used to combine more than one output into a cell, a tuple is being used.) (Also, a big technical distinction is that tuples are also different from vectors and other containers in that tuple types are *covariant* in their parameters, not *invariant*.)