#  Copyright (c) 1997-2021
#  Ewgenij Gawrilow, Michael Joswig, and the polymake team
#  Technische Universität Berlin, Germany
#  https://polymake.org
#
#  This program is free software; you can redistribute it and/or modify it
#  under the terms of the GNU General Public License as published by the
#  Free Software Foundation; either version 2, or (at your option) any
#  later version: http://www.gnu.org/licenses/gpl.txt.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#-------------------------------------------------------------------------------

# assign the proper number of columns to all empty matrices in a list
sub canonicalize_empty_matrices {
    my ($a)=@_;
    my $dim;
    foreach (@$a) { $dim=$_->cols and last }
    if ($dim) {
        foreach (@$a) { $_->clear(0,$dim) if $_->cols==0 }
    }
}

object Cone<Rational> {

# @category Lattice points in cones
# The number of elements of the [[HILBERT_BASIS]].
property N_HILBERT_BASIS : Int;


# @category Lattice points in cones
# Generators for the [[HILBERT_BASIS]] of a posiibly non-pointed cone
# the first matrix is a Hilbert basis of a pointed part of the cone
# the second matrix is a lattice basis of the lineality space
# note: the pointed part used in this property need not be the same as the one described by [[RAYS]] or [[INPUT_RAYS]]
#       it will be if the cone is pointed (the polytope is bounded)
# @depends 4ti2 (unbounded) or libnormaliz (bounded)
property HILBERT_BASIS_GENERATORS : Array<Matrix<Integer>> {

  sub canonical { &canonicalize_empty_matrices }

  # FIXME This test is too restrictive
  sub equal {
    my ($a, $b) = @_;
    return equal_up_to_row_permutation($a->[0],$b->[0]) && equal_up_to_row_permutation($a->[1],$b->[1]);
  }
}

}


object Polytope<Rational> {

# @category Lattice points in polytopes
# The lattice points in the polytope.
#property LATTICE_POINTS : Matrix<Integer> {
#
#    sub equal { &equal_up_to_row_permutation; }
#}

# @category Lattice points in polytopes
# The number of [[LATTICE_POINTS]]
property N_LATTICE_POINTS : Integer;

# @category Lattice points in polytopes
# The lattice points generators in the polytope.
# The output consists of three matrices [P,R,L], where
# P are lattice points which are contained in the polytope
# R are rays and L is the lineality.
# Together they form a description of all lattice points.
# Every lattice point can be described as
#    p + lambda*R + mu*L
# where p is a row in P and lambda has only non-negative
# integral coordinates and mu has arbitrary integral coordinates.
# @depends 4ti2 for unbounded polytopes
property LATTICE_POINTS_GENERATORS : Array<Matrix<Integer>> {

    sub canonical { &canonicalize_empty_matrices }

    sub equal {
        my ($a, $b) = @_;
        return equal_up_to_row_permutation($a->[0],$b->[0]) && equal_up_to_row_permutation($a->[1],$b->[1]) && equal_up_to_row_permutation($a->[2],$b->[2]);
    }
};

# @category Lattice points in polytopes
# The lattice points on the boundary of the polytope, including the vertices.
property BOUNDARY_LATTICE_POINTS : Matrix<Integer> {

    sub equal { &equal_up_to_row_permutation; }
}

# @category Lattice points in polytopes
# The number of [[BOUNDARY_LATTICE_POINTS]]
property N_BOUNDARY_LATTICE_POINTS : Integer;

# @category Lattice points in polytopes
# The lattice points strictly in the interior of the polytope
property INTERIOR_LATTICE_POINTS : Matrix<Integer> {

    sub equal { &equal_up_to_row_permutation; }
}

# @category Lattice points in polytopes
# The number of [[INTERIOR_LATTICE_POINTS]]
property N_INTERIOR_LATTICE_POINTS : Integer;


# @category Geometry
# The cone of all Minkowski summands of the polytope P.
# Up to scaling, a polytope S is a Minkowski summand of P if and only if
# the edge directions of S are a subset of those of P,
# and the closing condition around any 2-face of P is preserved.
# Coordinates of the cone correspond to the rescaled lengths
# of the edges of the graph of P (in the order given by the property [[EDGES]] of the [[GRAPH]] of P).
# The Minkowski cone is defined as the intersection of all
# equations given by the closing condition around 2-faces with the positive orthant.
# For more information see e.g.
# Klaus Altmann: The versal deformation of an isolated toric Gorenstein singularity
property MINKOWSKI_CONE : polytope::Cone<Rational>;



# @category Lattice points in cones
# The Ehrhart quasi-polynomial of a rational polytope.
# Coefficients are periodic functions of integral period.
# @depends libnormaliz
# @example [require bundled:libnormaliz] To obtain the Ehrhart quasi-polynomial of a scaled 2-dimensional cross polytope write:
# > $p=scale(cross(2),1/3);
# > local_var_names<UniPolynomial<Rational>>(qw(t)); print join("\n",@{$p->EHRHART_QUASI_POLYNOMIAL});
# | 2/9*t^2 + 2/3*t + 1
# | 2/9*t^2 + 2/9*t + 5/9
# | 2/9*t^2 -2/9*t + 5/9
property EHRHART_QUASI_POLYNOMIAL : Array<UniPolynomial<Rational>>;

}

