Skip to content

Commit 7b0546f

Browse files
committed
Let user pass coefficients to series(); show both this and the version with automatic coefficients in tutorial
1 parent 5f01f6a commit 7b0546f

File tree

3 files changed

+56
-22
lines changed

3 files changed

+56
-22
lines changed

docs/src/tutorials/perturbation.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,8 @@ quintic = x^5 + ϵ*x ~ 1
4747
```
4848
If $ϵ = 1$, we get our original problem. With $ϵ = 0$, the problem transforms to the easy quintic equation $x^5 = 1$ with the trivial real solution $x = 1$ (and four complex solutions which we ignore). Next, expand $x$ as a power series in $ϵ$:
4949
```@example perturb
50-
x_taylor = series(x, ϵ, 0:7) # expand x in a power series in ϵ
51-
x_coeffs = taylor_coeff(x_taylor, ϵ) # TODO: get coefficients at series creation
52-
x_taylor
50+
x_coeffs, = @variables a[0:7] # create Taylor series coefficients
51+
x_taylor = series(x_coeffs, ϵ) # expand x in a power series in ϵ
5352
```
5453
Then insert this into the quintic equation and expand it, too, to the same order:
5554
```@example perturb
@@ -58,7 +57,7 @@ quintic_taylor = taylor(quintic_taylor, ϵ, 0:7)
5857
```
5958
This messy equation must hold for each power of $ϵ$, so we can separate it into one nicer equation per order:
6059
```@example perturb
61-
quintic_eqs = taylor_coeff(quintic_taylor, ϵ)
60+
quintic_eqs = taylor_coeff(quintic_taylor, ϵ, 0:7)
6261
quintic_eqs[1:5] # for readability, show only 5 shortest equations
6362
```
6463
These equations show three important features of perturbation theory:
@@ -77,10 +76,11 @@ function solve_cascade(eqs, xs, x₀, ϵ)
7776
isequal(eq0.lhs, eq0.rhs) || error("$sol does not solve $(eqs[1])")
7877
7978
# solve remaining equations sequentially
80-
for i in 2:lastindex(eqs)
79+
for i in 2:length(eqs)
8180
eq = substitute(eqs[i], sol) # insert previous solutions
82-
x = Symbolics.symbolic_linear_solve(eq, xs[i]) # solve current equation
83-
sol = merge(sol, Dict(xs[i] => x)) # store solution
81+
x = xs[begin+i-1] # need not be 1-indexed
82+
xsol = Symbolics.symbolic_linear_solve(eq, x) # solve current equation
83+
sol = merge(sol, Dict(x => xsol)) # store solution
8484
end
8585
8686
return sol
@@ -117,8 +117,8 @@ println("Newton's method solution: E = ", E_newton)
117117

118118
Next, let us solve the same problem with the perturbative method. It is most common to expand $E$ as a series in $M$. Repeating the procedure from the quintic example, we get these equations:
119119
```@example perturb
120-
E_taylor = series(E, M, 0:5)
121-
E_coeffs = taylor_coeff(E_taylor, M) # TODO: get coefficients at series creation
120+
E_taylor = series(E, M, 0:5) # this auto-creates coefficients E[0:5]
121+
E_coeffs = taylor_coeff(E_taylor, M) # get a handle to the coefficients
122122
kepler_eqs = taylor_coeff(substitute(kepler, E => E_taylor), M, 0:5)
123123
kepler_eqs[1:4] # for readability
124124
```
@@ -142,7 +142,7 @@ E_wiki = 1/(1-e)*M - e/(1-e)^4*M^3/factorial(3) + (9e^2+e)/(1-e)^7*M^5/factorial
142142
Alternatively, we can expand $E$ in $e$ instead of $M$, giving the solution (the trivial solution when $e = 0$ is $E_0=M$):
143143
```@example perturb
144144
E_taylor′ = series(E, e, 0:5)
145-
E_coeffs′ = taylor_coeff(E_taylor′, e) # TODO: get at creation
145+
E_coeffs′ = taylor_coeff(E_taylor′, e)
146146
kepler_eqs′ = taylor_coeff(substitute(kepler, E => E_taylor′), e, 0:5)
147147
E_coeffs_sol′ = solve_cascade(kepler_eqs′, E_coeffs′, M, e)
148148
E_pert′ = substitute(E_taylor′, E_coeffs_sol′)

