#  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: polytope_properties.rules 9562 2010-03-12 18:52:58Z smoeser $


object Polytope {

# @category Basic properties
# Points such that the polyhedron is their convex hull.
# Redundancies are allowed.
# The vector (x<sub>0</sub>, x<sub>1</sub>, ... x<sub>d</sub>) represents a point in d-space given in homogeneous coordinates.
# Affine points are identified by x<sub>0</sub> > 0.
# Points with x<sub>0</sub> = 0 can be interpreted as rays.
#
# polymake automatically normalizes each coordinate vector, dividing them by the first non-zero element.
# The clients and rule subroutines can always assume that x<sub>0</sub> is either 0 or 1.
# Dual to [[INEQUALITIES]].
#
# Input section only.  Ask for [[VERTICES]] if you want to compute a V-representation from an H-representation.

property POINTS : Matrix<Scalar> {
   sub canonical { &canonicalize_points; }
}


# to be overloaded in special cases like Scalar==Float
sub prepare_computations { undef }

# @category Basic properties
# Vertices of the polyhedron. No redundancies are allowed.
# The coordinates are normalized the same way as [[POINTS]]. Dual to [[FACETS]].

property VERTICES : Matrix<Scalar> {
   sub canonical { &canonicalize_points; }
}

declare permutation VertexPerm {

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

rule VertexPerm.PERMUTATION : VertexPerm.VERTICES, VERTICES {
   my $cmp=$this->prepare_computations;
   $this->VertexPerm->PERMUTATION=find_vertex_permutation($this->VertexPerm->VERTICES, $this->VERTICES);
}

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

# @category Basic properties
# Inequalities that describe half-spaces such that the polyhedron is their intersection.
# Redundancies are allowed.  Dual to [[POINTS]].
#
# A vector (A<sub>0</sub>, A<sub>1</sub>, ..., A<sub>d</sub>) defines the
# (closed affine) half-space of points (1, x<sub>1</sub>, ..., x<sub>d</sub>) such that
# A<sub>0</sub> + A<sub>1</sub> x<sub>1</sub> + ... + A<sub>d</sub> x<sub>d</sub> >= 0.
#
# Input section only.  Ask for [[FACETS]] and [[AFFINE_HULL]] if you want to compute an H-representation
# from a V-representation.

property INEQUALITIES : Matrix<Scalar>;


# @category Basic properties
# Facets of the polyhedron, encoded as [[INEQUALITIES]]. Dual to [[VERTICES]].

property FACETS : Matrix<Scalar>;


declare permutation FacetPerm {

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

# @category Basic properties
# Equations that hold for all points of the polyhedron.
#
# A vector (A<sub>0</sub>, A<sub>1</sub>, ..., A<sub>d</sub>) describes the hyperplane
# of all points (1, x<sub>1</sub>, ..., x<sub>d</sub>) such that A<sub>0</sub> + A<sub>1</sub> x<sub>1</sub> + ... + A<sub>d</sub> x<sub>d</sub> = 0.
#
# Input section only.  Ask for [[AFFINE_HULL]] if you want to see an irredundant description of the affine span.

property EQUATIONS : Matrix<Scalar>;


# @category Basic properties
# Dual basis of the affine hull of the polyhedron.

property AFFINE_HULL : Matrix<Scalar> {
   sub canonical { &orthogonalize_subspace; }

   method equal {
      my ($this, $M1, $M2)=@_;
      $this->prepare_computations;
      $M1==$M2 || equal_bases($M1, $M2);
   }
}


rule FacetPerm.PERMUTATION : FacetPerm.FACETS, FACETS, AFFINE_HULL {
   my $cmp=$this->prepare_computations;
   $this->FacetPerm->PERMUTATION=find_facet_permutation($this->FacetPerm->FACETS, $this->FACETS, $this->AFFINE_HULL);
}

rule FacetPerm.AFFINE_HULL = AFFINE_HULL;

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

# @category Basic properties
# The i-th row is the normal vector of a hyperplane separating the i-th vertex from the others.
# This property is a by-product of redundant point elimination algorithm.

property VERTEX_NORMALS : Matrix<Scalar>;

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

# @category Basic properties
# Some point belonging to the polyhedron.

property VALID_POINT : Vector<Scalar> {
   sub canonical { &canonicalize_points; }
}

# @category Basic properties
# Dimension of the affine hull of the polyhedron = dimension of the polyhedron.
# If the polytope is given purely combinatorially, this is the dimension of a minimal embedding space
# deduced from the combinatorial structure.

property DIM : Int;


# @category Basic properties
# Dimension of the space in which the polyhedron lives.

property AMBIENT_DIM : Int;


# @category Basic properties
# Basis of the linear subspace orthogonal to all [[INEQUALITIES]] and [[EQUATIONS]]

property LINEALITY_SPACE : Matrix<Scalar> {
   sub canonical { &orthogonalize_subspace; }
}


# @category Basic properties
# Dimension of the [[LINEALITY_SPACE]] (>0 in the non-POINTED case)

property LINEALITY_DIM : Int;


# @category Basic properties
# True if the polyhedron is not empty.

property FEASIBLE : Bool;


# @category Basic properties
# True if the polyhedron does not contain an affine line.

property POINTED : Bool;


# @category Basic properties
# A vertex of a pointed polyhedron.

property ONE_VERTEX : Vector<Scalar> {
   sub canonical { &canonicalize_points; }
}


# @category Basic properties
# True if the polyhedron is a bounded polytope.

property BOUNDED : Bool;


# @category Basic properties
# True if (1, 0, 0, ...) is in the relative interior. Polar to [[BOUNDED]].

property CENTERED : Bool;


# @category Basic properties
# True if all vertices of the polyhedron have non-negative coordinates, that is, it lies entirely in the positive orthant.

property POSITIVE : Bool;


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

property N_POINTS : Int;


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

property N_INEQUALITIES : Int;


# @category Combinatorics
# Number of [[VERTICES]].

property N_VERTICES : Int;


# @category Combinatorics
# Number of [[FACETS]].

property N_FACETS : Int;


# @category Combinatorics
# Number of pairs of incident vertices and facets.

property N_VERTEX_FACET_INC : Int;


# @category Combinatorics
# Vertex-facet incidence matrix, with rows corresponding to facets and columns
# to vertices. Vertices and facets are numbered from 0 to [[N_VERTICES]]-1 rsp.
# [[N_FACETS]]-1, according to their order in [[VERTICES]] rsp. [[FACETS]].

property VERTICES_IN_FACETS : IncidenceMatrix;

# @topic credits/nauty

# @notest  Rule defined "in stock" - currently without use
rule VertexPerm.PERMUTATION : VertexPerm.VERTICES_IN_FACETS, VERTICES_IN_FACETS {
   $this->VertexPerm->PERMUTATION=find_row_col_permutation($this->VertexPerm->VERTICES_IN_FACETS, $this->VERTICES_IN_FACETS)->second;
}
weight 5.10;

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

# @topic credits/---

rule VERTICES_IN_FACETS : VertexPerm.VERTICES_IN_FACETS, VertexPerm.PERMUTATION {
   $this->VERTICES_IN_FACETS=permuted_cols($this->VertexPerm->VERTICES_IN_FACETS, $this->VertexPerm->PERMUTATION);
}
weight 1.20;

rule VERTICES_IN_FACETS : FacetPerm.VERTICES_IN_FACETS, FacetPerm.PERMUTATION {
   $this->VERTICES_IN_FACETS=permuted_rows($this->FacetPerm->VERTICES_IN_FACETS, $this->FacetPerm->PERMUTATION);
}
weight 1.20;

# @category Convex hull computation
# Similar to [[VERTICES_IN_FACETS]], but with columns corresponding to [[POINTS]] instead of [[VERTICES]].
# This property is a byproduct of convex hull computation algorithms.
# It is discarded as soon as [[VERTICES_IN_FACETS]] is computed.

property POINTS_IN_FACETS : IncidenceMatrix;

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

# @category Combinatorics
# transposed [[VERTICES_IN_FACETS]]
# Notice that this is a temporary property; it will not be stored in any file.

property FACETS_THRU_VERTICES : IncidenceMatrix;

# @category Convex hull computation
# Similar to [[VERTICES_IN_FACETS]], but with rows corresponding to [[INEQUALITIES]] instead of [[FACETS]].
# This property is a byproduct of convex hull computation algorithms.
# It is discarded as soon as [[VERTICES_IN_FACETS]] is computed.

property VERTICES_IN_INEQUALITIES : IncidenceMatrix;

# @notest  Rule defined "in stock" - currently without use
rule VERTICES_IN_INEQUALITIES : VertexPerm.VERTICES_IN_INEQUALITIES, VertexPerm.PERMUTATION {
   $this->VERTICES_IN_INEQUALITIES=permuted_cols($this->VertexPerm->VERTICES_IN_INEQUALITIES, $this->VertexPerm->PERMUTATION);
}
weight 1.20;

# @category Combinatorics
# transposed [[VERTICES_IN_INEQUALITIES]]

property INEQUALITIES_THRU_VERTICES : IncidenceMatrix;


# @category Combinatorics
# The face lattice of the polytope organized as a directed graph.
# Each node corresponds to some proper face of the polytope.
# The nodes corresponding to the vertices and facets appear in the same order
# as the elements of [[VERTICES]] and [[FACETS]] properties.
#
# Two special nodes represent the whole polytope and the empty face.

property HASSE_DIAGRAM : FaceLattice;

rule HASSE_DIAGRAM : VertexPerm.HASSE_DIAGRAM, VertexPerm.PERMUTATION {
   $this->HASSE_DIAGRAM=permuted_atoms($this->VertexPerm->HASSE_DIAGRAM, $this->VertexPerm->PERMUTATION);
}

rule HASSE_DIAGRAM : FacetPerm.HASSE_DIAGRAM, FacetPerm.PERMUTATION {
   $this->HASSE_DIAGRAM=permuted_coatoms($this->FacetPerm->HASSE_DIAGRAM, $this->FacetPerm->PERMUTATION);
}

# @category Combinatorics
# Number of incident facets for each vertex.

property VERTEX_SIZES : Array<Int>;

# @category Combinatorics
# Number of incident vertices for each facet.

property FACET_SIZES : Array<Int>;


# @category Unbounded polyhedra
# Indices of vertices that are rays.

property FAR_FACE : Set;

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

# @category Combinatorics
# Vertex-edge graph.

property GRAPH : objects::Graph {

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

}

rule GRAPH.NodePerm.PERMUTATION = VertexPerm.PERMUTATION;


# @category Combinatorics
# Facet-ridge graph. Dual to [[GRAPH]].

property DUAL_GRAPH : objects::Graph;

rule DUAL_GRAPH.NodePerm.PERMUTATION = FacetPerm.PERMUTATION;

# @category Combinatorics
# Lists for each occurring size (= number of incident vertices or edges) of a 2-face how many there are.

property TWO_FACE_SIZES : Map<Int,Int>;


# @category Combinatorics
# Lists for each occurring size (= number of incident facets or ridges) of a subridge how many there are.

property SUBRIDGE_SIZES : Map<Int,Int>;


# @category Combinatorics
# Let M be the vertex-facet incidence matrix, then the Altshulter determinant is
# defined as max{det(M &lowast; M^T), det(M^T &lowast M)}.

property ALTSHULER_DET : Integer;


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

property F_VECTOR : Vector<Integer>;


# @category Combinatorics
# f<sub>ik</sub> is the number of incident pairs of i-faces and k-faces; the main diagonal contains the [[F_VECTOR]].

property F2_VECTOR : Matrix<Integer>;


# @category Combinatorics
# All intermediate polytopes (with respect to the given insertion order) in the beneath-and-beyond algorithm are simplicial.
# We have the implications: [[VERTICES]] in general position => ESSENTIALLY_GENERIC => [[SIMPLICIAL]]

property ESSENTIALLY_GENERIC : Bool;


# @category Combinatorics
# True if the polytope is simplicial.

property SIMPLICIAL : Bool;


# @category Combinatorics
# True if the polytope is simple. Dual to [[SIMPLICIAL]].

property SIMPLE : Bool;


# @category Combinatorics
# True if the polytope is self-dual.

property SELF_DUAL : Bool;


# @category Combinatorics
# Maximal dimension in which all faces are simplices.

property SIMPLICIALITY : Int;


# @category Combinatorics
# Maximal dimension in which all dual faces are simplices.

property SIMPLICITY : Int;


# @category Combinatorics
# Maximal dimension in which all faces are simple polytopes.

property FACE_SIMPLICITY : Int;


# @category Combinatorics
# True if all facets are cubes.

property CUBICAL : Bool;


# @category Combinatorics
# Maximal dimension in which all facets are cubes.

property CUBICALITY : Int;


# @category Combinatorics
# Dual to [[CUBICAL]].

property COCUBICAL : Bool;


# @category Combinatorics
# Dual to [[CUBICALITY]].

property COCUBICALITY : Int;


# @category Combinatorics
# True if the polytope is neighborly.

property NEIGHBORLY : Bool;


# @category Combinatorics
# Maximal dimension in which all facets are neighborly.

property NEIGHBORLINESS : Int;


# @category Combinatorics
# Dual to [[NEIGHBORLY]].

property BALANCED : Bool;


# @category Combinatorics
# Maximal dimension in which all facets are balanced.

property BALANCE : Int;


# @category Combinatorics
# Parameter describing the shape of the face-lattice of a 4-polytope.

property FATNESS : Float;


# @category Combinatorics
# Parameter describing the shape of the face-lattice of a 4-polytope.

property COMPLEXITY : Float;


# @category Basic properties
# The center of gravity of the vertices of a bounded polytope.

property VERTEX_BARYCENTER : Vector<Scalar>;


# @category Basic properties
# The minimal angle between any two vertices (seen from the [[VERTEX_BARYCENTER]]).

property MINIMAL_VERTEX_ANGLE : Float;


# @category Basic properties
# DOC_FIXME: Incomprehensible!
# Contains the vector configuration for which a [[zonotope]] can be built.

property ZONOTOPE_INPUT_VECTORS : Matrix<Scalar>;


# @topic properties/Triangulation and volume
# Everything in this group is defined for [[BOUNDED]] polytopes only.


# @category Triangulation and volume
# Volume of the polytope.

property VOLUME : Scalar;


# Centroid (center of mass) of the polytope.

property CENTROID : Vector<Scalar>;


# @category Triangulation and volume
# Some triangulation of the polytope using only its vertices.
# Each line contains indices from [[VERTICES]] comprising a simplex.

property TRIANGULATION : topaz::SimplicialComplex {

   # The splits that are coarsenings of the current [[TRIANGULATION]].
   # If the triangulation is regular these form the unique split decomposition of
   # the corresponding weight function.

   property REFINED_SPLITS : Set<Int>;

   # GKZ-vector 
   # 	See Chapter 7 in Gelfand, Kapranov, and Zelevinsky:
   # 	Discriminants, Resultants and Multidimensional Determinants, Birkhäuser 1994

   property GKZ_VECTOR : Vector<Scalar>;
   
   
   # For each facet the set of simplex indices of BOUNDARY that triangulate it.

   property FACET_TRIANGULATIONS : Array<Set>;
}

rule TRIANGULATION.VertexPerm.PERMUTATION = VertexPerm.PERMUTATION;

# @category Triangulation and volume
# For each simplex in the [[TRIANGULATION]], contains the sign of the determinant of its coordinate matrix, telling about its orientation.
# @return Array<Int>

user_method TRIANGULATION_SIGNS : TRIANGULATION.FACETS, VERTICES {
   my $this=shift;
   triang_sign($this->TRIANGULATION->FACETS, $this->VERTICES);
}

#rule TRIANGULATION.FACET_TRIANGULATIONS : TRIANGULATION.BOUNDARY.FacetPerm.FACET_TRIANGULATIONS, TRIANGULATION.BOUNDARY.FacetPerm.PERMUTATION {
#   $this->TRIANGULATION->FACET_TRIANGULATIONS=permuted_elements($this->VertexPerm->TRIANGULATION->FACET_TRIANGULATIONS, $this->TRIANGULATION_BOUNDARY->FacetPerm->PERMUTATION);
#}
#weight 1.20;

rule TRIANGULATION.FACET_TRIANGULATIONS : FacetPerm.TRIANGULATION.FACET_TRIANGULATIONS, FacetPerm.PERMUTATION {
   $this->TRIANGULATION->FACET_TRIANGULATIONS=permuted($this->FacetPerm->TRIANGULATION->FACET_TRIANGULATIONS, $this->FacetPerm->PERMUTATION);
}
weight 1.10;

### FIXME: $apply_diff{FACETS}=\&permuted;


# @category Triangulation and volume
# Polytopal Subdivision of the polytope using only its vertices.
# Each line contains indices from [[VERTICES]] comprising a facet of the subdivision.

property POLYTOPAL_SUBDIVISION : Array<Set>;

rule POLYTOPAL_SUBDIVISION : VertexPerm.POLYTOPAL_SUBDIVISION, VertexPerm.PERMUTATION {
   $this->POLYTOPAL_SUBDIVISION=permuted_elements($this->VertexPerm->POLYTOPAL_SUBDIVISION, $this->VertexPerm->PERMUTATION);
}
weight 1.20;


# @category Triangulation and volume
# Similar to [[TRIANGULATION]], but using [[POINTS]].

property TRIANGULATION_INT : Array<Set>;


# @category Triangulation and volume
# Weight vector to construct a regular [[TRIANGULATION]].

property WEIGHTS : Vector<Scalar>;

# @category Triangulation and volume
# Tells that  [[WEIGHTS]] are generic.

property WEIGHTS_GENERIC : Bool;



# @category Combinatorics
# Minimal non-faces of a [[SIMPLICIAL]] polytope.

property MINIMAL_NON_FACES : Array<Set>;
### FIXME: $apply_diff{VERTICES}=\&permuted_elements;


# @category Visualization
# Reordered [[VERTICES_IN_FACETS]] for 2d and 3d-polytopes.
# Vertices are listed in the order of their appearance
# when traversing the facet border counterclockwise seen from outside of the polytope.
#
# For a 2d-polytope (which is a closed polygon), lists all vertices in the border traversing order.

property VIF_CYCLIC_NORMAL : Array< List<Int> >;

# @category Visualization
# Reordered [[DUAL_GRAPH]] for 3d-polytopes.
# The neighbor facets are listed in the order corresponding to [[VIF_CYCLIC_NORMAL]],
# so that the first two vertices in VIF_CYCLIC_NORMAL make up the ridge to the first neighbor
# facet and so on.

property NEIGHBOR_FACETS_CYCLIC_NORMAL : Array< List<Int> >;

# @category Visualization
# Reordered transposed [[VERTICES_IN_FACETS]]. Dual to [[VIF_CYCLIC_NORMAL]].

property FTV_CYCLIC_NORMAL : Array< List<Int> >;

# @category Visualization
# Reordered [[GRAPH]]. Dual to [[NEIGHBOR_FACETS_CYCLIC_NORMAL]].

property NEIGHBOR_VERTICES_CYCLIC_NORMAL : Array< List<Int> >;

# @category Basic properties
# Unique names assigned to the [[VERTICES]].
# If specified, they are shown by visualization tools instead of vertex indices.
#
# For a polytope build from scratch, you should create this property by yourself,
# either manually in a text editor, or with a client program.
#
# If you build a polytope with a construction function
# taking some other input polytope(s), you can create the labels automatically if you
# call the function with a //relabel// option. The exact format of the labels is dependent on the
# construction, and is described in the corresponding help topic.
# @option Bool relabel

property VERTEX_LABELS : Array<String> : mutable;

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

# Find the vertices by given labels.
# @param String label vertex labels ***DOC_FIXME*** any number of Strings as parameters
# @return Set<Int> vertex indices

user_method labeled_vertices {
   my $this=shift;
   if (defined (my $labels=$this->lookup("VERTEX_LABELS"))) {
      new Set([ find_labels($labels, @_) ]);
   } else {
      die "No VERTEX_LABELS stored in this complex";
   }
}


# @category Basic properties
# Unique names assigned to the [[FACETS]], analogous to [[VERTEX_LABELS]].

property FACET_LABELS : Array<String> : mutable;

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

# The splits of the polytope, i.e., hyperplanes cutting the polytope in
# two parts such that we have a regular subdivision.

property SPLITS : Matrix<Scalar>;

# Two [[SPLITS]] are compatible if the defining hyperplanes do not intersect in the
# interior of the polytope.  This defines a graph.

property SPLIT_COMPATIBILITY_GRAPH : objects::Graph;

# The splits that are coarsenings of the current [[POLYTOPAL_SUBDIVISION]].
# If the subdivision is regular these form the unique split decomposition of
# the corresponding weight function.

property SPLITS_IN_SUBDIVISION : Set<Int>;

# @category Oriented matroids
# Chirotope corresponding to the [[VERTICES]]

property CHIROTOPE : Text;

}

# @category Coordinate conversions
# provide a Polytope object with desired coordinate type
# @tparam Coord target coordinate type
# @param Polytope P source object
# @return Polytope<Coord> //P// if it already has the requested type, a new object otherwise

user_function convert_to<Coord>(Polytope) {
   my $target_type=typeof Coord;
   if ($_[0]->type->param==$target_type) {
      $_[0]
   } else {
      new Polytope<Coord>($_[0]);
   }
}

# @category Coordinate conversions
# dehomogenize the [[VERTICES|vertex coordinates]] and convert them to Float
# @param Polytope P source object
# @return Matrix<Float>

user_function affine_float_coords(Polytope) {
   my $P=shift;
   if (!$P->BOUNDED) {
      croak("polytope must be bounded");
   }
   dehomogenize(convert_to<Float>($P->VERTICES));
}


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