#  Copyright (c) 1997-2010
#  Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Darmstadt, Germany)
#  http://www.polymake.de
#
#  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.
#-------------------------------------------------------------------------------
#  $Project: polymake $$Id: latte.rules 9502 2010-02-24 00:26:29Z gawrilow $

# path to the LattE binaries
custom $latte_count;

CONFIGURE {
   find_via_path($latte_count,"count");
}

# additional parameters for calling LattE's "count". See the manual of LattE for details, recommended options are
# "--irrational-all-primal": use irrational decomposition instead of polarization
# "--maxdet=<n>": stop triangulating if determinant of cone < n (needs LiDIA)
# "--exponential": use exponential substitution for evaluating the generating function
custom $latte_count_param="";

# additional parameters for calling latte's "count --ehrhart-polynomial"
# see $latte_count_param for details
custom $latte_ehrhart_param="";

label latte

# @topic credits/latte
# LattE macchiato is an improved version of LattE, a free software dedicated
# to the problems of counting and detecting lattice points inside convex polytopes,
# and the solution of integer programs.
# Copyright by Matthias Koeppe, Jesus A. De Loera and others.
# http://www.math.ucdavis.edu/~mkoeppe/latte/

sub write_latte_ineq {
   my $tempname = shift;
   my $this = shift;
   my $int = shift;
   # daten: ineq / eq
   my $n_ineq = ($this->FACETS | INEQUALITIES)->rows;
   my $fac = eliminate_denominators($this->FACETS | INEQUALITIES);
   my $n_lines = $n_ineq;
   my $ah;
   if (defined (my $AH = $this->lookup("AFFINE_HULL | EQUATIONS"))) {
      $n_lines = $n_lines + ($AH->rows);
      $ah = eliminate_denominators($AH);
   }
        
   open(my $P, ">$tempname")
    or die "can't create temporary file $tempname: $!";
   #header
   print $P $n_lines, " ", (($this->AMBIENT_DIM)+1), "\n";
        
   # facet lines
   if ($int) {
      $fac=$fac*($this->DIM+1);
      for (my $i=0; $i<$fac->rows; $i++) {
        $fac->($i,0) -= 1;
      }
   }
   print $P $fac;

   # affine hull lines
   if ($n_lines > $n_ineq) {
      print $P $ah;
      print $P "linearity ", $n_lines-$n_ineq, " ";
      print $P ++$n_ineq," " while $n_ineq < $n_lines;
      print $P "\n";
   }
   close $P;
}

sub latte_cleanup {
    unlink qw( Check_emp.ddl Check_emp.out numOfLatticePoints Check_emp.lp Check_emp.lps numOfUnimodularCones Check_emp.ddl.old latte_stats totalTime );
}

object Polytope<Rational> {

    rule latte.npoints: N_LATTICE_POINTS : AMBIENT_DIM , FACETS | INEQUALITIES {
        my $tempname=new Tempfile;
        my $interior = 0;
        write_latte_ineq($tempname, $this, $interior);
        
        if ($Verbose::external) {
            dbg_print( "running latte's count: $latte_count $latte_count_param $tempname" );
        }
        open my $P, "$latte_count $latte_count_param $tempname 2>&1 |"
            or die "couldn't run LattE's 'count': $!";
        local $_;
        while (<$P>) {
            if (my ($n)=/number of lattice points\D+(\d+)/) {
                $this->N_LATTICE_POINTS = $n;
                close $P;
                latte_cleanup();
                return;
            } elsif(/Empty polytope/) {
                $this->N_LATTICE_POINTS = 0;
                close $P;
                latte_cleanup();
                return;
            }
        }
        close $P;
        latte_cleanup();
        die "can't parse output from LattE's 'count'\n";
    }
    precondition : BOUNDED;
    weight 5.10;

    # Read [[FACETS]], multiply with DIM+1 and substract 1 from the first column.
    # Call LattE's count on the polytope having this matrix as facet matrix.
    rule latte.nintpoints: N_INTERIOR_LATTICE_POINTS : AMBIENT_DIM , FACETS | INEQUALITIES , DIM {
        my $tempname=new Tempfile;
        my $interior = 1;
        write_latte_ineq($tempname, $this, $interior);
        
        if ($Verbose::external) {
            dbg_print( "running latte's count: $latte_count $latte_count_param $tempname" );
        }
        open my $P, "$latte_count $latte_count_param $tempname 2>&1 |"
            or die "couldn't run LattE's 'count': $!";
        local $_;
        while (<$P>) {
            if (my ($n)=/number of lattice points\D+(\d+)/) {
                $this->N_INTERIOR_LATTICE_POINTS = $n;
                close $P;
                latte_cleanup();
                return;
            } elsif(/Empty polytope/) {
                $this->N_LATTICE_POINTS = 0;
                close $P;
                latte_cleanup();
                return;
            }
        }
        close $P;
        latte_cleanup();
        die "can't parse output from LattE's 'count'\n";
    }
    weight 5.10;
    precondition : BOUNDED;
}

object LatticePolytope {

    rule latte.ehrhartpoly: LATTICE , EHRHART_POLYNOMIAL_COEFF : AMBIENT_DIM , FACETS | INEQUALITIES {
        my $tempname=new Tempfile;
        write_latte_ineq($tempname, $this);
        
        if ($Verbose::external) {
            dbg_print( "running latte's count: $latte_count $latte_ehrhart_param --ehrhart-polynomial $tempname" );
        }
        open my $P, "$latte_count $latte_ehrhart_param --ehrhart-polynomial $tempname 2>&1 |"
            or die "couldn't run LattE's 'count': $!";
        local $_;
        while (<$P>) {
            if(/only implemented for integral polytopes/) {
                $this->LATTICE = 0;
                close $P;
                latte_cleanup();
                return;
            } elsif (/^Ehrhart polynomial: /) {
                # parse: Ehrhart polynomial:  + 1 * t^0 + 6 * t^1 + 12 * t^2 + 8 * t^3
                #					+ 1 * t^0 + 8/3 * t^1 + 2 * t^2 + 4/3 * t^3
                my @coeffs = m/\s([-\+]\s\d+\/?\d*)\s\*\st\^\d+/gc;
                for my $item (@coeffs) {
                    $item =~ s/[\+\s]//g;
                }
                $this->EHRHART_POLYNOMIAL_COEFF = \@coeffs;
                $this->LATTICE=1;
                close $P;
                latte_cleanup();
                return;
            }
        }
        close $P;
        latte_cleanup();
        die "could not parse output from latte";

    }
    weight 5.15;

}


# Local Variables:
# mode: perl
# c-basic-offset:4
# End:
