#  Copyright (c) 1997-2009
#  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: hypersurface.rules 9562 2010-03-12 18:52:58Z smoeser $

package Visual::TropicalHypersurface;
use Polymake::Struct (
   [ '@ISA' => 'Container' ],
   '$TropicalHypersurface',
);


# A tropical hypersurface is the set of points in the tropical (d-1)-torus for which
# the minimum of a tropical polynomial is attained at least twice. It is
# given as a list of [[MONOMIALS]] and [[COEFFICIENTS]].
#
# Throughout this hypersurface is seen as a polyhedral complex in R<sup>d-1</sup>. 
declare object TropicalHypersurface<Scalar=Rational [ typechecks::is_ordered_field_with_unlimited_precision(Scalar) ]> {


# @category Basic properties
# Monomials of the (tropical) polynomial defining the hypersurface (Laurent polynomials are allowed.)
# The rows stands for the monomials, the columns for the variables. I.e., the entry in position (i,j) is the exponent of x<sub>j</sub> in the i-th monomial. 

property MONOMIALS : Matrix<Int>;

# @category Basic properties
# Coefficients of the (tropical) polynomial defining the hypersurface.

property COEFFICIENTS : Vector<Scalar>;

# @category Basic properties
# Points and rays of the hypersurface, vertices of the complex.

property POINTS : Matrix<Scalar> {

   sub canonical { my $this=shift; &canonicalize_to_leading_zero($this->minor(All,~[0])); }
}

declare permutation PointsPerm {

  # Transforming [[VERTICES]] from this into basic object
  property PERMUTATION : Array<Int>;
}

rule PointsPerm.PERMUTATION : PointsPerm.POINTS, POINTS {
   $this->PointsPerm->PERMUTATION=polytope::find_vertex_permutation($this->PointsPerm->POINTS, $this->POINTS);
}

rule POINTS : PointsPerm.POINTS, PointsPerm.PERMUTATION {
   $this->POINTS=permuted_rows($this->PointsPerm->POINTS, $this->PointsPerm->PERMUTATION);
}
weight 1.10;

# @category Basic properties
# Indices of the points that are rays.

property RAYS : Set;

rule RAYS : PointsPerm.RAYS, PointsPerm.PERMUTATION {
   $this->RAYS=permuted($this->PointsPerm->RAYS, $this->PointsPerm->PERMUTATION);
}
weight 1.10;

# @category Basic properties
# Maximal faces of the hypersurface as a polyhedral complex.

property MAXIMAL_FACES : Array<Set>;

rule MAXIMAL_FACES : PointsPerm.MAXIMAL_FACES, PointsPerm.PERMUTATION {
   my $mf=new Array<Set>($this->PointsPerm->MAXIMAL_FACES);
   foreach (@{$mf}) {
      $_=permuted($_, $this->PointsPerm->PERMUTATION);
   }
   $this->MAXIMAL_FACES=$mf;
}
weight 1.10;

# @category Basic properties
# Number of [[MONOMIALS]] and [[COEFFICIENTS]].

property SUPPORT_SIZE : Int;


# @category Basic properties
# Dimension of the affine hull of a maximal face of the hypersurface.

property DIM : Int;


# @category Basic properties
# Dimension of the tropical projective space containing the hypersurface.

property AMBIENT_DIM : Int;


# @category Basic properties
# Number of [[VERTICES]].

property N_VERTICES : Int;


# @category Basic properties
# Number of maximal faces.

property N_MAXIMAL_FACES : Int;


# @category Basic properties
# Number of [[POINTS]] (vertices plus rays).

property N_POINTS : Int;


# @category Basic properties
# Number of [[RAYS]].

property N_RAYS : Int;


rule SUPPORT_SIZE : MONOMIALS {
  $this->SUPPORT_SIZE=$this->MONOMIALS->rows;
}
weight 0.10;

rule DIM : MONOMIALS {
  $this->DIM=$this->MONOMIALS->cols-2;
}
weight 0.10;

rule DIM : POINTS {
  $this->DIM=$this->POINTS->cols-3;
}
weight 0.10;

rule AMBIENT_DIM : DIM {
  $this->AMBIENT_DIM=$this->DIM+1;
}
weight 0.10;

rule N_VERTICES : POINTS, RAYS {
   $this->N_VERTICES=$this->POINTS->rows-@{$this->RAYS};
}
weight 0.10;

rule N_POINTS : POINTS {
   $this->N_POINTS=$this->POINTS->rows;
}
weight 0.10;

rule N_RAYS : RAYS {
   $this->N_RAYS=@{$this->RAYS};
}
weight 0.10;

rule N_MAXIMAL_FACES : MAXIMAL_FACES {
   $this->N_MAXIMAL_FACES=@{$this->MAXIMAL_FACES};
}
weight 0.10;

rule POINTS, RAYS, MAXIMAL_FACES : MONOMIALS, COEFFICIENTS {
     hypersurface($this);
}
permutation : PointsPerm;


# @category Basic properties
# List the [[MONOMIALS]] for which the minimum is attained.
# @param Scalar x the value at which the tropical polynomial is evaluated
# @return Array

user_method min_attained($) : MONOMIALS, COEFFICIENTS {
  my ($this,$x)=@_;
  my $n=scalar(@{$this->MONOMIALS});
  my $val=$this->COEFFICIENTS->[0]+($x*$this->MONOMIALS->[0]);
  my @val_attained=(0);
  foreach my $i (1..$n-1) {
    my $v=$this->COEFFICIENTS->[$i]+($x*$this->MONOMIALS->[$i]);
    if ($v<$val) {
      $val=$v;
      @val_attained=($i);
    } elsif ($v==$val) {
      push @val_attained,$i;
    }
  }
  return \@val_attained;
}

# @category Basic properties
# Vertices of the hypersurface.

user_method VERTICES : RAYS, POINTS {
   my $this=shift;
   $this->POINTS->minor(~$this->RAYS, ~[0]);
}

# @category Visualization
# Visualizes the tropical hypersurface.
# @return Visual::TropicalHypersurface

user_method VISUAL(; $=bounding_box($_[0]->POINTS->minor(All, ~[1]), 6/5, 1), %Visual::Polygons::decorations) \
   : POINTS, RAYS, MAXIMAL_FACES {
   my ($this,$bbox,$decor)=@_;
   my $m=$this->POINTS->minor(All, ~[1]);
   my $bbox_facets=new Map< Vector<Scalar>, Bool>;
   $bbox_facets->{$_}=1 for @$bbox;
   my $vertex_map=new Map< Vector<Scalar>, String>;
   my $f=0;
   #if (defined (my $labels=$this->lookup("LABELS"))) {
   #   $vertex_map->{$_}=$labels->[$f++] for @{$m};
   #} else {
      $vertex_map->{$_}=$f++ for @{$m};
   #}
   my @cells_visual = map {
      my $p=new polytope::Polytope<Scalar>("$_",POINTS => $m->minor($_,All));
      if ($p->BOUNDED) {
         my @vertex_labels=map { defined($vertex_map->{$_} || " ") } @{$p->VERTICES};
         $p->VERTEX_LABELS=\@vertex_labels;
	 $p->VISUAL;
      }
      else {
         my $p_bounded=new polytope::Polytope<Scalar>($p->name."_bounded",INEQUALITIES => $p->FACETS / $bbox, AFFINE_HULL=>$p->AFFINE_HULL);
	 my @vertex_labels=map { defined($vertex_map->{$_} || " ") } @{$p_bounded->VERTICES};
         $p_bounded->VERTEX_LABELS=\@vertex_labels;
         #if ($p_bounded->DIM>2) {
	 #   $p_bounded->VISUAL(VertexThickness => sub { $vertex_labels[$_[0]] ne " " },FacetColor=>[ map { exists $bbox_facets->{$_} ? "red" : $Visual::Color::facets } @{$p_bounded->FACETS} ]);
	 #}
	 #else {
            $p_bounded->VISUAL(VertexThickness => sub { $vertex_labels[$_[0]] ne " " });
	 #}
      }
   } (@{$this->MAXIMAL_FACES});
   visualize( new Visual::TropicalHypersurface( Name => $this->name,
					   TropicalHypersurface => $this,
					   @cells_visual));
}
precondition : AMBIENT_DIM { $this->AMBIENT_DIM<=3 }

}


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