/* Copyright (c) 1997-2004
   Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Berlin, Germany)
   http://www.math.tu-berlin.de/polymake,  mailto:polymake@math.tu-berlin.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.
*/

#ident "$Project: polymake $$Id: facet.cc,v 1.19 2004/06/22 16:23:09 gawrilow Exp $"

#include <cstdlib>
#include <argv_options.h>
#include <labels.h>
#include <Array.h>
#include <Rational.h>
#include <Poly.h>
#include <Matrix.h>
#include <IncidenceMatrix.h>
#include <Graph.h>

enum { no_coordinates, relabel };

namespace polymake {
namespace polytope {

void facet(Poly& p_out, Poly& p_in, int facet_number, const argv_option* options)
{
   const IncidenceMatrix<> VIF=p_in.give("VERTICES_IN_FACETS");
   const Graph<> DG=p_in.give("DUAL_GRAPH");
   const int n_vertices=VIF.cols(), n_facets=VIF.rows();

   if (facet_number < 0 || facet_number >= n_facets)
      throw std::runtime_error("facet number out of range");

   const int n_vertices_out=VIF[facet_number].size();

   IncidenceMatrix<> VIF_out=VIF.minor(DG.neighbors(facet_number), VIF[facet_number]);
   p_out.take("VERTICES_IN_FACETS") << VIF_out;

   if (options[no_coordinates]) {
      if (p_in.exists("DIM")) {
	 const int dim=p_in.give("DIM");
	 p_out.take("DIM") << dim-1;
      }
   } else {
      const Matrix<Rational> V=p_in.give("VERTICES"),
	                     F=p_in.give("FACETS"),
	                     AH=p_in.give("AFFINE_HULL");
      p_out.take("VERTICES") << V.minor(VIF[facet_number],All);
      p_out.take("AFFINE_HULL") << AH / F[facet_number];
   }

   if (options[relabel]) {
      Array<std::string> labels(n_vertices);
      read_labels(p_in, "VERTEX_LABELS", labels.begin(), n_vertices);
      Array<std::string> labels_out(n_vertices_out, select(labels,VIF[facet_number]).begin());
      p_out.take("VERTEX_LABELS") << labels_out;
   }
}

} }

using namespace polymake;

/** @file facet
 *
 *  Extract the given facet of a polyhedron and write it as a new polyhedron.
 *  $n$ is the number of the chosen facet.
 *
 *  If the option @c -noc (no coordinates) is specified, only combinatorial description is
 *  produced.
 *
 *  The option @c -relabel creates an additional section @see VERTEX_LABELS.
 *  The vertices belonging to the extracted facet keep their labels from the original polytope.
 *
 *  @synopsis facet <output_file> <input_file> <n> [ -noc ] [ -relabel ]
 *
 *  @reading  VERTICES, VERTICES_IN_FACETS
 *  @writing  VERTICES, VERTICES_IN_FACETS
 *
 *  @index clients Producing a new polyhedron from others
 */

int main(int argc, const char *argv[]) {
   argv_option options[]={ { "-noc" }, { "-relabel" } };
   if (!extract_options(argc,argv,3,options)) {
      cerr << "usage: " << argv[0] << " <output file> <input file> <facet number> [ -noc ] [ -relabel ]" << endl;
      return 1;
   }
   try {
      Poly p_in(argv[2], ios::in);
      Poly p_out(argv[1], ios::out | ios::trunc);
      int facet_number=atoi(argv[3]);
      polytope::facet(p_out, p_in, facet_number, options);
   }
   catch (const std::exception& e) {
      cerr << e.what() << endl;
      return 1;
   }
   return 0;
}
