From 402d775f3ebdfe315f0e80255ab6e19fd7acee27 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 27 Sep 2019 13:47:33 +0200 Subject: [PATCH 01/11] add test case and include end-points for adaptive_grid --- src/adapted_grid.jl | 4 ++-- test/adaptive_test_functions.jl | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 test/adaptive_test_functions.jl diff --git a/src/adapted_grid.jl b/src/adapted_grid.jl index 3b0783f..5d945fe 100644 --- a/src/adapted_grid.jl +++ b/src/adapted_grid.jl @@ -40,7 +40,7 @@ function adapted_grid(f, minmax::Tuple{Real, Real}; max_recursions = 7) n_tot_refinements = zeros(Int, n_intervals) # We only evaluate the function on interior points - fs = [NaN; [f(x) for x in xs[2:end-1]]; NaN] + fs = f.(xs) while true curvatures = zeros(n_intervals) active = falses(n_intervals) @@ -139,5 +139,5 @@ function adapted_grid(f, minmax::Tuple{Real, Real}; max_recursions = 7) n_intervals = n_points ÷ 2 end - return xs[2:end-1] + return xs end diff --git a/test/adaptive_test_functions.jl b/test/adaptive_test_functions.jl new file mode 100644 index 0000000..8330227 --- /dev/null +++ b/test/adaptive_test_functions.jl @@ -0,0 +1,32 @@ +using Plots +const test_funcs = [ + (x -> 2, 0, 1), + (x-> x, -1, 1), + (x-> 5x, -1, 1), + (x-> 1/x, 0, 1), + (x-> 1/x, -1, 1), + (x->tan(x), 0, 4), + (x-> -1/x, 0, 1), + (x-> 1/abs(x),-1,1), + (x-> 1e6x, -1, 1), + (x-> 1e50x, -1, 1), + (x-> log(1+sin(cos(x))), -6, 6), + (x-> sin(x^3)+cos(x^3), 0, 6.28), + (x-> sin(x), -5, 200), + (x-> sin(1/x), -2, 2), + (x-> sin(x^4), -4, 4), + (x-> sin(300x), -4, 4), + (x-> 1 + x^2 + 0.0125log(abs(1-3(x-1))), -2, 2), + (x-> sin(exp(x)), -6, 6), + (x-> 1/sin(x), -10, 10), + (x-> sin(x)/x, -6, 6), + (x-> tan(x^3-x+1) + 1/(x+3exp(x)), -2, 2), + ] +## +plots = [plot(func...) for func in test_funcs] +pitchfork = plot(x->sqrt(x),0,10) +plot!(pitchfork, x->-sqrt(x),0,10) +plot!(pitchfork, x->0,-10,0) +plot!(pitchfork, x->0,0,10, linestyle=:dash) +push!(plots, pitchfork) +display.(plots) From e62c4bb7bc0a1914c301a58bc7c2f227af5979ae Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Fri, 27 Sep 2019 14:30:59 +0200 Subject: [PATCH 02/11] update comment --- src/adapted_grid.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/adapted_grid.jl b/src/adapted_grid.jl index 5d945fe..bcf7209 100644 --- a/src/adapted_grid.jl +++ b/src/adapted_grid.jl @@ -39,7 +39,7 @@ function adapted_grid(f, minmax::Tuple{Real, Real}; max_recursions = 7) n_tot_refinements = zeros(Int, n_intervals) - # We only evaluate the function on interior points + # We evaluate the function on the whole interval fs = f.(xs) while true curvatures = zeros(n_intervals) From 381fe0efdf932f1766099a784baa9b6160aebd59 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sat, 28 Sep 2019 21:43:55 +0200 Subject: [PATCH 03/11] also return function values --- src/adapted_grid.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/adapted_grid.jl b/src/adapted_grid.jl index bcf7209..e1a4ad0 100644 --- a/src/adapted_grid.jl +++ b/src/adapted_grid.jl @@ -139,5 +139,5 @@ function adapted_grid(f, minmax::Tuple{Real, Real}; max_recursions = 7) n_intervals = n_points ÷ 2 end - return xs + return xs, fs end From fe99344f2a92928f1101874ef309178c85f088c7 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sun, 29 Sep 2019 14:29:32 +0200 Subject: [PATCH 04/11] add Project.toml --- Project.toml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 Project.toml diff --git a/Project.toml b/Project.toml new file mode 100644 index 0000000..94b53a5 --- /dev/null +++ b/Project.toml @@ -0,0 +1,9 @@ +name = "PlotUtils" +uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043" + +[deps] +Colors = "5ae59095-9a9b-59fe-a467-6f913c188581" +Reexport = "189a3867-3050-52da-a836-e630ba90ab69" + +[compat] +julia = "≥ 0.7.0" From f341d579d1eefafc812c05cc40f3348e7ca9567b Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sun, 29 Sep 2019 15:06:27 +0200 Subject: [PATCH 05/11] refine all intervals --- src/adapted_grid.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/adapted_grid.jl b/src/adapted_grid.jl index e1a4ad0..1195f5b 100644 --- a/src/adapted_grid.jl +++ b/src/adapted_grid.jl @@ -52,7 +52,7 @@ function adapted_grid(f, minmax::Tuple{Real, Real}; max_recursions = 7) f_range = one(f_range) end # Skip first and last interval - for interval in 2:n_intervals-1 + for interval in 1:n_intervals p = 2 * interval if n_tot_refinements[interval] >= max_recursions # Skip intervals that have been refined too much From b83581eaf6f71a0de3be068df496919ed0caed08 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sun, 29 Sep 2019 15:06:55 +0200 Subject: [PATCH 06/11] respect ylimits --- src/adapted_grid.jl | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/adapted_grid.jl b/src/adapted_grid.jl index 1195f5b..1d815f5 100644 --- a/src/adapted_grid.jl +++ b/src/adapted_grid.jl @@ -1,8 +1,8 @@ """ - adapted_grid(f, minmax::Tuple{Number, Number}; max_recursions = 7) + adapted_grid(f, xlimits::Tuple{Number, Number}; max_recursions = 7) -Computes a grid `x` on the interval [minmax[1], minmax[2]] so that +Computes a grid `x` on the interval [xlimits[1], xlimits[2]] so that `plot(f, x)` gives a smooth "nice" plot. The method used is to create an initial uniform grid (21 points) and refine intervals where the second derivative is approximated to be large. When an interval @@ -12,8 +12,8 @@ exactly at the end points of the intervals. The parameter `max_recusions` computes how many times each interval is allowed to be refined. """ -function adapted_grid(f, minmax::Tuple{Real, Real}; max_recursions = 7) - if minmax[1] >= minmax[2] +function adapted_grid(f, xlimits::Tuple{Real, Real}, ylimits::Tuple{Real, Real}; max_recursions = 7) + if xlimits[1] >= xlimits[2] throw(ArgumentError("interval must be given as (min, max)")) end @@ -25,10 +25,8 @@ function adapted_grid(f, minmax::Tuple{Real, Real}; max_recursions = 7) n_intervals = n_points ÷ 2 @assert isodd(n_points) - xs = collect(range(minmax[1]; stop=minmax[2], length=n_points)) - # Move the first and last interior points a bit closer to the end points - xs[2] = xs[1] + (xs[2] - xs[1]) * 0.25 - xs[end-1] = xs[end] - (xs[end] - xs[end-1]) * 0.25 + # TODO: choose points equidistant on the scale to be plotted, might be log-scale + xs = collect(range(xlimits[1]; stop=xlimits[2], length=n_points)) # Wiggle interior points a bit to prevent aliasing and other degenerate cases rng = MersenneTwister(1337) @@ -41,6 +39,28 @@ function adapted_grid(f, minmax::Tuple{Real, Real}; max_recursions = 7) # We evaluate the function on the whole interval fs = f.(xs) + + binary_escape = function(x1, x2; rtol = 1e-2) + while x1 <= x2 + mx = (x1 + x2) ÷ 2 + mf = f(m) + if mf < ylimits[1] * (1 - rtol) || mf > ylimits[2] * (1 + rtol) + x1 = mx + elseif mf > ylimits[1] * (1 + rtol) || mf < ylimits[2] * (1 - rtol) + x2 = mx + else + return mx + end + end + return NaN + end + # Move the first and last points inside if function is out of bounds + if fs[1] < ylimits[1] || fs[1] > ylimits[2] + x[1] = binary_escape(x[1], x[2]) + end + if fs[end] < ylimits[1] || fs[end] > ylimits[2] + x[end] = binary_escape(x[end-1], x[end]) + end while true curvatures = zeros(n_intervals) active = falses(n_intervals) From e14473a251553d1521cea278461b983b9e66b81e Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sun, 29 Sep 2019 15:08:18 +0200 Subject: [PATCH 07/11] add comment --- test/adaptive_test_functions.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/test/adaptive_test_functions.jl b/test/adaptive_test_functions.jl index 8330227..25969ab 100644 --- a/test/adaptive_test_functions.jl +++ b/test/adaptive_test_functions.jl @@ -1,3 +1,4 @@ +# This is not run by runtests.jl. Only intended to be checked manually. using Plots const test_funcs = [ (x -> 2, 0, 1), From 5eb9a8b8e884b865903ceaca9a9da18616f78230 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sun, 29 Sep 2019 15:14:00 +0200 Subject: [PATCH 08/11] bump version --- Project.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Project.toml b/Project.toml index 94b53a5..0544b38 100644 --- a/Project.toml +++ b/Project.toml @@ -1,5 +1,6 @@ name = "PlotUtils" uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043" +version = "0.6.0" [deps] Colors = "5ae59095-9a9b-59fe-a467-6f913c188581" From 3b782204a2a51f16cbe9cb700ec7845e7f6d27a6 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sun, 29 Sep 2019 15:58:24 +0200 Subject: [PATCH 09/11] update Project --- .gitignore | 1 + Project.toml | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/.gitignore b/.gitignore index 8c960ec..3f02ca7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.jl.cov *.jl.*.cov *.jl.mem +Manifest.toml diff --git a/Project.toml b/Project.toml index 0544b38..7e2b61c 100644 --- a/Project.toml +++ b/Project.toml @@ -4,7 +4,17 @@ version = "0.6.0" [deps] Colors = "5ae59095-9a9b-59fe-a467-6f913c188581" +Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" +Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" [compat] julia = "≥ 0.7.0" + +[extras] +Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[targets] +test = ["Test", "Plots"] From f892adcaec75ed731c9a104d49fe9665ef1c9bf9 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sun, 29 Sep 2019 15:06:55 +0200 Subject: [PATCH 10/11] Revert "respect ylimits" This reverts commit b83581eaf6f71a0de3be068df496919ed0caed08. --- src/adapted_grid.jl | 36 ++++++++---------------------------- 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/src/adapted_grid.jl b/src/adapted_grid.jl index 1d815f5..1195f5b 100644 --- a/src/adapted_grid.jl +++ b/src/adapted_grid.jl @@ -1,8 +1,8 @@ """ - adapted_grid(f, xlimits::Tuple{Number, Number}; max_recursions = 7) + adapted_grid(f, minmax::Tuple{Number, Number}; max_recursions = 7) -Computes a grid `x` on the interval [xlimits[1], xlimits[2]] so that +Computes a grid `x` on the interval [minmax[1], minmax[2]] so that `plot(f, x)` gives a smooth "nice" plot. The method used is to create an initial uniform grid (21 points) and refine intervals where the second derivative is approximated to be large. When an interval @@ -12,8 +12,8 @@ exactly at the end points of the intervals. The parameter `max_recusions` computes how many times each interval is allowed to be refined. """ -function adapted_grid(f, xlimits::Tuple{Real, Real}, ylimits::Tuple{Real, Real}; max_recursions = 7) - if xlimits[1] >= xlimits[2] +function adapted_grid(f, minmax::Tuple{Real, Real}; max_recursions = 7) + if minmax[1] >= minmax[2] throw(ArgumentError("interval must be given as (min, max)")) end @@ -25,8 +25,10 @@ function adapted_grid(f, xlimits::Tuple{Real, Real}, ylimits::Tuple{Real, Real}; n_intervals = n_points ÷ 2 @assert isodd(n_points) - # TODO: choose points equidistant on the scale to be plotted, might be log-scale - xs = collect(range(xlimits[1]; stop=xlimits[2], length=n_points)) + xs = collect(range(minmax[1]; stop=minmax[2], length=n_points)) + # Move the first and last interior points a bit closer to the end points + xs[2] = xs[1] + (xs[2] - xs[1]) * 0.25 + xs[end-1] = xs[end] - (xs[end] - xs[end-1]) * 0.25 # Wiggle interior points a bit to prevent aliasing and other degenerate cases rng = MersenneTwister(1337) @@ -39,28 +41,6 @@ function adapted_grid(f, xlimits::Tuple{Real, Real}, ylimits::Tuple{Real, Real}; # We evaluate the function on the whole interval fs = f.(xs) - - binary_escape = function(x1, x2; rtol = 1e-2) - while x1 <= x2 - mx = (x1 + x2) ÷ 2 - mf = f(m) - if mf < ylimits[1] * (1 - rtol) || mf > ylimits[2] * (1 + rtol) - x1 = mx - elseif mf > ylimits[1] * (1 + rtol) || mf < ylimits[2] * (1 - rtol) - x2 = mx - else - return mx - end - end - return NaN - end - # Move the first and last points inside if function is out of bounds - if fs[1] < ylimits[1] || fs[1] > ylimits[2] - x[1] = binary_escape(x[1], x[2]) - end - if fs[end] < ylimits[1] || fs[end] > ylimits[2] - x[end] = binary_escape(x[end-1], x[end]) - end while true curvatures = zeros(n_intervals) active = falses(n_intervals) From 9193fa7617c8edaa94b331654d74c22786a96ca9 Mon Sep 17 00:00:00 2001 From: Simon Christ Date: Sun, 29 Sep 2019 16:32:09 +0200 Subject: [PATCH 11/11] update docstring --- src/adapted_grid.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/adapted_grid.jl b/src/adapted_grid.jl index 1195f5b..761229a 100644 --- a/src/adapted_grid.jl +++ b/src/adapted_grid.jl @@ -6,8 +6,7 @@ Computes a grid `x` on the interval [minmax[1], minmax[2]] so that `plot(f, x)` gives a smooth "nice" plot. The method used is to create an initial uniform grid (21 points) and refine intervals where the second derivative is approximated to be large. When an interval -becomes "straight enough" it is no longer divided. Functions are never evaluated -exactly at the end points of the intervals. +becomes "straight enough" it is no longer divided. Functions are evaluated at the end points of the intervals. The parameter `max_recusions` computes how many times each interval is allowed to be refined.