Skip to content

Commit 7410ab3

Browse files
authored
Accept normalization options (#10)
* normalized legendre polynomials * separate iterations for Pl and Plm * bugfix in Pl, fix docs * update docs * remove unused function normtype * remove lmax from iterator * accept lmin in collectPl* functions * embarrassing bugfix in Pl norm * Add logfactorial caches * Add tests for norm * update docs * Optionally set the CS phase * Add test for non-overflow * promote lmin/lmax in collectPl* * Add test for large-degree Pl * Accept negative orders * Add norm tests for negative order * update docs for negative m * Add precision tests for BigFloat * Add tests for parity
1 parent ee811ac commit 7410ab3

File tree

7 files changed

+644
-415
lines changed

7 files changed

+644
-415
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.0'
26+
- '1.6'
2727
- '1'
2828
- 'nightly'
2929
os:

Project.toml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
11
name = "LegendrePolynomials"
22
uuid = "3db4a2ba-fc88-11e8-3e01-49c72059a882"
3-
version = "0.3.6"
3+
version = "0.4.0"
44

55
[deps]
66
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
7+
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
78

89
[compat]
910
Aqua = "0.5"
1011
HyperDualNumbers = "4"
11-
OffsetArrays = "0.11, 1"
12-
julia = "1"
12+
OffsetArrays = "1"
13+
QuadGK = "2"
14+
SpecialFunctions = "2.1"
15+
julia = "1.6"
1316

1417
[extras]
1518
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
1619
HyperDualNumbers = "50ceba7f-c3ee-5a84-a6e8-3ad40456ec97"
20+
QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"
1721
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
1822

1923
[targets]
20-
test = ["Aqua", "HyperDualNumbers", "Test"]
24+
test = ["Aqua", "HyperDualNumbers", "Test", "QuadGK"]

README.md

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Iterative computation of Legendre Polynomials
1111

1212
## Installing
1313

14-
To install the package, run
14+
To install the package, run
1515

1616
```julia
1717
] add LegendrePolynomials
@@ -53,17 +53,14 @@ julia> collectPl(0.5, lmax = 5)
5353
0.08984375
5454
```
5555

56-
To compute all the associated Legendre polynomials for `0 <= l <= lmax`, use `collectPlm(x; m, lmax)`
56+
To compute all the associated Legendre polynomials for `abs(m) <= l <= lmax`, use `collectPlm(x; m, lmax)`
5757

5858
```julia
5959
julia> collectPlm(0.5, lmax = 5, m = 3)
60-
6-element OffsetArray(::Vector{Float64}, 0:5) with eltype Float64 with indices 0:5:
61-
0.0
62-
0.0
63-
0.0
60+
3-element OffsetArray(::Vector{Float64}, 3:5) with eltype Float64 with indices 3:5:
6461
-9.742785792574933
65-
-34.099750274012266
66-
-42.62468784251533
62+
-34.09975027401223
63+
-42.62468784251535
6764
```
6865

6966
To compute all the n-th derivatives for `0 <= l <= lmax`, use `collectdnPl(x; n, lmax)`

docs/src/index.md

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,45 @@ Compute [Legendre polynomials](https://en.wikipedia.org/wiki/Legendre_polynomial
1313
P_\ell(x) = \left((2\ell-1) x P_{\ell-1}(x) - (\ell-1)P_{\ell - 2}(x)\right)/\ell
1414
```
1515

16-
Currently this package evaluates the standard polynomials that satisfy ``P_\ell(1) = 1`` and ``P_0(x) = 1``. These are normalized as
16+
By default this package evaluates the standard polynomials that satisfy ``P_\ell(1) = 1`` and ``P_0(x) = 1``. These are normalized as
1717

1818
```math
1919
\int_{-1}^1 P_m(x) P_n(x) dx = \frac{2}{2n+1} \delta_{mn}.
2020
```
2121

22-
There are six main functions:
22+
Optionally, normalized polynomials may be evaluated that have an L2 norm of `1`.
2323

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-
* [`Plm(x, l, m)`](@ref Plm): this evaluates the associated Legendre polynomial ``P_\ell,m(x)`` at the argument ``x``. The argument needs to satisfy `-1 <= x <= 1`.
27-
* [`collectPlm(x; m, lmax)`](@ref collectPlm): this evaluates the associated Legendre polynomials with coefficient `m` for `l = 0:lmax`. There is also an in-place version [`collectPlm!`](@ref) that uses a pre-allocated array.
24+
Analogous to Legendre polynomials, one may evaluate associated Legendre polynomials using a 3-term recursion relation. This is evaluated by iterating over the normalized associated Legendre functions, and multiplying the norm at the final stage. Such an iteration avoids floating-point overflow.
25+
26+
The relation used in evaluating normalized associated Legendre polynomials ``\bar{P}_{\ell}^{m}\left(x\right)`` is
27+
28+
```math
29+
\bar{P}_{\ell}^{m}\left(x\right)=\alpha_{\ell m}\left(x\bar{P}_{\ell-1}^{m}\left(x\right)-\frac{1}{\alpha_{\ell-1m}}\bar{P}_{\ell-2}^{m}\left(x\right)\right),
30+
```
31+
32+
where
33+
```math
34+
\alpha_{\ell m}=\sqrt{\frac{\left(2\ell+1\right)\left(2\ell-1\right)}{\left(\ell-m\right)\left(\ell+m\right)}},
35+
```
36+
37+
The starting value for a specific ``m`` is obtained by setting ``\ell = m``, in which case we use the explicit relation
38+
39+
```math
40+
\bar{P}_{m}^{m}\left(x\right)=\left(-1\right)^{m}\left(2m-1\right)!!\sqrt{\frac{\left(2m+1\right)}{2\left(2m\right)!}}\left(1-x^{2}\right)^{\left(m/2\right)}.
41+
```
42+
43+
The polynomials, thus defined, include the Condon-Shortley phase ``(-1)^m``, and may be evaluated using the standard normalization as
44+
45+
```math
46+
P_{\ell}^{m}\left(x\right)=\sqrt{\frac{2\left(\ell+m\right)!}{\left(2\ell+1\right)\left(\ell-m\right)!}}\bar{P}_{\ell}^{m}\left(x\right).
47+
```
48+
49+
There are six main functions:
50+
51+
* [`Pl(x,l; [norm])`](@ref Pl): this evaluates the Legendre polynomial for a given degree `l` at the argument `x`. The argument needs to satisfy `-1 <= x <= 1`.
52+
* [`collectPl(x; lmax, [norm])`](@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.
53+
* [`Plm(x, l, m; [norm])`](@ref Plm): this evaluates the associated Legendre polynomial ``P_\ell^m(x)`` at the argument ``x``. The argument needs to satisfy `-1 <= x <= 1`.
54+
* [`collectPlm(x; m, lmax, [norm])`](@ref collectPlm): this evaluates the associated Legendre polynomials with coefficient `m` for `l = abs(m):lmax`. There is also an in-place version [`collectPlm!`](@ref) that uses a pre-allocated array.
2855
* [`dnPl(x, l, n)`](@ref dnPl): this evaluates the ``n``-th derivative of the Legendre polynomial ``P_\ell(x)`` at the argument ``x``. The argument needs to satisfy `-1 <= x <= 1`.
2956
* [`collectdnPl(x; n, lmax)`](@ref collectdnPl): this evaluates the ``n``-th derivative of all the Legendre polynomials for `l = 0:lmax`. There is also an in-place version [`collectdnPl!`](@ref) that uses a pre-allocated array.
3057

@@ -33,15 +60,21 @@ There are six main functions:
3360
Evaluate the Legendre polynomial for one `l` at an argument`x` as `Pl(x, l)`:
3461

3562
```jldoctest
36-
julia> Pl(0.5, 3)
63+
julia> p = Pl(0.5, 3)
3764
-0.4375
65+
66+
julia> p ≈ -7/16 # analytical value
67+
true
3868
```
3969

4070
Evaluate the associated Legendre Polynomial one `l,m` pair as `Plm(x, l, m)`:
4171

4272
```jldoctest
43-
julia> Plm(0.5, 3, 2)
44-
5.625
73+
julia> p = Plm(0.5, 3, 2)
74+
5.624999999999997
75+
76+
julia> p ≈ 45/8 # analytical value
77+
true
4578
```
4679

4780
Evaluate the `n`th derivative for one `l` as `dnPl(x, l, n)`:
@@ -51,7 +84,8 @@ julia> dnPl(0.5, 3, 2)
5184
7.5
5285
```
5386

54-
Evaluate all the polynomials for `l` in `0:lmax` as `collectPl(x; lmax)`
87+
Evaluate the Legendre polynomials for `l` in `lmin:lmax` as `collectPl(x; lmin, lmax)`.
88+
By default `lmin` is chosen to be `0`, and may be omitted.
5589

5690
```jldoctest
5791
julia> collectPl(0.5, lmax = 3)
@@ -62,17 +96,15 @@ julia> collectPl(0.5, lmax = 3)
6296
-0.4375
6397
```
6498

65-
Evaluate all the associated Legendre Polynomials for coefficient `m` as `collectPlm(x; lmax, m)`:
99+
Evaluate the associated Legendre Polynomials for order `m` and degree `l` in `lmin:lmax`
100+
as `collectPlm(x; m, lmin, lmax)`. By default `lmin` is chosen to be `abs(m)`, and may be omitted.
66101

67102
```jldoctest
68103
julia> collectPlm(0.5, lmax = 5, m = 3)
69-
6-element OffsetArray(::Vector{Float64}, 0:5) with eltype Float64 with indices 0:5:
70-
0.0
71-
0.0
72-
0.0
104+
3-element OffsetArray(::Vector{Float64}, 3:5) with eltype Float64 with indices 3:5:
73105
-9.742785792574933
74-
-34.099750274012266
75-
-42.62468784251533
106+
-34.09975027401223
107+
-42.62468784251535
76108
```
77109

78110
Evaluate all the `n`th derivatives as `collectdnPl(x; lmax, n)`:
@@ -123,6 +155,8 @@ julia> dnPl(big(1)/2, 300, 200) # BigFloat
123155
1.738632750542319394663553898425873258768856732308227932150592526951212145232716e+499
124156
```
125157

158+
In general, one would need to use higher precision for both the argument `x` and the degree `l` to obtain accurate results.
159+
126160
# Reference
127161

128162
```@autodocs

0 commit comments

Comments
 (0)