Skip to content

Commit 7c4bcf2

Browse files
authored
Use Literate.jl in generating examples (#816)
* Use in generating examples * Add GR ENV var * Remove unused images
1 parent 6c0475c commit 7c4bcf2

File tree

20 files changed

+321
-362
lines changed

20 files changed

+321
-362
lines changed

.github/workflows/docs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,5 @@ jobs:
3939
env:
4040
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
4141
DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} # If authenticating with SSH deploy key
42+
GKSwstype: "100" # https://discourse.julialang.org/t/generation-of-documentation-fails-qt-qpa-xcb-could-not-connect-to-display/60988
4243
run: julia --project=docs/ docs/make.jl

.gitignore

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,6 @@
1-
examples/.ipynb_checkpoints/RectPDE Examples-checkpoint.ipynb
2-
examples/.ipynb_checkpoints/Wave and Klein-Gordon equation on a square-checkpoint.ipynb
3-
examples/.ipynb_checkpoints/Manipulate Helmholtz-checkpoint.ipynb
4-
examples/.ipynb_checkpoints/RectPDE Timings-checkpoint.ipynb
5-
examples/.ipynb_checkpoints/PDE Examples-checkpoint.ipynb
6-
examples/.ipynb_checkpoints/Periodic PDEs-checkpoint.ipynb
7-
examples/.ipynb_checkpoints/Rectangle PDEs-checkpoint.ipynb
8-
examples/.ipynb_checkpoints/Time Evolution PDEs on Square-checkpoint.ipynb
9-
examples/.ipynb_checkpoints/Time Evolution PDEs on Disk-checkpoint.ipynb
10-
examples/.ipynb_checkpoints/PDE Timings-checkpoint.ipynb
11-
examples/.ipynb_checkpoints/Disk PDEs-checkpoint.ipynb
12-
examples/.ipynb_checkpoints/Manipulate ODEs and PDEs-checkpoint.ipynb
13-
examples/.ipynb_checkpoints/Time Evolution PDEs on Interval-checkpoint.ipynb
14-
examples/.ipynb_checkpoints/Time Evolution PDEs on Square (Gadfly)-checkpoint.ipynb
15-
examples/.ipynb_checkpoints/Time Evolution PDEs on Square (GLPlot)-checkpoint.ipynb
16-
examples/.ipynb_checkpoints/Untitled0-checkpoint.ipynb
17-
examples/.ipynb_checkpoints/Floquet-checkpoint.ipynb
18-
examples/.ipynb_checkpoints/Sampling-checkpoint.ipynb
19-
examples/.ipynb_checkpoints/Time Evolution PDEs on Disk (GLPlot)-checkpoint.ipynb
20-
examples/.ipynb_checkpoints/Time Evolution PDEs on Square (PlotlyJS)-checkpoint.ipynb
21-
examples/gks.svg
22-
examples/.ipynb_checkpoints/Fractional Integral Equations-checkpoint.ipynb
231
docs/build/index.md
242
docs/build
3+
docs/src/generated
254

265
src/.DS_Store
276
.DS_Store

Project.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ DomainSets = "0.3, 0.4, 0.5"
3030
DualNumbers = "0.6.2"
3131
FFTW = "1"
3232
FastTransforms = "0.13, 0.14"
33+
Plots = "1"
3334
RecipesBase = "1.0"
3435
Reexport = "1.0"
3536
SpecialFunctions = "1.1, 2"
@@ -38,8 +39,9 @@ julia = "1.6"
3839
[extras]
3940
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
4041
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
42+
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
4143
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
4244
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
4345

4446
[targets]
45-
test = ["Aqua", "Documenter", "Test", "Random"]
47+
test = ["Aqua", "Documenter", "Plots", "Random", "Test"]

README.md

