#  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.
#-------------------------------------------------------------------------------
#  Contributed by authors as mentioned on:
#  https://github.com/lkastner/polymake_toric/wiki/Authors
#
#  Project home:
#  https://github.com/lkastner/polymake_toric

REQUIRE fan::gfan.rules

CREDIT gfan


# path to gfan
custom $gfan_buchberger;

custom $gfan_homogenize;

custom $gfan_tropicalbruteforce;

custom $gfan_tropicalhypersurface;

custom $gfan_tropicalintersection;

custom $gfan_tropicalstartingcone;

custom $gfan_tropicaltraverse;


CONFIGURE {
   $gfan_buchberger = $fan::gfan_bases =~ s/gfan_bases$/gfan_buchberger/r;
   $gfan_homogenize = $gfan_buchberger =~ s/gfan_buchberger$/gfan_homogenize/r;
   $gfan_tropicalbruteforce = $gfan_buchberger =~ s/gfan_buchberger$/gfan_tropicalbruteforce/r;
   $gfan_tropicalhypersurface = $gfan_buchberger =~ s/gfan_buchberger$/gfan_tropicalhypersurface/r;
   $gfan_tropicalintersection = $gfan_buchberger =~ s/gfan_buchberger$/gfan_tropicalintersection/r;
   $gfan_tropicalstartingcone = $gfan_buchberger =~ s/gfan_buchberger$/gfan_tropicalstartingcone/r;
   $gfan_tropicaltraverse = $gfan_buchberger =~ s/gfan_buchberger$/gfan_tropicaltraverse/r;
}


# @category gfan
# Calls gfan_tropicalintersection for a homogeneous ideal.
# @param ideal::Ideal I homogeneous ideal
# @return Cycle<Max> most likely not balanced
user_function gfan_tropicalintersection(ideal::Ideal) {
   my ($I) = @_;
   return gfan_to_tropical_cycle(fan::run_gfan(sub { fan::gfan_print_ideal($_[0], $I) },
                                               $gfan_tropicalintersection));
}

# @category gfan
# Calls gfan_tropicalhypersurface for a single polynomial.
# If the polynomial is a monomial, gfan will return an empty object and the xslt parsing fails. We do not catch this for you.
# @param Polynomial<Rational> p homogeneous polynomial
# @return Cycle<Max>
user_function gfan_tropicalhypersurface(Polynomial) {
   my ($g) = @_;
   my $I = new ideal::Ideal(GENERATORS => [$g]);
   return gfan_to_tropical_cycle(fan::run_gfan(sub { fan::gfan_print_ideal($_[0], $I) },
                                               $gfan_tropicalhypersurface));
}



# @category gfan
# Calls gfan_tropicalstartingcone | gfan_tropicaltraverse for a homogeneous prime ideal.
# If the ideal contains a monomial, gfan will return an empty object and the xslt parsing fails. We do not catch this for you.
# @param ideal::Ideal I homogeneous prime ideal
# @return Cycle<Max>
user_function gfan_tropicalvariety_of_prime(ideal::Ideal) {
   my ($I) = @_;
   return gfan_to_tropical_cycle(fan::run_gfan(sub { fan::gfan_print_ideal($_[0], $I) },
                                               $gfan_tropicalstartingcone, $gfan_tropicaltraverse));
}

# @category gfan
# Calls gfan_tropicalbruteforce for a homogeneous ideal.
# If the ideal contains a monomial, gfan will return an empty object. We do not catch this for you.
# @param ideal::Ideal I homogeneous ideal
# @return fan::PolyhedralFan
user_function gfan_tropicalbruteforce(ideal::Ideal) {
   my ($I) = @_;
   return fan::gfan_to_symmetric_fan(fan::run_gfan(sub { fan::gfan_print_ideal($_[0], $I) },
                                                   $gfan_tropicalbruteforce));
}

sub gfan_to_tropical_cycle {
   my ($data) = @_;
   my $result = new Cycle<Max>();

   my $ambient_dim = $data->{AMBIENT_DIM};
   $result->FAN_AMBIENT_DIM = $ambient_dim+1;
   $result->FAN_DIM = $data->{DIM};
   $result->PURE = $data->{PURE};
   $result->SIMPLICIAL = $data->{SIMPLICIAL};

   # concatenate all vectors in MULTIPLICITIES and rename to WEIGHTS
   if (defined(my $m = $data->{MULTIPLICITIES})) {
      $result->WEIGHTS = [ map { @$_ } @$m ];
   }

   # add leading 0 to RAYS and the origin, rename to PROJECTIVE_VERTICES
   if (defined(my $rays = $data->{RAYS})) {
      unshift @$_, "0" for @$rays;
      push @$rays, [ "1", ("0") x $ambient_dim ];
      $result->PROJECTIVE_VERTICES = $rays;
   }

   # add leading 0 to LINEALITY_SPACE; mod out (1,1...1)
   my $lineality = $data->{LINEALITY_SPACE};
   if (defined($lineality) && @$lineality) {
      unshift @$_, "0" for @$lineality;
      $lineality = new Matrix<Rational>($lineality);
      canonicalize_scalar_to_leading_zero($lineality->minor(All, range_from(1)));
      $result->LINEALITY_SPACE = $lineality->minor(basis_rows($lineality), All);
   } else {
      $result->LINEALITY_SPACE = new Matrix<Rational>(0, $ambient_dim+1);
   }

   # add new ray to MAXIMAL_CONES
   my $mc = $data->{MAXIMAL_CONES};
   if (defined($mc) && @$mc) {
      my $last_ray = $data->{N_RAYS};
      foreach (@$mc) {
         if (is_hash($_)) {
            if (defined($_->{cols})) {
               $_->{cols}++;
            } elsif (keys %$_ == 0) {
               # empty row
               $_ = [ $last_ray ];
            } else {
               die "unexpected row in MAXIMAL_CONES input\n";
            }
         } else {
            push @$_, $last_ray;
         }
      }
      $result->MAXIMAL_POLYTOPES = $mc;
   }

   $result->commit();
   return $result;
}


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