object_specialization Polytope::Lattice {

# @category Lattice points in cones
# [[VERTICES]] are interpreted as coefficient vectors for this basis
# given in affine form
# assumed to the the standard basis if not explicitely specified.
    property LATTICE_BASIS : Matrix<Rational>;

# @category Lattice points in cones
# True if the polytope and its dual have integral vertices.
    property REFLEXIVE : Bool;

# @category Lattice points in cones
# The polytope is __Gorenstein__ if a dilation of the polytope is [[REFLEXIVE]] up to translation.
    property GORENSTEIN : Bool;

# @category Lattice points in cones
# If the polytope is [[GORENSTEIN]] then this is the multiple such that the polytope is [[REFLEXIVE]].
    property GORENSTEIN_INDEX : Integer;

# @category Lattice points in cones
# If the polytope is [[GORENSTEIN]], then this is the unique interior lattice point
# in the multiple of the polytope that is [[REFLEXIVE]].
    property GORENSTEIN_VECTOR : Vector<Integer>;

# @category Lattice points in cones
# The polytope is __canonical__ if there is exactly one interior lattice point.
    property CANONICAL : Bool;

# @category Lattice points in cones
# The polytope is __terminal__ if there is exactly one interior lattice point and all other lattice points are vertices.
    property TERMINAL : Bool;

# @category Lattice points in cones
# True if the polytope contains no lattice points other than the vertices.
    property LATTICE_EMPTY : Bool;

# @category Lattice points in cones
# The normalized volume of the polytope.
    property LATTICE_VOLUME : Integer;

# @category Lattice points in cones
# The degree of the h*-polynomial or Ehrhart polynomial.
    property LATTICE_DEGREE : Int;

# @category Lattice points in cones
# [[COMBINATORIAL_DIM]]+1-[[LATTICE_DEGREE]] or the smallest integer k such that k*P has an interior lattice point.
    property LATTICE_CODEGREE : Int;

# @category Lattice points in cones
# The Ehrhart polynomial.
# @depends latte or libnormaliz
    property EHRHART_POLYNOMIAL : UniPolynomial<Rational>;

# @category Lattice points in cones
# The polytope is __normal__ if the Hilbert basis of the cone spanned by P x {1} is at height 1.
# Equivalently points in integral dilates of P are positive integral sums of lattice points of P.
# @depends 4ti2 or libnormaliz
    property NORMAL : Bool;

# @category Lattice points in cones
# The entry (i,j) equals the lattice distance of vertex j from facet i.
  property FACET_VERTEX_LATTICE_DISTANCES : Matrix<Integer>;

# @category Lattice points in cones
# The maximal integral width of the polytope with respect to the facet normals.
    property FACET_WIDTH : Integer;

# @category Lattice points in cones
# The integral width of the polytope with respect to each facet normal.
    property FACET_WIDTHS : Vector<Integer>;

# @category Lattice points in cones
# True if the [[FACET_WIDTH]] is one.
    property COMPRESSED : Bool;

# @category Lattice points in cones
# The polytope is __smooth__ if the associated projective variety is smooth; the determinant of the edge directions is +/-1 at every vertex.
    property SMOOTH : Bool;

# @category Lattice points in cones
# The polytope is __spanning__ if the lattice points generate the lattice
    property SPANNING : Bool;

# @category Lattice points in cones
# The lattice polytope is __polar to smooth__ if it is [[REFLEXIVE]] and the polar of the polytope (wrt to its interior point) is a [[SMOOTH]] lattice polytope.
    property POLAR_SMOOTH : Bool;

# @category Lattice points in cones
# The polytope is __very ample__ if the Hilbert Basis of the cone spanned by the edge-directions of any vertex lies inside the polytope.
# @depends 4ti2 or libnormaliz
    property VERY_AMPLE : Bool;

# @category Lattice points in cones
# One direction which realizes [[LATTICE_WIDTH]] of the polytope.
    property LATTICE_WIDTH_DIRECTION : Vector<Integer>;

# @category Lattice points in cones
# The minimal integral width of the polytope.
    property LATTICE_WIDTH : Integer;

}