Lines changed: 10 additions & 190 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,17 @@
1111
[![Join the chat at https://gitter.im/JuliaApproximation/ApproxFun.jl](https://badges.gitter.im/JuliaApproximation/ApproxFun.jl.svg)](https://gitter.im/JuliaApproximation/ApproxFun.jl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
1212

1313

14-
1514
ApproxFun is a package for approximating functions. It is in a similar vein to the Matlab
1615
package [`Chebfun`](http://www.chebfun.org) and the Mathematica package [`RHPackage`](https://github.com/dlfivefifty/RHPackage).
1716

18-
The [`ApproxFun Documentation`](https://JuliaApproximation.github.io/ApproxFun.jl/latest) contains detailed information, or read on for a brief overview of the package.
17+
The [`ApproxFun Documentation`](https://JuliaApproximation.github.io/ApproxFun.jl/latest) contains detailed information, or read on for a brief overview of the package. The documentation contains examples of usage, such as solving ordinary and partial differential equations.
1918

20-
The [`ApproxFun Examples`](https://github.com/JuliaApproximation/ApproxFunExamples) contains many examples of
21-
using this package, in Jupyter notebooks and Julia scripts.
19+
The [`ApproxFun Examples`](https://github.com/JuliaApproximation/ApproxFunExamples) repo contains many examples of
20+
using this package, in Jupyter notebooks and Julia scripts. Note that this is independently maintained, so it might not always be in sync with the latest version of `ApproxFun`. We recommend checking the examples in the documentation first, as these will always be compatible with the latest version of the package.
2221

2322
## Introduction
2423

24+
### Approximating Functions
2525

2626
Take your two favourite functions on an interval and create approximations to them as simply as:
2727

@@ -50,15 +50,14 @@ scatter!(rp, h.(rp); label="extrema")
5050
<img src=https://github.com/JuliaApproximation/ApproxFun.jl/raw/master/images/extrema.png width=500 height=400>
5151

5252

53-
## Differentiation and integration
53+
### Differentiation and integration
5454

5555

5656
Notice from above that to find the extrema, we used `'` overridden for the `differentiate` function. Several other `Julia`
57-
base functions are overridden for the purposes of calculus. Because the exponential is its own
58-
derivative, the `norm` is small:
57+
base functions are overridden for the purposes of calculus. We may check that the exponential is its own derivative, by evaluating the norm of the difference and checking that it is small:
5958

6059
```julia
61-
f = Fun(x->exp(x), -1..1)
60+
f = Fun(exp, -1..1)
6261
norm(f-f') # 4.4391656415701095e-14
6362
```
6463

@@ -70,7 +69,7 @@ g = g + f(-1)
7069
norm(f-g) # 3.4989733283850415e-15d
7170
```
7271

73-
Algebraic and differential operations are also implemented where possible, and most of Julia's built-in functions are overridden to accept `Fun`s:
72+
Algebraic and differential operations are also implemented where possible, and most of Julia's built-in functions (and special functions from [`SpecialFunctions.jl`](https://github.com/JuliaMath/SpecialFunctions.jl)) are overridden to accept `Fun`s:
7473

7574
```julia
7675
x = Fun()
@@ -79,188 +78,9 @@ g = besselj(3,exp(f))
7978
h = airyai(10asin(f)+2g)
8079
```
8180

81+
## Examples of Usage
8282

83-
## Solving ordinary differential equations
84-
85-
86-
We can also solve differential equations. Consider the Airy ODE `u'' - x u = 0` as a boundary value problem on `[-1000,200]` with conditions `u(-1000) = 1` and `u(200) = 2`. The unique solution is a linear combination of Airy functions. We can calculate it as follows:
87-
88-
```julia
89-
x = Fun(identity, -1000..200) # the function x on the interval -1000..200
90-
D = Derivative() # The derivative operator
91-
B = Dirichlet() # Dirichlet conditions
92-
L = D^2 - x # the Airy operator
93-
u = [B;L] \ [[1,2],0] # Calculate u such that B*u == [1,2] and L*u == 0
94-
plot(u; label="u")
95-
```
96-
97-
<img src=https://github.com/JuliaApproximation/ApproxFun.jl/raw/master/images/airy.png width=500 height=400>
98-
99-
100-
## Nonlinear Boundary Value problems
101-
102-
Solve a nonlinear boundary value problem satisfying the ODE `0.001u'' + 6*(1-x^2)*u' + u^2 = 1` with boundary conditions `u(-1)==1`, `u(1)==-0.5` on `[-1,1]`:
103-
104-
```julia
105-
x = Fun()
106-
u₀ = 0.0x # initial guess
107-
N = u -> [u(-1)-1, u(1)+0.5, 0.001u'' + 6*(1-x^2)*u' + u^2 - 1]
108-
u = newton(N, u₀) # perform Newton iteration in function space
109-
plot(u)
110-
```
111-
112-
<img src=https://github.com/JuliaApproximation/ApproxFun.jl/raw/master/images/nbvp.png width=500 height=400>
113-
114-
One can also solve a system nonlinear ODEs with potentially nonlinear boundary conditions:
115-
116-
```julia
117-
118-
x = Fun(identity, 0..1)
119-
N = (u1,u2) -> [u1'(0) - 0.5*u1(0)*u2(0);
120-
u2'(0) + 1;
121-
u1(1) - 1;
122-
u2(1) - 1;
123-
u1'' + u1*u2;
124-
u2'' - u1*u2]
125-
126-
u10 = one(x)
127-
u20 = one(x)
128-
u1,u2 = newton(N, [u10,u20])
129-
130-
plot(u1, label="u1")
131-
plot!(u2, label="u2")
132-
```
133-
134-
<img src=images/example_nonlin.png width=500 height=400>
135-
136-
137-
## Periodic functions
138-
139-
140-
There is also support for Fourier representations of functions on periodic intervals.
141-
Specify the space `Fourier` to ensure that the representation is periodic:
142-
143-
```julia
144-
f = Fun(cos, Fourier(-π..π))
145-
norm(f' + Fun(sin, Fourier(-π..π))) # 5.923502902288505e-17
146-
```
147-
148-
Due to the periodicity, Fourier representations allow for the asymptotic savings of `2/π`
149-
in the number of coefficients that need to be stored compared with a Chebyshev representation.
150-
ODEs can also be solved when the solution is periodic:
151-
152-
```julia
153-
s = Chebyshev(-π..π)
154-
a = Fun(t-> 1+sin(cos(2t)), s)
155-
L = Derivative() + a
156-
f = Fun(t->exp(sin(10t)), s)
157-
B = periodic(s,0)
158-
uChebyshev = [B;L] \ [0.;f]
159-
160-
s = Fourier(-π..π)
161-
a = Fun(t-> 1+sin(cos(2t)), s)
162-
L = Derivative() + a
163-
f = Fun(t->exp(sin(10t)), s)
164-
uFourier = L\f
165-
166-
ncoefficients(uFourier)/ncoefficients(uChebyshev),2/π
167-
plot(uFourier)
168-
```
169-
170-
<img src=https://github.com/JuliaApproximation/ApproxFun.jl/raw/master/images/periodic.png width=500 height=400>
171-
172-
173-
174-
## Sampling
175-
176-
177-
Other operations including random number sampling using [Olver & Townsend 2013]. The
178-
following code samples 10,000 from a PDF given as the absolute value of the sine function on `[-5,5]`:
179-
180-
```julia
181-
f = abs(Fun(sin, -5..5))
182-
x = ApproxFun.sample(f,10000)
183-
histogram(x;normed=true)
184-
plot!(f/sum(f))
185-
```
186-
187-
<img src=https://github.com/JuliaApproximation/ApproxFun.jl/raw/master/images/sample.png width=500 height=400>
188-
189-
190-
## Solving partial differential equations
191-
192-
193-
We can solve PDEs, the following solves Helmholtz `Δu + 100u=0` with `u(±1,y)=u(x,±1)=1`
194-
on a square. This function has weak singularities at the corner,
195-
so we specify a lower tolerance to avoid resolving these singularities
196-
completely.
197-
198-
```julia
199-
d = ChebyshevInterval()^2 # Defines a rectangle
200-
Δ = Laplacian(d) # Represent the Laplacian
201-
f = ones((d)) # one at the boundary
202-
u = \([Dirichlet(d); Δ+100I], [f;0.]; # Solve the PDE
203-
tolerance=1E-5)
204-
surface(u) # Surface plot
205-
```
206-
207-
<img src=https://github.com/JuliaApproximation/ApproxFun.jl/raw/master/images/helmholtz.png width=500 height=400>
208-
209-
210-
<!-- We can also evolve PDEs. The following solves advection—diffusion
211-
`u_t = 0.01Δu - 4u_x -3u_y` on a rectangle
212-
213-
```julia
214-
d = ChebyshevInterval()^2
215-
u0 = Fun((x,y)->exp(-40(x-.1)^2-40(y+.2)^2),d)
216-
B = dirichlet(d)
217-
D = Derivative(ChebyshevInterval())
218-
L = (0.01D^2-4D)⊗I + I⊗(0.01D^2-3D)
219-
h = 0.002
220-
timeevolution(B,L,u0,h) # Requires GLPlot
221-
``` -->
222-
223-
224-
## High precision
225-
226-
Solving differential equations with high precision types is available. The following calculates `e` to 300 digits by solving the ODE `u' = u`:
227-
228-
```julia
229-
setprecision(1000) do
230-
d = BigFloat(0)..BigFloat(1)
231-
D = Derivative(d)
232-
u = [ldirichlet(); D-I] \ [1; 0]
233-
@test u(1) exp(BigFloat(1))
234-
end
235-
```
236-
237-
238-
## Self-adjoint eigenvalue problems
239-
240-
This solves the confined anharmonic oscillator, `[-𝒟² + V(x)] u = λu`, where `u(±10) = 0`, `V(x) = ω*x² + x⁴`, and `ω = 25`.
241-
```julia
242-
n = 3000
243-
ω = 25.0
244-
d = Segment(-10..10)
245-
S = Ultraspherical(0.5, d)
246-
NS = NormalizedPolynomialSpace(S)
247-
V = Fun(x->ω*x^2+x^4, S)
248-
L = -Derivative(S, 2) + V
249-
C = Conversion(domainspace(L), rangespace(L))
250-
B = Dirichlet(S)
251-
QS = QuotientSpace(B)
252-
Q = Conversion(QS, S)
253-
D1 = Conversion(S, NS)
254-
D2 = Conversion(NS, S)
255-
R = D1*Q
256-
P = cache(PartialInverseOperator(C, (0, ApproxFun.bandwidth(L, 1) + ApproxFun.bandwidth(R, 1) + ApproxFun.bandwidth(C, 2))))
257-
A = R'D1*P*L*D2*R
258-
B = R'R
259-
SA = Symmetric(A[1:n,1:n], :L)
260-
SB = Symmetric(B[1:n,1:n], :L)
261-
λ = eigvals(SA, SB)[1:round(Int, 3n/5)]
262-
```
263-
83+
Check the [documentation](https://JuliaApproximation.github.io/ApproxFun.jl/latest) for examples of usage.
26484

26585
## References
26686

docs/Project.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,13 @@ BandedMatrices = "aae01518-5342-5314-be14-df237901396f"
44
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
55
DomainSets = "5b8099bc-c8ec-5219-889f-1d9e522a28bf"
66
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
7+
Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
8+
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
9+
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
10+
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
11+
12+
[compat]
13+
Documenter = "0.27"
14+
Literate = "2"
15+
Plots = "1"
16+
SpecialFunctions = "2"

docs/make.jl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
11
using Documenter, ApproxFun, BandedMatrices, DomainSets, LinearAlgebra
2+
using Literate
3+
4+
# Generate examples using Literate
5+
# See https://github.com/fredrikekre/Literate.jl/blob/master/docs/make.jl
6+
example_dir = joinpath(@__DIR__, "..", "examples")
7+
output_dir = joinpath(@__DIR__, "src/generated")
8+
9+
for example in ["ODE.jl", "PDE.jl", "Sampling.jl", "Periodic.jl",
10+
"Eigenvalue.jl", "NonlinearBVP.jl"]
11+
filename = joinpath(example_dir, example)
12+
Literate.markdown(filename, output_dir, documenter=true)
13+
end
214

315
makedocs(
416
doctest = false,
@@ -15,6 +27,14 @@ makedocs(
1527
"Operators" => "usage/operators.md",
1628
"Linear Equations" => "usage/equations.md"
1729
],
30+
"Examples" => [
31+
"generated/ODE.md",
32+
"generated/PDE.md",
33+
"generated/Sampling.md",
34+
"generated/Periodic.md",
35+
"generated/Eigenvalue.md",
36+
"generated/NonlinearBVP.md",
37+
],
1838
"Frequently Asked Questions" => "faq.md",
1939
"Library" => "library.md"
2040
]

examples/Eigenvalue.jl

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# # Self-adjoint Eigenvalue Problem
2+
# Ref:
3+
# [J. L. Aurentz & R. M. Slevinsky (2019), arXiv:1903.08538](https://arxiv.org/abs/1903.08538)
4+
5+
# We solve the confined anharmonic oscillator
6+
# ```math
7+
# \left[-\frac{d^2}{dx^2} + V(x)\right] u = λu,
8+
# ```
9+
# where ``u(\pm 10) = 0``, ``V(x) = ωx^2 + x^4``, and ``ω = 25``.
10+
11+
using ApproxFun
12+
using LinearAlgebra
13+
14+
# Define parameters
15+
ω = 25.0
16+
d = -10..10;
17+
S = Legendre(d)
18+
NS = NormalizedPolynomialSpace(S) # NormalizedLegendre
19+
D1 = Conversion(S, NS)
20+
D2 = Conversion(NS, S);
21+
22+
# Construct the differential operator
23+
V = Fun(x -> ω * x^2 + x^4, S)
24+
L = -Derivative(S, 2) + V;
25+
26+
# Basis recombination to transform to one that satisfies Dirichlet boundary conditions
27+
B = Dirichlet(S)
28+
QS = QuotientSpace(B)
29+
Q = Conversion(QS, S)
30+
R = D1*Q;
31+
32+
# This inversion is computed approximately, such that
33+
# $\mathrm{C}^-1 * \mathrm{C} ≈ \mathrm{I}$ up to a certain bandwidth
34+
C = Conversion(domainspace(L), rangespace(L))
35+
P = cache(PartialInverseOperator(C, (0, ApproxFun.bandwidth(L, 1) + ApproxFun.bandwidth(R, 1) + ApproxFun.bandwidth(C, 2))));
36+
37+
A = R'D1*P*L*D2*R
38+
B = R'R;
39+
40+
# We impose a cutoff to obtain approximate finite matrix representations
41+
n = 3000
42+
SA = Symmetric(A[1:n,1:n], :L)
43+
SB = Symmetric(B[1:n,1:n], :L)
44+
λ = eigvals(SA, SB)[1:round(Int, 3n/5)];
45+
46+
# We plot the eigenvalues
47+
import Plots
48+
Plots.plot(λ; title = "Eigenvalues", legend=false)

0 commit comments

Comments
 (0)