OSCAR, a Tech Preview (Part I)

A tiny example, which makes use of the cornerstone systems polymake and GAP.

The Setup

The configuration can be cloned via copying the Project.toml file and using instantiate in the REPL mode.

In [1]:
versioninfo()

using Pkg
Pkg.status()
Julia Version 1.5.3
Commit 788b2c77c1 (2020-11-09 13:37 UTC)
Platform Info:
  OS: Linux (x86_64-pc-linux-gnu)
  CPU: Intel(R) Core(TM) i7-7600U CPU @ 2.80GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-9.0.1 (ORCJIT, skylake)
Status `/data/polymake/oscar-system/oscar-notebooks/MPI-demo-200124/Project.toml`
  [7073ff75] IJulia v1.23.1
  [f1435218] Oscar v0.5.1 `https://github.com/oscar-system/Oscar.jl#d0908f5`
 [9b87118b] PackageCompiler v1.2.5
  [8f399da3] Libdl
Info packages marked with  not downloaded, use `instantiate` to download

polymake's Functions Are Available

In [2]:
using Oscar
const pm=Polymake;
 -----    -----    -----      -      -----   
|     |  |     |  |     |    | |    |     |  
|     |  |        |         |   |   |     |  
|     |   -----   |        |     |  |-----   
|     |        |  |        |-----|  |   |    
|     |  |     |  |     |  |     |  |    |   
 -----    -----    -----   -     -  -     -  

...combining (and extending) ANTIC, GAP, Polymake and Singular
Version 0.5.1 ... 
 ... which comes with absolutely no warranty whatsoever
Type: '?Oscar' for more information
(c) 2019-2021 by The Oscar Development Team

In the context of Hilbert's 16th Problem Itenberg and Viro constructed a counter-example to a conjecture of Ragsdale, via patchworking. This is just to show that (almost) all of polymake's functionality is available through Julia.

In [3]:
R = pm.tropical.ragsdale_counterexample();

Interactive visualization is possible, also within a Jupyter notebook. Yet, for static web versions svg output is nicer.

In [4]:
pm.display_svg(R)
unnamed

The actual example starts here. We construct a regular $4$-cube, with $\pm1$-coordinates, but the precise coordinates will not matter here.

In [5]:
C = pm.polytope.cube(4);

We can get the combinatorial automorphism group directly.

In [6]:
G_polymake = pm.group.automorphism_group(C.VERTICES_IN_FACETS);

From the type information output (which is suppressed by ";" following the command) we see that the group is given as a permutation group. What is not obvious, but true: this is the natural action on the eight facets.

In [7]:
gens = G_polymake.PERMUTATION_ACTION.GENERATORS
Out[7]:
pm::Array<pm::Array<long>>
0 1 2 3 6 7 4 5
0 1 4 5 2 3 6 7
2 3 0 1 4 5 6 7
1 0 2 3 4 5 6 7

Note that polymake is $0$-based, while Julia is $1$-based.

In [8]:
gens[2]
Out[8]:
pm::Array<long>
0 1 4 5 2 3 6 7

Generic Julia functions can convert between $0$- and $1$-based containers. Future Polymake.jl versions will have this built-in.

In [9]:
to_one_based_indexing(n::Number) = n + one(n)
to_zero_based_indexing(n::Number) = (n > zero(n) ? n - one(n) : throw(ArgumentError("Can't use negative index")))

for f in [:to_one_based_indexing, :to_zero_based_indexing]
    @eval begin
        $f(itr) = $f.(itr)
        $f(s::S) where S<:AbstractSet = S($f.(s))
    end
end

Applying this to the generators of the group computed by polymake yields a standard Julia datatype.

In [10]:
to_one_based_indexing(gens)
Out[10]:
[[$1$, $2$, $3$, $4$, $7$, $8$, $5$, $6$], [$1$, $2$, $5$, $6$, $3$, $4$, $7$, $8$], [$3$, $4$, $1$, $2$, $5$, $6$, $7$, $8$], [$2$, $1$, $3$, $4$, $5$, $6$, $7$, $8$]]

Use GAP For Groups

The software of choice to deal with groups is GAP. Here is a micro-demo, which constructs a symmetric group of degree four from a 4-cycle and a transposition.

In [11]:
S4 = GAP.Globals.Group(GAP.@gap [(1,2,3,4), (1,2)])
@show S4
GAP.Globals.Order(S4)
S4 = GAP: Group([ (1,2,3,4), (1,2) ])
Out[11]:
$24$

A typical OSCAR-function will provide natural ways of communication between the cornerstone systems. The function is fairly short, the bulk of the code are some straightforward conversions.

In [12]:
function combinatorial_automorphism_group(P)
    G = pm.group.automorphism_group(P.VERTICES_IN_FACETS)
    gens_polymake = G.PERMUTATION_ACTION.GENERATORS # acting on the facets
    gens_julia = Vector{Int64}.(pm.to_one_based_indexing(gens_polymake))
    gens_gap = GAP.Globals.PermList.(GAP.julia_to_gap.(gens_julia))
    return GAP.Globals.Group(gens_gap...)
end
Out[12]:
combinatorial_automorphism_group (generic function with 1 method)

Recognizing the isomorphism type of the (combinatorial) automorphism group of a polytope is available neither in GAP nor polymake alone.

In [13]:
G = combinatorial_automorphism_group(C)
GAP.Globals.StructureDescription(G)
Out[13]:
GAP: "((((C2 x C2 x C2) : (C2 x C2)) : C3) : C2) : C2"

Some functions are implemented independently in both systems. This can be employed for cross-certification.

In [14]:
@show G_polymake.ORDER
@show GAP.Globals.Order(G)
G_polymake.ORDER = 384
GAP.Globals.Order(G) = 384
Out[14]:
$384$