#  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 gfan
  Gfan is a software package for computing Groebner fans and tropical varieties.
  Copyright by Anders Jensen
  http://home.imf.au.dk/jensen/software/gfan/gfan.html

# path to gfan_bases
custom $gfan_bases;

# path to gfan_secondaryfan
custom $gfan_secondaryfan;

# path to gfan_topolyhedralfan
custom $gfan_topolyhedralfan;

CONFIGURE {
    find_program($gfan_bases, "gfan_bases");
    find_program($gfan_secondaryfan = $gfan_bases =~ s/gfan_bases$/gfan_secondaryfan/r,
		 "gfan_secondaryfan");
    find_program($gfan_topolyhedralfan = $gfan_bases =~ s/gfan_bases$/gfan_topolyhedralfan/r,
		 "gfan_topolyhedralfan");
}

# command, input_generator => serialized BigObject in JSON
sub run_gfan {
  require Polymake::Core::XMLtoJSON;

  my ($input_gen, @pipeline) = @_;
  my $tempfile = new TempTextFile;
  $input_gen->($tempfile);
  $pipeline[0] .= " <$tempfile";
  if (!$DebugLevel) {
    $_ .= " 2>/dev/null" for @pipeline;
  }
  my $cmd = join(" | ", @pipeline) . " --xml |";
  open my $P, $cmd
    or die "can't run `$cmd': $!\n";
  my $data = Core::XMLtoJSON::from_filehandle($P);
  close $P;
  die "`$cmd' failed with exit code $?\n" if $?;
  return $data;
}

sub gfan_to_symmetric_fan {
  my ($data) = @_;
  my $version = $data->{_ns}{polymake}[1];
  if ($version eq "2.9.9") {
    # remove leading "1" from F_VECTOR
    # other adaptations will be done by upgrade rules
    if (defined(my $v = $data->{F_VECTOR})) {
      shift @$v;
    }
  }
  Core::Serializer::deserialize($data)
}


# @category Producing a fan
# Call [[wiki:external_software#gfan]] to compute the secondary fan of a point configuration.
#
# @param Matrix M a matrix whose rows are the vectors in the configuration
# @return PolyhedralFan
# @example Four points in the plane of which none three are on a line give
# us a secondary fan consisting of two opposing cones with 3-dimensional lineality:
# > $f = gfan_secondary_fan(new PointConfiguration(POINTS=>[[1,0,0],[1,1,0],[1,0,1],[1,1,1]]));
# > print $f->RAYS;
# | -1 1 1 -1
# | 1 -1 -1 1
# > print $f->MAXIMAL_CONES;
# | {0}
# | {1}
# > print $f->LINEALITY_SPACE;
# | 1 0 0 -1
# | 0 1 0 1
# | 0 0 1 1
user_function gfan_secondary_fan(Matrix) {
  my ($M) = @_;
  return gfan_to_symmetric_fan(run_gfan(sub { gfan_print_matrix($_[0], eliminate_denominators_entire_affine($M)) },
                                        $gfan_secondaryfan));
}

sub gfan_print_matrix {
  my ($infile, $M) = @_;

  print $infile "{";
  my $r = $M->rows();
  my $c = $M->cols();
  for (my $i = 0; $i < $r; ++$i) {
    print $infile "," if $i != 0;
    print $infile "(";
    for (my $j = 0; $j < $c; ++$j) {
      print $infile "," if $j != 0;
      print $infile $M->elem($i, $j);
    }
    print $infile ")";
  }
  print $infile "}\n";
}

# @category Producing a fan
# Call [[wiki:external_software#gfan]] to compute the secondary fan of a point configuration.
#
# @param polytope::PointConfiguration P
# @return PolyhedralFan
user_function gfan_secondary_fan(polytope::PointConfiguration) {
  my ($pc)=@_;
  return gfan_secondary_fan($pc->POINTS);
}

# @category Producing a fan
# Call [[wiki:external_software#gfan]] to compute the greobner fan of an ideal.
#
# @param ideal::Ideal I input ideal
# @return PolyhedralFan
user_function groebner_fan(ideal::Ideal) {
  my ($I) = @_;
  return gfan_to_symmetric_fan(run_gfan(sub { gfan_print_ideal($_[0], $I) }, $gfan_bases,
                                        $gfan_topolyhedralfan));
}

sub gfan_print_ideal {
  my ($infile, $I) = @_;
  print $infile "Q[", join(",", monomials($I->N_VARIABLES)), "]\n";
  print $infile "{", join(",", @{$I->GENERATORS}), "}\n";
}

# Local Variables:
# mode: perl
# cperl-indent-level:2
# End:
