From 372895df1b52b4f4fe5a8dbb65f0985b1279a784 Mon Sep 17 00:00:00 2001 From: Paul Breiding Date: Tue, 8 Apr 2025 13:59:21 +0200 Subject: [PATCH 1/7] add automated triangle inequality --- src/monodromy.jl | 2 +- src/unique_points.jl | 27 ++++++++++++++++++++++++--- test/monodromy_test.jl | 10 +++++++++- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/monodromy.jl b/src/monodromy.jl index c64ade8f..51befefd 100644 --- a/src/monodromy.jl +++ b/src/monodromy.jl @@ -37,7 +37,7 @@ Base.@kwdef struct MonodromyOptions{D,GA<:Union{Nothing,GroupActions}} permutations::Bool = false # unique points options distance::D = EuclideanNorm() - triangle_inequality::Bool = true + triangle_inequality::Union{Nothing,Bool} = nothing unique_points_atol::Union{Nothing,Float64} = nothing unique_points_rtol::Union{Nothing,Float64} = nothing # diff --git a/src/unique_points.jl b/src/unique_points.jl index 197c0908..a8c73d81 100644 --- a/src/unique_points.jl +++ b/src/unique_points.jl @@ -128,11 +128,12 @@ Base.iterate(p::SymmetricGroup, s) = iterate(p.permutations, s) A data structure for assessing quickly whether a point is close to an indexed point as determined by the given distances function `M`. The distance function has to be a *metric*. -The indexed points are only stored by their identifiers `Id`. `triangle_inequality` should be set to `true`, if the metric satisfies the triangle inequality. Otherwise, it should be set to `false`. +The indexed points are only stored by their identifiers `Id`. +`triangle_inequality` should be set to `true`, if the metric satisfies the triangle inequality. Otherwise, it should be set to `false`. If `triangle_inequality` is nothing the algorithm will try to detect whether the triangle is satisfied. UniquePoints(v::AbstractVector{T}, id::Id; metric = EuclideanNorm(), - triangle_inequality = true, + triangle_inequality = nothing, group_actions = nothing) @@ -168,7 +169,7 @@ function UniquePoints( v::AbstractVector, id; metric = EuclideanNorm(), - triangle_inequality = true, + triangle_inequality = nothing, group_action = nothing, group_actions = isnothing(group_action) ? nothing : GroupActions(group_action), ) @@ -176,6 +177,26 @@ function UniquePoints( group_actions = GroupActions(group_actions) end + + + if isnothing(triangle_inequality) + if metric == EuclideanNorm() + triangle_inequality = true + else + n = length(v) + v₁ = randn(ComplexF64, n) + v₂ = randn(ComplexF64, n) + v₃ = randn(ComplexF64, n) + @show metric(v₁, v₂), metric(v₁, v₃) + metric(v₃, v₂) + if metric(v₁, v₂) ≤ metric(v₁, v₃) + metric(v₃, v₂) && + metric(v₁, 4 .* v₁) ≤ metric(v₁, 2 .* v₁) + metric(2 .* v₁, 4 .* v₁) + triangle_inequality = true + else + triangle_inequality = false + end + end + end + tree = VoronoiTree(v, id; metric = metric, triangle_inequality = triangle_inequality) UniquePoints(tree, group_actions, zeros(eltype(v), length(v))) end diff --git a/test/monodromy_test.jl b/test/monodromy_test.jl index d0ad26c7..8d540abb 100644 --- a/test/monodromy_test.jl +++ b/test/monodromy_test.jl @@ -69,14 +69,22 @@ monodromy_solve(F.expressions, [x₀, rand(6)], p₀, parameters = F.parameters) @test length(solutions(result)) == 21 - # different distance function + # distance function that satisfies triangle inequality result = monodromy_solve(F, x₀, p₀, distance = (x, y) -> 0.0) @test length(solutions(result)) == 1 + # distance function that does not satisfy triangle inequality + result = monodromy_solve(F, x₀, p₀, distance = (x, y) -> norm(x - y, 2)^2) + @test length(solutions(result)) == 21 + # don't use triangle inequality result = monodromy_solve(F, x₀, p₀, triangle_inequality = false) @test length(solutions(result)) == 21 + # use triangle inequality + result = monodromy_solve(F, x₀, p₀, triangle_inequality = true) + @test length(solutions(result)) == 21 + # Test stop heuristic with no target solutions count result = monodromy_solve(F, x₀, p₀) @test is_heuristic_stop(result) From 15356219db9b3798c09026e603bfbb5e446cb508 Mon Sep 17 00:00:00 2001 From: Paul Breiding Date: Tue, 8 Apr 2025 14:04:02 +0200 Subject: [PATCH 2/7] replace metric by distance --- src/monodromy.jl | 2 +- src/unique_points.jl | 41 ++++++++++++++++++----------------- src/voronoi_tree.jl | 44 ++++++++++++++++++++++---------------- test/monodromy_test.jl | 2 +- test/unique_points_test.jl | 8 +++++-- 5 files changed, 54 insertions(+), 43 deletions(-) diff --git a/src/monodromy.jl b/src/monodromy.jl index 51befefd..bada75d4 100644 --- a/src/monodromy.jl +++ b/src/monodromy.jl @@ -458,7 +458,7 @@ function MonodromySolver( unique_points = UniquePoints( x₀, 1; - metric = options.distance, + distance = options.distance, group_actions = group_actions, triangle_inequality = options.triangle_inequality, ) diff --git a/src/unique_points.jl b/src/unique_points.jl index a8c73d81..74cc9a0b 100644 --- a/src/unique_points.jl +++ b/src/unique_points.jl @@ -127,12 +127,13 @@ Base.iterate(p::SymmetricGroup, s) = iterate(p.permutations, s) UniquePoints{T, Id, M} A data structure for assessing quickly whether a point is close to an indexed point as -determined by the given distances function `M`. The distance function has to be a *metric*. +determined by the given distance function `M`. The indexed points are only stored by their identifiers `Id`. -`triangle_inequality` should be set to `true`, if the metric satisfies the triangle inequality. Otherwise, it should be set to `false`. If `triangle_inequality` is nothing the algorithm will try to detect whether the triangle is satisfied. +`triangle_inequality` should be set to `true`, if the distance function satisfies the triangle inequality. +Otherwise, it should be set to `false`. If `triangle_inequality` is nothing the algorithm will try to detect whether the triangle is satisfied. UniquePoints(v::AbstractVector{T}, id::Id; - metric = EuclideanNorm(), + distance = EuclideanNorm(), triangle_inequality = nothing, group_actions = nothing) @@ -168,7 +169,7 @@ end function UniquePoints( v::AbstractVector, id; - metric = EuclideanNorm(), + d = EuclideanNorm(), triangle_inequality = nothing, group_action = nothing, group_actions = isnothing(group_action) ? nothing : GroupActions(group_action), @@ -180,16 +181,16 @@ function UniquePoints( if isnothing(triangle_inequality) - if metric == EuclideanNorm() + if d == EuclideanNorm() triangle_inequality = true else n = length(v) v₁ = randn(ComplexF64, n) v₂ = randn(ComplexF64, n) v₃ = randn(ComplexF64, n) - @show metric(v₁, v₂), metric(v₁, v₃) + metric(v₃, v₂) - if metric(v₁, v₂) ≤ metric(v₁, v₃) + metric(v₃, v₂) && - metric(v₁, 4 .* v₁) ≤ metric(v₁, 2 .* v₁) + metric(2 .* v₁, 4 .* v₁) + @show d(v₁, v₂), d(v₁, v₃) + d(v₃, v₂) + if d(v₁, v₂) ≤ d(v₁, v₃) + d(v₃, v₂) && + d(v₁, 4 .* v₁) ≤ d(v₁, 2 .* v₁) + d(2 .* v₁, 4 .* v₁) triangle_inequality = true else triangle_inequality = false @@ -197,7 +198,7 @@ function UniquePoints( end end - tree = VoronoiTree(v, id; metric = metric, triangle_inequality = triangle_inequality) + tree = VoronoiTree(v, id; distance = d, triangle_inequality = triangle_inequality) UniquePoints(tree, group_actions, zeros(eltype(v), length(v))) end @@ -278,7 +279,7 @@ function add!( atol::Float64 = 1e-14, rtol::Float64 = sqrt(eps()), ) where {T,Id,M,GA} - n = UP.tree.metric(v, UP.zero_vec) + n = UP.tree.distance(v, UP.zero_vec) rad = max(atol, rtol * n) add!(UP, v, id, rad) end @@ -287,10 +288,10 @@ end ## Multiplicities ## #################### """ - multiplicities(vectors; metric = EuclideanNorm(), atol = 1e-14, rtol = 1e-8, kwargs...) + multiplicities(vectors; distance = EuclideanNorm(), atol = 1e-14, rtol = 1e-8, kwargs...) Returns a `Vector{Vector{Int}}` `v`. Each vector `w` in 'v' contains all indices `i`,`j` -such that `w[i]` and `w[j]` have `distance` at most `max(atol, rtol * metric(0,w[i]))`. +such that `w[i]` and `w[j]` have `distance` at most `max(atol, rtol * distance(0,w[i]))`. The remaining `kwargs` are things that can be passed to [`UniquePoints`](@ref). ```julia-repl @@ -310,19 +311,19 @@ julia> m = multiplicities(X, group_action = permutation) ``` """ multiplicities(v; kwargs...) = multiplicities(identity, v; kwargs...) -function multiplicities(f::F, v; metric = EuclideanNorm(), kwargs...) where {F<:Function} +function multiplicities(f::F, v; distance = EuclideanNorm(), kwargs...) where {F<:Function} isempty(v) && return Vector{Vector{Int}}() - _multiplicities(f, v, metric; kwargs...) + _multiplicities(f, v, distance; kwargs...) end function _multiplicities( f::F, V, - metric; + distance; atol::Float64 = 1e-14, rtol::Float64 = 1e-8, kwargs..., ) where {F<:Function} - unique_points = UniquePoints(f(first(V)), 1; metric = metric, kwargs...) + unique_points = UniquePoints(f(first(V)), 1; distance = distance, kwargs...) mults = Dict{Int,Vector{Int}}() for (i, vᵢ) in enumerate(V) wᵢ = f(vᵢ) @@ -338,14 +339,14 @@ function _multiplicities( collect(values(mults)) end """ - unique_points(vectors; metric = EuclideanNorm(), atol = 1e-14, rtol = 1e-8, kwargs...) + unique_points(vectors; distance = EuclideanNorm(), atol = 1e-14, rtol = 1e-8, kwargs...) -Returns all elements in `vector` for which two elements have `distance` at most `max(atol, rtol * metric(0,w[i]))`. +Returns all elements in `vector` for which two elements have `distance` at most `max(atol, rtol * distance(0,w[i]))`. Note that the output can depend on the order of elements in vectors. The remaining `kwargs` are things that can be passed to [`UniquePoints`](@ref). """ -function unique_points(V; metric = EuclideanNorm(), atol = 1e-14, rtol = 1e-8, kwargs...) - unique_points = UniquePoints(first(V), 1; metric = metric, kwargs...) +function unique_points(V; distance = EuclideanNorm(), atol = 1e-14, rtol = 1e-8, kwargs...) + unique_points = UniquePoints(first(V), 1; distance = distance, kwargs...) out = Vector{eltype(V)}() for (i, vᵢ) in enumerate(V) _, new_point = add!(unique_points, vᵢ, i; atol = atol, rtol = rtol) diff --git a/src/voronoi_tree.jl b/src/voronoi_tree.jl index 4eace4e7..8da24413 100644 --- a/src/voronoi_tree.jl +++ b/src/voronoi_tree.jl @@ -29,9 +29,9 @@ Base.length(node::VTNode) = node.nentries Base.isempty(node::VTNode) = length(node) == 0 capacity(node::VTNode) = length(node.children) -function compute_distances!(node, x, metric::M) where {M} +function compute_distances!(node, x, distance::M) where {M} for j = 1:length(node) - node.distances[j] = (metric(x, view(node.values, :, j)), j) + node.distances[j] = (distance(x, view(node.values, :, j)), j) end node.distances end @@ -40,7 +40,7 @@ function search_in_radius( node::VTNode{T,Id}, x, tol::Real, - metric::M, + distance::M, triangle_inequality::Bool, ) where {T,Id,M} !isempty(node) || return nothing @@ -62,7 +62,7 @@ function search_in_radius( m₁ = m₂ = m₃ = (Inf, 1) # we have a distances cache per thread - distances = compute_distances!(node, x, metric) + distances = compute_distances!(node, x, distance) for i = 1:n dᵢ = first(distances[i]) # early exit @@ -95,7 +95,7 @@ function search_in_radius( # Check smallest element first if isassigned(node.children, last(m₁)) retid = - search_in_radius(node.children[last(m₁)], x, tol, metric, triangle_inequality) + search_in_radius(node.children[last(m₁)], x, tol, distance, triangle_inequality) if !isnothing(retid) # we rely on the distances for insertion, so place the smallest element first distances[1] = m₁ @@ -112,7 +112,7 @@ function search_in_radius( # Case 2) If we have a triangle in equality, we know m₂[1] - m₁[1] ≤ 2tol if isassigned(node.children, last(m₂)) retid = - search_in_radius(node.children[last(m₂)], x, tol, metric, triangle_inequality) + search_in_radius(node.children[last(m₂)], x, tol, distance, triangle_inequality) if !isnothing(retid) # we rely on the distances for insertion, so place the smallest element first distances[1] = m₁ @@ -128,7 +128,7 @@ function search_in_radius( # Since we know also the third element, let's check it if isassigned(node.children, last(m₃)) retid = - search_in_radius(node.children[last(m₃)], x, tol, metric, triangle_inequality) + search_in_radius(node.children[last(m₃)], x, tol, distance, triangle_inequality) if !isnothing(retid) # we rely on the distances for insertion, so place at the first place the smallest element distances[1] = m₁ @@ -146,8 +146,13 @@ function search_in_radius( dᵢ, i = distances[k] if dᵢ - m₁[1] < 2tol || !triangle_inequality if isassigned(node.children, i) - retid = - search_in_radius(node.children[i], x, tol, metric, triangle_inequality) + retid = search_in_radius( + node.children[i], + x, + tol, + distance, + triangle_inequality, + ) if !isnothing(retid) return retid::Id end @@ -165,7 +170,7 @@ function _insert!( node::VTNode{T,Id}, v, id::Id, - metric::M; + distance::M; use_distances::Bool = false, ) where {T,Id,M} # if not filled so far, just add it to the current node @@ -179,14 +184,14 @@ function _insert!( if use_distances dᵢ, minᵢ = first(node.distances) else - compute_distances!(node, v, metric) + compute_distances!(node, v, distance) dᵢ, minᵢ = findmin(node.distances) end if !isassigned(node.children, minᵢ) node.children[minᵢ] = VTNode{T,Id}(v, id; capacity = capacity(node)) else # a node already exists, so recurse - _insert!(node.children[minᵢ], v, id, metric) + _insert!(node.children[minᵢ], v, id, distance) end nothing @@ -206,29 +211,30 @@ end VoronoiTree( v::AbstractVector{T}, id::Id; - metric = EuclideanNorm(), + distance = EuclideanNorm(), capacity = 8, triangle_inequality = true ) Construct a Voronoi tree data structure for vector `v` of element type `T` and with identifiers -`Id`. Each node has the given `capacity` and distances are measured by the given `metric`. `triangle_inequality` should be set to `true`, if `metric` satisfies the triangle inequality. Otherwise, it should be set to `false`. +`Id`. Each node has the given `capacity` and distances are measured by the given `distance`. +`triangle_inequality` should be set to `true`, if `distance` satisfies the triangle inequality. Otherwise, it should be set to `false`. """ mutable struct VoronoiTree{T,Id,M} root::VTNode{T,Id} nentries::Int - metric::M + distance::M triangle_inequality::Bool end function VoronoiTree{T,Id}( d::Int; - metric = EuclideanNorm(), + distance = EuclideanNorm(), capacity::Int = 8, triangle_inequality::Bool = true, ) where {T,Id} root = VTNode(T, Id, d; capacity = capacity) - VoronoiTree(root, 0, metric, triangle_inequality) + VoronoiTree(root, 0, distance, triangle_inequality) end function VoronoiTree(v::AbstractVector{T}, id::Id; kwargs...) where {T,Id} @@ -254,7 +260,7 @@ function Base.insert!( id::Id; use_distances::Bool = false, ) where {T,Id} - _insert!(tree.root, v, id, tree.metric; use_distances = use_distances) + _insert!(tree.root, v, id, tree.distance; use_distances = use_distances) tree.nentries += 1 tree end @@ -266,7 +272,7 @@ Search whether the given `tree` contains a point `p` with distances at most `tol Returns `nothing` if no point exists, otherwise the identifier of `p` is returned. """ function search_in_radius(tree::VoronoiTree, v, tol::Real) - search_in_radius(tree.root, v, tol, tree.metric, tree.triangle_inequality) + search_in_radius(tree.root, v, tol, tree.distance, tree.triangle_inequality) end diff --git a/test/monodromy_test.jl b/test/monodromy_test.jl index 8d540abb..224ad5d8 100644 --- a/test/monodromy_test.jl +++ b/test/monodromy_test.jl @@ -448,7 +448,7 @@ target_solutions_count = 305, ) - UP = unique_points(solutions(points), metric = dist, rtol = 1e-8, atol = 1e-14) + UP = unique_points(solutions(points), distance = dist, rtol = 1e-8, atol = 1e-14) @test length(solutions(points)) == length(UP) end diff --git a/test/unique_points_test.jl b/test/unique_points_test.jl index a99f7696..a71b9d9e 100644 --- a/test/unique_points_test.jl +++ b/test/unique_points_test.jl @@ -338,7 +338,7 @@ end M = multiplicities(V) @test length(M) == 0 - N = multiplicities(W, metric = InfNorm(), atol = 1e-5) + N = multiplicities(W, distance = InfNorm(), atol = 1e-5) sort!(N, by = first) @test length(N) == 10 @test unique([length(m) for m in N]) == [2] @@ -347,7 +347,11 @@ end O = multiplicities([U; U]) @test length(O) == 20 - P = multiplicities(X, metric = (x, y) -> 1 - abs(LinearAlgebra.dot(x, y)), atol = 1e-5) + P = multiplicities( + X, + distance = (x, y) -> 1 - abs(LinearAlgebra.dot(x, y)), + atol = 1e-5, + ) @test length(P) == 3 # Test with group action From 446861b15d88f74537a43598c43a2d78e2d13e00 Mon Sep 17 00:00:00 2001 From: Paul Breiding Date: Tue, 8 Apr 2025 14:04:53 +0200 Subject: [PATCH 3/7] remove unnecessary line --- src/unique_points.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/unique_points.jl b/src/unique_points.jl index 74cc9a0b..fd14d474 100644 --- a/src/unique_points.jl +++ b/src/unique_points.jl @@ -178,8 +178,6 @@ function UniquePoints( group_actions = GroupActions(group_actions) end - - if isnothing(triangle_inequality) if d == EuclideanNorm() triangle_inequality = true From 159a2ebf9b987c764f3ccfa07876c4e8668b689e Mon Sep 17 00:00:00 2001 From: Paul Breiding Date: Tue, 8 Apr 2025 14:05:15 +0200 Subject: [PATCH 4/7] remove @show --- src/unique_points.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/unique_points.jl b/src/unique_points.jl index fd14d474..7f384f26 100644 --- a/src/unique_points.jl +++ b/src/unique_points.jl @@ -186,7 +186,6 @@ function UniquePoints( v₁ = randn(ComplexF64, n) v₂ = randn(ComplexF64, n) v₃ = randn(ComplexF64, n) - @show d(v₁, v₂), d(v₁, v₃) + d(v₃, v₂) if d(v₁, v₂) ≤ d(v₁, v₃) + d(v₃, v₂) && d(v₁, 4 .* v₁) ≤ d(v₁, 2 .* v₁) + d(2 .* v₁, 4 .* v₁) triangle_inequality = true From 6213f383ee60ed171e69e0d17580c0ea439fb192 Mon Sep 17 00:00:00 2001 From: Paul Breiding Date: Tue, 8 Apr 2025 14:09:06 +0200 Subject: [PATCH 5/7] bug fix --- src/unique_points.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/unique_points.jl b/src/unique_points.jl index 7f384f26..23de11c4 100644 --- a/src/unique_points.jl +++ b/src/unique_points.jl @@ -169,7 +169,7 @@ end function UniquePoints( v::AbstractVector, id; - d = EuclideanNorm(), + distance = EuclideanNorm(), triangle_inequality = nothing, group_action = nothing, group_actions = isnothing(group_action) ? nothing : GroupActions(group_action), @@ -178,6 +178,8 @@ function UniquePoints( group_actions = GroupActions(group_actions) end + d = distance + if isnothing(triangle_inequality) if d == EuclideanNorm() triangle_inequality = true From 33f0445b155e4701fb96d5ae16d619cd23901208 Mon Sep 17 00:00:00 2001 From: Paul Breiding Date: Tue, 8 Apr 2025 18:38:30 +0200 Subject: [PATCH 6/7] replace EuclideanNorm by InfNorm --- src/monodromy.jl | 4 ++-- src/unique_points.jl | 14 +++++++------- test/unique_points_test.jl | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/monodromy.jl b/src/monodromy.jl index bada75d4..28d0d86d 100644 --- a/src/monodromy.jl +++ b/src/monodromy.jl @@ -36,7 +36,7 @@ Base.@kwdef struct MonodromyOptions{D,GA<:Union{Nothing,GroupActions}} reuse_loops::Symbol = :all permutations::Bool = false # unique points options - distance::D = EuclideanNorm() + distance::D = InfNorm() triangle_inequality::Union{Nothing,Bool} = nothing unique_points_atol::Union{Nothing,Float64} = nothing unique_points_rtol::Union{Nothing,Float64} = nothing @@ -533,7 +533,7 @@ See also [`linear_subspace_homotopy`](@ref) for the `intrinsic` option. for evaluation. This induces a compilation overhead. If `false` then the generated program is only interpreted ([`InterpretedSystem`](@ref) resp. [`InterpretedHomotopy`](@ref)). This is slower than the compiled version, but does not introduce compilation overhead. -* `distance = EuclideanNorm()`: The distance function used for [`UniquePoints`](@ref). +* `distance = InfNorm()`: The distance function used for [`UniquePoints`](@ref). * `loop_finished_callback = always_false`: A callback to end the computation. This function is called with all current [`PathResult`](@ref)s after a loop is exhausted. 2 arguments. Return `true` if the compuation should be stopped. diff --git a/src/unique_points.jl b/src/unique_points.jl index 23de11c4..bc850294 100644 --- a/src/unique_points.jl +++ b/src/unique_points.jl @@ -133,7 +133,7 @@ The indexed points are only stored by their identifiers `Id`. Otherwise, it should be set to `false`. If `triangle_inequality` is nothing the algorithm will try to detect whether the triangle is satisfied. UniquePoints(v::AbstractVector{T}, id::Id; - distance = EuclideanNorm(), + distance = InfNorm(), triangle_inequality = nothing, group_actions = nothing) @@ -169,7 +169,7 @@ end function UniquePoints( v::AbstractVector, id; - distance = EuclideanNorm(), + distance = InfNorm(), triangle_inequality = nothing, group_action = nothing, group_actions = isnothing(group_action) ? nothing : GroupActions(group_action), @@ -181,7 +181,7 @@ function UniquePoints( d = distance if isnothing(triangle_inequality) - if d == EuclideanNorm() + if typeof(d) <: AbstractNorm triangle_inequality = true else n = length(v) @@ -287,7 +287,7 @@ end ## Multiplicities ## #################### """ - multiplicities(vectors; distance = EuclideanNorm(), atol = 1e-14, rtol = 1e-8, kwargs...) + multiplicities(vectors; distance = InfNorm(), atol = 1e-14, rtol = 1e-8, kwargs...) Returns a `Vector{Vector{Int}}` `v`. Each vector `w` in 'v' contains all indices `i`,`j` such that `w[i]` and `w[j]` have `distance` at most `max(atol, rtol * distance(0,w[i]))`. @@ -310,7 +310,7 @@ julia> m = multiplicities(X, group_action = permutation) ``` """ multiplicities(v; kwargs...) = multiplicities(identity, v; kwargs...) -function multiplicities(f::F, v; distance = EuclideanNorm(), kwargs...) where {F<:Function} +function multiplicities(f::F, v; distance = InfNorm(), kwargs...) where {F<:Function} isempty(v) && return Vector{Vector{Int}}() _multiplicities(f, v, distance; kwargs...) end @@ -338,13 +338,13 @@ function _multiplicities( collect(values(mults)) end """ - unique_points(vectors; distance = EuclideanNorm(), atol = 1e-14, rtol = 1e-8, kwargs...) + unique_points(vectors; distance = InfNorm(), atol = 1e-14, rtol = 1e-8, kwargs...) Returns all elements in `vector` for which two elements have `distance` at most `max(atol, rtol * distance(0,w[i]))`. Note that the output can depend on the order of elements in vectors. The remaining `kwargs` are things that can be passed to [`UniquePoints`](@ref). """ -function unique_points(V; distance = EuclideanNorm(), atol = 1e-14, rtol = 1e-8, kwargs...) +function unique_points(V; distance = InfNorm(), atol = 1e-14, rtol = 1e-8, kwargs...) unique_points = UniquePoints(first(V), 1; distance = distance, kwargs...) out = Vector{eltype(V)}() for (i, vᵢ) in enumerate(V) diff --git a/test/unique_points_test.jl b/test/unique_points_test.jl index a71b9d9e..944758f6 100644 --- a/test/unique_points_test.jl +++ b/test/unique_points_test.jl @@ -338,7 +338,7 @@ end M = multiplicities(V) @test length(M) == 0 - N = multiplicities(W, distance = InfNorm(), atol = 1e-5) + N = multiplicities(W, distance = EuclideanNorm(), atol = 1e-5) sort!(N, by = first) @test length(N) == 10 @test unique([length(m) for m in N]) == [2] From 9e1fb4cacead2c93668c2b82bd449a1dc7a215a9 Mon Sep 17 00:00:00 2001 From: Paul Breiding Date: Tue, 8 Apr 2025 18:43:13 +0200 Subject: [PATCH 7/7] back to EuclideanNorm (doesnt make a big difference) --- src/monodromy.jl | 4 ++-- src/unique_points.jl | 12 ++++++------ test/unique_points_test.jl | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/monodromy.jl b/src/monodromy.jl index 28d0d86d..bada75d4 100644 --- a/src/monodromy.jl +++ b/src/monodromy.jl @@ -36,7 +36,7 @@ Base.@kwdef struct MonodromyOptions{D,GA<:Union{Nothing,GroupActions}} reuse_loops::Symbol = :all permutations::Bool = false # unique points options - distance::D = InfNorm() + distance::D = EuclideanNorm() triangle_inequality::Union{Nothing,Bool} = nothing unique_points_atol::Union{Nothing,Float64} = nothing unique_points_rtol::Union{Nothing,Float64} = nothing @@ -533,7 +533,7 @@ See also [`linear_subspace_homotopy`](@ref) for the `intrinsic` option. for evaluation. This induces a compilation overhead. If `false` then the generated program is only interpreted ([`InterpretedSystem`](@ref) resp. [`InterpretedHomotopy`](@ref)). This is slower than the compiled version, but does not introduce compilation overhead. -* `distance = InfNorm()`: The distance function used for [`UniquePoints`](@ref). +* `distance = EuclideanNorm()`: The distance function used for [`UniquePoints`](@ref). * `loop_finished_callback = always_false`: A callback to end the computation. This function is called with all current [`PathResult`](@ref)s after a loop is exhausted. 2 arguments. Return `true` if the compuation should be stopped. diff --git a/src/unique_points.jl b/src/unique_points.jl index bc850294..bf3d4ae5 100644 --- a/src/unique_points.jl +++ b/src/unique_points.jl @@ -133,7 +133,7 @@ The indexed points are only stored by their identifiers `Id`. Otherwise, it should be set to `false`. If `triangle_inequality` is nothing the algorithm will try to detect whether the triangle is satisfied. UniquePoints(v::AbstractVector{T}, id::Id; - distance = InfNorm(), + distance = EuclideanNorm(), triangle_inequality = nothing, group_actions = nothing) @@ -169,7 +169,7 @@ end function UniquePoints( v::AbstractVector, id; - distance = InfNorm(), + distance = EuclideanNorm(), triangle_inequality = nothing, group_action = nothing, group_actions = isnothing(group_action) ? nothing : GroupActions(group_action), @@ -287,7 +287,7 @@ end ## Multiplicities ## #################### """ - multiplicities(vectors; distance = InfNorm(), atol = 1e-14, rtol = 1e-8, kwargs...) + multiplicities(vectors; distance = EuclideanNorm(), atol = 1e-14, rtol = 1e-8, kwargs...) Returns a `Vector{Vector{Int}}` `v`. Each vector `w` in 'v' contains all indices `i`,`j` such that `w[i]` and `w[j]` have `distance` at most `max(atol, rtol * distance(0,w[i]))`. @@ -310,7 +310,7 @@ julia> m = multiplicities(X, group_action = permutation) ``` """ multiplicities(v; kwargs...) = multiplicities(identity, v; kwargs...) -function multiplicities(f::F, v; distance = InfNorm(), kwargs...) where {F<:Function} +function multiplicities(f::F, v; distance = EuclideanNorm(), kwargs...) where {F<:Function} isempty(v) && return Vector{Vector{Int}}() _multiplicities(f, v, distance; kwargs...) end @@ -338,13 +338,13 @@ function _multiplicities( collect(values(mults)) end """ - unique_points(vectors; distance = InfNorm(), atol = 1e-14, rtol = 1e-8, kwargs...) + unique_points(vectors; distance = EuclideanNorm(), atol = 1e-14, rtol = 1e-8, kwargs...) Returns all elements in `vector` for which two elements have `distance` at most `max(atol, rtol * distance(0,w[i]))`. Note that the output can depend on the order of elements in vectors. The remaining `kwargs` are things that can be passed to [`UniquePoints`](@ref). """ -function unique_points(V; distance = InfNorm(), atol = 1e-14, rtol = 1e-8, kwargs...) +function unique_points(V; distance = EuclideanNorm(), atol = 1e-14, rtol = 1e-8, kwargs...) unique_points = UniquePoints(first(V), 1; distance = distance, kwargs...) out = Vector{eltype(V)}() for (i, vᵢ) in enumerate(V) diff --git a/test/unique_points_test.jl b/test/unique_points_test.jl index 944758f6..a71b9d9e 100644 --- a/test/unique_points_test.jl +++ b/test/unique_points_test.jl @@ -338,7 +338,7 @@ end M = multiplicities(V) @test length(M) == 0 - N = multiplicities(W, distance = EuclideanNorm(), atol = 1e-5) + N = multiplicities(W, distance = InfNorm(), atol = 1e-5) sort!(N, by = first) @test length(N) == 10 @test unique([length(m) for m in N]) == [2]