forked from SciML/SciMLBook
-
Notifications
You must be signed in to change notification settings - Fork 42
/
Copy pathLorenzManyWays.jl
176 lines (160 loc) · 4.47 KB
/
LorenzManyWays.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
using BenchmarkTools
function lorenz(u,p)
α,σ,ρ,β = p
du1 = u[1] + α*(σ*(u[2]-u[1]))
du2 = u[2] + α*(u[1]*(ρ-u[3]) - u[2])
du3 = u[3] + α*(u[1]*u[2] - β*u[3])
[du1,du2,du3] # returns a vector
end
p = (0.02,10.0,28.0,8/3)
# first try
function solve_system_save(f,u0,p,n)
u = Vector{typeof(u0)}(undef,n)
u[1] = u0
for i in 1:n-1
u[i+1] = f(u[i],p)
end
u
end
@btime solve_system_save(lorenz,[1.0,0.0,0.0],p,1000);
# second try (shows that pushing doesnt hurt or help)
# you might think that not allocating the memory would slow you down, but...
# julia doubles memory each time
function solve_system_save_push(f,u0,p,n)
u = Vector{typeof(u0)}(undef,1) # note the 1
u[1] = u0
for i in 1:n-1
push!(u,f(u[i],p))
end
u
end
@btime solve_system_save_push(lorenz,[1.0,0.0,0.0],p,1000);
# matlab users might prefer matrices
# third try
function solve_system_save_matrix(f,u0,p,n)
u = Matrix{eltype(u0)}(undef,length(u0),n)
u[:,1] = u0
for i in 1:n-1
u[:,i+1] = f(u[:,i],p)
end
u
end
@btime solve_system_save_matrix(lorenz,[1.0,0.0,0.0],p,1000);
# slicing into the matrix is expensive
#fourth try -- fix with a view
function solve_system_save_matrix_view(f,u0,p,n)
u = Matrix{eltype(u0)}(undef,length(u0),n)
u[:,1] = u0
for i in 1:n-1
u[:,i+1] = f(@view(u[:,i]),p)
end
u
end
@btime solve_system_save_matrix_view(lorenz,[1.0,0.0,0.0],p,1000);
#okay that's more like it
# Note that growing matrices adaptively is a really bad idea
function solve_system_save_matrix_resize(f,u0,p,n)
u = Matrix{eltype(u0)}(undef,length(u0),1)
u[:,1] = u0
for i in 1:n-1
u = hcat(u,f(@view(u[:,i]),p))
end
u
end
@btime solve_system_save_matrix_resize(lorenz,[1.0,0.0,0.0],p,1000);
# so let's go back to matrices of vectors
function lorenz(u,p)
α,σ,ρ,β = p
du1 = u[1] + α*(σ*(u[2]-u[1]))
du2 = u[2] + α*(u[1]*(ρ-u[3]) - u[2])
du3 = u[3] + α*(u[1]*u[2] - β*u[3])
[du1,du2,du3] # returns a vector
end
function solve_system_save(f,u0,p,n)
u = Vector{typeof(u0)}(undef,n)
u[1] = u0
for i in 1:n-1
u[i+1] = f(u[i],p)
end
u
end
function lorenz2(du,u,p) # du is now an argument so it can mutate
α,σ,ρ,β = p
du[1] = u[1] + α*(σ*(u[2]-u[1]))
du[2] = u[2] + α*(u[1]*(ρ-u[3]) - u[2])
du[3] = u[3] + α*(u[1]*u[2] - β*u[3])
end
p = (0.02,10.0,28.0,8/3)
function solve_system_save2(f,u0,p,n)
u = Vector{typeof(u0)}(undef,n)
du = similar(u0) # new line
u[1] = u0
for i in 1:n-1
f(du,u[i],p) # now called with du [no allocations!]
u[i+1] = du
end
u
end
@btime solve_system_save2(lorenz2,[1.0,0.0,0.0],p,1000);
#but
# solve_system_save2(lorenz2,[1.0,0.0,0.0],p,1000)
# we are changign the data every time, can't get around that
function solve_system_save_copy(f,u0,p,n)
u = Vector{typeof(u0)}(undef,n)
du = similar(u0)
u[1] = u0
for i in 1:n-1
f(du,u[i],p)
u[i+1] = copy(du)
end
u
end
@btime solve_system_save_copy(lorenz2,[1.0,0.0,0.0],p,1000);
# static array approach
using StaticArrays
function lorenz3(u,p)
α,σ,ρ,β = p
du1 = u[1] + α*(σ*(u[2]-u[1]))
du2 = u[2] + α*(u[1]*(ρ-u[3]) - u[2])
du3 = u[3] + α*(u[1]*u[2] - β*u[3])
@SVector [du1,du2,du3]
end
p = (0.02,10.0,28.0,8/3)
function solve_system_save(f,u0,p,n)
u = Vector{typeof(u0)}(undef,n)
u[1] = u0
for i in 1:n-1
u[i+1] = f(u[i],p)
end
u
end
@btime solve_system_save(lorenz3,@SVector[1.0,0.0,0.0],p,1000);
# people like inbounds, i don't find it saves that much that often, but sometimes.
function lorenz4(u,p)
α,σ,ρ,β = p
@inbounds begin
du1 = u[1] + α*(σ*(u[2]-u[1]))
du2 = u[2] + α*(u[1]*(ρ-u[3]) - u[2])
du3 = u[3] + α*(u[1]*u[2] - β*u[3])
end
@SVector [du1,du2,du3]
end
function solve_system_save(f,u0,p,n)
u = Vector{typeof(u0)}(undef,n)
@inbounds u[1] = u0
@inbounds for i in 1:n-1
u[i+1] = f(u[i],p)
end
u
end
@btime solve_system_save(lorenz4,@SVector[1.0,0.0,0.0],p,1000);
# the single allocation is the output , that can be removed
function solve_system_save!(u,f,u0,p,n) # add an output u to be mutated as well
@inbounds u[1] = u0
@inbounds for i in 1:length(u)-1
u[i+1] = f(u[i],p)
end
u
end
u = Vector{typeof(@SVector([1.0,0.0,0.0]))}(undef,1000)
@btime solve_system_save!(u,lorenz4,@SVector([1.0,0.0,0.0]),p,1000);