From 3fe205819c5b090378a29888438b2c0d107bc250 Mon Sep 17 00:00:00 2001 From: Benjamin Lorenz Date: Wed, 25 Oct 2023 12:29:14 +0200 Subject: [PATCH 1/7] Polyhedral: add hash method for Cone + Polyhedron where we have a custom == function, see #2222 --- src/PolyhedralGeometry/Cone/constructors.jl | 7 +++++++ src/PolyhedralGeometry/Polyhedron/constructors.jl | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/src/PolyhedralGeometry/Cone/constructors.jl b/src/PolyhedralGeometry/Cone/constructors.jl index 31b0d06d989a..3d92007b0569 100644 --- a/src/PolyhedralGeometry/Cone/constructors.jl +++ b/src/PolyhedralGeometry/Cone/constructors.jl @@ -91,6 +91,13 @@ function ==(C0::Cone{T}, C1::Cone{T}) where T<:scalar_types return Polymake.polytope.equal_polyhedra(pm_object(C0), pm_object(C1)) end +# we do not want to force a convex hull computation and even if we did, that +# would not give a normal form +function Base.hash(x::T, h::UInt) where {T <: Cone} + h = hash(ambient_dim(x), h) + h = hash(T, h) + return h +end @doc raw""" cone_from_inequalities([::Union{Type{T}, Field} = QQFieldElem,] I::AbstractCollection[LinearHalfspace] [, E::AbstractCollection[LinearHyperplane]]; non_redundant::Bool = false) diff --git a/src/PolyhedralGeometry/Polyhedron/constructors.jl b/src/PolyhedralGeometry/Polyhedron/constructors.jl index d5347eeb6780..d50f3c888df5 100644 --- a/src/PolyhedralGeometry/Polyhedron/constructors.jl +++ b/src/PolyhedralGeometry/Polyhedron/constructors.jl @@ -137,6 +137,14 @@ function ==(P0::Polyhedron{T}, P1::Polyhedron{T}) where T<:scalar_types Polymake.polytope.equal_polyhedra(pm_object(P0), pm_object(P1)) end +# we do not want to force a convex hull computation and even if we did, that +# would not give a normal form +function Base.hash(x::T, h::UInt) where {T <: Polyhedron} + h = hash(ambient_dim(x), h) + h = hash(T, h) + return h +end + ### Construct polyhedron from V-data, as the convex hull of points, rays and lineality. @doc raw""" convex_hull([::Union{Type{T}, Field} = QQFieldElem,] V [, R [, L]]; non_redundant::Bool = false) From ca358faa48b1d6b724f74439bd6acea04ad72d62 Mon Sep 17 00:00:00 2001 From: Benjamin Lorenz Date: Wed, 25 Oct 2023 12:29:33 +0200 Subject: [PATCH 2/7] LP: add ambient_dim --- docs/src/PolyhedralGeometry/linear_programs.md | 1 + .../PolyhedralGeometry/mixed_integer_linear_programs.md | 2 ++ src/PolyhedralGeometry/linear_program.jl | 7 +++++++ src/PolyhedralGeometry/mixed_integer_linear_program.jl | 7 +++++++ 4 files changed, 17 insertions(+) diff --git a/docs/src/PolyhedralGeometry/linear_programs.md b/docs/src/PolyhedralGeometry/linear_programs.md index 7ec8e216b901..0c70acec22ca 100644 --- a/docs/src/PolyhedralGeometry/linear_programs.md +++ b/docs/src/PolyhedralGeometry/linear_programs.md @@ -101,6 +101,7 @@ julia> V = optimal_vertex(LP) ```@docs feasible_region(lp::LinearProgram) +ambient_dim(lp::LinearProgram) objective_function(lp::LinearProgram{T}; as::Symbol = :pair) where T<:scalar_types solve_lp(LP::LinearProgram) optimal_value(lp::LinearProgram{T}) where T<:scalar_types diff --git a/docs/src/PolyhedralGeometry/mixed_integer_linear_programs.md b/docs/src/PolyhedralGeometry/mixed_integer_linear_programs.md index d3a100c55cb6..3c9e022f20c8 100644 --- a/docs/src/PolyhedralGeometry/mixed_integer_linear_programs.md +++ b/docs/src/PolyhedralGeometry/mixed_integer_linear_programs.md @@ -28,6 +28,8 @@ mixed_integer_linear_program ## Functions ```@docs +feasible_region(milp::MixedIntegerLinearProgram) +ambient_dim(milp::MixedIntegerLinearProgram) optimal_value(milp::MixedIntegerLinearProgram{T}) where T<:scalar_types optimal_solution solve_milp diff --git a/src/PolyhedralGeometry/linear_program.jl b/src/PolyhedralGeometry/linear_program.jl index dc604856fe7b..5a7a9a8c5ec1 100644 --- a/src/PolyhedralGeometry/linear_program.jl +++ b/src/PolyhedralGeometry/linear_program.jl @@ -207,3 +207,10 @@ Return a pair `(m,v)` where the optimal value `m` of the objective `nothing`. """ solve_lp(lp::LinearProgram) = optimal_value(lp), optimal_vertex(lp) + +@doc raw""" + ambient_dim(LP::LinearProgram) + +Return the ambient dimension of the feasible reagion of `LP`. +""" +ambient_dim(lp::LinearProgram) = ambient_dim(feasible_region(lp)) diff --git a/src/PolyhedralGeometry/mixed_integer_linear_program.jl b/src/PolyhedralGeometry/mixed_integer_linear_program.jl index a0176ef04d95..a678e00fefa1 100644 --- a/src/PolyhedralGeometry/mixed_integer_linear_program.jl +++ b/src/PolyhedralGeometry/mixed_integer_linear_program.jl @@ -248,3 +248,10 @@ julia> solve_milp(milp) ``` """ solve_milp(milp::MixedIntegerLinearProgram) = optimal_value(milp), optimal_solution(milp) + +@doc raw""" + ambient_dim(MILP::MixedIntegerLinearProgram) + +Return the ambient dimension of the feasible reagion of `MILP`. +""" +ambient_dim(milp::MixedIntegerLinearProgram) = ambient_dim(feasible_region(milp)) From 591ed5ef73f7ffea58a073f53372ddf91cdfebe7 Mon Sep 17 00:00:00 2001 From: Benjamin Lorenz Date: Wed, 25 Oct 2023 13:30:07 +0200 Subject: [PATCH 3/7] Polyhedral: test for unique (hash) --- test/PolyhedralGeometry/cone.jl | 3 +++ test/PolyhedralGeometry/polyhedron.jl | 1 + 2 files changed, 4 insertions(+) diff --git a/test/PolyhedralGeometry/cone.jl b/test/PolyhedralGeometry/cone.jl index f40d2d69b558..48bc3ce9ce21 100644 --- a/test/PolyhedralGeometry/cone.jl +++ b/test/PolyhedralGeometry/cone.jl @@ -78,6 +78,9 @@ @test is_fulldimensional(Cone2) @test Cone2 == Cone3 @test Cone4 != Cone2 + + @test length(unique([Cone2, Cone3, Cone4])) == 2 + @test dim(Cone4) == 2 @test dim(Cone2) == 3 @test ambient_dim(Cone2) == 3 diff --git a/test/PolyhedralGeometry/polyhedron.jl b/test/PolyhedralGeometry/polyhedron.jl index 2a684cd9b6b0..28da4a4815f7 100644 --- a/test/PolyhedralGeometry/polyhedron.jl +++ b/test/PolyhedralGeometry/polyhedron.jl @@ -183,6 +183,7 @@ @test vertex_sizes(Q1)[1] == 2 @test length(vertex_sizes(Q2)) == 0 + @test length(unique([cube(2), cube(2), simplex(2), simplex(2)])) == 2 end @testset "volume" begin From 8e0e157061ac156f6f6edb72912f901be67b5d52 Mon Sep 17 00:00:00 2001 From: Benjamin Lorenz Date: Wed, 25 Oct 2023 13:30:30 +0200 Subject: [PATCH 4/7] Polyhedral: cleanup obsolete check --- test/PolyhedralGeometry/polyhedron.jl | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/test/PolyhedralGeometry/polyhedron.jl b/test/PolyhedralGeometry/polyhedron.jl index 28da4a4815f7..d968984f506b 100644 --- a/test/PolyhedralGeometry/polyhedron.jl +++ b/test/PolyhedralGeometry/polyhedron.jl @@ -222,12 +222,10 @@ @test upper_bound_h_vector(4,8) == [1, 4, 10, 4 ,1] A = archimedean_solid("cuboctahedron") @test count(F -> nvertices(F) == 3, faces(A, 2)) == 8 - # due to GLIBCXX issues with the outdated julia-shipped libstdc++ - # we run this only where recent CompilerSupportLibraries are available - if VERSION >= v"1.6" - C = catalan_solid("triakis_tetrahedron") - @test count(F -> nvertices(F) == 3, faces(C, 2)) == 12 - end + + C = catalan_solid("triakis_tetrahedron") + @test count(F -> nvertices(F) == 3, faces(C, 2)) == 12 + @test polyhedron(facets(A)) == A b1 = birkhoff_polytope(3) b2 = birkhoff_polytope(3, even = true) From 4658ecea6ed0d9867fe4b37e181f06d724d347ce Mon Sep 17 00:00:00 2001 From: Benjamin Lorenz Date: Wed, 25 Oct 2023 13:35:36 +0200 Subject: [PATCH 5/7] Polyhedral: test ambient dim for lp --- test/PolyhedralGeometry/linear_program.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/PolyhedralGeometry/linear_program.jl b/test/PolyhedralGeometry/linear_program.jl index a148d8472cf6..0b638d591816 100644 --- a/test/PolyhedralGeometry/linear_program.jl +++ b/test/PolyhedralGeometry/linear_program.jl @@ -24,6 +24,8 @@ @test LP2 isa LinearProgram{T} @test LP3 isa LinearProgram{T} + @test ambient_dim(LP1) == 2 + @test solve_lp(LP1)==(4,[1,1]) @test solve_lp(LP2)==(-1,[-1,-1]) if T == QQFieldElem @@ -43,6 +45,8 @@ @test MILP2 isa MixedIntegerLinearProgram{T} @test MILP3 isa MixedIntegerLinearProgram{T} + @test ambient_dim(MILP3) == 3 + @test solve_milp(MILP1)==(11//2,[1,3//2]) @test solve_milp(MILP2)==(-1,[-1,-1]) @test string(solve_milp(MILP3))==string("(inf, nothing)") From 38c0df298c918dfd12677f94c15ed498078d3170 Mon Sep 17 00:00:00 2001 From: Benjamin Lorenz Date: Thu, 26 Oct 2023 17:52:27 +0200 Subject: [PATCH 6/7] Polyhedral: update comment for hash function as suggested --- src/PolyhedralGeometry/Cone/constructors.jl | 6 ++++-- src/PolyhedralGeometry/Polyhedron/constructors.jl | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/PolyhedralGeometry/Cone/constructors.jl b/src/PolyhedralGeometry/Cone/constructors.jl index 3d92007b0569..667988413440 100644 --- a/src/PolyhedralGeometry/Cone/constructors.jl +++ b/src/PolyhedralGeometry/Cone/constructors.jl @@ -91,8 +91,10 @@ function ==(C0::Cone{T}, C1::Cone{T}) where T<:scalar_types return Polymake.polytope.equal_polyhedra(pm_object(C0), pm_object(C1)) end -# we do not want to force a convex hull computation and even if we did, that -# would not give a normal form +# For a proper hash function for cones we should use a "normal form", +# which would require a potentially expensive convex hull computation +# (and even that is not enough). But hash methods should be fast, so we +# just consider the ambient dimension and the precise type of the cone. function Base.hash(x::T, h::UInt) where {T <: Cone} h = hash(ambient_dim(x), h) h = hash(T, h) diff --git a/src/PolyhedralGeometry/Polyhedron/constructors.jl b/src/PolyhedralGeometry/Polyhedron/constructors.jl index d50f3c888df5..9bb2ac4e2a53 100644 --- a/src/PolyhedralGeometry/Polyhedron/constructors.jl +++ b/src/PolyhedralGeometry/Polyhedron/constructors.jl @@ -137,8 +137,10 @@ function ==(P0::Polyhedron{T}, P1::Polyhedron{T}) where T<:scalar_types Polymake.polytope.equal_polyhedra(pm_object(P0), pm_object(P1)) end -# we do not want to force a convex hull computation and even if we did, that -# would not give a normal form +# For a proper hash function for cones we should use a "normal form", +# which would require a potentially expensive convex hull computation +# (and even that is not enough). But hash methods should be fast, so we +# just consider the ambient dimension and the precise type of the polyhedron. function Base.hash(x::T, h::UInt) where {T <: Polyhedron} h = hash(ambient_dim(x), h) h = hash(T, h) From 829b8424697f6b202a0b2135cf68d03a7f32609a Mon Sep 17 00:00:00 2001 From: Benjamin Lorenz Date: Thu, 26 Oct 2023 17:54:10 +0200 Subject: [PATCH 7/7] Polyhedron: remove obsolete code in == operator --- src/PolyhedralGeometry/Cone/constructors.jl | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/PolyhedralGeometry/Cone/constructors.jl b/src/PolyhedralGeometry/Cone/constructors.jl index 667988413440..4ca23cb04a0a 100644 --- a/src/PolyhedralGeometry/Cone/constructors.jl +++ b/src/PolyhedralGeometry/Cone/constructors.jl @@ -84,11 +84,7 @@ cone(f::scalar_type_or_field, x...) = positive_hull(f, x...) function ==(C0::Cone{T}, C1::Cone{T}) where T<:scalar_types - # TODO: Remove the following 3 lines, see #758 - for pair in Iterators.product([C0, C1], ["RAYS", "FACETS"]) - Polymake.give(pm_object(pair[1]),pair[2]) - end - return Polymake.polytope.equal_polyhedra(pm_object(C0), pm_object(C1)) + return Polymake.polytope.equal_polyhedra(pm_object(C0), pm_object(C1))::Bool end # For a proper hash function for cones we should use a "normal form",