From c06342598fc34d0489737d97101544df741f6131 Mon Sep 17 00:00:00 2001 From: Joshua Lampert Date: Mon, 2 Dec 2024 16:25:52 +0100 Subject: [PATCH 1/8] allow general RNG in random_* functions --- Project.toml | 2 ++ src/KernelInterpolation.jl | 1 + src/nodes.jl | 70 ++++++++++++++++++++++++-------------- 3 files changed, 48 insertions(+), 25 deletions(-) diff --git a/Project.toml b/Project.toml index b9b6f6e7..422f4b19 100644 --- a/Project.toml +++ b/Project.toml @@ -8,6 +8,7 @@ DiffEqCallbacks = "459566f4-90b8-5000-8ac3-15dfb0a30def" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" ReadVTK = "dc215faf-f008-4882-a9f7-a79a826fadc3" RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" @@ -32,6 +33,7 @@ ForwardDiff = "0.10.36" LinearAlgebra = "1" Meshes = "0.52.1" Printf = "1" +Random = "1" ReadVTK = "0.2" RecipesBase = "1.3.4" Reexport = "1.2" diff --git a/src/KernelInterpolation.jl b/src/KernelInterpolation.jl index c4c7d9e0..2afc5fb8 100644 --- a/src/KernelInterpolation.jl +++ b/src/KernelInterpolation.jl @@ -15,6 +15,7 @@ using DiffEqCallbacks: PeriodicCallback, PeriodicCallbackAffect using ForwardDiff: ForwardDiff using LinearAlgebra: Symmetric, I, norm, tr, muladd, dot, diagind using Printf: @sprintf +using Random: Random using ReadVTK: VTKFile, get_points, get_point_data, get_data using RecipesBase: RecipesBase, @recipe, @series using SciMLBase: ODEFunction, ODEProblem, ODESolution, DiscreteCallback, u_modified! diff --git a/src/nodes.jl b/src/nodes.jl index 481339e9..adf0b0ef 100644 --- a/src/nodes.jl +++ b/src/nodes.jl @@ -220,22 +220,27 @@ end # Some convenience function to create some specific `NodeSet`s """ - random_hypercube(n, x_min = ntuple(_ -> 0.0, dim), x_max = ntuple(_ -> 1.0, dim); [dim]) + random_hypercube([rng], n, x_min = ntuple(_ -> 0.0, dim), x_max = ntuple(_ -> 1.0, dim); [dim]) Create a [`NodeSet`](@ref) with `n` random nodes each of dimension `dim` inside a hypercube defined by the bounds `x_min` and `x_max`. If the bounds are given as single values, they are applied for each dimension. If they are `Tuple`s of size `dim` the hypercube has the according bounds. If `dim` is not given explicitly, it is inferred by the lengths of `x_min` and `x_max` if possible. +Optionally, pass a random number generator `rng`. """ -function random_hypercube(n::Int, x_min::Real = 0.0, x_max::Real = 1.0; dim = 1) - nodes = x_min .+ (x_max - x_min) .* rand(n, dim) +function random_hypercube(n, x_min = 0.0, x_max = 1.0; kwargs...) + random_hypercube(Random.default_rng(), n, x_min, x_max; kwargs...) +end + +function random_hypercube(rng::Random.AbstractRNG, n::Int, x_min::Real = 0.0, x_max::Real = 1.0; dim = 1) + nodes = x_min .+ (x_max - x_min) .* rand(rng, n, dim) return NodeSet(nodes) end -function random_hypercube(n::Int, x_min::NTuple{Dim}, x_max::NTuple{Dim}; +function random_hypercube(rng::Random.AbstractRNG, n::Int, x_min::NTuple{Dim}, x_max::NTuple{Dim}; dim = Dim) where {Dim} @assert dim == Dim - nodes = rand(n, dim) + nodes = rand(rng, n, dim) for i in 1:dim nodes[:, i] = x_min[i] .+ (x_max[i] - x_min[i]) .* view(nodes, :, i) end @@ -243,24 +248,29 @@ function random_hypercube(n::Int, x_min::NTuple{Dim}, x_max::NTuple{Dim}; end """ - random_hypercube_boundary(n, x_min = ntuple(_ -> 0.0, dim), x_max = ntuple(_ -> 1.0, dim); [dim]) + random_hypercube_boundary([rng], n, x_min = ntuple(_ -> 0.0, dim), x_max = ntuple(_ -> 1.0, dim); [dim]) Create a [`NodeSet`](@ref) with `n` random nodes each of dimension `dim` on the boundary of a hypercube defined by the bounds `x_min` and `x_max`. If the bounds are given as single values, they are applied for each dimension. If they are `Tuple`s of size `dim` the hypercube has the according bounds. If `dim` is not given explicitly, it is inferred by the lengths of `x_min` and `x_max` if possible. +Optionally, pass a random number generator `rng`. """ -function random_hypercube_boundary(n::Int, x_min::Real = 0.0, x_max::Real = 1.0; dim = 1) - random_hypercube_boundary(n, ntuple(_ -> x_min, dim), ntuple(_ -> x_max, dim)) +function random_hypercube_boundary(n, x_min = 0.0, x_max = 1.0; kwargs...) + random_hypercube_boundary(Random.default_rng(), n, x_min, x_max; kwargs...) +end + +function random_hypercube_boundary(rng::Random.AbstractRNG, n::Int, x_min::Real = 0.0, x_max::Real = 1.0; dim = 1) + random_hypercube_boundary(rng, n, ntuple(_ -> x_min, dim), ntuple(_ -> x_max, dim)) end -function project_on_hypercube_boundary!(nodeset::NodeSet{Dim}, x_min::NTuple{Dim}, +function project_on_hypercube_boundary!(rng::Random.AbstractRNG, nodeset::NodeSet{Dim}, x_min::NTuple{Dim}, x_max::NTuple{Dim}) where {Dim} for i in eachindex(nodeset) # j = argmin([abs.(nodeset[i] .- x_min); abs.(nodeset[i] .- x_max)]) # Project to random axis - j = rand(1:Dim) - if rand([1, 2]) == 1 + j = rand(rng, 1:Dim) + if rand(rng, [1, 2]) == 1 nodeset[i][j] = x_min[j] else nodeset[i][j] = x_max[j] @@ -268,7 +278,7 @@ function project_on_hypercube_boundary!(nodeset::NodeSet{Dim}, x_min::NTuple{Dim end end -function random_hypercube_boundary(n::Int, x_min::NTuple{Dim}, x_max::NTuple{Dim}; +function random_hypercube_boundary(rng::Random.AbstractRNG, n::Int, x_min::NTuple{Dim}, x_max::NTuple{Dim}; dim = Dim) where {Dim} @assert dim == Dim if dim == 1 && n >= 2 @@ -276,9 +286,9 @@ function random_hypercube_boundary(n::Int, x_min::NTuple{Dim}, x_max::NTuple{Dim return NodeSet([x_min[1], x_max[1]]) end # First, create random nodes *inside* hypercube - nodeset = random_hypercube(n, x_min, x_max) + nodeset = random_hypercube(rng, n, x_min, x_max) # Then, project all the nodes on the boundary - project_on_hypercube_boundary!(nodeset, x_min, x_max) + project_on_hypercube_boundary!(rng, nodeset, x_min, x_max) return nodeset end @@ -406,44 +416,54 @@ function homogeneous_hypercube_boundary(n::NTuple{Dim}, end """ - random_hypersphere(n, r = 1.0, center = zeros(dim); [dim]) + random_hypersphere([rng], n, r = 1.0, center = zeros(dim); [dim]) Create a [`NodeSet`](@ref) with `n` random nodes each of dimension `dim` inside a hypersphere with radius `r` around the center `center`. If `dim` is not given explicitly, it is inferred by the length of `center` if possible. +Optionally, pass a random number generator `rng`. """ -function random_hypersphere(n::Int, r = 1.0; dim = 2) - random_hypersphere(n, r, zeros(dim)) +function random_hypersphere(n, r; kwargs...) + random_hypersphere(Random.default_rng(), n, r; kwargs...) end -function random_hypersphere(n::Int, r::Real, center::AbstractVector; dim = length(center)) +function random_hypersphere(rng::Random.AbstractRNG, n::Int, r = 1.0; dim = 2) + random_hypersphere(rng, n, r, zeros(dim)) +end + +function random_hypersphere(rng::Random.AbstractRNG, n::Int, r::Real, center::AbstractVector; dim = length(center)) @assert length(center) == dim - nodes = randn(n, dim) + nodes = randn(rng, n, dim) for i in 1:n - nodes[i, :] .= center .+ r .* nodes[i, :] ./ norm(nodes[i, :]) * rand()^(1 / dim) + nodes[i, :] .= center .+ r .* nodes[i, :] ./ norm(nodes[i, :]) * rand(rng)^(1 / dim) end return NodeSet(nodes) end """ - random_hypersphere_boundary(n, r = 1.0, center = zeros(dim); [dim]) + random_hypersphere_boundary([rng], n, r = 1.0, center = zeros(dim); [dim]) Create a [`NodeSet`](@ref) with `n` random nodes each of dimension `dim` at the boundary of a hypersphere with radius `r` around the center `center`. If `dim` is not given explicitly, it is inferred by the length of `center` if possible. +Optionally, pass a random number generator `rng`. """ -function random_hypersphere_boundary(n::Int, r = 1.0; dim = 2) - random_hypersphere_boundary(n, r, zeros(dim)) +function random_hypersphere_boundary(n, r; kwargs...) + random_hypersphere_boundary(Random.default_rng(), n, r; kwargs...) +end + +function random_hypersphere_boundary(rng::Random.AbstractRNG, n::Int, r = 1.0; dim = 2) + random_hypersphere_boundary(rng, n, r, zeros(dim)) end -function random_hypersphere_boundary(n::Int, r::Real, center::AbstractVector; +function random_hypersphere_boundary(rng::Random.AbstractRNG, n::Int, r::Real, center::AbstractVector; dim = length(center)) @assert length(center) == dim if dim == 1 && n >= 2 @warn "For one dimension the boundary of the hypersphere consists only of 2 points" return NodeSet([-r, r]) end - nodes = randn(n, dim) + nodes = randn(rng, n, dim) for i in 1:n nodes[i, :] .= center .+ r .* nodes[i, :] ./ norm(nodes[i, :]) end From 72d888a197ede04f3122e4d4ef87f6fdffa5d666 Mon Sep 17 00:00:00 2001 From: Joshua Lampert <51029046+JoshuaLampert@users.noreply.github.com> Date: Mon, 2 Dec 2024 16:28:31 +0100 Subject: [PATCH 2/8] Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/nodes.jl | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/nodes.jl b/src/nodes.jl index adf0b0ef..b94b6aad 100644 --- a/src/nodes.jl +++ b/src/nodes.jl @@ -232,12 +232,14 @@ function random_hypercube(n, x_min = 0.0, x_max = 1.0; kwargs...) random_hypercube(Random.default_rng(), n, x_min, x_max; kwargs...) end -function random_hypercube(rng::Random.AbstractRNG, n::Int, x_min::Real = 0.0, x_max::Real = 1.0; dim = 1) +function random_hypercube(rng::Random.AbstractRNG, n::Int, x_min::Real = 0.0, + x_max::Real = 1.0; dim = 1) nodes = x_min .+ (x_max - x_min) .* rand(rng, n, dim) return NodeSet(nodes) end -function random_hypercube(rng::Random.AbstractRNG, n::Int, x_min::NTuple{Dim}, x_max::NTuple{Dim}; +function random_hypercube(rng::Random.AbstractRNG, n::Int, x_min::NTuple{Dim}, + x_max::NTuple{Dim}; dim = Dim) where {Dim} @assert dim == Dim nodes = rand(rng, n, dim) @@ -260,11 +262,13 @@ function random_hypercube_boundary(n, x_min = 0.0, x_max = 1.0; kwargs...) random_hypercube_boundary(Random.default_rng(), n, x_min, x_max; kwargs...) end -function random_hypercube_boundary(rng::Random.AbstractRNG, n::Int, x_min::Real = 0.0, x_max::Real = 1.0; dim = 1) +function random_hypercube_boundary(rng::Random.AbstractRNG, n::Int, x_min::Real = 0.0, + x_max::Real = 1.0; dim = 1) random_hypercube_boundary(rng, n, ntuple(_ -> x_min, dim), ntuple(_ -> x_max, dim)) end -function project_on_hypercube_boundary!(rng::Random.AbstractRNG, nodeset::NodeSet{Dim}, x_min::NTuple{Dim}, +function project_on_hypercube_boundary!(rng::Random.AbstractRNG, nodeset::NodeSet{Dim}, + x_min::NTuple{Dim}, x_max::NTuple{Dim}) where {Dim} for i in eachindex(nodeset) # j = argmin([abs.(nodeset[i] .- x_min); abs.(nodeset[i] .- x_max)]) @@ -278,7 +282,8 @@ function project_on_hypercube_boundary!(rng::Random.AbstractRNG, nodeset::NodeSe end end -function random_hypercube_boundary(rng::Random.AbstractRNG, n::Int, x_min::NTuple{Dim}, x_max::NTuple{Dim}; +function random_hypercube_boundary(rng::Random.AbstractRNG, n::Int, x_min::NTuple{Dim}, + x_max::NTuple{Dim}; dim = Dim) where {Dim} @assert dim == Dim if dim == 1 && n >= 2 @@ -431,7 +436,8 @@ function random_hypersphere(rng::Random.AbstractRNG, n::Int, r = 1.0; dim = 2) random_hypersphere(rng, n, r, zeros(dim)) end -function random_hypersphere(rng::Random.AbstractRNG, n::Int, r::Real, center::AbstractVector; dim = length(center)) +function random_hypersphere(rng::Random.AbstractRNG, n::Int, r::Real, + center::AbstractVector; dim = length(center)) @assert length(center) == dim nodes = randn(rng, n, dim) for i in 1:n @@ -456,7 +462,8 @@ function random_hypersphere_boundary(rng::Random.AbstractRNG, n::Int, r = 1.0; d random_hypersphere_boundary(rng, n, r, zeros(dim)) end -function random_hypersphere_boundary(rng::Random.AbstractRNG, n::Int, r::Real, center::AbstractVector; +function random_hypersphere_boundary(rng::Random.AbstractRNG, n::Int, r::Real, + center::AbstractVector; dim = length(center)) @assert length(center) == dim if dim == 1 && n >= 2 From 07997d47cc1129ecc65cecdd93bd005d1a42714e Mon Sep 17 00:00:00 2001 From: Joshua Lampert Date: Mon, 2 Dec 2024 16:36:06 +0100 Subject: [PATCH 3/8] fix missing method --- src/nodes.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/nodes.jl b/src/nodes.jl index adf0b0ef..8595ddb7 100644 --- a/src/nodes.jl +++ b/src/nodes.jl @@ -427,6 +427,10 @@ function random_hypersphere(n, r; kwargs...) random_hypersphere(Random.default_rng(), n, r; kwargs...) end +function random_hypersphere(n, r, center; kwargs...) + random_hypersphere(Random.default_rng(), n, r, center; kwargs...) +end + function random_hypersphere(rng::Random.AbstractRNG, n::Int, r = 1.0; dim = 2) random_hypersphere(rng, n, r, zeros(dim)) end From c6b9cf13db7d263be24e5d3eef345db0f28b0c1e Mon Sep 17 00:00:00 2001 From: Joshua Lampert Date: Mon, 2 Dec 2024 16:41:42 +0100 Subject: [PATCH 4/8] add another missing method --- src/nodes.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/nodes.jl b/src/nodes.jl index 00c5ad20..f9a03e17 100644 --- a/src/nodes.jl +++ b/src/nodes.jl @@ -462,6 +462,10 @@ function random_hypersphere_boundary(n, r; kwargs...) random_hypersphere_boundary(Random.default_rng(), n, r; kwargs...) end +function random_hypersphere_boundary(n, r, center; kwargs...) + random_hypersphere_boundary(Random.default_rng(), n, r, center; kwargs...) +end + function random_hypersphere_boundary(rng::Random.AbstractRNG, n::Int, r = 1.0; dim = 2) random_hypersphere_boundary(rng, n, r, zeros(dim)) end From d1ecf1d3b0ccb85572351154e47197a52b69076f Mon Sep 17 00:00:00 2001 From: Joshua Lampert Date: Mon, 2 Dec 2024 16:48:14 +0100 Subject: [PATCH 5/8] add defaults --- src/nodes.jl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/nodes.jl b/src/nodes.jl index f9a03e17..7bc66a78 100644 --- a/src/nodes.jl +++ b/src/nodes.jl @@ -428,20 +428,20 @@ radius `r` around the center `center`. If `dim` is not given explicitly, it is inferred by the length of `center` if possible. Optionally, pass a random number generator `rng`. """ -function random_hypersphere(n, r; kwargs...) +function random_hypersphere(n, r = 1.0; kwargs...) random_hypersphere(Random.default_rng(), n, r; kwargs...) end -function random_hypersphere(n, r, center; kwargs...) +function random_hypersphere(n, r = 1.0, center; kwargs...) random_hypersphere(Random.default_rng(), n, r, center; kwargs...) end -function random_hypersphere(rng::Random.AbstractRNG, n::Int, r = 1.0; dim = 2) +function random_hypersphere(rng::Random.AbstractRNG, n, r = 1.0; dim = 2) random_hypersphere(rng, n, r, zeros(dim)) end -function random_hypersphere(rng::Random.AbstractRNG, n::Int, r::Real, - center::AbstractVector; dim = length(center)) +function random_hypersphere(rng::Random.AbstractRNG, n, r = 1.0, + center; dim = length(center)) @assert length(center) == dim nodes = randn(rng, n, dim) for i in 1:n @@ -466,12 +466,12 @@ function random_hypersphere_boundary(n, r, center; kwargs...) random_hypersphere_boundary(Random.default_rng(), n, r, center; kwargs...) end -function random_hypersphere_boundary(rng::Random.AbstractRNG, n::Int, r = 1.0; dim = 2) +function random_hypersphere_boundary(rng::Random.AbstractRNG, n, r = 1.0; dim = 2) random_hypersphere_boundary(rng, n, r, zeros(dim)) end -function random_hypersphere_boundary(rng::Random.AbstractRNG, n::Int, r::Real, - center::AbstractVector; +function random_hypersphere_boundary(rng::Random.AbstractRNG, n, r = 1.0, + center; dim = length(center)) @assert length(center) == dim if dim == 1 && n >= 2 From 4ea38113caa24e0dffb200a34f34a0c96f6ba8f5 Mon Sep 17 00:00:00 2001 From: Joshua Lampert Date: Mon, 2 Dec 2024 16:51:13 +0100 Subject: [PATCH 6/8] remove default --- src/nodes.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nodes.jl b/src/nodes.jl index 7bc66a78..8a837307 100644 --- a/src/nodes.jl +++ b/src/nodes.jl @@ -432,7 +432,7 @@ function random_hypersphere(n, r = 1.0; kwargs...) random_hypersphere(Random.default_rng(), n, r; kwargs...) end -function random_hypersphere(n, r = 1.0, center; kwargs...) +function random_hypersphere(n, r, center; kwargs...) random_hypersphere(Random.default_rng(), n, r, center; kwargs...) end @@ -440,7 +440,7 @@ function random_hypersphere(rng::Random.AbstractRNG, n, r = 1.0; dim = 2) random_hypersphere(rng, n, r, zeros(dim)) end -function random_hypersphere(rng::Random.AbstractRNG, n, r = 1.0, +function random_hypersphere(rng::Random.AbstractRNG, n, r, center; dim = length(center)) @assert length(center) == dim nodes = randn(rng, n, dim) From bb6ad240ce3d1d9feb20641ffb1d194241e2ffea Mon Sep 17 00:00:00 2001 From: Joshua Lampert Date: Mon, 2 Dec 2024 16:53:42 +0100 Subject: [PATCH 7/8] remove default --- src/nodes.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nodes.jl b/src/nodes.jl index 8a837307..c4761276 100644 --- a/src/nodes.jl +++ b/src/nodes.jl @@ -470,7 +470,7 @@ function random_hypersphere_boundary(rng::Random.AbstractRNG, n, r = 1.0; dim = random_hypersphere_boundary(rng, n, r, zeros(dim)) end -function random_hypersphere_boundary(rng::Random.AbstractRNG, n, r = 1.0, +function random_hypersphere_boundary(rng::Random.AbstractRNG, n, r, center; dim = length(center)) @assert length(center) == dim From 666458fa94dd144b579d7cd9a4089408025fd19b Mon Sep 17 00:00:00 2001 From: Joshua Lampert Date: Mon, 2 Dec 2024 17:02:43 +0100 Subject: [PATCH 8/8] add another default... --- src/nodes.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nodes.jl b/src/nodes.jl index c4761276..f8fcef0a 100644 --- a/src/nodes.jl +++ b/src/nodes.jl @@ -458,7 +458,7 @@ hypersphere with radius `r` around the center `center`. If `dim` is not given explicitly, it is inferred by the length of `center` if possible. Optionally, pass a random number generator `rng`. """ -function random_hypersphere_boundary(n, r; kwargs...) +function random_hypersphere_boundary(n, r = 1.0; kwargs...) random_hypersphere_boundary(Random.default_rng(), n, r; kwargs...) end