Skip to content

Commit

Permalink
WIP: posets
Browse files Browse the repository at this point in the history
  • Loading branch information
benlorenz committed Jul 11, 2024
1 parent 34fc1bf commit 998fcc9
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 0 deletions.
169 changes: 169 additions & 0 deletions src/Combinatorics/PartiallyOrderedSet/functions.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
function pm_object(P::PartiallyOrderedSet)
return P.pm_poset
end
# TODO: move to Polymake.jl soon
Polymake.Meta.translate_type_to_pm_string(::Type{<:Polymake.BasicDecoration}) = "graph::BasicDecoration"

function partially_ordered_set(pp::Polymake.BigObject)
@req startswith(Polymake.type_name(pp), "PartiallyOrderedSet") "Not a polymake PartiallyOrderedSet: $(Polymake.type_name(pp))"
return PartiallyOrderedSet(pp)
end

@doc raw"""
 partially_ordered_set(covrels::Matrix{Int})
Construct a partially ordered set from covering relations `covrels`, given in
the form of the adjacency matrix of a Hasse diagram. The covering relations
must be given in topological order, i.e. `covrels` must be strictly upper
triangular.
"""
function partially_ordered_set(covrels::Matrix{Int})
pg = Polymake.Graph{Directed}(IncidenceMatrix(covrels))
nelem = nrows(covrels)
return partially_ordered_set(Graph{Directed}(pg), 1, nelem)
end


@doc raw"""
 partially_ordered_set_from_inclusions(i::IncidenceMatrix)
Construct an inclusion based partially ordered with rows of `i` as co-atoms.
"""
function partially_ordered_set_from_inclusions(i::IncidenceMatrix)
# we want to make sure it is always built from the bottom up
# and just need to specify some arbitrary upper bound for the rank
pos = Polymake.call_function(:polytope, :lower_hasse_diagram, i, ncols(i))
return partially_ordered_set(pos)
end


_pmdec(elem::Int, r::Int) = Polymake.BasicDecoration(Polymake.Set{Int}(elem), r)
_pmdec(r::Int) = Polymake.BasicDecoration(Polymake.Set{Int}(), r)

@doc raw"""
 partially_ordered_set(g::Graph{Directed}, minimal_element::Int, maximal_element::Int)
Construct a partially ordered set from a directed graph describing the Hasse diagram.
The graph must be acyclic and have unique minimal and maximal elements.
"""
function partially_ordered_set(g::Graph{Directed}, minimal_element::Int, maximal_element::Int)
stack = [minimal_element]
gc = Polymake.Graph{Directed}(pm_object(g))
dec = Polymake.NodeMap{Directed, Polymake.BasicDecoration}(gc)
# we need to generate some valid rank function
es = Polymake.Set{Int}()
Polymake._set_entry(dec, minimal_element-1, _pmdec(minimal_element, 0))
while !isempty(stack)
src = pop!(stack)
r = Polymake.decoration_rank(Polymake._get_entry(dec, src-1))
for t in neighbors(g, src)
rr = Polymake.decoration_rank(Polymake._get_entry(dec, t-1))
Polymake._set_entry(dec, t-1, _pmdec(t, max(r+1, rr)))
push!(stack, t)
end
end
pos = Polymake.graph.PartiallyOrderedSet{Polymake.BasicDecoration}(
ADJACENCY=gc,
DECORATION=dec,
TOP_NODE=maximal_element-1,
BOTTOM_NODE=minimal_element-1
)
return PartiallyOrderedSet(pos)
end

@doc raw"""
partially_ordered_set(g::Graph{Directed}, node_ranks::Dict{Int,Int})
Construct a partially ordered set from a directed graph describing the Hasse diagram.
The graph must be acyclic and have unique minimal and maximal elements.
A The dictionary `node_ranks` must give a valid rank for each node in the graph, strictly
increasing from the unique minimal element to the unique maximal element.
"""
function partially_ordered_set(g::Graph{Directed}, node_ranks::Dict{Int,Int})
gc = Polymake.Graph{Directed}(pm_object(g))
dec = Polymake.NodeMap{Directed, Polymake.BasicDecoration}(gc)
for n in 1:n_vertices(g)
Polymake._set_entry(dec, n-1, _pmdec(n, node_ranks[n]))
end
bottom = findmin(node_ranks)[2]
top = findmax(node_ranks)[2]
pos = Polymake.graph.PartiallyOrderedSet{Polymake.BasicDecoration}(
ADJACENCY=gc,
DECORATION=dec,
TOP_NODE=top-1,
BOTTOM_NODE=bottom-1
)
return PartiallyOrderedSet(pos)
end

comparability_graph(pos::PartiallyOrderedSet) = Graph{Undirected}(pm_object(pos).COMPARABILITY_GRAPH::Polymake.Graph{Undirected})

# this will compute the comparability graph on first use
# the graph will be kept in the polymake object
function compare(pos::PartiallyOrderedSet, a::Int, b::Int)
cg = comparability_graph(pos)
has_edge(cg, a, b) || return false
return rank(pos, a) < rank(pos, b)
end

