1- using DualArrays, LinearAlgebra, Plots, BenchmarkTools
1+ using DualArrays, LinearAlgebra, Plots, BenchmarkTools, BandedMatrices, ForwardDiff, Zygote
22
33"""
44Solving the Catenary Problem using DualArrays.jl
@@ -11,6 +11,19 @@ The computation of finite differences keeps the Jacobian sparse,
1111so we can use DualArrays.jl
1212"""
1313
14+ const plot_args = (
15+ xscale = :log10 ,
16+ yscale = :log10 ,
17+ lw = 2.5 ,
18+ marker = :circle ,
19+ color = :steelblue4 ,
20+ legend = :topleft ,
21+ framestyle = :box ,
22+ size = (960 , 600 ),
23+ left_margin = 10 Plots. mm,
24+ bottom_margin = 10 Plots. mm,
25+ )
26+
1427function L (y, h, alpha, beta)
1528 """
1629 Evaluate functional with boundary conditions (alpha, beta)
@@ -24,33 +37,109 @@ function L(y, h, alpha, beta)
2437 return y_mid .* sqrt .(1 .+ dy.^ 2 )
2538end
2639
27- function learn_catenary (h = 0.1 , alpha = cosh (- 1 ), beta = cosh (1 ), epochs = 2000 , lr = 0.01 )
40+ function learn_catenary_dualarrays (h = 0.1 , alpha = cosh (- 1 ), beta = cosh (1 ), epochs = 2000 , lr = 0.01 )
41+ n = Int (2 / h) - 1
42+ y = ones (n) * (alpha + beta) / 2
43+ for _ = 1 : epochs
44+ jac = DualArrays. jacobian (y -> L (y, h, alpha, beta), y, BandedMatrix)
45+ grads = h * sum (jac, dims= 1 )
46+ y -= lr * vec (grads)
47+ end
48+ return y
49+ end
50+
51+ function learn_catenary_forwarddiff (h = 0.1 , alpha = cosh (- 1 ), beta = cosh (1 ), epochs = 2000 , lr = 0.01 )
52+ n = Int (2 / h) - 1
53+ y = ones (n) * (alpha + beta) / 2
54+ for _ = 1 : epochs
55+ jac = ForwardDiff. jacobian (y -> L (y, h, alpha, beta), y)
56+ grads = h * sum (jac, dims= 1 )
57+ y -= lr * vec (grads)
58+ end
59+ return y
60+ end
61+
62+ function learn_catenary_zygote (h = 0.1 , alpha = cosh (- 1 ), beta = cosh (1 ), epochs = 2000 , lr = 0.01 )
2863 n = Int (2 / h) - 1
2964 y = ones (n) * (alpha + beta) / 2
3065 for _ = 1 : epochs
31- jac = jacobian (y -> L (y, h, alpha, beta), y, id = " banded " )
66+ jac = only (Zygote . jacobian (y -> L (y, h, alpha, beta), y) )
3267 grads = h * sum (jac, dims= 1 )
3368 y -= lr * vec (grads)
3469 end
3570 return y
3671end
3772
38- function plot_solution (h )
73+ function plot_solution (save = undef;h = 0.1 , alpha = cosh ( - 1 ), beta = cosh ( 1 ), epochs = 5000 , lr = 0.02 )
3974 x = collect (- 1 + h: h: 1 - h)
40- y = learn_catenary ()
41- plot (x, y, label = " Approximation" )
42- plot! (x, cosh .(x), label = " Exact Solution" )
75+ y = learn_catenary_dualarrays (h, alpha, beta, epochs, lr)
76+ plot (x, y, label = " Approximate solution (DualArrays)" , title= " Catenary Solution" , legend= :topleft )
77+ plot! (x, cosh .(x), label = " Exact Solution (cosh(x))" , ls = :dash )
78+ if save != = undef
79+ savefig (save)
80+ end
4381end
4482
45- function plot_times ()
46- hs = [0.1 , 0.05 , 0.02 , 0.01 , 0.005 , 0.002 ]
83+ function plot_times (save= undef; hs = [0.04 , 0.02 , 0.01 , 0.005 , 0.0025 , 0.00125 ], epochs = 200 , lr = 0.01 )
4784 ns = Int .(2 ./ hs) .- 1
4885 dualvector_times = Float64[]
86+ forwarddiff_times = Float64[]
87+ zygote_times = Float64[]
4988
5089 for (h, n) in zip (hs, ns)
5190 println (" Computing solution with h = $h , n = $n " )
52- push! (dualvector_times, @belapsed learn_catenary ($ h, cosh (- 1 ), cosh (1 ), 2000 , 0.01 ))
91+ push! (dualvector_times, @belapsed learn_catenary_dualarrays ($ h, cosh (- 1 ), cosh (1 ), $ epochs, $ lr))
92+ push! (forwarddiff_times, @belapsed learn_catenary_forwarddiff ($ h, cosh (- 1 ), cosh (1 ), $ epochs, $ lr))
93+ push! (zygote_times, @belapsed learn_catenary_zygote ($ h, cosh (- 1 ), cosh (1 ), $ epochs, $ lr))
94+ end
95+
96+ plot (
97+ ns,
98+ dualvector_times,
99+ ;
100+ label = " DualArrays" ,
101+ title = " Catenary Gradient Descent Runtime" ,
102+ xlabel = " Number of points (n)" ,
103+ ylabel = " Runtime (seconds)" ,
104+ yticks = 10 .^ collect (- 3 : 0.25 : 2 ),
105+ xticks = 10 .^ collect (1.5 : 0.25 : 3.5 ),
106+ plot_args... ,
107+ )
108+ plot! (ns, forwarddiff_times, label = " ForwardDiff" , lw = 2.5 , marker = :square , color = :darkorange2 )
109+ plot! (ns, zygote_times, label = " Zygote" , lw = 2.5 , marker = :diamond , color = :forestgreen )
110+ if save != = undef
111+ savefig (save)
53112 end
113+ end
54114
55- plot (ns, dualvector_times, label= " DualArrays" )
115+ function plot_memory (save= undef; hs = [0.04 , 0.02 , 0.01 , 0.005 , 0.0025 , 0.00125 ], epochs = 200 , lr = 0.01 )
116+ ns = Int .(2 ./ hs) .- 1
117+ dualvector_memory = Float64[]
118+ forwarddiff_memory = Float64[]
119+ zygote_memory = Float64[]
120+
121+ for (h, n) in zip (hs, ns)
122+ println (" Computing solution with h = $h , n = $n " )
123+ push! (dualvector_memory, @ballocated learn_catenary_dualarrays ($ h, cosh (- 1 ), cosh (1 ), $ epochs, $ lr))
124+ push! (forwarddiff_memory, @ballocated learn_catenary_forwarddiff ($ h, cosh (- 1 ), cosh (1 ), $ epochs, $ lr))
125+ push! (zygote_memory, @ballocated learn_catenary_zygote ($ h, cosh (- 1 ), cosh (1 ), $ epochs, $ lr))
126+ end
127+
128+ plot (
129+ ns,
130+ dualvector_memory,
131+ ;
132+ label = " DualArrays" ,
133+ title = " Catenary Gradient Descent Memory" ,
134+ xlabel = " Number of points (n)" ,
135+ ylabel = " Allocated bytes" ,
136+ yticks = 10 .^ collect (6 : 0.5 : 11 ),
137+ xticks = 10 .^ collect (1.5 : 0.25 : 3.5 ),
138+ plot_args... ,
139+ )
140+ plot! (ns, forwarddiff_memory, label = " ForwardDiff" , lw = 2.5 , marker = :square , color = :darkorange2 )
141+ plot! (ns, zygote_memory, label = " Zygote" , lw = 2.5 , marker = :diamond , color = :forestgreen )
142+ if save != = undef
143+ savefig (save)
144+ end
56145end
0 commit comments