Skip to content

Commit 160f8c0

Browse files
committed
Fine tuning text
Looks nearly ready...
1 parent a992a82 commit 160f8c0

File tree

1 file changed

+77
-22
lines changed

1 file changed

+77
-22
lines changed

examples/NDLPwriteup.jl

Lines changed: 77 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ using InteractiveUtils
88
using Plots, QuadGK, DataInterpolations, LinearAlgebra, StaticArrays, TypedTables
99

1010
# ╔═╡ ad7b8fa0-e966-4c3b-8163-02d2817b1c9d
11-
using ForwardDiff:derivative as D # AD derivatives
11+
using ForwardDiff:derivative as D # Automatic derivatives
1212

1313
# ╔═╡ 4e8f4214-f9b3-4dbf-9507-eea0504a6933
1414
md"""
@@ -137,11 +137,11 @@ Note that while the deviation estimate that is the basis of this parameterizatio
137137
md"""
138138
### Results
139139
140-
We evaluate each method on the test curves defined above, using a maximum segment length of `Δs=1/20` and a deviation limit of $d_n$=`devlimit=1/100`. The results are summarized in the tables below, reporting the following metrics:
141-
- `L∞δ`: the maximum deviation scaled by the allowed deviation (should be close to 1),
142-
- `σ`: the stretching/efficiency, defined as the excess percentage of segments needed to hit the deviation limit (lower is better),
143-
- `Rₜᵥ`: the total variation of segment lengths scaled by total curve length (lower is better),
144-
- `R∞`: the maximum variation of segment lengths scaled by $\Delta s$ (lower is better).
140+
We evaluate each method on the test curves defined above, using a maximum segment length of $\Delta s=L/20$ and a deviation limit of $d_n=1/100$. The results are summarized in the tables below, reporting the following metrics:
141+
- `δ∞`=$\max(\delta)/(d_n\Delta s)$: the scaled normal deviation,
142+
- `σ`=$N\Delta s/L-1$: the scaled number of extra segments needed to hit the deviation limit (lower is better),
143+
- `Rₜᵥ`=$\sum(R)/L$ where $R_i=|Δl_{i+1}-Δl_i|$: the scale total variation of segment lengths (lower is better),
144+
- `R∞`=$\max(R)/\Delta s$: the scale maximum variation of segment lengths (lower is better).
145145
146146
The NDLP segmentation consistently produces a max deviation which is tight to the prescribed limit, resulting in with minimal excess segments, outperforming both adaptive subdivision and curvature-weighted sampling. In particular the measured deviation is within ±4% of the deviation limit, while the curvature weighted method has a ±15% variation **even after tuning**, and the subdivision method can be up to 50% oversampled.
147147
@@ -150,13 +150,13 @@ Adjacent segment lengths under NDLP sampling differ by at most $O(\Delta s)$, in
150150