function compare(a::PartiallyOrderedSetElement, b::PartiallyOrderedSetElement)
@req parent(a) === parent(b) "cannot compare elements in different posets"
return compare(parent(a), data(a), data(b))
end

parent(pose::PartiallyOrderedSetElement) = pose.parent
data(pose::PartiallyOrderedSetElement) = pose.node_id

Base.length(p::PartiallyOrderedSet) = pm_object(p).N_NODES::Int

function rank(p::PartiallyOrderedSet, i::Int64)
dec = pm_object(p).DECORATION::Polymake.NodeMap{Directed,Polymake.BasicDecoration}
elemdec = Polymake._get_entry(dec, i-1)::Polymake.BasicDecoration
return Polymake.decoration_rank(elemdec)::Int
end

function maximal_chains(p::PartiallyOrderedSet)
mc = Polymake.graph.maximal_chains_of_lattice(pm_object(p))::IncidenceMatrix
return row.(Ref(mc), 1:nrows(mc))
end

function Base.show(io::IO, p::PartiallyOrderedSet)
if is_terse(io)
print(io, "Partially ordered set")
else
print(io, "Partially ordered set on $(length(p)) elements")
end
end

function visualize(p::PartiallyOrderedSet; kwargs...)
Polymake.visual(pm_object(p); kwargs...)
end

function face_lattice(p::Union{Polyhedron,Cone,PolyhedralFan,PolyhedralComplex})
return partially_ordered_set(pm_object(p).HASSE_DIAGRAM)
end

function order_polytope(p::PartiallyOrderedSet)
return polyhedron(Polymake.polytope.order_polytope(pm_object(p)))
end

function chain_polytope(p::PartiallyOrderedSet)
return polyhedron(Polymake.polytope.chain_polytope(pm_object(p)))
end

@doc raw"""
maximal_ranked_poset(v::AbstractVector{Int})
Maximal ranked partially ordered set with number of nodes per rank given in
`v`, from bottom to top and excluding the minimal and maximal elements.
See Ahmad, Fourier, Joswig, arXiv:2309.01626
TODO: ref
"""
function maximal_ranked_poset(v::AbstractVector{Int})
return partially_ordered_set(Polymake.graph.maximal_ranked_poset(Polymake.Array{Int}(v)))
end

graph(p::PartiallyOrderedSet) = Graph{Directed}(pm_object(p).ADJACENCY)

node_ranks(p::PartiallyOrderedSet) = Dict((i => rank(p, i)) for i in 1:length(p))
11 changes: 11 additions & 0 deletions src/Combinatorics/PartiallyOrderedSet/structs.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
abstract type AbstractPartiallyOrderedSet end

struct PartiallyOrderedSet <: AbstractPartiallyOrderedSet
pm_poset::Polymake.BigObject
end

struct PartiallyOrderedSetElement{T}
parent::PartiallyOrderedSet
node_id::Int
elem::T
end
2 changes: 2 additions & 0 deletions src/Oscar.jl
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,8 @@ include("Combinatorics/SimplicialComplexes.jl")
include("Combinatorics/OrderedMultiIndex.jl")
include("Combinatorics/Matroids/JMatroids.jl")
include("Combinatorics/EnumerativeCombinatorics/EnumerativeCombinatorics.jl")
include("Combinatorics/PartiallyOrderedSet/structs.jl")
include("Combinatorics/PartiallyOrderedSet/functions.jl")

include("PolyhedralGeometry/visualization.jl") # needs SimplicialComplex

Expand Down
6 changes: 6 additions & 0 deletions src/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ export cellular_primary_decomposition
export center, has_center, set_center
export centralizer
export chain_complex
export chain_polytope
export chain_range
export chamber
export character_field
Expand Down Expand Up @@ -355,6 +356,7 @@ export collector
export coloops
export column
export combinatorial_symmetries
export comparability_graph
export composition
export compositions
export comm
Expand Down Expand Up @@ -992,11 +994,13 @@ export maxes
export maximal_abelian_quotient, has_maximal_abelian_quotient, set_maximal_abelian_quotient
export maximal_blocks
export maximal_cells
export maximal_chains
export maximal_cones
export maximal_extension
export maximal_groebner_cone
export maximal_normal_subgroups, has_maximal_normal_subgroups, set_maximal_normal_subgroups
export maximal_polyhedra, maximal_polyhedra_and_multiplicities
export maximal_ranked_poset
export maximal_subgroup_classes, has_maximal_subgroup_classes, set_maximal_subgroup_classes
export maximal_subgroups
export metadata
Expand Down Expand Up @@ -1134,6 +1138,7 @@ export orbit_representatives_and_stabilizers
export orbits
export order, has_order, set_order
export order_field_of_definition
export order_polytope
export ordering
export orders_centralizers
export orders_class_representatives
Expand All @@ -1149,6 +1154,7 @@ export parallel_extension
export parametrization
export parametrization_conic
export parent
export partially_ordered_set
export partition
export partitions
export patches
Expand Down

0 comments on commit 998fcc9

Please sign in to comment.