Using Polymake.jl
In this section, the main functionality of Polymake.jl
is covered: how to access polymake
's powerful abilities. For this cause one needs to know how to call polymake
methods and how to handle the supported types.
Executing Polymake Methods
Directly calling a polymake
method
One of the simplest yet most useful possibilities Polymake.jl
offers is to directly use a polymake
method via the following macro:
Polymake.@pm
— Macro@pm polymakeapp.function_name{Template, parameters}(args)
This macro can be used to
- create
polymake
Big Objects (such as polytopes) - call
polymake
functions with specific template parameters.
The expression passed to the macro has to be:
- a fully qualified name of a
polymake
object (i.e. starting with the
lowercase name of a polymake application), or
- a function with template parameters enclosed in
{ ... }
.
Examples
julia> P = @pm polytope.Polytope{QuadraticExtension}(POINTS=[1 0 0; 0 1 0])
type: Polytope<QuadraticExtension<Rational>>
POINTS
1 0 0
0 1 0
julia> @pm common.convert_to{Float}(P)
type: Polytope<Float>
POINTS
1 0 0
0 1 0
CONE_AMBIENT_DIM
3
julia> @pm tropical.Polytope{Max}(POINTS=[1 0 0; 0 1 0])
type: Polytope<Max, Rational>
POINTS
0 -1 -1
0 1 0
!!! Note the expression in @pm
macro is parsed syntactically, so it has to be a valid julia
expression. However template parameters need not to be defined in julia
, but must be valid names of polymake
property types. Nested types (such as {QuadraticExtension{Rational}}
) are allowed.
The @pm
macro can be used to issue more complicated calls to polymake from julia. If You need to pass templates to BigObject
s, some limited support is provided in costructors. For example one can construct polytope.Polytope{Float64}(...)
. However for this to work templates need to be valid julia types/object, hence it is not possible to construct a Polytope<QuadraticExtension>
through such call. For this (and in general: for passing more complicated templates) one needs the @pm
macro:
$obj = new BigObject<Template,Parameters>(args)
becomes
obj = @pm appname.BigObject{Template, Parameters}(args)
Examples:
tropical.Polytope{max, Polymake.Rational}(POINTS=[1 0 0; 1 1 0; 1 1 1])
# call to constructor, note that max is a julia function, hence a valid object
@pm tropical.Polytope{Max, QuadraticExtension}(POINTS=[1 0 0; 1 1 0; 1 1 1])
# macro call: none of the types in templates need to exist in julia
As a rule of thumb any template passed to @pm
macro needs to be translatable on syntax level to a C++
one. E.g. Matrix{Integer}
works, as it translates to pm::Matrix<pm::Integer>
.
Such templates can be passed to functions as well. A very useful example is the common.convert_to
:
julia> c = polytope.cube(3);
julia> f = c.FACETS;
julia> f[1,1] # f is an opaque pm::perl::PropertyValue to julia
ERROR: MethodError: no method matching getindex(::Polymake.PropertyValueAllocated, ::Int64, ::Int64)
Stacktrace:
[...]
julia> m = @pm common.convert_to{Matrix{Integer}}(f) # the template must consist of C++ names
pm::Matrix<pm::Integer>
1 1 0 0
1 -1 0 0
1 0 1 0
1 0 -1 0
1 0 0 1
1 0 0 -1
julia> m[1,1]
1
Since the combination of the @pm
macro and common.convert_to
is quite common there is a specialized @convert_to
macro for this:
julia> m = @convert_to Matrix{Integer} f # the template must consist of C++ names
pm::Matrix<pm::Integer>
1 1 0 0
1 -1 0 0
1 0 1 0
1 0 -1 0
1 0 0 1
1 0 0 -1
Wrapped methods
As the @pm
macro allows to access polymake
's library, there is no need for every method to be wrapped. In general, the wrapped methods restrict to simpler ones in the context of small types, guaranteeing compatibility with julia
or allowing easy modification/operations of/with instances of these types. This results in a handling of these types which is equivalent to julia
's syntax, e.g. arrays can be accessed with the brackets operator []
or addition can be applied by using +
:
julia> m = Polymake.Matrix{Polymake.Rational}(4,6)
pm::Matrix<pm::Rational>
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
julia> m[2,1] = 9
9
julia> m
pm::Matrix<pm::Rational>
0 0 0 0 0 0
9 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
julia> a = Polymake.TropicalNumber{Polymake.Min}(7)
pm::TropicalNumber<pm::Min, pm::Rational>
7
julia> b = Polymake.TropicalNumber{Polymake.Min}(10)
pm::TropicalNumber<pm::Min, pm::Rational>
10
julia> a + b
pm::TropicalNumber<pm::Min, pm::Rational>
7
Function Arguments
Functions in Polymake.jl
accept the following types for their arguments:
- simple data types (bools, machine integers, floats)
- wrapped native types (
Polymake.Integer
,Polymake.Rational
,Polymake.Vector
,Polymake.Matrix
,Polymake.Set
etc.) - other objects returned by polymake:
Polymake.BigObject
,Polymake.PropertyValue
(containers opaque to Julia)
If an object passed to Polymake.jl
function is of a different type the software will try its best to convert it to a known one. However, if the conversion doesn't work an ArgumentError
will be thrown:
ERROR: ArgumentError: Unrecognized argument type: SomeType.
You need to convert to polymake compatible type first.
You can tell Polymake.jl
how to convert it by definig
Base.convert(::Type{Polymake.PolymakeType}, x::SomeType)
The returned value must be of one of the types as above. For example to use AbstractAlgebra.jl
matrices as input to Polymake.jl
one may define
Base.convert(::Type{Polymake.PolymakeType}, M::Generic.MatSpaceElem) = Polymake.Matrix(M.entries)
and the following should run smoothly.
julia> using AbstractAlgebra, Polymake
polymake version 4.0
Copyright (c) 1997-2020
Ewgenij Gawrilow, Michael Joswig (TU Berlin)
https://polymake.org
This is free software licensed under GPL; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
julia> mm = AbstractAlgebra.matrix(ZZ, [1 2 3; 4 5 6])
[1 2 3]
[4 5 6]
julia> polytope.Polytope(POINTS=mm)
ERROR: ArgumentError: Unrecognized argument type: AbstractAlgebra.Generic.MatSpaceElem{Int64}.
You need to convert to polymake compatible type first.
[...]
julia> Base.convert(::Type{Polymake.PolymakeType}, M::Generic.MatSpaceElem) = Polymake.Matrix(M.entries)
julia> polytope.Polytope(POINTS=mm)
type: Polytope<Rational>
POINTS
1 2 3
1 5/4 3/2
Accessing the polyDB
Polymake.jl
allows the user to access the objects stored within the polyDB
via the Mongoc.jl
package; this functionality can be found in another sub-module, Polymake.Polydb
, which requires no additional interaction to be loaded. It offers two different ways for querying, as well as some methods for information. For demonstration purposes, there also is a Jupyter notebook
in the examples/
folder.
General tools
There are three types one needs to know when working with Polymake.Polydb
:
Polymake.Polydb.Database
— Type Database
Type for referencing a specific database (usually the polyDB
)
Polymake.Polydb.Collection
— Type Collection{T}
Type for referencing a specific collection. T<:Union{Polymake.BigObject, Mongoc.BSON}
defines the template and/or element types returned by operations applied on objects of this type.
Polymake.Polydb.Cursor
— Type Cursor{T}
Type containing the results of a query. Can be iterated, but the iterator can not be reset. For this cause, one has to query again. T<:Union{Polymake.BigObject, Mongoc.BSON}
defines the element types.
To receive the Database
object referencing to the polyDB
, there is the get_db()
method:
Polymake.Polydb.get_db
— Method get_db()
Connect to the polyDB
and return Database
instance.
The uri of the server can be set in advance by writing its String
representation into ENV["POLYDBTESTURI"]. (used to connect to the github services container for testing)
Examples
julia> db = Polymake.Polydb.get_db();
julia> typeof(db)
Polymake.Polydb.Database
A specific Collection
object can then be obtained with the brackets operator:
Base.getindex
— Method getindex(db::Database, name::AbstractString)
Return a Polymake.Polydb.Collection{Polymake.BigObject}
instance from db
with the given name
. Sections and collections in the name are connected with the '.' sign.
Examples
julia> db = Polymake.Polydb.get_db();
julia> collection = getindex(db, "Polytopes.Lattice.SmoothReflexive")
Polymake.Polydb.Collection{Polymake.BigObject}: Polytopes.Lattice.SmoothReflexive
julia> collection = db["Matroids.Small"]
Polymake.Polydb.Collection{Polymake.BigObject}: Matroids.Small
By default, the results are parsed to Polymake.BigObject
s when accessed, but one may choose to change this behaviour by adjusting the typing template of Collection
or Cursor
using the following method:
Polymake.Polydb.Collection
— Method Collection{T}(c::Collection)
Create another Collection
object with a specific template parameter referencing the same collection as c
. T
can be chosen from Polymake.BigObject
and Mongoc.BSON
.
Examples
julia> db = Polymake.Polydb.get_db();
julia> collection = db["Polytopes.Lattice.SmoothReflexive"]
Polymake.Polydb.Collection{Polymake.BigObject}: Polytopes.Lattice.SmoothReflexive
julia> collection_bson = Polymake.Polydb.Collection{Mongoc.BSON}(collection)
Polymake.Polydb.Collection{Mongoc.BSON}: Polytopes.Lattice.SmoothReflexive
julia> collection_bo = Polymake.Polydb.Collection{Polymake.BigObject}(collection_bson)
Polymake.Polydb.Collection{Polymake.BigObject}: Polytopes.Lattice.SmoothReflexive
Information
Polymake.Polydb.info
— Function info(db::Database, level::Base.Integer=1)
Print a structured list of the sections and collections of the Polydb together with information about each of these (if existent).
Detail of the output determined by value of level
:
- 1: short description,
- 2: description,
- 3: description, authors, maintainers,
- 4: full info,
- 5: full info and list of recommended search fields.
info(c::Collection, level::Base.Integer=1)
Print information about collection c
(if existent).
Detail of the output determined by value of level
:
- 1: short description,
- 2: description,
- 3: description, authors, maintainers,
- 4: full info,
- 5: full info and list of recommended search fields.
Polymake.Polydb.get_collection_names
— Function get_collection_names(db::Database)
Return a Vector{String}
containing the names of all collections in the Polydb, excluding meta collections.
Examples
julia> db = Polymake.Polydb.get_db();
julia> Polymake.Polydb.get_collection_names(db)
16-element Vector{String}:
"Polytopes.Combinatorial.FacesBirkhoffPolytope"
"Polytopes.Combinatorial.SmallSpheresDim4"
"Polytopes.Geometric.01Polytopes"
"Polytopes.Lattice.SmoothReflexive"
"Polytopes.Lattice.ExceptionalMaximalHollow"
"Tropical.TOM"
⋮
"Polytopes.Lattice.Panoptigons"
"Tropical.Cubics"
"Tropical.SchlaefliFan"
"Polytopes.Lattice.Reflexive"
"Polytopes.Combinatorial.CombinatorialTypes"
Polymake.Polydb.get_fields
— Function get_fields(c::Collection)
Return a Vector{String}
containing the names of the fields of c
.
Examples
julia> db = Polymake.Polydb.get_db();
julia> collection = db["Matroids.Small"]
Polymake.Polydb.Collection{Polymake.BigObject}: Matroids.Small
julia> Polymake.Polydb.get_fields(collection)
27-element Vector{String}:
"DUAL"
"N_BASES"
"TUTTE_POLYNOMIAL"
"SERIES_PARALLEL"
"N_FLATS"
"SPLIT_FLACETS"
⋮
"TERNARY"
"REGULAR"
"TRANSVERSAL"
"IDENTICALLY_SELF_DUAL"
"BETA_INVARIANT"
Querying
There are two ways for querying within Polymake.jl
.
Methods
Mongoc.find
— Functionfind(collection::Collection, bson_filter::BSON=BSON();
options::Union{Nothing, BSON}=nothing) :: Cursor
Executes a query on collection
and returns an iterable Cursor
.
Example
function find_contract_codes(collection, criteria::Dict=Dict()) :: Vector{String}
result = Vector{String}()
let
bson_filter = Mongoc.BSON(criteria)
bson_options = Mongoc.BSON("""{ "projection" : { "_id" : true }, "sort" : { "_id" : 1 } }""")
for bson_document in Mongoc.find(collection, bson_filter, options=bson_options)
push!(result, bson_document["_id"])
end
end
return result
end
Check the libmongoc documentation for more information.
find(bucket::Bucket, bson_filter::BSON=BSON();
options::BSON=BSON()) :: Cursor
Looks for files in GridFS bucket.
find(c::Collection{T}, d::Dict=Dict(); opts::Union{Nothing, Dict})
Search a collection c
for documents matching the criteria given by d
. Apply search options opts
.
Examples
julia> db = Polymake.Polydb.get_db();
julia> collection = db["Polytopes.Lattice.SmoothReflexive"];
julia> query = Dict("DIM"=>3, "N_FACETS"=>5);
julia> results = Polymake.Polydb.find(collection, query);
julia> typeof(results)
Polymake.Polydb.Cursor{Polymake.BigObject}
find(c::Collection{T}, d::Pair...)
Search a collection c
for documents matching the criteria given by d
.
Examples
julia> db = Polymake.Polydb.get_db();
julia> collection = db["Polytopes.Lattice.SmoothReflexive"];
julia> results = Polymake.Polydb.find(collection, "DIM"=>3, "N_FACETS"=>5);
julia> typeof(results)
Polymake.Polydb.Cursor{Polymake.BigObject}
Macros
Polymake.Polydb.@select
— MacroPolymake.Polydb.@select collectionName
This macro can be used as part of a chain for easy (i.e. human readable) querying. Generate a method asking a container for the entry with key collectionName
.
Examples
julia> db = Polymake.Polydb.get_db();
julia> collection = db |>
Polymake.Polydb.@select("Polytopes.Lattice.SmoothReflexive")
Polymake.Polydb.Collection{Polymake.BigObject}: Polytopes.Lattice.SmoothReflexive
Polymake.Polydb.@filter
— MacroPolymake.Polydb.@filter conditions...
This macro can be used as part of a chain for easy (i.e. human readable) querying. Convert conditions
into the corresponding Dict
and generate a method expanding its input by this Dict
. Multiple conditions can be passed in the same line and/or in different lines.
Examples
julia> db = Polymake.Polydb.get_db();
julia> query_tuple = db |>
Polymake.Polydb.@select("Polytopes.Lattice.SmoothReflexive") |>
Polymake.Polydb.@filter("DIM" <= 3) |>
Polymake.Polydb.@filter("N_VERTICES" == 8)
(Polymake.Polydb.Collection{Polymake.BigObject}
COLLECTION: Polytopes.Lattice.SmoothReflexive
Smooth reflexive lattice polytopes in dimensions up to 9, up to lattice equivalence. The lists were computed with the algorithm of Mikkel Oebro (see [[http://arxiv.org/abs/0704.0049|arxiv: 0704.0049]]) and are taken from the [[http://polymake.org/polytopes/paffenholz/www/fano.html|website of Andreas Paffenholz]]. They also contain splitting data according to [[https://arxiv.org/abs/1711.02936| arxiv: 1711.02936]].
Authored by
Andreas Paffenholz, paffenholz@opt.tu-darmstadt.de, TU Darmstadt
Benjamin Lorenz, paffenholz@opt.tu-darmstadt.de, TU Berlin
Mikkel Oebro
Fields: AFFINE_HULL, CONE_DIM, DIM, EHRHART_POLYNOMIAL, F_VECTOR, FACET_SIZES, FACET_WIDTHS, FACETS, H_STAR_VECTOR, LATTICE_DEGREE, LATTICE_VOLUME, LINEALITY_SPACE, N_BOUNDARY_LATTICE_POINTS, N_EDGES, N_FACETS, N_INTERIOR_LATTICE_POINTS, N_LATTICE_POINTS, N_RIDGES, N_VERTICES, REFLEXIVE, SMOOTH, SELF_DUAL, SIMPLE, TERMINAL, VERTEX_SIZES, VERTICES, VERTICES_IN_FACETS, VERY_AMPLE, ALTSHULER_DET, BALANCED, CENTROID, DIAMETER, NORMAL, N_HILBERT_BASIS, IS_PRISM, IS_PRODUCT, IS_SKEW_PRISM, IS_SIMPLEX_SUM, PRISM_BASE, PRODUCT_FACTORS, SIMPLEX_SUM_BASES, SKEW_PRISM_BASES, Dict{String,Any}("DIM" => Dict{String,Any}("$lte" => 3),"N_VERTICES" => Dict{String,Any}("$eq" => 8)))
julia> query_tuple = db |>
Polymake.Polydb.@select("Polytopes.Lattice.SmoothReflexive") |>
Polymake.Polydb.@filter("DIM" <= 3, "N_VERTICES" == 8)
(Polymake.Polydb.Collection{Polymake.BigObject}
COLLECTION: Polytopes.Lattice.SmoothReflexive
Smooth reflexive lattice polytopes in dimensions up to 9, up to lattice equivalence. The lists were computed with the algorithm of Mikkel Oebro (see [[http://arxiv.org/abs/0704.0049|arxiv: 0704.0049]]) and are taken from the [[http://polymake.org/polytopes/paffenholz/www/fano.html|website of Andreas Paffenholz]]. They also contain splitting data according to [[https://arxiv.org/abs/1711.02936| arxiv: 1711.02936]].
Authored by
Andreas Paffenholz, paffenholz@opt.tu-darmstadt.de, TU Darmstadt
Benjamin Lorenz, paffenholz@opt.tu-darmstadt.de, TU Berlin
Mikkel Oebro
Fields: AFFINE_HULL, CONE_DIM, DIM, EHRHART_POLYNOMIAL, F_VECTOR, FACET_SIZES, FACET_WIDTHS, FACETS, H_STAR_VECTOR, LATTICE_DEGREE, LATTICE_VOLUME, LINEALITY_SPACE, N_BOUNDARY_LATTICE_POINTS, N_EDGES, N_FACETS, N_INTERIOR_LATTICE_POINTS, N_LATTICE_POINTS, N_RIDGES, N_VERTICES, REFLEXIVE, SMOOTH, SELF_DUAL, SIMPLE, TERMINAL, VERTEX_SIZES, VERTICES, VERTICES_IN_FACETS, VERY_AMPLE, ALTSHULER_DET, BALANCED, CENTROID, DIAMETER, NORMAL, N_HILBERT_BASIS, IS_PRISM, IS_PRODUCT, IS_SKEW_PRISM, IS_SIMPLEX_SUM, PRISM_BASE, PRODUCT_FACTORS, SIMPLEX_SUM_BASES, SKEW_PRISM_BASES, Dict{String,Any}("DIM" => Dict{String,Any}("$lte" => 3),"N_VERTICES" => Dict{String,Any}("$eq" => 8)))
Polymake.Polydb.@map
— MacroPolymake.Polydb.@map [optFields...]
This macro can be used as part of a chain for easy (i.e. human readable) querying. Generate a method running a query given a Tuple{Collection, Dict}
. If optFields
are given (as String
s), the results only contain the stated fields and the objects metadata.
Examples
julia> db = Polymake.Polydb.get_db();
julia> results = db |>
Polymake.Polydb.@select("Polytopes.Lattice.SmoothReflexive") |>
Polymake.Polydb.@filter("DIM" == 3, "N_VERTICES" == 8) |>
Polymake.Polydb.@map() |>
collect
7-element Vector{Polymake.BigObject}:
Polymake.BigObjectAllocated(Ptr{Nothing} @0x00000000028c5320)
Polymake.BigObjectAllocated(Ptr{Nothing} @0x000000000abd7b40)
Polymake.BigObjectAllocated(Ptr{Nothing} @0x000000000a6d7bf0)
Polymake.BigObjectAllocated(Ptr{Nothing} @0x000000000a431470)
Polymake.BigObjectAllocated(Ptr{Nothing} @0x000000000bcaf290)
Polymake.BigObjectAllocated(Ptr{Nothing} @0x00000000098fb670)
Polymake.BigObjectAllocated(Ptr{Nothing} @0x000000000a1ba460)