object_specialization Polytope::Lattice {

  property GRAPH {

    # @category Lattice points in cones
    # the lattice lengths of the edges of the polytope
    # i.e. for each edge one less than the number of lattice points on that edge
    property LATTICE_EDGE_LENGTHS : EdgeMap<Undirected, Integer> : construct(ADJACENCY);

    # @category Lattice points in cones
    # a map associating to each edge length of the polytope the number of edges with this length
    # the lattice edge length of an edge is one less than the number of lattice points on that edge
    property LATTICE_ACCUMULATED_EDGE_LENGTHS : Map<Integer,Int>;
  }

  # @category Lattice points in cones
  # The toric ideal of the lattice polytope. Roughly speaking, this is an
  # algebraic structure associated with the vertices of the lattice polytope,
  # which contains rich information about the combinatorics and geometry of
  # the polytope.
  #
  # The toric ideal is represented by a groebner basis, so, in order to compute
  # the toric ideal of a lattice polytope, one additionally needs to specify
  # the term order. See the example for details.
  #
  # @example [notest] The following computes the groebner basis of the toric
  #          ideal of the square in lex order. This requires example 4ti2 to be
  #          configured.
  # > $p = cube(2);
  # > print $p->TORIC_IDEAL->GROEBNER(ORDER_NAME=>"lp")->BINOMIAL_BASIS;
  # | 0 0 0 0 0 0 1 -2 1
  # | 0 0 0 0 1 -1 -1 1 0
  # | 0 0 0 0 1 -1 0 -1 1
  # | 0 0 0 1 -2 1 0 0 0
  # | 0 0 0 1 -1 0 -1 1 0
  # | 0 0 0 1 0 -1 -1 0 1
  # | 0 0 1 0 -2 0 1 0 0
  # | 0 0 1 0 -1 -1 0 1 0
  # | 0 0 1 0 0 -2 0 0 1
  # | 0 1 -1 -1 1 0 0 0 0
  # | 0 1 -1 0 -1 1 0 0 0
  # | 0 1 0 -1 -1 0 1 0 0
  # | 0 1 0 0 -2 0 0 1 0
  # | 0 1 0 0 -1 -1 0 0 1
  # | 1 -2 1 0 0 0 0 0 0
  # | 1 -1 0 -1 1 0 0 0 0
  # | 1 0 -1 -1 0 1 0 0 0
  # | 1 0 0 -2 0 0 1 0 0
  # | 1 0 0 -1 -1 0 0 1 0
  # | 1 0 0 0 -2 0 0 0 1
  property TORIC_IDEAL : ideal::Ideal;
}



object Cone<Rational> {

# @category Lattice points in cones
# A cone is __Q-Gorenstein__ if all primitive generators of the cone lie in an affine hyperplane spanned by a lattice functional in the dual cone (but not in the lineality space of the dual cone).
  property Q_GORENSTEIN_CONE : Bool;

# @category Lattice points in cones
# If a cone is [[Q_GORENSTEIN_CONE|Q-Gorenstein]], then its index is the common lattice height of the primitive generators with respect to the origin. Otherwise Q_GORENSTEIN_CONE_INDEX is undefined.
  property Q_GORENSTEIN_CONE_INDEX : Int;

# @category Lattice points in cones
# A cone is [[GORENSTEIN_CONE|Gorenstein]] if it is [[Q_GORENSTEIN_CONE|Q-Gorenstein]] with index one
  property GORENSTEIN_CONE : Bool;

# @category Lattice points in cones
# A cone is __smooth__ if the primitive generators are part of a lattice basis.
  property SMOOTH_CONE : Bool;

# @category Lattice points in cones
# True if the primitive generators of the rays lie on an affine hyperplane in the span of the rays.
  property HOMOGENEOUS : Bool;

# @category Lattice points in cones
# A grading for the monoid given by the intersection of the cone with the
# lattice Z^d, should be positive for all generators.
#
# If this property is not specified by the user there are two defaults:
#     For rational polytopes the affine hyperplane defined by (1,0,\ldots,0) will be used.
#     For [[HOMOGENEOUS]] cones the affine hyperplane containing the primitive generators
#     will be used.
  property MONOID_GRADING : Vector<Integer>;

# @category Lattice points in cones
# Elements of the [[HILBERT_BASIS]] for the cone of degree 1 with respect
# to the [[MONOID_GRADING]].
  property DEGREE_ONE_GENERATORS : Matrix<Integer> {

    sub equal { &equal_up_to_row_permutation; }
}

# @category Lattice points in cones
# Hilbert series of the monoid, given by the intersection of the cone with
# the lattice Z^d with respect to the [[MONOID_GRADING]]
# @depends libnormaliz
  property HILBERT_SERIES : RationalFunction;

# @category Lattice points in cones
# The coefficients of the Hilbert polynomial,
# the h^*-polynomial for lattice polytopes,
# with respect to the [[MONOID_GRADING]],
# starting at the constant coefficient.
# For lattice polytopes the length of this vector is [[CONE_DIM]].
# In general the length is one less than the degree of the
# denominator of the [[HILBERT_SERIES]].
# @depends latte or libnormaliz
  property H_STAR_VECTOR : Vector<Integer>;

# @category Lattice points in cones
# The Hilbert polynomial,
# the h^*-polynomial for lattice polytopes. The degree is at most
# on less then the h^*-vector.
# @depends latte or libnormaliz
  property H_STAR_POLYNOMIAL : UniPolynomial<Rational>;

# @category Lattice points in cones
# The ideal whose vanishing set is the affine toric variety given
# by the cone.
# In other words the rows of its [[ideal::Ideal::BINOMIAL_GENERATORS]] give
# the relations between the Hilbert basis elements.
# @depends 4ti2
  property CONE_TORIC_IDEAL : ideal::Ideal;

}


# Local Variables:
# mode: perl
# cperl-indent-level:4
# indent-tabs-mode:nil
# End:
