#  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: unbounded_polyhedron.rules 9547 2010-03-09 07:21:34Z smoeser $

object Polytope {

rule BOUNDED : FAR_FACE {
   $this->BOUNDED= !@{$this->FAR_FACE};
}
weight 0.10;

rule FAR_FACE : VERTICES {
   $this->FAR_FACE=far_points($this->VERTICES);
}
weight 1.10;

method has_far_facet {
   my ($this)=@_;
   my $Points=$this->VERTICES | POINTS;
   rank($Points->minor(far_points($Points), range(1,$Points->cols-1))) == $this->DIM
}

# @category Unbounded polyhedra
# Indices of facets that are unbounded.

property UNBOUNDED_FACETS : Set;

# @notest  Rule defined "in stock" - currently without use
rule UNBOUNDED_FACETS : FacetPerm.UNBOUNDED_FACETS, FacetPerm.PERMUTATION {
   $this->UNBOUNDED_FACETS=permuted($this->FacetPerm->UNBOUNDED_FACETS, $this->FacetPerm->PERMUTATION);
}
weight 1.10;

rule UNBOUNDED_FACETS : VERTICES_IN_FACETS, FAR_FACE {
   $this->UNBOUNDED_FACETS=incident_rows($this->VERTICES_IN_FACETS, $this->FAR_FACE);
}
precondition : !BOUNDED;


# @category Unbounded polyhedra
# A linear objective function for which each unbounded edge is increasing;
# only defined for unbounded polyhedra.

property TOWARDS_FAR_FACE : Vector<Scalar>;

rule TOWARDS_FAR_FACE : VERTICES, AFFINE_HULL, FAR_FACE {
   my $cone=new Polytope<Rational>(INEQUALITIES => $this->VERTICES->minor($this->FAR_FACE,All),
				   AFFINE_HULL => $this->AFFINE_HULL);
   $this->TOWARDS_FAR_FACE=$cone->REL_INT_POINT;
}
precondition : !BOUNDED;

rule TOWARDS_FAR_FACE : { $this->TOWARDS_FAR_FACE=undef }
precondition : BOUNDED;


# @category Unbounded polyhedra
# True if each bounded vertex of a (possibly unbounded) d-polyhedron has vertex degree d in the [[GRAPH]].
# The vertex degrees of the vertices on the [[FAR_FACE]] do not matter.

property SIMPLE_POLYHEDRON : Bool;

rule SIMPLE, SIMPLE_POLYHEDRON : DIM, FAR_FACE, GRAPH.NODE_DEGREES {
   my $simple=1;
   my $simple_polyhedron=1;
   my $v=0;
   foreach (@{$this->GRAPH->NODE_DEGREES}) {
      if ($_ != $this->DIM) {
         $simple=0;
	 if (!exists($this->FAR_FACE->{$v})) {
            $simple_polyhedron=0;
            last;
	 }
      }
      ++$v;
   }
   $this->SIMPLE=$simple;
   $this->SIMPLE_POLYHEDRON=$simple_polyhedron;
}
weight 1.10;


rule SIMPLE_POLYHEDRON : { $this->SIMPLE_POLYHEDRON=1 }
precondition : SIMPLE;
weight 0.10;


# @category Unbounded polyhedra
# Number of bounded vertices (non-rays).

property N_BOUNDED_VERTICES : Int;

rule N_BOUNDED_VERTICES : N_VERTICES, FAR_FACE {
   $this->N_BOUNDED_VERTICES=$this->N_VERTICES-@{$this->FAR_FACE};
}
weight 0.10;

# @category Unbounded polyhedra
# Indices of [[VERTICES]] that are no rays.
# @return Set<Int>
user_method BOUNDED_VERTICES : FAR_FACE, N_VERTICES {
   my $this=shift;
   range(0,$this->N_VERTICES-1) - $this->FAR_FACE;
}

# @category Unbounded polyhedra
# Indices of [[FACETS]] that are bounded.
# @return Set<Int> 
user_method BOUNDED_FACETS : UNBOUNDED_FACETS, N_FACETS {
   my $this=shift;
   range(0,$this->N_FACETS-1) - $this->UNBOUNDED_FACETS;
}


# @category Unbounded polyhedra
# Graph of the bounded subcomplex.

property BOUNDED_GRAPH : objects::Graph {

  # Each edge indicates the maximal dimension of a bounded
  # face containing it.  Mainly used for visualization purposes.

  property EDGE_COLORS : EdgeMap<Undirected,Int>;

  # Difference of the vertices for each edge (only defined up to signs).
  property EDGE_DIRECTIONS : EdgeMap<Undirected,Vector<Scalar>>;

}

rule BOUNDED_GRAPH.NodePerm.PERMUTATION = VertexPerm.PERMUTATION;

rule BOUNDED_GRAPH.ADJACENCY : GRAPH.ADJACENCY, FAR_FACE, BOUNDED {
   $this->BOUNDED_GRAPH->ADJACENCY= $this->BOUNDED ? $this->GRAPH->ADJACENCY : induced_subgraph($this->GRAPH->ADJACENCY, ~ $this->FAR_FACE);
}
weight 1.20;

# there is a rule for tight spans with the same signature which is faster
rule BOUNDED_GRAPH.EDGE_COLORS : BOUNDED_GRAPH.ADJACENCY, HASSE_DIAGRAM, FAR_FACE {
   edge_colored_bounded_graph($this->BOUNDED_GRAPH,$this->HASSE_DIAGRAM, $this->FAR_FACE)
}
weight 4.20;

rule BOUNDED_GRAPH.EDGE_DIRECTIONS : BOUNDED_GRAPH.ADJACENCY, VERTICES {
   $this->BOUNDED_GRAPH->EDGE_DIRECTIONS = edge_directions($this->BOUNDED_GRAPH,$this->VERTICES);
}


# @category Unbounded polyhedra
# Dual graph of the bounded subcomplex.

property BOUNDED_DUAL_GRAPH : objects::Graph;

rule BOUNDED_DUAL_GRAPH.NodePerm.PERMUTATION = FacetPerm.PERMUTATION;

rule BOUNDED_DUAL_GRAPH.ADJACENCY : DUAL_GRAPH.ADJACENCY, UNBOUNDED_FACETS, BOUNDED {
   $this->BOUNDED_DUAL_GRAPH->ADJACENCY= $this->BOUNDED ? $this->DUAL_GRAPH->ADJACENCY : induced_subgraph($this->DUAL_GRAPH->ADJACENCY, ~ $this->UNBOUNDED_FACETS);
}
weight 1.20;

rule BOUNDED_GRAPH.NODE_LABELS = VERTEX_LABELS;

rule BOUNDED_DUAL_GRAPH.NODE_LABELS = FACET_LABELS;


# @category Unbounded polyhedra
# [[HASSE_DIAGRAM]] constrained to affine vertices
# Nodes representing the maximal inclusion-independent faces are connected to the top-node
# regardless of their dimension

property BOUNDED_HASSE_DIAGRAM : FaceLattice;

# FIXME:
#$apply_diff{VERTICES}=
#$apply_diff{FACETS}=

rule BOUNDED_HASSE_DIAGRAM : VERTICES_IN_FACETS, FAR_FACE {
   $this->BOUNDED_HASSE_DIAGRAM=bounded_hasse_diagram($this->VERTICES_IN_FACETS, $this->FAR_FACE);
}
precondition : !BOUNDED;
weight 6.20;


# @category Unbounded polyhedra
# Dimension of the [[BOUNDED_COMPLEX]] of an unbounded polyhedron.

property BOUNDED_DIM : Int;

rule BOUNDED_DIM : BOUNDED_HASSE_DIAGRAM {
   $this->BOUNDED_DIM=$this->BOUNDED_HASSE_DIAGRAM->dim;
}
precondition : !BOUNDED;
weight 0.10;


# @category Unbounded polyhedra
# f<sub>k</sub> is the number of bounded k-faces.

property BOUNDED_F_VECTOR : Vector<Int>;

rule BOUNDED_F_VECTOR : BOUNDED_HASSE_DIAGRAM, BOUNDED_DIM {
   $this->BOUNDED_F_VECTOR=[ map { scalar( @{$this->BOUNDED_HASSE_DIAGRAM->nodes_of_dim($_)} ) } 0..$this->BOUNDED_DIM ];
}


# @category Unbounded polyhedra
# Bounded subcomplex.
# **FIXME:** type should be a newly defined "PolyhedralComplex"

property BOUNDED_COMPLEX : IncidenceMatrix;

rule BOUNDED_COMPLEX : VERTICES_IN_FACETS, FAR_FACE {
   $this->BOUNDED_COMPLEX=bounded_complex($this->VERTICES_IN_FACETS, $this->FAR_FACE);
}
precondition : !BOUNDED;
weight 6.10;

rule BOUNDED_COMPLEX : HASSE_DIAGRAM, FAR_FACE {
   $this->BOUNDED_COMPLEX=bounded_complex($this->HASSE_DIAGRAM, $this->FAR_FACE);
}
precondition : !BOUNDED;

rule BOUNDED_COMPLEX : BOUNDED_HASSE_DIAGRAM {
   $this->BOUNDED_COMPLEX(temporary)=bounded_complex($this->BOUNDED_HASSE_DIAGRAM);
}
precondition : !BOUNDED;
weight 1.10;

}

object LinearProgram {

# @category Unbounded polyhedra
# Subgraph of [[BOUNDED_GRAPH]]. Consists only of directed arcs along which the value of the objective function increases.

property DIRECTED_BOUNDED_GRAPH : Graph<Directed>;

}

object Polytope {

rule LP.DIRECTED_BOUNDED_GRAPH.ADJACENCY : LP.DIRECTED_GRAPH.ADJACENCY, FAR_FACE, BOUNDED {
   $this->LP->DIRECTED_BOUNDED_GRAPH->ADJACENCY= $this->BOUNDED ? $this->LP->DIRECTED_GRAPH->ADJACENCY : induced_subgraph($this->LP->DIRECTED_GRAPH->ADJACENCY, ~ $this->FAR_FACE);
}
weight 1.20;

}

object Polytope<Rational> {

rule VERTICES, BOUNDED, FAR_FACE, BOUNDED_GRAPH.ADJACENCY : ONE_VERTEX, FACETS | INEQUALITIES {
   reverse_search_graph($this,$this->ONE_VERTEX);
}
precondition : SIMPLE_POLYHEDRON;
weight 4.20;
permutation : VertexPerm;

}


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