Skip to content

Commit 0776652

Browse files
authored
shift to iterators (#3)
* shift to iterators * fix docs
1 parent b47a399 commit 0776652

File tree

12 files changed

+401
-604
lines changed

12 files changed

+401
-604
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
fail-fast: false
2424
matrix:
2525
version:
26-
- '1.2'
26+
- '1.0'
2727
- '1'
2828
- 'nightly'
2929
os:

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
Manifest.toml
22
docs/build
33
docs/Manifest.toml
4+
*.html

Project.toml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
name = "LegendrePolynomials"
22
uuid = "3db4a2ba-fc88-11e8-3e01-49c72059a882"
3-
version = "0.2.4"
3+
version = "0.3"
44

55
[deps]
6-
HyperDualNumbers = "50ceba7f-c3ee-5a84-a6e8-3ad40456ec97"
76
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
87

98
[compat]
10-
HyperDualNumbers = "4"
119
OffsetArrays = "0.11, 1"
1210
julia = "1"
11+
12+
[extras]
13+
HyperDualNumbers = "50ceba7f-c3ee-5a84-a6e8-3ad40456ec97"
14+
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
15+
16+
[targets]
17+
test = ["HyperDualNumbers", "Test"]

README.md

Lines changed: 14 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,10 @@
44
[![stable](https://img.shields.io/badge/docs-stable-blue.svg)](https://jishnub.github.io/LegendrePolynomials.jl/stable)
55
[![dev](https://img.shields.io/badge/docs-latest-blue.svg)](https://jishnub.github.io/LegendrePolynomials.jl/dev)
66

7-
Legendre polynomials and their derivatives using automatic differentiation
7+
Iterative computation of Legendre Polynomials
88

99
# Getting Started
1010

11-
## Prerequisites
12-
13-
The package depends on `HyperDualNumbers` and `OffsetArrays`.
14-
1511
## Installing
1612

1713
To install the package, run
@@ -20,134 +16,29 @@ To install the package, run
2016
] add LegendrePolynomials
2117
```
2218

23-
## Using
24-
25-
This package computes Legendre polynomials and their first and second derivatives in one pass using hyperdual numbers. All the functions require an argument `x` that satisfies `-1<=x<=1`, and either an integer `l` that indicates the degree of the polynomial, or a possibly optional keyword argument `lmax` that indicates the maximum degree of the Legendre polynomials that will be computed. The polynomials are computed iteratively using a three-term recurrence relation, so all the values in the range will have to be computed.
26-
27-
There are two classes of functions, one that returns the value of the Legendre polynomial and its derivatives for a single `l`, and one that returns the values for all `l` in `0:lmax` for a specified `lmax` as an array. The arrays returned will have the Legendre polynomials and their derivatives stored along columns.
28-
29-
There are three quantities that can be computed: `Pl`, `dPl` and `d2Pl`. It's possible to compute them individually or as combinations of two or three at once. There are allocating as well as non-allocating methods that do the same.
30-
31-
### Individual degrees
19+
## Quick start
3220

33-
The way to compute Legendre polynomials of degree `l` and argument `x` is through the function `Pl(x,l)`. This is the general signature followed by the other functions as well that compute the derivatives for a single degree. The functions are relatively accurate and performant till degrees of millions, although a thorough test of accuracy has not been carried out (verified roughly with results from Mathematica for some degrees).
21+
To compute the Legendre polynomials for a given argument `x` and a degree `l`, use `Pl(x,l)`:
3422

3523
```julia
36-
julia> Pl(0.5,10)
37-
-0.18822860717773438
38-
39-
julia> @btime Pl(0.5,1_000_000)
40-
13.022 ms (0 allocations: 0 bytes)
41-
-0.0006062610545162491
24+
julia> Pl(0.5, 20)
25+
-0.04835838106737356
4226
```
4327

44-
The accuracy can be increased by using Arbitrary Precision Arithmetic, through the use of
45-
`BigInt` and `BigFloat`. This comes at the expense of performance though.
28+
To compute all the polynomials for `0 <= l <= lmax`, use
4629

4730
```julia
48-
julia> @btime Pl(1/3,1_000)
49-
11.135 μs (0 allocations: 0 bytes)
50-
0.01961873093750127
51-
52-
julia> @btime Pl(big(1)/3,1_000)
53-
1.751 ms (58965 allocations: 3.13 MiB)
54-
0.01961873093750094969323575593064773353450010511010742490834078609343359408691498
55-
```
56-
57-
The way to compute the derivatives is through `dPl(x,l)` and `d2Pl(x,l)`, for example
58-
59-
```julia
60-
julia> dPl(0.5,5)
61-
-2.2265625000000004
62-
63-
julia> d2Pl(0.5,5)
64-
-6.5625
65-
```
66-
67-
Combinations of these three can be computed as well, for example
68-
69-
```julia
70-
julia> Pl_dPl(0.5,5)
71-
(0.08984375, -2.2265625000000004)
72-
73-
julia> Pl_d2Pl(0.5,5)
74-
(0.08984375, -6.5625)
75-
76-
julia> dPl_d2Pl(0.5,5)
77-
(-2.2265625000000004, -6.5625)
78-
79-
julia> Pl_dPl_d2Pl(0.5,5)
80-
(0.08984375, -2.2265625000000004, -6.5625)
81-
```
82-
83-
### All degrees up to a cutoff
84-
85-
The second class of methods return all the polynomials up to a cutoff degree `lmax`. They are returned as `OffsetArrays` that have 0-based indexing, keeping in mind that the polynomials start from `l=0`.
86-
87-
The polynomials and their derivatives can be computed in general by calling the function `P(x;lmax)`, where `P` has to be chosen appropriately as necessary. The keyword argument has to be specified in the allocating functions, whereas it may be inferred from the array in the non-allocating versions.
88-
89-
An example of the allocating functions are
90-
91-
```julia
92-
julia> Pl(0.5,lmax=3)
93-
4-element OffsetArray(::Array{Float64,1}, 0:3) with eltype Float64 with indices 0:3:
94-
1.0
95-
0.5
96-
-0.125
31+
julia> collectPl(0.5, lmax = 5)
32+
6-element OffsetArray(::Array{Float64,1}, 0:5) with eltype Float64 with indices 0:5:
33+
1.0
34+
0.5
35+
-0.125
9736
-0.4375
98-
99-
julia> dPl(0.5,lmax=3)
100-
4-element OffsetArray(::Array{Float64,1}, 0:3) with eltype Float64 with indices 0:3:
101-
0.0
102-
1.0
103-
1.5
104-
0.3750000000000001
105-
106-
julia> d2Pl(0.5,lmax=3)
107-
4-element OffsetArray(::Array{Float64,1}, 0:3) with eltype Float64 with indices 0:3:
108-
0.0
109-
0.0
110-
3.0
111-
7.5
112-
```
113-
114-
It's possible to compute combinations analogous to the ones seen earlier, for example
115-
116-
```julia
117-
julia> Pl_dPl_d2Pl(0.5,lmax=3)
118-
([1.0, 0.5, -0.125, -0.4375], [0.0, 1.0, 1.5, 0.3750000000000001], [0.0, 0.0, 3.0, 7.5])
119-
```
120-
121-
This returns a 3-tuple of `OffsetArrays` `Pl`, `dPl` and `d2Pl`.
122-
123-
There are non-allocating functions as well that can be called using a pre-allocated array. As an example
124-
125-
```julia
126-
julia> P=zeros(0:3,0:2)
127-
4×3 OffsetArray(::Array{Float64,2}, 0:3, 0:2) with eltype Float64 with indices 0:3×0:2:
128-
0.0 0.0 0.0
129-
0.0 0.0 0.0
130-
0.0 0.0 0.0
131-
0.0 0.0 0.0
132-
133-
julia> Pl_dPl_d2Pl!(P,0.5)
134-
4×3 OffsetArray(::Array{Float64,2}, 0:3, 0:2) with eltype Float64 with indices 0:3×0:2:
135-
1.0 0.0 0.0
136-
0.5 1.0 0.0
137-
-0.125 1.5 3.0
138-
-0.4375 0.375 7.5
139-
140-
julia> fill!(P,0);
141-
142-
julia> dPl!(P,0.5)
143-
4×3 OffsetArray(::Array{Float64,2}, 0:3, 0:2) with eltype Float64 with indices 0:3×0:2:
144-
0.0 0.0 0.0
145-
0.0 1.0 0.0
146-
0.0 1.5 0.0
147-
0.0 0.375 0.0
37+
-0.2890625
38+
0.08984375
14839
```
14940

150-
Note that the column number that will be populated depends on the order of the derivative, assuming 0-based indexing. Therefore `Pl!` will fill column 0, `dPl!` will fill column 1 and `d2Pl!` will fill column 2. Combinations of these will fill multiple columns as expected.
41+
Check the documentation for other usage.
15142

15243
# License
15344

docs/Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
[deps]
22
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
3+
HyperDualNumbers = "50ceba7f-c3ee-5a84-a6e8-3ad40456ec97"
34
LegendrePolynomials = "3db4a2ba-fc88-11e8-3e01-49c72059a882"
45

56
[compat]
67
Documenter = "0.26"
8+
HyperDualNumbers = "4"

docs/make.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ makedocs(;
1414
assets=String[],
1515
),
1616
pages=[
17-
"Reference" => "index.md",
17+
"Introduction" => "index.md",
18+
"Derivatives" => "derivatives.md",
1819
],
1920
)
2021

docs/src/derivatives.md

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Derivatives of Legendre Polynomials
2+
3+
The Julia automatic differentiation framework may be used to compute the derivatives of Legendre polynomials alongside their values. Since the defintions of the polynomials are completely general, they may be called with dual or hyperdual numbers as arguments to evaluate derivarives in one go.
4+
We demonstrate one example of this using the package [`HyperDualNumbers.jl`](https://github.com/JuliaDiff/HyperDualNumbers.jl) v4:
5+
6+
```@meta
7+
DocTestSetup = quote
8+
using LegendrePolynomials
9+
end
10+
```
11+
12+
```jldoctest hyperdual
13+
julia> x = 0.5;
14+
15+
julia> Pl(x, 3)
16+
-0.4375
17+
18+
julia> using HyperDualNumbers
19+
20+
julia> xh = Hyper(x, one(x), one(x), zero(x));
21+
22+
julia> p = Pl(xh, 3)
23+
-0.4375 + 0.375ε₁ + 0.375ε₂ + 7.5ε₁ε₂
24+
```
25+
26+
The Legendre polynomial ``P_\ell(x)`` may be obtained using
27+
28+
```jldoctest hyperdual
29+
julia> realpart(p)
30+
-0.4375
31+
```
32+
33+
The first derivative ``dP_\ell(x)/dx`` may be obtained as
34+
35+
```jldoctest hyperdual
36+
julia> ε₁part(p)
37+
0.375
38+
```
39+
40+
The second derivative ``d^2P_\ell(x)/dx^2`` may be obtained using
41+
42+
```jldoctest hyperdual
43+
julia> ε₁ε₂part(p)
44+
7.5
45+
```
46+
47+
Something similar may also be evaluated for all `l` iteratively. For example, the function `collectPl` evaluates Legendre polynomials for the `HyperDualNumber` argument for a range of `l`:
48+
49+
```jldoctest hyperdual
50+
julia> collectPl(xh, lmax=4)
51+
5-element OffsetArray(::Array{Hyper{Float64},1}, 0:4) with eltype Hyper{Float64} with indices 0:4:
52+
1.0 + 0.0ε₁ + 0.0ε₂ + 0.0ε₁ε₂
53+
0.5 + 1.0ε₁ + 1.0ε₂ + 0.0ε₁ε₂
54+
-0.125 + 1.5ε₁ + 1.5ε₂ + 3.0ε₁ε₂
55+
-0.4375 + 0.375ε₁ + 0.375ε₂ + 7.5ε₁ε₂
56+
-0.2890625 - 1.5625ε₁ - 1.5625ε₂ + 5.625ε₁ε₂
57+
```
58+
59+
We may extract the first derivatives by broadcasting the function `ε₁part` on the array as:
60+
61+
```jldoctest hyperdual
62+
julia> ε₁part.(collectPl(xh, lmax=4))
63+
5-element OffsetArray(::Array{Float64,1}, 0:4) with eltype Float64 with indices 0:4:
64+
0.0
65+
1.0
66+
1.5
67+
0.375
68+
-1.5625
69+
```
70+
71+
Similarly the function `ε₁ε₂part` may be used to obtain the second derivatives.
72+
73+
Several convenience functions to compute the derivatives of Legendre polynomials were available in `LegendrePolynomials` v0.2, but have been removed in v0.3. The users are encouraged to implement convenience functions to extract the derivatives as necessary. As an exmaple, we may compute the polynomials and their first and second derivatives together as
74+
75+
```jldoctest
76+
julia> using HyperDualNumbers
77+
78+
julia> function Pl_dPl_d2Pl(x; lmax)
79+
xh = Hyper(x, one(x), one(x), zero(x))
80+
p = collectPl(xh, lmax = lmax)
81+
realpart.(p), ε₁part.(p), ε₁ε₂part.(p)
82+
end
83+
Pl_dPl_d2Pl (generic function with 1 method)
84+
85+
julia> Pl_dPl_d2Pl(0.5, lmax = 3)
86+
([1.0, 0.5, -0.125, -0.4375], [0.0, 1.0, 1.5, 0.375], [0.0, 0.0, 3.0, 7.5])
87+
```

docs/src/index.md

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,75 @@
11
```@meta
22
CurrentModule = LegendrePolynomials
3+
DocTestSetup = quote
4+
using LegendrePolynomials
5+
end
36
```
47

5-
# LegendrePolynomials.jl
8+
# Introduction
9+
10+
Compute [Legendre polynomials](https://en.wikipedia.org/wiki/Legendre_polynomials) using a 3-term recursion relation (Bonnet’s recursion formula).
11+
12+
```math
13+
P_\ell(x) = \left((2\ell-1) x P_{\ell-1}(x) - (\ell-1)P_{\ell - 2}(x)\right)/\ell
14+
```
15+
16+
Currently this package evaluates the standard polynomials that satisfy ``P_\ell(1) = 1``. These are normalized as
17+
18+
```math
19+
\int P_m(x) P_n(x) dx = \frac{2}{2n+1} \delta_{mn}.
20+
```
21+
22+
There are two main functions:
23+
24+
* [`Pl(x,l)`](@ref Pl): this evaluates the Legendre polynomial for a given degree `l` at the argument `x`. The argument needs to satisfy `-1 <= x <= 1`.
25+
* [`collectPl(x; lmax)`](@ref collectPl): this evaluates all the polynomials for `l` lying in `0:lmax` at the argument `x`. As before the argument needs to lie in the domain of validity. Functionally this is equivalent to `Pl.(x, 0:lmax)`, except `collectPl` evaluates the result in one pass, and is therefore faster. There is also the in-place version [`collectPl!`](@ref) that uses a pre-allocated array.
26+
27+
# Quick Start
28+
29+
Evaluate the Legendre polynomial for one `l` at an argument`x` as `Pl(x, l)`:
30+
31+
```jldoctest
32+
julia> Pl(0.5, 3)
33+
-0.4375
34+
```
35+
36+
Evaluate all the polynomials for `l` in `0:lmax` as
37+
38+
```jldoctest
39+
julia> collectPl(0.5, lmax = 3)
40+
4-element OffsetArray(::Array{Float64,1}, 0:3) with eltype Float64 with indices 0:3:
41+
1.0
42+
0.5
43+
-0.125
44+
-0.4375
45+
```
46+
47+
# Increase precision
48+
49+
The precision of the result may be changed by using arbitrary-precision types such as `BigFloat`. For example, using `Float64` arguments we obtain
50+
51+
```jldoctest
52+
julia> Pl(1/3, 5)
53+
0.33333333333333337
54+
```
55+
56+
whereas using `BigFloat`, we obtain
57+
58+
```jldoctest
59+
julia> Pl(big(1)/3, 5)
60+
0.3333333333333333333333333333333333333333333333333333333333333333333333333333305
61+
```
62+
63+
The precision of the latter may be altered using `setprecision`, as
64+
65+
```jldoctest
66+
julia> setprecision(300) do
67+
Pl(big(1)/3, 5)
68+
end
69+
0.33333333333333333333333333333333333333333333333333333333333333333333333333333333333333333317
70+
```
71+
72+
# Reference
673

774
```@autodocs
875
Modules = [LegendrePolynomials]

0 commit comments

Comments
 (0)