src/taylor.jl

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,43 @@
11
"""
2-
series(y, x, [x0=0,] ns; name = nameof(y))
2+
series(cs, x, [x0=0,], ns=0:length(cs)-1)
33
4-
Expand the variable `y` in a power series in the variable `x` around `x0` to orders `ns`.
4+
Return the power series in `x` around `x0` to the powers `ns` with coefficients `cs`.
5+
6+
series(y, x, [x0=0,] ns)
7+
8+
Return the power series in `x` around `x0` to the powers `ns` with coefficients automatically created from the variable `y`.
59
610
Examples
711
========
812
913
```julia
10-
julia> @variables z ϵ
11-
2-element Vector{Num}:
14+
julia> @variables x y[0:3] z
15+
3-element Vector{Any}:
16+
x
17+
y[0:3]
1218
z
13-
ϵ
1419
15-
julia> series(z, ϵ, 2, 0:3)
16-
z[0] + z[1]*(-2 + ϵ) + z[2]*((-2 + ϵ)^2) + z[3]*((-2 + ϵ)^3)
20+
julia> series(y, x, 2)
21+
y[0] + (-2 + x)*y[1] + ((-2 + x)^2)*y[2] + ((-2 + x)^3)*y[3]
22+
23+
julia> series(z, x, 2, 0:3)
24+
z[0] + (-2 + x)*z[1] + ((-2 + x)^2)*z[2] + ((-2 + x)^3)*z[3]
1725
```
1826
"""
19-
function series(y, x, x0, ns; name = nameof(y))
20-
c, = @variables $name[ns]
21-
return sum(c[n] * (x - x0)^n for n in ns)
27+
function series(cs::AbstractArray, x::Number, x0::Number, ns::AbstractArray = 0:length(cs)-1)
28+
length(cs) == length(ns) || error("There are different numbers of coefficients and orders")
29+
s = sum(c * (x - x0)^n for (c, n) in zip(cs, ns))
30+
return s
31+
end
32+
function series(cs::AbstractArray, x::Number, ns::AbstractArray = 0:length(cs)-1)
33+
return series(cs, x, 0, ns)
34+
end
35+
function series(y::Num, x::Number, x0::Number, ns::AbstractArray)
36+
cs, = @variables $(nameof(y))[ns]
37+
return series(cs, x, x0, ns)
2238
end
23-
function series(y, x, ns; kwargs...)
24-
return series(y, x, 0, ns; kwargs...)
39+
function series(y::Num, x::Number, ns::AbstractArray)
40+
return series(y, x, 0, ns)
2541
end
2642

2743
"""

test/taylor.jl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
11
using Symbolics
22

3+
# test all variations of series() input
4+
ns = 0:3
5+
Y, = @variables y[ns]
6+
@variables x y
7+
8+
# 1) first argument is a variable
9+
@test isequal(series(y, x, 7, ns), Y[0] + Y[1]*(x-7)^1 + Y[2]*(x-7)^2 + Y[3]*(x-7)^3)
10+
@test isequal(series(y, x, ns), substitute(series(y, x, 7, ns), x => x + 7))
11+
@test_throws ErrorException series(2*y, x, ns) # 2*y is a meaningless variable name
12+
13+
# 2) first argument is coefficients
14+
@test isequal(series(Y, x, 7), series(y, x, 7, ns))
15+
@test isequal(series(Y, x, ns), substitute(series(Y, x, 7), x => x + 7))
16+
@test isequal(series([1,2,3], 8, 4, [5,6,7]), 1*(8-4)^5 + 2*(8-4)^6 + 3*(8-4)^7)
17+
@test isequal(series([1,2,3], 8, 4), 1 + 2*(8-4)^1 + 3*(8-4)^2)
18+
@test isequal(series([1,2,3], 4, [5,6,7]), series([1,2,3], 8, 4, [5,6,7]))
19+
@test isequal(series([1,2,3], 4), 1^0 + 2*4^1 + 3*4^2)
20+
321
# https://en.wikipedia.org/wiki/Taylor_series#List_of_Maclaurin_series_of_some_common_functions
422
@variables x
523
@test taylor(exp(x), x, 0:9) - sum(x^n//factorial(n) for n in 0:9) == 0

0 commit comments

Comments
 (0)