This tutorial is probably also available as a Jupyter notebook in the `demo`

folder in the polymake source and on github.

Different versions of this tutorial: latest release, release 4.12, release 4.11, release 4.10, release 4.9, release 4.8, release 4.7, release 4.6, release 4.5, release 4.4, release 4.3, release 4.2, release 4.1, release 4.0, release 3.6, nightly master

# Toric polymake tutorial

This tutorial will go over the basics of polymake and then focus on the `application "fulton"`

for toric varieties.

## Quick start

Below you see a small sample session. First switch to the application with the following command.

> application "fulton";

Start by creating a cone.

> $c = new Cone(INPUT_RAYS=>[[-2,1],[1,1]]); > print $c->HILBERT_BASIS;

You can ask for the binomials generating the associated toric ideal in two ways: The first gives a matrix of the binomial exponents, the second gives you the actual binomials.

> $toric = $c->CONE_TORIC_IDEAL; > print $toric->BINOMIAL_GENERATORS, "\n"; > print join("\n", @{$toric->GENERATORS});

Asking for properties of the toric variety is done in the same manner as for polytopes.

> $tv = new NormalToricVariety($c); > print "Is smooth? ", $tv->SMOOTH, "\n"; > print "Is affine? ", $tv->AFFINE, "\n"; > print "Is orbifold? ", $tv->ORBIFOLD, "\n"; > print "Is complete? ", $tv->COMPLETE, "\n"; > $tv->properties();

## Affine toric varieties

Affine toric varieties arise from cones. To dualize a (pointed) cone just construct a new cone switching facets and rays.

> $sigma = new Cone(INPUT_RAYS=>[[1,0,0],[0,1,0],[1,0,1],[0,1,1]]); > $sigmad = polarize($sigma); > print $sigmad->HILBERT_BASIS, "\n"; > print $sigmad->CONE_TORIC_IDEAL->BINOMIAL_GENERATORS, "\n"; > print $sigmad->CONE_TORIC_IDEAL->GENERATORS, "\n";

The exponent vectors of the binomials generate the lattice of relations of the Hilbert basis of the dual cone. In particular we have

> $hb = $sigmad->HILBERT_BASIS; > $binomials = $sigmad->CONE_TORIC_IDEAL->BINOMIAL_GENERATORS; > print $binomials * $hb;

#### Cyclic quotient singularities

Two-dimensional pointed cones in two-dimensional space can always be generated by two rays in the standard form `[[1,0],[-q,n]]`

with `0<q<n`

and `q`

and `n`

coprime.

> $N7Q3 = new CyclicQuotient(N=>7, Q=>3); > print primitive($N7Q3->RAYS);

CQS are deeply connected with the associated continued fractions.

> $cf = new Vector<Rational>($N7Q3->CONTINUED_FRACTION); > print $cf, "\n"; > print $cf->[0] -1/( $cf->[1] -1/ $cf->[2]), "\n"; > $dcf = new Vector<Rational>($N7Q3->DUAL_CONTINUED_FRACTION); > print $dcf, "\n"; > print $dcf->[0] -1/ $dcf->[1], "\n";

If we start with the Hilbert basis of the dual cone, sorted by first coordinate:

> print $N7Q3->WEIGHT_CONE->HILBERT_BASIS, "\n"; > $sorted = new Matrix(sort(@{$N7Q3->WEIGHT_CONE->HILBERT_BASIS})); > print $sorted;

Then the dual continued fraction expansion of `n/(n-q)`

gives us relations among these elements:

> print $sorted->[0] + $sorted->[2] == $dcf->[0] * $sorted->[1],"\n"; > print $sorted->[1] + $sorted->[3] == $dcf->[1] * $sorted->[2],"\n";

Q: Derive and prove the general relation formula.

### Projective varieties

Projective toric varieties arise from polytopes. Normal projective toric varieties arise from fans. To construct a projective toric variety, simply take the normal fan of a polytope and give it to the `NormalToricVariety`

