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

#include <ctime>
#include <argv_options.h>
#include <labels.h>
#include <vector>
#include <Rational.h>
#include <Poly.h>
#include <Matrix.h>
#include <Set.h>
#include <IncidenceMatrix.h>
#include <sstream>

namespace {
   enum { relabel=0 };
}

namespace polymake { namespace polytope {

namespace {

struct wreath_label {
   typedef const std::string first_argument_type;
   typedef const std::string second_argument_type;
   typedef const std::string result_type;
    
   result_type operator() (first_argument_type l1, second_argument_type l2) const {
      return l1 + '^' + l2;
   }
};
  
Matrix<Rational>
wreath_coord(const Matrix<Rational>& V1, const Matrix<Rational>& V2)
{
   const int n_vertices1(V1.rows()), n_vertices2(V2.rows()), dim1(V1.cols()-1), dim2(V2.cols()-1), d(n_vertices2*dim1+dim2+1);
   Matrix<Rational> V(n_vertices1*n_vertices2,d);
    
   for (int i=0; i<n_vertices1; ++i)
      for (int k=0; k<n_vertices2; ++k) {
	const int ik(i*n_vertices2+k);
	V(ik,0)=1;
	const int kd1(k*dim1); 
	int j(1);
	for ( ; j<=kd1; ++j) V(ik,j)=0;
	for ( ; j<=kd1+dim1; ++j) V(ik,j)=V1(i,j-kd1);
	for ( ; j<=n_vertices2*dim1; ++j) V(ik,j)=0;
	for ( ; j<d; ++j) V(ik,j)=V2(k,j-n_vertices2*dim1);
      }
    
   return V;
}
  
} // end unnamed namespace

void wreath (Poly& p_out, Poly& p_in1, Poly& p_in2, const argv_option* options)
{
   const Matrix<Rational> V1=p_in1.give("VERTICES"),
                          V2=p_in2.give("VERTICES");
   const int n_vertices1(V1.rows()), n_vertices2(V2.rows()),
             n_vertices_out(n_vertices1*n_vertices2);

   const Matrix<Rational> V_out=wreath_coord(V1, V2);
   p_out.take("VERTICES") << V_out;
   
   if (options[relabel]) {
      std::vector<std::string> labels1(n_vertices1), labels2(n_vertices2),
	                       labels_out(n_vertices_out);
      read_labels(p_in1, "VERTEX_LABELS", labels1.begin(), n_vertices1);
      read_labels(p_in2, "VERTEX_LABELS", labels2.begin(), n_vertices2);
      std::copy(entire(product(labels1, labels2, wreath_label())), labels_out.begin());
      p_out.take("VERTEX_LABELS") << labels_out;
   }
}

} }

using namespace polymake;

/** @file wreath
 *
 *  Construct a new polytope as the wreath product of two given ones.
 *  Unbounded polyhedra are not allowed.
 *
 *  If the option @c -noc (no coordinates) is set, only combinatorial information is handled.
 *
 *  The option @c -relabel creates an additional section @see VERTEX_LABELS.
 *  The label of a new vertex corresponding to $v_1 &oplus; v_2$ will
 *  have the form "$LABEL_1*LABEL_2$".
 *
 *  @synopsis wreath <output_file> <input_file_1> <input_file_2> [ -relabel ]
 *
 *  @reading  VERTICES
 *  @writing  VERTICES
 *
 *  @index clients Producing a new polyhedron from others
 */

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