/* 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: vertex_permutation.cc,v 1.26 2004/09/20 16:13:39 gawrilow Exp $"

#include <Rational.h>
#include <Poly.h>
#include <Matrix.h>
#include <permutations.h>
#include <linalg.h>
#include <argv_options.h>

namespace polymake { namespace polytope {

namespace {

using namespace pm;

template <typename E>
void orthogonalize_facets(Matrix<E>& F, const Matrix<E>& AH, const Vector<E>& AH_sqrs)
{
   for (typename Entire< Rows< Matrix<E> > >::iterator f=entire(rows(F)); !f.at_end(); ++f) {
      typename Vector<E>::const_iterator s=AH_sqrs.begin();
      for (typename Entire< Rows< Matrix<E> > >::const_iterator a=entire(rows(AH)); !a.at_end(); ++a, ++s) {
	 const E x= f->slice(1) * a->slice(1);
	 if (x) *f -= (x/(*s)) * (*a);
      }
   }
}

template <typename Matrix1, typename Matrix2> inline
void canonicalize(GenericMatrix<Matrix1>& M1, GenericMatrix<Matrix2>& M2)
{
   canonicalize(entire(rows(M1)));
   canonicalize(entire(rows(M2)));
}

template <typename Matrix1, typename Matrix2> inline
void canonicalize(GenericMatrix<Matrix1, double>&, GenericMatrix<Matrix2, double>&) { }

template <typename Matrix1, typename Matrix2> inline
Array<int> get_permutation(const GenericMatrix<Matrix1>& M1, const GenericMatrix<Matrix2>& M2)
{
   return find_permutation(rows(M1), rows(M2));
}

template <typename Matrix1, typename Matrix2> inline
Array<int> get_permutation(GenericMatrix<Matrix1, double>& M1, GenericMatrix<Matrix2, double>& M2)
{
   normalize(entire(rows(M1)));
   normalize(entire(rows(M2)));
   return find_permutation(rows(M1), rows(M2), operations::cmp_epsilon());
}

} // end anonymous namespace

template <typename Coord>
void vertex_permutation(Poly& p, const char *perm_section, const char *matrix1, const char *matrix2)
{
   Matrix<Coord> M1=p.give(matrix1),
                 M2=p.give(matrix2);
   const Array<int> perm=get_permutation(M1, M2);
   p.take(perm_section) << perm;
}

template <typename Coord>
void facet_permutation(Poly& p, const char *perm_section, const char *matrix1, const char *matrix2)
{
   Matrix<Coord> M1=p.give(matrix1),
                 M2=p.give(matrix2),
                 AH=p.give("AFFINE_HULL");
   if (AH.rows()) {
      Vector<Coord> AH_sqrs(AH.rows());
      orthogonalize_affine(entire(rows(AH)), AH_sqrs.begin());
      orthogonalize_facets(M1, AH, AH_sqrs);
      orthogonalize_facets(M2, AH, AH_sqrs);
   }
   canonicalize(M1, M2);
   const Array<int> perm=get_permutation(M1, M2);
   p.take(perm_section) << perm;
}

} }

using namespace polymake;

int main(int argc, const char *argv[])
{
   argv_option options[]={ { "-primal" }, { "-dual" } };
   enum { primal, dual };
   if (argc!=6 || !extract_options(argc,argv,1,options) || argc!=5) {
      cerr << "usage: " << argv[0] << " <file> <perm> <old> <new> { -primal, -dual }" << endl;
      return 1;
   }
   try {
      Poly p(argv[1], ios::in | ios::out);
      if (p.isa("RationalPolytope")) {
	 if (options[primal])
	    polytope::vertex_permutation<Rational>(p, argv[2], argv[3], argv[4]);
	 else
	    polytope::facet_permutation<Rational>(p, argv[2], argv[3], argv[4]);

      } else if (p.isa("FloatPolytope")) {
	 p.lookup("EPSILON") >> conv<double,bool>::global_epsilon;
	 if (options[primal])
	    polytope::vertex_permutation<double>(p, argv[2], argv[3], argv[4]);
	 else
	    polytope::facet_permutation<double>(p, argv[2], argv[3], argv[4]);

      } else {
	 throw std::runtime_error("don't know how to proceed with " + p.type());
      }
   }
   catch (const std::exception& e) {
      cerr << e.what() << endl;
      return 1;
   }
   return 0;
}
