/* 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: polarize.cc 10061 2011-03-16 12:46:53Z herr $
*/

#include "polymake/client.h"
#include "polymake/Matrix.h"
#include "polymake/Array.h"
#include "polymake/IncidenceMatrix.h"
#include "polymake/linalg.h"

namespace polymake { namespace polytope {

template <typename Scalar>
perl::Object polarize(perl::Object p_in, perl::OptionSet options)
{
   bool some_section_read = false;
   const bool no_coordinates=options["noc"];

   perl::Object p_out("Polytope<Rational>");
   p_out.set_description() << "Polytope polarized from " << p_in.name() << endl;

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

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

      Matrix<Scalar> ineq, AH;
      std::string got_property;
      if (p_in.lookup_with_property_name("VERTICES | POINTS", got_property) >> ineq) {
         ineq.minor(All, range(1,ineq.cols()-1)).negate();
         p_out.take( got_property=="VERTICES" ? "FACETS" : "INEQUALITIES") << ineq;
         p_out.take("AFFINE_HULL") << AH;
         some_section_read = true;
      }

      Matrix<Scalar> pts;
      if (p_in.lookup_with_property_name("FACETS | INEQUALITIES", got_property) >> pts) {
         pts.minor(All, range(1,pts.cols()-1)).negate();
         p_out.take( got_property=="FACETS" ? "VERTICES" : "POINTS") << 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<Scalar> tau;
      if (p_in.get_attachment("REVERSE_TRANSFORMATION") >> tau)
         p_out.attach("REVERSE_TRANSFORMATION") << T(inv(tau));
        
      // now let's claim that the result is bounded, centered, and full-dimensional
      p_out.take("BOUNDED") << true;
      p_out.take("CENTERED") << true;
      p_out.take("CONE_AMBIENT_DIM") << ambient_dim+1;
      p_out.take("CONE_DIM") << dim+1;
   }

   Array<std::string> labels;
   if (p_in.lookup("VERTEX_LABELS") >> labels)
      p_out.take("FACET_LABELS") << labels;
   if (p_in.lookup("FACET_LABELS") >> labels)
      p_out.take("VERTEX_LABELS") << labels;

   return p_out;
}

UserFunctionTemplate4perl("# @category Transforming a polyhedron"
                          "# Given a bounded, centered, and full-dimensional polytope //P//, produce its polar,"
                          "# that is, polar with respect to the standard Euclidean scalar product."
                          "# @param Polytope P"
                          "# @option Bool noc only combinatorial information is handled"
                          "# @return Polytope",
                          "polarize<Scalar> (Polytope<Scalar>, { noc => 0 })");
} }

// Local Variables:
// mode:C++
// c-basic-offset:3
// indent-tabs-mode:nil
// End:
