/* 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: cube_complex.cc,v 1.13 2004/10/26 18:57:02 gawrilow Exp $"

#include <Poly.h>
#include <Array.h>
#include <Matrix.h>
#include <Vector.h>
#include <Set.h>
#include <MultiDimCounter.h>

#include <list>
#include <algorithm>

namespace polymake {
namespace topaz {

namespace {
  
// prodces a triangulated cube
std::list< Set<int> > triang_cube(const int lower_corner, const Array<int>& x_diff)
{
   std::list< Set<int> > cube;
   const int dim = x_diff.size();
   
   Array<int> path(dim);
   for (int i=0; i<dim; ++i)
      path[i] = i;
   
   // iterate over all monotonous paths from vertex 0 to vertex 2^dim - 1
   while (true) {
      Set<int> simplex;
      simplex += lower_corner;
      
      // follow path
      int vertex = 0;
      for (int i=0; i<dim; ++i) {
	 vertex |= 1<<path[i];
	 
	 // compute coordinates in the cube complex
	 int corner = lower_corner;
	 for (int j=0; j<dim; ++j)
	    if ((vertex&(1<<j)) != 0)
	       corner += x_diff[dim-j-1];
	 simplex += corner;
      }
      
      // add simplex
      cube.push_back(simplex);
      
      // generate next path
      if (!std::next_permutation(path.begin(), path.end()))  break;
   }
   
   return cube;
}

}

void cube_complex(Poly& p, const Array<int> x_param)
{
   const int dim = x_param.size();
   int n = x_param[dim-1];
   Array<int> x_diff(dim);
   x_diff[dim-1] = 1;

   for (int i=dim-2; i>=0; --i) {
      x_diff[i] = x_diff[i+1] * x_param[i+1];
      n *= x_param[i];
   }
   
   Matrix<int> Coordinates(n,dim);
   std::list< Set<int> > Pile;
   int corner=0;
   for (MultiDimCounter<false> counter(x_param); !counter.at_end(); ++corner, ++counter) {
      
      // compute coordinates
      std::copy(entire(*counter), Coordinates[corner].begin());
      
      // compute cube
      bool cube_corner = true;
      for (int i=0; i<dim; ++i)
	 if ((*counter)[i] == x_param[i]-1) {
	    cube_corner = false;
	    break;
	 }
      
      if (cube_corner) {
	 std::list< Set<int> > cube = triang_cube(corner, x_diff);
	 Pile.splice(Pile.end(), cube);
      }
   }
  
   std::ostringstream comment;
   for (int i=0; i<dim-1; ++i)
      comment << x_param[i]-1 << "x";
   comment << x_param[dim-1]-1 << " Pile of " << dim << "-dimensional triangulated cubes.";

   p.take("DESCRIPTION") << comment.str();
   p.take("FACETS") << as_array(Pile);
   p.take("DIM") << dim;
   p.take("GEOMETRIC_REALIZATION") << Coordinates;
   p.take("MANIFOLD") << 1;
   p.take("ORIENTED_PSEUDO_MANIFOLD") << 1;
   p.take("BALL") << 1;
}

} }

using namespace polymake;

/** @file cube_complex
 *
 *  Produces a triangulated pile of hyper cubes: Each cube is split into
 *  d! tetrahedra, and the tetrahedra are all grouped around one of the
 *  diagonal axes of the cube.
 *
 *  @synopsis cube_complex <file> <x_1> <x_2> .. <x_d>
 *
 *  @writing  DESCRIPTION, FACETS, GEOMETRIC_REALIZATION, MANIFOLD, ORIENTED_PSEUDO_MANIFOLD, PURE, DIM, BALL
 *
 *  @index clients Producing from scratch
 */

int main(int argc, const char* argv[])
{
   if (argc < 3) {
      cerr << "usage: " << argv[0] << " <file> <x_1> <x_2> .. <x_d>" << endl;
      return 1;
   }
   try {
      Poly p(argv[1], ios::out | ios::trunc, "topaz::default");

      Array<int> x_param(argc-2);
      for (int i=2; i<argc; ++i)
	 x_param[i-2] = atoi(argv[i]) + 1;
      
      topaz::cube_complex(p, x_param);
   } 
   catch (const std::exception& e) {
      cerr << e.what() << endl;
      return 1;
   }
   return 0;
}


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