/* Copyright (c) 1997-2006
   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: polarize.cc,v 1.37 2006/03/07 18:06:42 gawrilow Exp $"

#include <Rational.h>
#include <argv_options.h>
#include <Poly.h>
#include <Matrix.h>
#include <transform.h>

enum { no_coordinates };

namespace polymake { namespace polytope {

void polarize (Poly& p_out, Poly& p_in, const std::string& comment, const argv_option* options)
{
   bool some_section_read = false;

   if (options[no_coordinates] || p_in.exists("VERTICES_IN_FACETS")) {
      const IncidenceMatrix<> VIF=p_in.give("VERTICES_IN_FACETS");
      p_out.take("VERTICES_IN_FACETS") << comment << T(VIF);
      some_section_read = true;
   }

   if (!options[no_coordinates]) {
      const bool is_bounded=p_in.give("BOUNDED"),
	         is_centered=p_in.give("CENTERED");
      const int  ambient_dim=p_in.give("AMBIENT_DIM"),
	         dim=p_in.give("DIM");
      if (!is_bounded || !is_centered || dim!=ambient_dim)
	 throw std::runtime_error("polarize: polytope must be bounded, centered, and full-dimensional");

      Matrix<Rational> ineq;
      if (p_in.lookup("VERTICES | POINTS") >> ineq) {
	 inv_sign(ineq.minor(All, range(1,ineq.cols()-1)));
	 p_out.take( p_in.given()=="VERTICES" ? "FACETS" : "INEQUALITIES") << comment << ineq;
	 p_out.take("AFFINE_HULL") << comment;
	 some_section_read = true;
      }

      Matrix<Rational> pts;
      if (p_in.lookup("FACETS | INEQUALITIES") >> pts) {
	 inv_sign(pts.minor(All, range(1,pts.cols()-1)));
	 p_out.take( p_in.given()=="FACETS" ? "VERTICES" : "POINTS") << comment << pts;
	 some_section_read = true;
      }

      // let's see if we produced something at all
      if (!some_section_read)
	 throw std::runtime_error("polarize: no useful coordinate section found in input");

      // if p was obtained by some transformation,
      // then the reverse transformation also makes sense for the polar
      Matrix<Rational> tau;
      if (p_in.lookup("REVERSE_TRANSFORMATION") >> tau) {
	 p_out.take("REVERSE_TRANSFORMATION") << comment << T(inv(tau));
      }
	
      // now let's claim that the result is bounded, centered, and full-dimensional
      p_out.take("BOUNDED") << comment << true;
      p_out.take("CENTERED") << comment << true;
      p_out.take("AMBIENT_DIM") << comment << ambient_dim;
      p_out.take("DIM") << comment << dim;
   }

   transform_copy_labels(p_out, p_in, comment, "FACET_LABELS", "VERTEX_LABELS");
   transform_copy_labels(p_out, p_in, comment, "VERTEX_LABELS", "FACET_LABELS");
}

} }

using namespace polymake;

/** @file polarize
 *
 *  Given a bounded, centered, and full-dimensional polytope $P$, produce its polar,
 *  that is, polar with respect to the standard Euclidean scalar product.
 *
 *  If the option @c -noc (no coordinates) is set, then only combinatorial 
 *  information is handled.
 *
 *  @synopsis polarize <output_file> <input_file> [-noc]
 *
 *  @reading  AMBIENT_DIM, DIM, BOUNDED, CENTERED, VERTICES | POINTS, FACETS | INEQUALITIES, REVERSE_TRANSFORMATION or VERTICES_IN_FACETS 
 *  @writing  AMBIENT_DIM, DIM, BOUNDED, CENTERED, VERTICES | POINTS, FACETS | INEQUALITIES, REVERSE_TRANSFORMATION or VERTICES_IN_FACETS
 *
 *  @index clients Transforming a polyhedron
 */

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