Skip to content

Commit

Permalink
TropicalGeometry: add and improve polymake conversions (#3426)
Browse files Browse the repository at this point in the history
* tropical: add conversion helpers for polymake tropicalnumber

* tropicalgeometry: simplify several polymake conversions

* use accessor
  • Loading branch information
benlorenz authored Feb 27, 2024
1 parent 2cc5013 commit 222c200
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 32 deletions.
19 changes: 12 additions & 7 deletions src/PolyhedralGeometry/helpers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,15 @@ Set{Int64} with 1 element:
"""
column(i::IncidenceMatrix, n::Int) = convert(Set{Int}, Polymake.col(i, n))

const _polymake_scalars = Union{Polymake.Integer, Polymake.Rational, Polymake.QuadraticExtension, Polymake.OscarNumber, Float64, Polymake.TropicalNumber}
const _polymake_compatible_scalars = Union{QQFieldElem, ZZRingElem, Base.Integer, Base.Rational, _polymake_scalars}

function assure_matrix_polymake(m::Union{AbstractMatrix{Any}, AbstractMatrix{FieldElem}})
a, b = size(m)
if a > 0
i = findfirst(_cannot_convert_to_fmpq, m)
t = i === nothing ? QQFieldElem : typeof(m[i])
if t <: Union{Polymake.Rational, Polymake.QuadraticExtension{Polymake.Rational}, Polymake.OscarNumber, Float64}
if t <: _polymake_scalars
m = Polymake.Matrix{Polymake.convert_to_pm_type(t)}(m)
else
m = Polymake.Matrix{_scalar_type_to_polymake(t)}(m)
Expand All @@ -95,9 +98,9 @@ assure_matrix_polymake(m::AbstractMatrix{<:FieldElem}) = Polymake.Matrix{Polymak

assure_matrix_polymake(m::MatElem) = Polymake.Matrix{_scalar_type_to_polymake(eltype(m))}(m)

assure_matrix_polymake(m::Union{Oscar.ZZMatrix, Oscar.QQMatrix, AbstractMatrix{<:Union{QQFieldElem, ZZRingElem, Base.Integer, Base.Rational, Polymake.Rational, Polymake.QuadraticExtension, Polymake.OscarNumber, Float64}}}) = m
assure_matrix_polymake(m::Union{Oscar.ZZMatrix, Oscar.QQMatrix, AbstractMatrix{<:_polymake_compatible_scalars}}) = m

assure_matrix_polymake(m::SubArray{T, 2, U, V, W}) where {T<:Union{Polymake.Rational, Polymake.QuadraticExtension, Float64}, U, V, W} = Polymake.Matrix{T}(m)
assure_matrix_polymake(m::SubArray{T, 2, U, V, W}) where {T<:Union{_polymake_scalars}, U, V, W} = Polymake.Matrix{T}(m)

function assure_vector_polymake(v::Union{AbstractVector{Any}, AbstractVector{FieldElem}})
i = findfirst(_cannot_convert_to_fmpq, v)
Expand All @@ -107,7 +110,7 @@ end

assure_vector_polymake(v::AbstractVector{<:FieldElem}) = Polymake.Vector{Polymake.OscarNumber}(v)

assure_vector_polymake(v::AbstractVector{<:Union{QQFieldElem, ZZRingElem, Base.Integer, Base.Rational, Polymake.Rational, Polymake.QuadraticExtension, Polymake.OscarNumber, Float64}}) = v
assure_vector_polymake(v::AbstractVector{<:_polymake_compatible_scalars}) = v

affine_matrix_for_polymake(x::Tuple{<:AnyVecOrMat, <:AbstractVector}) = augment(unhomogenized_matrix(x[1]), -Vector(assure_vector_polymake(x[2])))
affine_matrix_for_polymake(x::Tuple{<:AnyVecOrMat, <:Any}) = homogenized_matrix(x[1], -x[2])
Expand All @@ -125,7 +128,7 @@ number_of_rows(x::SubArray{T, 2, U, V, W}) where {T, U, V, W} = size(x, 1)
_isempty_halfspace(x::Pair{<:Union{Oscar.MatElem, AbstractMatrix}, Any}) = isempty(x[1])
_isempty_halfspace(x) = isempty(x)

function Polymake.Matrix{T}(x::Union{MatElem,AbstractMatrix{<:FieldElem}}) where T<:Union{Float64, Polymake.Rational, Polymake.Integer, Polymake.OscarNumber}
function Polymake.Matrix{T}(x::Union{MatElem,AbstractMatrix{<:FieldElem}}) where T<:_polymake_scalars
res = Polymake.Matrix{T}(size(x)...)
return res .= x
end
Expand Down Expand Up @@ -188,14 +191,16 @@ end
(F::Field)(x::Polymake.Rational) = F(QQ(x))
(F::Field)(x::Polymake.OscarNumber) = F(Polymake.unwrap(x))

Polymake.convert_to_pm_type(::Type{typeof(min)}) = Polymake.Min
Polymake.convert_to_pm_type(::Type{typeof(max)}) = Polymake.Max

Polymake.convert_to_pm_type(::Type{ZZMatrix}) = Polymake.Matrix{Polymake.Integer}
Polymake.convert_to_pm_type(::Type{QQMatrix}) = Polymake.Matrix{Polymake.Rational}
Polymake.convert_to_pm_type(::Type{ZZRingElem}) = Polymake.Integer
Polymake.convert_to_pm_type(::Type{QQFieldElem}) = Polymake.Rational
Polymake.convert_to_pm_type(::Type{T}) where T<:FieldElem = Polymake.OscarNumber
Polymake.convert_to_pm_type(::Type{<:Oscar.MatElem}) = Polymake.Matrix{Polymake.OscarNumber}
Polymake.convert_to_pm_type(::Type{<:MatElem{T}}) where T = Polymake.Matrix{Polymake.convert_to_pm_type(T)}
Polymake.convert_to_pm_type(::Type{<:Graph{T}}) where T<:Union{Directed,Undirected} = Polymake.Graph{T}
Polymake.convert_to_pm_type(::Type{<:MatElem{Float64}}) = Polymake.Matrix{Float64}

Base.convert(::Type{<:Polymake.Graph{T}}, g::Graph{T}) where T<:Union{Directed,Undirected} = Oscar.pm_object(g)

Expand Down
4 changes: 4 additions & 0 deletions src/Serialization/polymake.jl
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ _pmdata_for_oscar(s::Polymake.Integer, coeff::Field) = ZZ(s)
_pmdata_for_oscar(s::Polymake.Rational, coeff::Field) = QQ(s)
_pmdata_for_oscar(s::Polymake.OscarNumber, coeff::Field) = coeff(s)

_convert_pm_minormax(::Type{Polymake.Max}) = typeof(max)
_convert_pm_minormax(::Type{Polymake.Min}) = typeof(min)
_pmdata_for_oscar(s::Polymake.TropicalNumber{A}, coeff::Field) where A = tropical_semiring(_convert_pm_minormax(A))(s)

_pmdata_for_oscar(s::Polymake.CxxWrap.StdString, coeff::Field) = String(s)

_pmdata_for_oscar(a::Polymake.Array, coeff::Field) = [_pmdata_for_oscar(e, coeff) for e in a]
Expand Down
30 changes: 5 additions & 25 deletions src/TropicalGeometry/hypersurface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,30 +51,11 @@ function tropical_hypersurface(TropV::TropicalVarietySupertype{minOrMax,true}) w
return tropical_hypersurface(polyhedral_complex(TropV),multiplicities(TropV),convention(TropV))
end

# Decompose a tropical polynomial into parts that Polymake can eat.
# First function deals with the coefficients,
# Second function then deals with the entire polynomial.
function homogenize_and_convert_to_pm(t::TropicalSemiringElem{minOrMax}) where {minOrMax<:Union{typeof(max), typeof(min)}}
Add = (minOrMax==typeof(max)) ? Polymake.Max : Polymake.Min
if isinf(t)
return Polymake.TropicalNumber{Add}()
else
return Polymake.TropicalNumber{Add}(Polymake.new_rational_from_fmpq(data(t)))
end
end

# Decompose and homogenize a tropical polynomial into parts that Polymake can eat.
function homogenize_and_convert_to_pm(f::Oscar.MPolyRingElem{TropicalSemiringElem{minOrMax}}) where {minOrMax<:Union{typeof(max), typeof(min)}}
Add = (minOrMax==typeof(max)) ? Polymake.Max : Polymake.Min
coeffs = Polymake.TropicalNumber{Add}[]
td = total_degree(f)
exps = Vector{Int}[]
for (c,alpha) in zip(coefficients(f),exponents(f))
push!(coeffs, homogenize_and_convert_to_pm(c))
prepend!(alpha, td-sum(alpha))
push!(exps, alpha)
end
exps = matrix(ZZ, exps)
coeffs = Polymake.Vector{Polymake.TropicalNumber{Add, Polymake.Rational}}(coeffs)
exps = matrix(ZZ, collect([td-sum(alpha); alpha] for alpha in exponents(f)))
coeffs = collect(coefficients(f))
return coeffs, exps
end

Expand Down Expand Up @@ -175,9 +156,8 @@ julia> # tropical_hypersurface(Delta) # issue 2628
function tropical_hypersurface(Delta::SubdivisionOfPoints, minOrMax::Union{typeof(min),typeof(max)}=min;
weighted_polyhedral_complex_only::Bool=false)

PMinOrMax = (minOrMax==typeof(min)) ? Polymake.Min : Polymake.Max
coeffs = Polymake.TropicalNumber{PMinOrMax}.(Polymake.new_integer_from_fmpz.(min_weights(Delta)))
exps = ZZ.(matrix(QQ,points(Delta)))
coeffs = min_weights(Delta)
exps = points(Delta)
pmhypproj = Polymake.tropical.Hypersurface{minOrMax}(MONOMIALS=exps, COEFFICIENTS=coeffs)
pmhyp = Polymake.tropical.affine_chart(pmhypproj)

Expand Down
19 changes: 19 additions & 0 deletions src/TropicalGeometry/semiring.jl
Original file line number Diff line number Diff line change
Expand Up @@ -408,3 +408,22 @@ end

Oscar.mul!(x::TropicalSemiringElem, y::TropicalSemiringElem, z::TropicalSemiringElem) = y * z
Oscar.addeq!(y::TropicalSemiringElem, z::TropicalSemiringElem) = y + z


################################################################################
#
# helpers for polymake conversion
#
################################################################################

Polymake.convert_to_pm_type(::Type{<:TropicalSemiringElem{A}}) where A = Polymake.TropicalNumber{Polymake.convert_to_pm_type(A),Polymake.Rational}

function Base.convert(::Type{<:Polymake.TropicalNumber{PA}}, t::TropicalSemiringElem{A}) where {A <: Union{typeof(min),typeof(max)}, PA <: Union{Polymake.Min, Polymake.Max}}
@req PA == Polymake.convert_to_pm_type(A) "cannot convert between different tropical conventions"
isinf(t) ? Polymake.TropicalNumber{PA}() : Polymake.TropicalNumber{PA}(convert(Polymake.Rational, data(t)))
end

function (T::TropicalSemiring{A})(t::Polymake.TropicalNumber{PA}) where {A <: Union{typeof(min),typeof(max)}, PA <: Union{Polymake.Min, Polymake.Max}}
@req PA == Polymake.convert_to_pm_type(A) "cannot convert between different tropical conventions"
t == Polymake.zero(t) ? zero(T) : T(Polymake.scalar(t))
end

0 comments on commit 222c200

Please sign in to comment.