151151
# ╔═╡ b38c2b1c-a48c-4f1f-954b-95faaba680d7
152152
begin # sample `r` using `method`, and report metrics
153-
function metrics(method, r, u₀, u₁, Δs, devlimit)
153+
function metrics(method, r, u₀, u₁, Δs, dₙ)
154154
L = quadgk(arcspeed(r), u₀, u₁)[1]; Δs *= L
155-
u = method(r, u₀, u₁, Δs, devlimit); N =
155+
u = method(r, u₀, u₁, Δs, dₙ); N =
156156
dl,δ = seg_len(r,u),seg_dev(r,u)
157-
(;L∞δ = maximum(δ)/(Δs*devlimit), # scaled max deviation, should => 1!
158-
σ = length(δ)*Δs/L-1, # extra segments needed to hit devlimit
159-
Rₜᵥ = sum(abs,diff(dl))/L, # total variation of segment length
157+
(;δ∞ = maximum(δ)/(Δs*dₙ), # scaled max deviation, should => 1!
158+
σ = length(δ)*Δs/L-1, # extra segments needed to hit dₙ
159+
Rₜᵥ = sum(abs,diff(dl))/L, # total variation of segment length
160160
R∞ = maximum(abs,diff(dl))/Δs # max variation of segment length
161161
)
162162
end
@@ -176,11 +176,11 @@ end
176176

177177
# ╔═╡ cc1fa09e-21da-425d-bb6c-a8c906a65e98
178178
begin
179-
function subdivision(r, u₀, u₁, Δs, devlimit)
179+
function subdivision(r, u₀, u₁, Δs, dₙ)
180180
u₀, u₁ = Float64.((u₀, u₁))
181181
segments = [(; u₀, u₁, dl=seg_len(r,u₀,u₁), δ=seg_dev(r,u₀,u₁))]
182182
while true
183-
i = findfirst(s -> s.dl > Δs || s.δ > Δs*devlimit, segments)
183+
i = findfirst(s -> s.dl > Δs || s.δ > Δs*dₙ, segments)
184184
i === nothing && break
185185
s = segments[i]; um = (s.u₀ + s.u₁)/2
186186
# we need to keep checking the length and deviation! 🤢
@@ -190,15 +190,16 @@ begin
190190
end
191191
[getfield.(segments,:u₀);u₁]
192192
end
193-
function κ_weighted(r, u₀, u₁, Δs, devlimit)
193+
function κ_weighted(r, u₀, u₁, Δs, dₙ)
194194
C = 11 # Hand tuned to work on the test_curves! 🤢
195195
speed(u) = (arcspeed(r)(u)^2+C*Δs*aₙ(r,u))
196196
S,s⁻¹ = ∫speed(speed, u₀, u₁)
197197
return s⁻¹.(range(0, S, round(Int,S/Δs)+1))
198198
end
199-
function NDLP(r, u₀, u₁, Δs, devlimit) # so nice 🤓
200-
speed(u) = max(arcspeed(r)(u),(Δs*aₙ(r,u)/8devlimit))
201-
S,s⁻¹ = ∫speed(speed, u₀, u₁)
199+
function NDLP(r, u₀, u₁, Δs, dₙ) # so nice 🤓
200+
speed(u) = max(arcspeed(r)(u),(Δs*aₙ(r,u)/8dₙ))
201+
rtol = 1e-6Δs # only needed since convergence study lets Δs→0
202+
S,s⁻¹ = ∫speed(speed, u₀, u₁; rtol)
202203
return s⁻¹.(range(0, S, round(Int,S/Δs)+1))
203204
end
204205
function ∫speed(speed, u₀, u₁; rtol=1e-5,order=3)
@@ -226,23 +227,71 @@ plot(); let
226227
end; plot!(aspect_ratio=:equal,xlabel="x",ylabel="y")
227228

228229
# ╔═╡ 0394397a-1198-444b-9340-b3b737e1b638
229-
Δs = 1/20; devlimit = 1/100
230+
Δs = 1/20; dₙ = 1/100;
230231

231232
# ╔═╡ f7a8cdf1-2cdb-4d6b-a10f-3f2d980c836e
232233
map(test_curves) do (name, r, range, _)
233-
(;name,metrics(subdivision,r,range...,1/21,devlimit)...)
234+
(;name,metrics(subdivision,r,range...,Δs,dₙ)...)
234235
end |> Table |> display
235236

236237
# ╔═╡ 11a078e6-0eca-49c2-84d6-829b4b9351f8
237238
map(test_curves) do (name, r, range, _)
238-
(;name,metrics(κ_weighted,r,range...,Δs,devlimit)...)
239+
(;name,metrics(κ_weighted,r,range...,Δs,dₙ)...)
239240
end |> Table |> display
240241

241242
# ╔═╡ 30dbf23a-1ac7-47f3-9a8f-11fb1712366c
242243
map(test_curves) do (name, r, range, _)
243-
(;name,metrics(NDLP,r,range...,Δs,devlimit)...)
244+
(;name,metrics(NDLP,r,range...,Δs,dₙ)...)
244245
end |> Table |> display
245246

247+
# ╔═╡ 561a1373-57a4-4b67-be5a-9d94c9496360
248+
md"""
249+
## Convergence study
250+
251+
We also evaluate the convergence of the NDLP segmentation metrics as the $\Delta s$ and $d_n$ limits vary. We use the cubic spline fish as a representative curve.
252+
253+
Holding $d_n=1$% constant and *reducing* $\Delta s$ shows two distance phases.
254+
- In the first phase, the deviation $\max(\delta)$ goes rapidly to the limit $d_n\Delta s$ and holds steady while the excess number of segments and total variation in the panel lengths drops to zero quadratically with $\Delta s$. (Note the scaling of $\max(R)$ by $\Delta s$ makes this look linear in the plot.)
255+
- In the second phase the deviation limit is no longer active, so $\max(\delta)$ goes to zero without any additional segments or any length variation.
256+
"""
257+
258+
# ╔═╡ 1273c8c7-20b9-42c0-9b0d-d9bb8db57ec2
259+
convergeΔs = map(logrange(1e-1,1e-4,70)) do Δs
260+
(;Δs,metrics(NDLP,test_curves[3].r,test_curves[3].range...,Δs,1e-2)...)
261+
end |> Table;
262+
263+
# ╔═╡ dcb68886-2771-4b37-91b6-9c983e118728
264+
begin
265+
plot(convergeΔs.Δs,convergeΔs.δ∞,label="max(δ)/dₙΔs")
266+
plot!(convergeΔs.Δs,convergeΔs.σ,label="NΔs/L-1")
267+
plot!(convergeΔs.Δs,convergeΔs.Rₜᵥ,label="sum(R)/L")
268+
plot!(convergeΔs.Δs,convergeΔs.R∞,label="max(R)/Δs")
269+
plot!(ylabel="scaled metrics",xlabel="Δs",xscale=:log10,xflip=true)
270+
plot!(title="NDLP segmentation metrics with fixed dₙ=1%")
271+
end
272+
273+
# ╔═╡ 67eba604-640b-4388-bc08-928f4e5e62ca
274+
md"""
275+
Holding $\Delta s=L/100$ and _increasing_ $d_n$ shows a similar trend.
276+
- Again, in the first phase, the deviation limit is honored while the excess segments and total variation in segment lengths drop to zero. The key difference is that the $\max(R)$ remains roughly constant through this range; approximately $\Delta s/3$ for this example. Again, this indicates Lipschitz-continuous spacing, even for finite $\Delta s$ and large $d_n$.
277+
- In the second phase, the $d_n$ limit deactivates, letting $\max(\delta)$ scaled by $d_n$ and $\max(R)$ both drop to zero as the sampling becomes uniformly spaced.
278+
"""
279+
280+
# ╔═╡ 260406ec-97ff-49fc-bb17-4f28fe12b8b6
281+
convergedₙ = map(logrange(1,6e-4,70)) do dₙ
282+
(;dₙ,metrics(NDLP,test_curves[3].r,test_curves[3].range...,1e-2,dₙ)...)
283+
end |> Table;
284+
285+
# ╔═╡ f67fc432-8031-4230-899b-b24fcb7b44f4
286+
begin
287+
plot(convergedₙ.dₙ,convergedₙ.δ∞,label="max(δ)/dₙΔs")
288+
plot!(convergedₙ.dₙ,convergedₙ.σ,label="NΔs/L-1")
289+
plot!(convergedₙ.dₙ,convergedₙ.Rₜᵥ,label="sum(R)/L")
290+
plot!(convergedₙ.dₙ,convergedₙ.R∞,label="max(R)/Δs")
291+
plot!(ylabel="scaled metrics",xlabel="dₙ",xscale=:log10)
292+
plot!(title="NDLP segmentation metrics with fixed Δs=L/100")
293+
end
294+
246295
# ╔═╡ 6094d19e-e64a-4434-b6db-e5647fd71e78
247296
md"""
248297
## Conclusions
@@ -1554,7 +1603,7 @@ version = "1.13.0+0"
15541603
# ╠═ad7b8fa0-e966-4c3b-8163-02d2817b1c9d
15551604
# ╟─60fc45b3-8cea-4cae-83f4-9c05011b1dee
15561605
# ╟─e1bc7e76-a497-41db-8f91-b8912e359e0e
1557-
# ╠═28abbec4-f1ea-4edb-8bd7-bcdc63c7cd82
1606+
# ╟─28abbec4-f1ea-4edb-8bd7-bcdc63c7cd82
15581607
# ╟─957d0951-2070-4d64-8fc9-58b5121bdfc1
15591608
# ╟─10b2e0b0-f373-4a02-b6dc-fd1085b1f34a
15601609
# ╠═cc1fa09e-21da-425d-bb6c-a8c906a65e98
@@ -1564,6 +1613,12 @@ version = "1.13.0+0"
15641613
# ╠═f7a8cdf1-2cdb-4d6b-a10f-3f2d980c836e
15651614
# ╠═11a078e6-0eca-49c2-84d6-829b4b9351f8
15661615
# ╠═30dbf23a-1ac7-47f3-9a8f-11fb1712366c
1616+
# ╟─561a1373-57a4-4b67-be5a-9d94c9496360
1617+
# ╠═1273c8c7-20b9-42c0-9b0d-d9bb8db57ec2
1618+
# ╟─dcb68886-2771-4b37-91b6-9c983e118728
1619+
# ╟─67eba604-640b-4388-bc08-928f4e5e62ca
1620+
# ╠═260406ec-97ff-49fc-bb17-4f28fe12b8b6
1621+
# ╟─f67fc432-8031-4230-899b-b24fcb7b44f4
15671622
# ╟─6094d19e-e64a-4434-b6db-e5647fd71e78
15681623
# ╟─00000000-0000-0000-0000-000000000001
15691624
# ╟─00000000-0000-0000-0000-000000000002

0 commit comments

Comments
 (0)