constructor.

> $PP2 = new NormalToricVariety(normal_fan(simplex(2))); > print $PP2->RAYS; > print $PP2->MAXIMAL_CONES; > $PP2->VISUAL;

The Hasse diagram looks as follows:

> $PP2->HASSE_DIAGRAM->VISUAL;

Now consider the following two cones:

> $c1 = new Cone(simplex(2)); > print $c1->HILBERT_BASIS, "\n"; > $c2 = new Cone(simplex(2,2)); > print $c2->HILBERT_BASIS, "\n";

Lets look at the associated toric ideals:

> print "C1: ", join("\n", @{$c1->CONE_TORIC_IDEAL->GROEBNER(ORDER_NAME=>"dp")->BASIS}),"\n"; > print "C2: ", join("\n", @{$c2->CONE_TORIC_IDEAL->GROEBNER(ORDER_NAME=>"dp")->BASIS}),"\n";

The first ideal is actually `0`

. Both ideals are homogeneous and hence, they define projective varieties.

Q: What are these projective varieties?

#### A non-projective toric variety

Not every fan is the normal fan of a polytope. Here we give an example.

> $f = new PolyhedralFan(INPUT_RAYS=> > [[1,0,0],[0,1,0],[-1,-1,-1], > [0,0,1],[2,1,1],[1,2,1],[1,1,2]], > INPUT_CONES=>[[0,1,2],[0,2,3], > [1,2,3],[4,5,6],[0,1,4],[1,3,5], > [0,3,6],[1,4,5],[3,5,6],[0,4,6]] > ); > $tv = new NormalToricVariety($f); > print "Projective? ", $tv->PROJECTIVE, "\n"; > print "Smooth? ", $tv->SMOOTH, "\n"; > print "Complete? ", $tv->COMPLETE, "\n"; > $tv->VISUAL;

#### Hirzebruch surfaces

Hirzebruch surfaces come from two-dimensional complete fans with exactly four rays. Smoothness makes it possible to bring these fans into a standard form such that we arrive at a one-parameter family.

> $h1 = hirzebruch_surface(1); > print $h1->RAYS; > $h1->VISUAL; > $h2 = hirzebruch_surface(2); > print $h2->RAYS; > $h2->VISUAL;

Q: Construct the/an associated polytope.

Q: Prove the standard form for complete smooth fans in two dimensions with exactly four rays.

polymake has a method to reconstruct a polytope from a regular fan / projective toric variety.

> $A = generating_polyhedron_facets($h2); > print $A;

This polytope has the given fan as a normal fan.

> $P = new Polytope(INEQUALITIES=>$A); > $FF = normal_fan($P); > print $FF->RAYS; > print $FF->MAXIMAL_CONES;

The polytope we just constructed looks like:

> $P->VISUAL;

The polytope is not unique. Any polytope with the same facet vectors and combinatorics will have the same normal fan.

Its normal fan is exactly the fan we started with.

> $FF->VISUAL;

#### Simple, not smooth

> $p = new Polytope(POINTS=>[ > [1, 0, 0, 0], > [1, 1, 1, 0], > [1, 1, 0, 1], > [1, 0, 1, 1]]); > print "Simple? ", $p->SIMPLE, "\n"; > print "Smooth? ", $p->SMOOTH, "\n";

### Non-normal toric varieties

polymake only handles normal toric varieties. Nevertheless we can use it to get at the toric ideal of a non-normal toric variety by giving the semigroup generators directly as a mock Hilbert basis. For example for the Neil parabola use:

> $c = new Cone(HILBERT_BASIS_GENERATORS=>[[[2],[3]],[[]]]); > print $c->CONE_TORIC_IDEAL->BINOMIAL_GENERATORS; > print $c->CONE_TORIC_IDEAL->GENERATORS;

If we build a new cone from this semigroup, we see that it was not saturated. The semigroup generated by 2 and 3 does not come from a cone.

