/* Copyright (c) 1997-2006
   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: zonotope_facets.cc,v 1.2 2006/03/09 16:21:35 gawrilow Exp $"

#include <Poly.h>
#include <Rational.h>
#include <Matrix.h>
#include <Set.h>
#include <PowerSet.h>
#include <Map.h>
#include <CubeFacets.h>
#include <linalg.h>

namespace polymake { namespace polytope {
  
void zonotope_facets(Poly& p)
{
   const Matrix<Rational> Zones=p.give("ZONOTOPE_INPUT_VECTORS");

   const int dim=Zones.cols()-1;
   const int n_zones = Zones.rows();
   const sequence set = sequence(0,n_zones);
   bool general_position = true;

   Set< Vector<Rational> > Facets;
   Set< Vector<Rational> > Vertices;
   
   for (Entire< Subsets_of_k< sequence > >::const_iterator si = entire(all_subsets_of_k(set,dim-1)); 
	!si.at_end(); ++si) { //, ++fi) {
      Vector< Rational > facet(dim+1);
      int sign = -1;
      for( int i = 1; i <= dim; ++i, sign *= -1 ) {
	 // (*fi)[i] = sign*det(Zones.minor(*si,sequence(1,dim)-i));
	 facet[i] = sign*det(Zones.minor(*si,sequence(1,dim)-i));
      }

      Vector<Rational> facet_center(dim+1);
      Set<int> subset(*si);

      Set<int> complement = set-subset;
      for( Entire< Set<int> >::const_iterator zi = entire(complement); !zi.at_end(); ++zi) {
	 Rational scalar_product = (Zones[*zi])*facet;
	 if(scalar_product == 0) {
	    general_position = false;
	    subset += *zi;
	 } else {
	    facet_center += (scalar_product>0?1:-1)*(Zones[*zi]);
	 }
      }
      // (*fi)[0] = facet_center * (*fi);
      facet[0] = facet_center * facet;
      Facets += facet;
      //      const Vector<Rational> facet = *fi;
      //      (*(++fi)) = -facet; 
      //      (*fi)[0] *= -1;
      facet *= -1; facet[0] *= -1;
      Facets += facet;

      //Calculate the 2^(dim-1) vertices of each facet.
      for(int i = 0; i < 1<<(subset.size()); ++i) {
	 Vector<Rational> vertex = facet_center;
	 int j = 0;
	 for(Entire< Set< int > >::const_iterator zi = entire(subset); !zi.at_end(); ++zi, ++j) {
	    vertex += ((i/(1<<j)%2)?1:-1)*(Zones[*zi]);
	 }
	 
	 vertex[0] = 1;
	 Vertices += vertex;
	 vertex *= -1;
	 vertex[0] = 1;
	 Vertices += vertex;
      }
   }
   if(general_position) {
      p.take("VERTICES") << as_array(Vertices);
      p.take("FACETS") << as_array(Facets);
   } else {
      p.take("POINTS") << as_array(Vertices);
      p.take("INEQUALITIES") << as_array(Facets);
   }
}

} }

using namespace polymake;

/** @file zonotope_facets
 *
 *  Produce a zonotope from given vectors.
 *  The zonotope is obtained as the iterated Minkowski sum of all intervals $[-x,x]$,
 *  where $x$ ranges over the rows of a given matrix. If the input vectors are in general
 *  position VERTICES and FACETS are written, otherwise POINTS and INEQUALITIES
 *
 *  @synopsis zonotope_facets <file>
 *
 *  @reading  ZONOTOPE_INPUT_VECTORS
 *  @writing  VERTICES, FACETS or POINTS, INEQUALITIES
 *
 *  @index clients Producing from given data
 */

int main(int argc, char *argv[])
{
   if (argc!=2) {
      cerr << "usage: " << argv[0] << " <file>" << endl;
      return 1;
   }
   try {
      Poly p(argv[1], ios::in | ios::out);
      polytope::zonotope_facets(p);
   }
   catch (const std::exception& e) {
      cerr << e.what() << endl;
      return 1;
   }
   return 0;
}
