Skip to content
Merged

V0.24 #151

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
30be930
WIP
jverzani Apr 16, 2025
b5f0300
WIP
jverzani Apr 23, 2025
a650cf8
Merge branch 'main' into v0.24
jverzani Apr 23, 2025
fa5f9f4
add matrix calculus notes
jverzani Apr 30, 2025
ad52202
edits
jverzani May 9, 2025
4f60e9a
typos
jverzani Jun 14, 2025
c8f9fd4
merge main
jverzani Jun 14, 2025
580e87c
orthogonal; work around plotly()
jverzani Jun 27, 2025
c4bd214
WIP: Plots
jverzani Jun 27, 2025
23e0086
Plots
jverzani Jun 27, 2025
50cc2b2
xxx
jverzani Jun 27, 2025
2af5a6a
WIP
jverzani Jun 27, 2025
145bc60
WIP
jverzani Jun 28, 2025
30300f2
adjust plots
jverzani Jun 28, 2025
aa8e9e0
script to adjust plotly position in loading of javascript
jverzani Jun 28, 2025
5013211
work on better figures
jverzani Jul 2, 2025
2a7e0cb
Merge branch 'main' of https://github.com/jverzani/CalculusWithJuliaN…
jverzani Jul 2, 2025
6c10803
modify adjust_plotly
jverzani Jul 2, 2025
c38a7c9
WIP; better figures
jverzani Jul 2, 2025
31ce21c
merge in main
jverzani Jul 2, 2025
c3a9487
edits
jverzani Jul 23, 2025
e0b14c2
Merge branch 'main' of https://github.com/jverzani/CalculusWithJuliaN…
jverzani Jul 23, 2025
c3b221c
Merge branch 'main' into v0.24
jverzani Jul 23, 2025
33c6e62
em dash; sentence case
jverzani Jul 27, 2025
05bf5af
Merge branch 'main' of https://github.com/jverzani/CalculusWithJuliaN…
jverzani Jul 27, 2025
e9efe69
ignore more
jverzani Jul 27, 2025
beb166e
merge main
jverzani Jul 27, 2025
50cb645
add some examples, figures
jverzani Jul 29, 2025
8398f21
typos
jverzani Jul 29, 2025
d7c0d08
typos
jverzani Jul 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ docs/site
test/benchmarks.json
Manifest.toml
TODO.md
Changelog.md
/*/_pdf_index.pdf
/*/*/_pdf_index.pdf
/*/_pdf_index.typ
/*/*/_pdf_index.typ
/*/CalculusWithJulia.pdf
default.profraw
/quarto/default.profraw
/*/*/default.profraw
/*/*/default.profraw
/*/bonepile.qmd
/*/*/bonepile.qmd
/*/*_files
43 changes: 43 additions & 0 deletions adjust_plotly.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# The issue with `PlotlyLight` appears to be that
# the `str` below is called *after* the inclusion of `require.min.js`
# (That str is included in the `.qmd` file to be included in the header
# but the order of inclusion appears not to be adjustable)
# This little script just adds a line *before* the require call
# which seems to make it all work. The line number 83 might change.

#alternatives/plotly_plotting.html
function _add_plotly(f)
lineno = 117

str = """
<script src="https://cdn.plot.ly/plotly-2.11.0.min.js"></script>
"""

r = readlines(f)
open(f, "w") do io
for (i,l) ∈ enumerate(r)
i == lineno && println(io, str)
println(io, l)
end
end
end



function (@main)(args...)
for (root, dirs, files) in walkdir("_book")
for fᵢ ∈ files
f = joinpath(root, fᵢ)
if endswith(f, ".html")
_add_plotly(f)
end
end
end

#f = "_book/integrals/center_of_mass.html"
#_add_plotly(f)

return 1
end

["ODEs", "alternatives", "derivatives", "differentiable_vector_calculus", "integral_vector_calculus", "integrals", "limits", "misc", "precalc", "site_libs"]
1 change: 1 addition & 0 deletions quarto/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
/_freeze/
/*/*_files/
/*/*.ipynb/
/*/bonepile.qmd
/*/references.bib
weave_support.jl
20 changes: 11 additions & 9 deletions quarto/ODEs/differential_equations.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ R(0) &= 0\\
\end{align*}
$$

In `Julia` we define these, `N` to model the total population, and `u0` to be the proportions.
In `Julia` we define these parameter values and `N` to model the total population and `u0` to be represent the proportions.


```{julia}
Expand All @@ -94,18 +94,20 @@ An *estimated* set of values for $k$ and $b$ are $k=1/3$, coming from the averag
Okay, the mathematical modeling is done; now we try to solve for the unknown functions using `DifferentialEquations`.


To warm up, if $b=0$ then $i'(t) = -k \cdot i(t)$ describes the infected. (There is no circulation of people in this case.) The solution would be achieved through:
To warm up, if $b=0$ then $i'(t) = -k \cdot i(t)$ describes the infected. (There is no circulation of people in this case.) This is a single ODE. The solution would be achieved through:


```{julia}
#| hold: true
k = 1/3

f(u,p,t) = -k * u # solving u′(t) = - k u(t)

uᵢ0= I0/N
time_span = (0.0, 20.0)

prob = ODEProblem(f, I0/N, time_span)
sol = solve(prob, Tsit5(), reltol=1e-8, abstol=1e-8)
prob = ODEProblem(f, uᵢ0, time_span)
sol = solve(prob, Tsit5(); reltol=1e-8, abstol=1e-8)

plot(sol)
```
Expand All @@ -120,7 +122,7 @@ $$
\frac{di}{dt} = -k \cdot i(t) = F(i(t), k, t)
$$

where $F$ depends on the current value ($i$), a parameter ($k$), and the time ($t$). We did not utilize $p$ above for the parameter, as it was easy not to, but could have, and will in the following. The time variable $t$ does not appear by itself in our equation, so only `f(u, p, t) = -k * u` was used, `u` the generic name for a solution which in this case is $i$.
where $F$ depends on the current value ($i$), a parameter ($k$), and the time ($t$). We did not utilize $p$ above for the parameter, as it was easy not to, but could have, and will in the following. The time variable $t$ does not appear by itself in our equation, so only `f(u, p, t) = -k * u` was used, `u` the generic name for a solution which in this case was labeled with an $i$.


The problem we set up needs an initial value (the $u0$) and a time span to solve over. Here we want time to model real time, so use floating point values.
Expand Down Expand Up @@ -167,7 +169,7 @@ The `sir!` function has the trailing `!` indicating – by convention – it *mu

:::

With the update function defined, the problem is setup and a solution found with in the same manner:
With the update function defined, the problem is setup and a solution is found using the same manner as before:


```{julia}
Expand All @@ -193,7 +195,7 @@ p = (k=1/2, b=2) # change b from 1/2 to 2 -- more daily contact
prob = ODEProblem(sir!, u0, time_span, p)
sol = solve(prob, Tsit5())

plot(sol)
plot(sol; legend=:right)
```

The graphs are somewhat similar, but the steady state is reached much more quickly and nearly everyone became infected.
Expand Down Expand Up @@ -252,7 +254,7 @@ end
p
```

The 3-dimensional graph with `plotly` can have its viewing angle adjusted with the mouse. When looking down on the $x-y$ plane, which code `b` and `k`, we can see the rapid growth along a line related to $b/k$.
(A 3-dimensional graph with `plotly` or `Makie` can have its viewing angle adjusted with the mouse. When looking down on the $x-y$ plane, which code `b` and `k`, we can see the rapid growth along a line related to $b/k$.)


Smith and Moore point out that $k$ is roughly the reciprocal of the number of days an individual is sick enough to infect others. This can be estimated during a breakout. However, they go on to note that there is no direct way to observe $b$, but there is an indirect way.
Expand Down Expand Up @@ -382,7 +384,7 @@ SOL = solve(trajectory_problem, Tsit5(); p = ps, callback=cb)
plot(t -> SOL(t)[1], t -> SOL(t)[2], TSPAN...; legend=false)
```

Finally, we note that the `ModelingToolkit` package provides symbolic-numeric computing. This allows the equations to be set up symbolically, as in `SymPy` before being passed off to `DifferentialEquations` to solve numerically. The above example with no wind resistance could be translated into the following:
Finally, we note that the `ModelingToolkit` package provides symbolic-numeric computing. This allows the equations to be set up symbolically, as has been illustrated with `SymPy`, before being passed off to `DifferentialEquations` to solve numerically. The above example with no wind resistance could be translated into the following:


```{julia}
Expand Down
8 changes: 4 additions & 4 deletions quarto/ODEs/euler.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ plot(exp(-1/2)*exp(x^2/2), x0, 2)
plot!(xs, ys)
```

Not bad. We wouldn't expect this to be exact - due to the concavity of the solution, each step is an underestimate. However, we see it is an okay approximation and would likely be better with a smaller $h$. A topic we pursue in just a bit.
Not bad. We wouldn't expect this to be exact---due to the concavity of the solution, each step is an underestimate. However, we see it is an okay approximation and would likely be better with a smaller $h$. A topic we pursue in just a bit.


Rather than type in the above command each time, we wrap it all up in a function. The inputs are $n$, $a=x_0$, $b=x_n$, $y_0$, and, most importantly, $F$. The output is massaged into a function through a call to `linterp`, rather than two vectors. The `linterp` function[^Interpolations] we define below just finds a function that linearly interpolates between the points and is `NaN` outside of the range of the $x$ values:
Expand Down Expand Up @@ -263,7 +263,7 @@ Each step introduces an error. The error in one step is known as the *local trun
The total error, or more commonly, *global truncation error*, is the error between the actual answer and the approximate answer at the end of the process. It reflects an accumulation of these local errors. This error is *bounded* by a constant times $h$. Since it gets smaller as $h$ gets smaller in direct proportion, the Euler method is called *first order*.


Other, somewhat more complicated, methods have global truncation errors that involve higher powers of $h$ - that is for the same size $h$, the error is smaller. In analogy is the fact that Riemann sums have error that depends on $h$, whereas other methods of approximating the integral have smaller errors. For example, Simpson's rule had error related to $h^4$. So, the Euler method may not be employed if there is concern about total resources (time, computer, ...), it is important for theoretical purposes in a manner similar to the role of the Riemann integral.
Other, somewhat more complicated, methods have global truncation errors that involve higher powers of $h$---that is for the same size $h$, the error is smaller. In analogy is the fact that Riemann sums have error that depends on $h$, whereas other methods of approximating the integral have smaller errors. For example, Simpson's rule had error related to $h^4$. So, the Euler method may not be employed if there is concern about total resources (time, computer, ...), it is important for theoretical purposes in a manner similar to the role of the Riemann integral.


In the examples, we will see that for many problems the simple Euler method is satisfactory, but not always so. The task of numerically solving differential equations is not a one-size-fits-all one. In the following, a few different modifications are presented to the basic Euler method, but this just scratches the surface of the topic.
Expand Down Expand Up @@ -648,7 +648,7 @@ plot(euler2(x0, xn, y0, yp0, 360), 0, 4T)
plot!(x -> pi/4*cos(sqrt(g/l)*x), 0, 4T)
```

Even now, we still see that something seems amiss, though the issue is not as dramatic as before. The oscillatory nature of the pendulum is seen, but in the Euler solution, the amplitude grows, which would necessarily mean energy is being put into the system. A familiar instance of a pendulum would be a child on a swing. Without pumping the legs - putting energy in the system - the height of the swing's arc will not grow. Though we now have oscillatory motion, this growth indicates the solution is still not quite right. The issue is likely due to each step mildly overcorrecting and resulting in an overall growth. One of the questions pursues this a bit further.
Even now, we still see that something seems amiss, though the issue is not as dramatic as before. The oscillatory nature of the pendulum is seen, but in the Euler solution, the amplitude grows, which would necessarily mean energy is being put into the system. A familiar instance of a pendulum would be a child on a swing. Without pumping the legs---putting energy in the system---the height of the swing's arc will not grow. Though we now have oscillatory motion, this growth indicates the solution is still not quite right. The issue is likely due to each step mildly overcorrecting and resulting in an overall growth. One of the questions pursues this a bit further.


## Questions
Expand Down Expand Up @@ -794,7 +794,7 @@ Modify the `euler2` function to implement the Euler-Cromer method. What do you s
#| hold: true
#| echo: false
choices = [
"The same as before - the amplitude grows",
"The same as before---the amplitude grows",
"The solution is identical to that of the approximation found by linearization of the sine term",
"The solution has a constant amplitude, but its period is slightly *shorter* than that of the approximate solution found by linearization",
"The solution has a constant amplitude, but its period is slightly *longer* than that of the approximate solution found by linearization"]
Expand Down
13 changes: 7 additions & 6 deletions quarto/ODEs/odes.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ $$
U'(t) = -r U(t), \quad U(0) = U_0.
$$

This shows that the rate of change of $U$ depends on $U$. Large positive values indicate a negative rate of change - a push back towards the origin, and large negative values of $U$ indicate a positive rate of change - again, a push back towards the origin. We shouldn't be surprised to either see a steady decay towards the origin, or oscillations about the origin.
This shows that the rate of change of $U$ depends on $U$. Large positive values indicate a negative rate of change---a push back towards the origin, and large negative values of $U$ indicate a positive rate of change---again, a push back towards the origin. We shouldn't be surprised to either see a steady decay towards the origin, or oscillations about the origin.


What will we find? This equation is different from the previous two equations, as the function $U$ appears on both sides. However, we can rearrange to get:
Expand Down Expand Up @@ -177,7 +177,7 @@ $$
In words, the initial difference in temperature of the object and the environment exponentially decays to $0$.


That is, as $t > 0$ goes to $\infty$, the right hand will go to $0$ for $r > 0$, so $T(t) \rightarrow T_a$ - the temperature of the object will reach the ambient temperature. The rate of this is largest when the difference between $T(t)$ and $T_a$ is largest, so when objects are cooling the statement "hotter things cool faster" is appropriate.
That is, as $t > 0$ goes to $\infty$, the right hand will go to $0$ for $r > 0$, so $T(t) \rightarrow T_a$---the temperature of the object will reach the ambient temperature. The rate of this is largest when the difference between $T(t)$ and $T_a$ is largest, so when objects are cooling the statement "hotter things cool faster" is appropriate.


A graph of the solution for $T_0=200$ and $T_a=72$ and $r=1/2$ is made as follows. We've added a few line segments from the defining formula, and see that they are indeed tangent to the solution found for the differential equation.
Expand Down Expand Up @@ -403,7 +403,7 @@ To finish, we call `dsolve` to find a solution (if possible):
out = dsolve(eqn)
```

This answer - to a first-order equation - has one free constant, `C₁`, which can be solved for from an initial condition. We can see that when $a > 0$, as $x$ goes to positive infinity the solution goes to $1$, and when $x$ goes to negative infinity, the solution goes to $0$ and otherwise is trapped in between, as expected.
This answer---to a first-order equation---has one free constant, `C₁`, which can be solved for from an initial condition. We can see that when $a > 0$, as $x$ goes to positive infinity the solution goes to $1$, and when $x$ goes to negative infinity, the solution goes to $0$ and otherwise is trapped in between, as expected.


The limits are confirmed by investigating the limits of the right-hand:
Expand Down Expand Up @@ -618,6 +618,7 @@ nothing
```

![The cables of an unloaded suspension bridge have a different shape than a loaded suspension bridge. As seen, the cables in this [figure](https://www.brownstoner.com/brooklyn-life/verrazano-narrows-bridge-anniversary-historic-photos/) would be modeled by a catenary.](./figures/verrazano-narrows-bridge-anniversary-historic-photos-2.jpeg)

---


Expand All @@ -641,7 +642,7 @@ $$
x''(t) = 0, \quad y''(t) = -g.
$$

That is, the $x$ position - where no forces act - has $0$ acceleration, and the $y$ position - where the force of gravity acts - has constant acceleration, $-g$, where $g=9.8m/s^2$ is the gravitational constant. These equations can be solved to give:
That is, the $x$ position---where no forces act---has $0$ acceleration, and the $y$ position---where the force of gravity acts---has constant acceleration, $-g$, where $g=9.8m/s^2$ is the gravitational constant. These equations can be solved to give:


$$
Expand Down Expand Up @@ -957,7 +958,7 @@ radioq(choices, answ)
##### Question


The example with projectile motion in a medium has a parameter $\gamma$ modeling the effect of air resistance. If `y` is the answer - as would be the case if the example were copy-and-pasted in - what can be said about `limit(y, gamma=>0)`?
The example with projectile motion in a medium has a parameter $\gamma$ modeling the effect of air resistance. If `y` is the answer---as would be the case if the example were copy-and-pasted in---what can be said about `limit(y, gamma=>0)`?


```{julia}
Expand All @@ -966,7 +967,7 @@ The example with projectile motion in a medium has a parameter $\gamma$ modeling
choices = [
"The limit is a quadratic polynomial in `x`, mirroring the first part of that example.",
"The limit does not exist, but the limit to `oo` gives a quadratic polynomial in `x`, mirroring the first part of that example.",
"The limit does not exist -- there is a singularity -- as seen by setting `gamma=0`."
"The limit does not exist---there is a singularity---as seen by setting `gamma=0`."
]
answ = 1
radioq(choices, answ)
Expand Down
14 changes: 9 additions & 5 deletions quarto/ODEs/solve.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,10 @@ function solve(prob::Problem, alg::EulerMethod)
end
```

The post has a more elegant means to unpack the parameters from the structures, but for each of the above, the parameters are unpacked, and then the corresponding algorithm employed. As of version `v1.7` of `Julia`, the syntax `(;g,y0,v0,tspan) = prob` could also be employed.
The post has a more elegant means to unpack the parameters from the structures, but for each of the above, the parameters are unpacked using the dot notation for `getproperty`, and then the corresponding algorithm employed. As of version `v1.7` of `Julia`, the syntax `(;g,y0,v0,tspan) = prob` could also have been employed.


The exact formulas, `y(t) = y0 + v0*(t - t0) - g*(t - t0)^2/2` and `v(t) = v0 - g*(t - t0)`, follow from well-known physics formulas. Each answer is wrapped in a `Solution` type so that the answers found can be easily extracted in a uniform manner.
The exact answers, `y(t) = y0 + v0*(t - t0) - g*(t - t0)^2/2` and `v(t) = v0 - g*(t - t0)`, follow from well-known physics formulas for constant-acceleration motion. Each answer is wrapped in a `Solution` type so that the answers found can be easily extracted in a uniform manner.


For example, plots of each can be obtained through:
Expand All @@ -138,7 +138,9 @@ plot!(sol_exact.t, sol_exact.y; label="exact solution", ls=:auto)
title!("On the Earth"; xlabel="t", legend=:bottomleft)
```

Following the post, since the time step `dt = 0.1` is not small enough, the error of the Euler method is rather large. Next we change the algorithm parameter, `dt`, to be smaller:
Following the post, since the time step `dt = 0.1` is not small enough, the error of the Euler method is readily identified.

Next we change the algorithm parameter, `dt`, to be smaller:


```{julia}
Expand All @@ -155,7 +157,7 @@ title!("On the Earth"; xlabel="t", legend=:bottomleft)
It is worth noting that only the first line is modified, and only the method requires modification.


Were the moon to be considered, the gravitational constant would need adjustment. This parameter is part of the problem, not the solution algorithm.
Were the moon to be considered, the gravitational constant would need adjustment. This parameter is a property of the problem, not the solution algorithm, as `dt` is.


Such adjustments are made by passing different values to the `Problem` constructor:
Expand All @@ -175,7 +177,9 @@ title!("On the Moon"; xlabel="t", legend=:bottomleft)
The code above also adjusts the time span in addition to the graviational constant. The algorithm for exact formula is set to use the `dt` value used in the `euler` formula, for easier comparison. Otherwise, outside of the labels, the patterns are the same. Only those things that need changing are changed, the rest comes from defaults.


The above shows the benefits of using a common interface. Next, the post illustrates how *other* authors could extend this code, simply by adding a *new* `solve` method. For example,
The above shows the benefits of using a common interface.

Next, the post illustrates how *other* authors could extend this code, simply by adding a *new* `solve` method. For example, a sympletic method conserves a quantity, so can track long-term evolution without drift.


```{julia}
Expand Down
12 changes: 11 additions & 1 deletion quarto/README-quarto.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,22 @@ Short cut. Run first command until happy, then run second to publish

```
quarto render
#julia adjust_plotly.jl # <-- no longer needed
# maybe git config --global http.postBuffer 157286400
quarto publish gh-pages --no-render
```


But better to

```
quarto render
# commit changes and push
# fix typos
quarto render
quarto publish gh-pages --no-render
```


To compile the pages through quarto


Expand Down
Loading