/* 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: wedge.cc,v 1.29 2004/06/22 16:23:08 gawrilow Exp $"

#include <cstdlib>
#include <argv_options.h>
#include <labels.h>
#include <vector>
#include <Poly.h>
#include <Rational.h>
#include <Vector.h>
#include <Matrix.h>
#include <IncidenceMatrix.h>

namespace {
   enum { no_coordinates=0, relabel=1 };
}

namespace polymake { namespace polytope {

Matrix<Rational>
wedge_coord(const Matrix<Rational>& V,
	    const Vector<Rational>& z0,
	    const IncidenceMatrix<>& VIF,
	    int edge_facet,
	    const Rational& z,
	    const Rational& z_prime);

void wedge(Poly& p_out, Poly& p_in, const int& edge_facet, const Rational& z, const Rational& z_prime, 
	   const argv_option* options)
{
   if (!options[no_coordinates] && z==z_prime)
      throw std::runtime_error("wedge: z and z' must not be equal");

   const IncidenceMatrix<> VIF=p_in.give("VERTICES_IN_FACETS");
   const int n_vertices=VIF.cols(), n_facets=VIF.rows();

   if (edge_facet < 0 || edge_facet >= n_facets)
      throw std::runtime_error("wedge : edge facet number out of range");
    
   const int n_vertices_edge=VIF[edge_facet].size(),
             n_vertices_out= 2*n_vertices-n_vertices_edge;

   IncidenceMatrix<> VIF_out=
      (VIF | VIF.minor(All, ~VIF[edge_facet])) // side facet = original facet + its clone - intersection with the edge
      / range(0,n_vertices-1);		  // bottom facet = original polytope

   // top facet = edge facet + all clones
   VIF_out[edge_facet]+=range(n_vertices,n_vertices_out-1);

   p_out.take("N_VERTICES") << VIF_out.cols(); 
   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");
      const Vector<Rational> z0=p_in.give("VERTEX_BARYCENTER");
      const Matrix<Rational> V_out=wedge_coord(V,z0,VIF,edge_facet,z,z_prime);
      p_out.take("VERTICES") << V_out;
      p_out.take("BOUNDED") << true;
   }
    
   if (options[relabel]) {
      std::vector<std::string> labels(n_vertices_out);
      read_labels(p_in, "VERTEX_LABELS", labels.begin(), n_vertices);
      const std::string tick="'";
      std::copy(entire(attach_operation(select(labels, sequence(0,n_vertices)-VIF[edge_facet]),
					constant(tick), operations::add())),
		labels.begin()+n_vertices);
      p_out.take("VERTEX_LABELS") << labels;
   }
}
  
} }
using namespace polymake;

/** @file wedge
 *
 *  Make a wedge from a polytope over its facet.
 *
 *  $facet$ is the number of the `cutting edge' facet. The inclination of the bottom and top side facet
 *  is controlled by $z$ and $z'$ paremeters, where $z$ is the height of the projection of the old vertex
 *  barycenter on the bottom side facet, and $z'$ - on the top one.
 *
 *  Default heights are $[0,1]$; if only $z$ is specified and non-zero, then $z'$ defaults to $-z$.
 *
 *  The polytope must be bounded.
 *
 *  If the option @c -noc (no coordinates) is set, then only combinatorial information
 *  is handled.
 *
 *  The option @c -relabel creates an additional section @see VERTEX_LABELS.
 *  The bottom facet vertices get the labels from the original polytope;
 *  the labels of their clones in the top facet get a tick (') appended.
 *
 *  @synopsis wedge <output_file> <input_file> <facet> [ <z> [ <z'> ] | -noc  ] [ -relabel ]
 *
 *  @reading  DIM, VERTICES_IN_FACETS or BOUNDED, VERTICES, VERTEX_BARYCENTER or both
 *  @writing  DIM, N_VERTICES, VERTICES_IN_FACETS or BOUNDED, VERTICES or both
 *
 *  @index clients Producing a new polyhedron from others
 *
 *  @author Kerstin Fritzsche (initial version)
 */

int main(int argc, const char* argv[]) {
   argv_option options[]={ { "-noc" }, { "-relabel" } };
   if (!extract_options(argc,argv,3,options) ||
       argc > (options[no_coordinates] ? 4 : 6)) {
     cerr << "usage: " << argv[0] << " <out_file> <in_file> <facet> [ <z> [ <z'> ] | -noc ] [ -relabel ]" << endl;
     return 1;
   }
   try {
      const Rational z= argc>4 ? Rational(argv[4]) : Rational(0);
      const Rational z_prime= argc>5 ? Rational(argv[5]) : z ? -z : Rational(1);

      Poly p_in(argv[2], ios::in);
      Poly p_out(argv[1], ios::out | ios::trunc);
      const int facet = atoi(argv[3]);
      polytope::wedge(p_out, p_in, facet, z, z_prime, options);
   }
   catch (const std::exception& e) {
      cerr << e.what() << endl;
      return 1;
   }
   return 0;
}