> $cc = new Cone(INPUT_RAYS=>$c->HILBERT_BASIS_GENERATORS->[0]); > print $cc->RAYS, "\n"; > print $cc->HILBERT_BASIS, "\n";

Q: What are necessary conditions for a semigroup to come from a cone?

#### Smooth vs normal

It is an open question by Oda whether smoothness and normality of polytopes are equivalent.

> print $p->VERTICES, "\n"; > print "Normal? ", $p->NORMAL, "\n"; > print "Smooth? ", $p->SMOOTH, "\n"; > help "NORMAL"; > help "SMOOTH"; > print $p->HILBERT_BASIS;

## Dealing with torus invariant divisors

The application `fulton`

allows one to compute several properties of divisors and even divisor classes. First build a divisor from its representation as a sum of primitive divisors.

> $tv = hirzebruch_surface(4); > $d = $tv->DIVISOR(COEFFICIENTS=>[1,1,1,1]);

Then treat them like any polymake object.

> print "Effective? ", $d->EFFECTIVE, "\n"; > print "Ample? ", $d->AMPLE, "\n"; > print "Basepoint free? ", $d->BASEPOINT_FREE, "\n"; > print "Nef? ", $d->NEF, "\n"; > print "Cartier? ", $d->CARTIER, "\n";

The following code produces the vertices of the polytope of global sections.

> $pd = $d->SECTION_POLYTOPE; > print $pd->VERTICES;

Furthermore one can deal with rational divisor classes, rather than divisors, using the class group exact sequence. Its projection matrix can be produced as follows.

> print $tv->RATIONAL_DIVISOR_CLASS_GROUP->PROJECTION;

Then one can access the nef cone, effective cone and Mori cone of the toric variety:

> print "Nef cone:\n", $tv->NEF_CONE->RAYS,"\n"; > print "Effective cone:\n", $tv->EFFECTIVE_CONE->RAYS,"\n"; > print "Mori cone:\n", $tv->MORI_CONE->RAYS,"\n";

## Accessing Singular

Singular is a computer algebra system developed in Kaiserslautern. It can be accessed from polymake on different levels. For ideals there are low-level c++ methods providing basic funtionality to compute Groebner bases, radicals, etc. At top level for users there are perl methods giving the opportunity to send command strings to Singular if something has not been accessed on c++ level yet. This allows fast proof of concept implementations.

> application "fulton"; > $c = new Cone(INPUT_RAYS=>[[-1,1],[0,1],[1,1]]); > $tv = new NormalToricVariety($c); > $toric = $c->CONE_TORIC_IDEAL; > singular_eval("listvar();"); > $radical = $toric->RADICAL; > print join("\n", @{$radical->GENERATORS}); > singular_eval("listvar();"); > $ideal = $tv->WEIGHT_CONE->CONE_TORIC_IDEAL; > print $ideal;

It is possible to execute arbitrary Singular commands from polymake using the `singular_eval`

command. First build your command as a string.

> $cmd = "ring r = 0,(x_0,x_1,x_2),dp;"; > print $cmd;

Then hand this string to `singular_eval`

.

> singular_eval($cmd); > singular_eval("r;");

One can also retrieve variables from Singular to polymake using the `singular_get_var`

command in the following manner.

> singular_eval("int n = nvars(r);"); > $n = singular_get_var("n"); > print $n,"\n";

It is possible to retrieve the following datatypes from Singular: `int`

, `intmat`

, `intvec`

and `poly`

.

> singular_eval("poly p = x_2^2-x_0*x_1"); > $p = singular_get_var("p"); > print $p,"\n";

To load a Singular library, you can use the `load_singular_library`

command with the library name. Afterwards all library methods are accessible, as in the following example.

> load_singular_library("deform.lib"); > singular_eval("ideal i = x_0*x_1, x_2;"); > singular_eval("def L = versal(i);"); > singular_eval("L;");