/* 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: minkowski_sum.cc,v 1.16 2004/09/20 16:35:37 gawrilow Exp $"

#include <Rational.h>
#include <Poly.h>
#include <linalg.h>

namespace polymake { namespace polytope {

namespace {

template <typename E, typename Matrix1, typename Matrix2>
Matrix<E>
minkowski_sum(const GenericMatrix<Matrix1,E>& A, const GenericMatrix<Matrix2,E>& B)
{
   Matrix<E> result(A.rows()*B.rows(), A.cols(),
		    product(rows(A), rows(B), operations::add()).begin());
   result.col(0).fill(1);
   return result;
}

}

void minkowski_sum(Poly& p_out, Poly& p_in1, Poly& p_in2)
{
   const Matrix<Rational> V1=p_in1.give("VERTICES | POINTS"),
                          V2=p_in2.give("VERTICES | POINTS");

   if (V1.cols() != V2.cols())
      throw std::runtime_error("dimension mismatch");

   const Set<int> rays1=far_points(V1),
	          rays2=far_points(V2);

   const Matrix<Rational> P= rays1.empty() && rays2.empty()
	                     ? minkowski_sum(V1,V2)
	                     : minkowski_sum(V1.minor(~rays1,All), V2.minor(~rays2,All)) /
	                       V1.minor(rays1,All) /
	                       V2.minor(rays2,All) ;

   p_out.take("POINTS") << P;
}

} }

using namespace polymake;

/** @file minkowski_sum
 *
 *  Construct a new polytope as the Minkowski sum of two given ones.
 *  Unbounded polyhedra are allowed.
 *
 *  @synopsis minkowski_sum <output_file> <input_file_1> <input_file_2>
 *
 *  @reading  VERTICES | POINTS
 *  @writing  POINTS
 *
 *  @index clients Producing a new polyhedron from others
 */

int main(int argc, char *argv[]) {
   if (argc != 4) {
      cerr << "usage: " << argv[0] << " <out_file> <in_file_1> <in_file_2>" << endl;
      return 1;
   }
   try {
      Poly p_out(argv[1], ios::out | ios::trunc);
      Poly p_in1(argv[2], ios::in);
      Poly p_in2(argv[3], ios::in);
      polytope::minkowski_sum(p_out, p_in1, p_in2);
   }
   catch (const std::exception& e) {
      cerr << e.what() << endl;
      return 1;
   }
   return 0;
}
