{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# OSCAR, a Tech Preview (Part I)\n", "\n", "A tiny example, which makes use of the cornerstone systems polymake and GAP.\n", "\n", "## The Setup\n", "\n", "The configuration can be cloned via copying the Project.toml file and using instantiate in the REPL mode." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Julia Version 1.5.3\n", "Commit 788b2c77c1 (2020-11-09 13:37 UTC)\n", "Platform Info:\n", " OS: Linux (x86_64-pc-linux-gnu)\n", " CPU: Intel(R) Core(TM) i7-7600U CPU @ 2.80GHz\n", " WORD_SIZE: 64\n", " LIBM: libopenlibm\n", " LLVM: libLLVM-9.0.1 (ORCJIT, skylake)\n", "\u001b[32m\u001b[1mStatus\u001b[22m\u001b[39m `/data/polymake/oscar-system/oscar-notebooks/MPI-demo-200124/Project.toml`\n", " \u001b[90m [7073ff75] \u001b[39m\u001b[37mIJulia v1.23.1\u001b[39m\n", " \u001b[90m [f1435218] \u001b[39m\u001b[37mOscar v0.5.1 `https://github.com/oscar-system/Oscar.jl#d0908f5`\u001b[39m\n", "\u001b[31m→\u001b[39m\u001b[90m [9b87118b] \u001b[39m\u001b[37mPackageCompiler v1.2.5\u001b[39m\n", " \u001b[90m [8f399da3] \u001b[39m\u001b[37mLibdl\u001b[39m\n", "\u001b[32m\u001b[1mInfo\u001b[22m\u001b[39m packages marked with \u001b[31m→\u001b[39m not downloaded, use `instantiate` to download\n" ] } ], "source": [ "versioninfo()\n", "\n", "using Pkg\n", "Pkg.status()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## polymake's Functions Are Available" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " ----- ----- ----- - ----- \n", "| | | | | | | | | | \n", "| | | | | | | | \n", "| | ----- | | | |----- \n", "| | | | |-----| | | \n", "| | | | | | | | | | \n", " ----- ----- ----- - - - - \n", "\n", "...combining (and extending) ANTIC, GAP, Polymake and Singular\n", "Version\u001b[32m 0.5.1 \u001b[39m... \n", " ... which comes with absolutely no warranty whatsoever\n", "Type: '?Oscar' for more information\n", "(c) 2019-2021 by The Oscar Development Team\n" ] } ], "source": [ "using Oscar\n", "const pm=Polymake;" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "R = pm.tropical.ragsdale_counterexample();" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Interactive visualization is possible, also within a Jupyter notebook. Yet, for static web versions svg output is nicer." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", "\tunnamed\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "\t\n", "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "pm.display_svg(R)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The actual example starts here. We construct a regular $4$-cube, with $\\pm1$-coordinates, but the precise coordinates will not matter here." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "C = pm.polytope.cube(4);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can get the combinatorial automorphism group directly." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "G_polymake = pm.group.automorphism_group(C.VERTICES_IN_FACETS);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "pm::Array>\n", "0 1 2 3 6 7 4 5\n", "0 1 4 5 2 3 6 7\n", "2 3 0 1 4 5 6 7\n", "1 0 2 3 4 5 6 7\n" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gens = G_polymake.PERMUTATION_ACTION.GENERATORS" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that polymake is $0$-based, while Julia is $1$-based." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "pm::Array\n", "0 1 4 5 2 3 6 7" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gens[2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Generic Julia functions can convert between $0$- and $1$-based containers. Future Polymake.jl versions will have this built-in." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "to_one_based_indexing(n::Number) = n + one(n)\n", "to_zero_based_indexing(n::Number) = (n > zero(n) ? n - one(n) : throw(ArgumentError(\"Can't use negative index\")))\n", "\n", "for f in [:to_one_based_indexing, :to_zero_based_indexing]\n", " @eval begin\n", " $f(itr) = $f.(itr)\n", " $f(s::S) where S<:AbstractSet = S($f.(s))\n", " end\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Applying this to the generators of the group computed by polymake yields a standard Julia datatype." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/html": [ "[[$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$]]" ], "text/plain": [ "4-element Array{Array{Int64,1},1}:\n", " [1, 2, 3, 4, 7, 8, 5, 6]\n", " [1, 2, 5, 6, 3, 4, 7, 8]\n", " [3, 4, 1, 2, 5, 6, 7, 8]\n", " [2, 1, 3, 4, 5, 6, 7, 8]" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "to_one_based_indexing(gens)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Use GAP For Groups" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "S4 = GAP: Group([ (1,2,3,4), (1,2) ])\n" ] }, { "data": { "text/html": [ "$24$" ], "text/plain": [ "24" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "S4 = GAP.Globals.Group(GAP.@gap [(1,2,3,4), (1,2)])\n", "@show S4\n", "GAP.Globals.Order(S4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "combinatorial_automorphism_group (generic function with 1 method)" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function combinatorial_automorphism_group(P)\n", " G = pm.group.automorphism_group(P.VERTICES_IN_FACETS)\n", " gens_polymake = G.PERMUTATION_ACTION.GENERATORS # acting on the facets\n", " gens_julia = Vector{Int64}.(pm.to_one_based_indexing(gens_polymake))\n", " gens_gap = GAP.Globals.PermList.(GAP.julia_to_gap.(gens_julia))\n", " return GAP.Globals.Group(gens_gap...)\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Recognizing the isomorphism type of the (combinatorial) automorphism group of a polytope is available neither in GAP nor polymake alone." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "GAP: \"((((C2 x C2 x C2) : (C2 x C2)) : C3) : C2) : C2\"" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "G = combinatorial_automorphism_group(C)\n", "GAP.Globals.StructureDescription(G)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some functions are implemented independently in both systems. This can be employed for cross-certification." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "G_polymake.ORDER = 384\n", "GAP.Globals.Order(G) = 384\n" ] }, { "data": { "text/html": [ "$384$" ], "text/plain": [ "384" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@show G_polymake.ORDER\n", "@show GAP.Globals.Order(G)" ] } ], "metadata": { "kernelspec": { "display_name": "Julia 1.5.3", "language": "julia", "name": "julia-1.5" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.5.3" } }, "nbformat": 4, "nbformat_minor": 2 }