#  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.
#-------------------------------------------------------------------------------

CREDIT porta
  PORTA is a collection of routines for analyzing polytopes and polyhedra.
  Copyright by Thomas Christof and Andreas Loebel.
  http://www.iwr.uni-heidelberg.de/groups/comopt/software/PORTA/

# path to the xporta executable
custom $xporta;

CONFIGURE {
   find_program($xporta, "xporta");
}

require PortaParser;

INCLUDE
   # porta_convexhull.rules

# @category Transformations
# Primal transformation via porta. Computes facets and affine hull from
# vertices or points.
user_function porta_primal {
   my($p) = @_;
   my $dim = $p->CONE_AMBIENT_DIM;
   my $pts = $p->give("VERTICES | POINTS");
   my $has_far_facet = $p->has_far_facet;
   my $tempname=new Tempfile;
   my $converter=new PortaConverter("$tempname.poi");
   $converter->print_dim($dim-1);
   $converter->print_points($pts);
   $converter->finish;

   my $command="$xporta -l -T $tempname.poi";
   $command.=" >/dev/null 2>&1" unless $DebugLevel;
   system($command) and die "porta exited with error code\n";

   my $parser=new PortaParser("$tempname.poi.ieq");
   if ($has_far_facet) {
      push @{$parser->Ineq}, [ 1, (0) x ($dim-1) ];
   }
   my $facets = @{$parser->Ineq} > 0 ? 
                   $parser->Ineq : 
                   new Matrix(0,$dim);
   my $affine_hull = @{$parser->Eq} > 0 ? 
                        $parser->Eq : 
                        new Matrix(0,$dim);
   unlink "porta.log";
   return ($facets, $affine_hull);
}

# @category Transformations
# Dual transformation via porta. Computes vertices and lineality space from
# inequalities and equations.
user_function porta_dual {
   my($p) = @_;
   my $dim = $p->CONE_AMBIENT_DIM;
   my $validpt = $p->VALID_POINT;
   my $ineq = $p->give("FACETS | INEQUALITIES");
   my $eq = $p->lookup("AFFINE_HULL | EQUATIONS");
   my $tempname=new Tempfile;
   my $converter=new PortaConverter("$tempname.ieq");
   $converter->print_dim($dim-1);
   $converter->print_valid_point($validpt);
   $converter->print_inequalities($ineq, $eq);
   $converter->finish;

   my $command="$xporta -l -T $tempname.ieq";
   $command.=" >/dev/null 2>&1" unless $DebugLevel;
   system($command) and die "xporta exited with error code\n";

   my $parser=new PortaParser("$tempname.ieq.poi");
   my $vertices = @{$parser->Points} > 0 ? 
                     $parser->Points : 
                     new Matrix(0,$dim);
   my $lineality =new Matrix<Rational>(0,$dim);
   unlink "porta.log";
   return ($vertices, $lineality);
}

# @category Optimization
# take a rational polytope and write a porta input file (.ieq or .poi)
# @param Polytope<Rational> p
# @param String file filename for the porta file (.ieq or .poi) or an open IO handle
# @option Bool primal true if points should be written, false if inequalities should be written (default is true)

user_function poly2porta(Polytope<Rational>, $, {primal=>1} ) {
    
    require PortaParser;

    my ($p, $filename, $options) = @_;
    
    my $converter=new PortaConverter($filename);
    if ( $options->{primal} ) {
        $converter->print_dim($p->CONE_AMBIENT_DIM-1);
        $converter->print_points($p->give("VERTICES | POINTS"), $p->lookup("LINEALITY_SPACE | INPUT_LINEALITY"));
    } else {
        $converter->print_dim($p->CONE_AMBIENT_DIM-1);
        $converter->print_valid_point($p->VALID_POINT);
        $converter->print_inequalities($p->give("FACETS | INEQUALITIES"), $p->lookup("AFFINE_HULL | EQUATIONS"));
    }
    $converter->finish;    
}


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