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

#include <Poly.h>
#include <read_str_args.h>
#include <complex_tools.h>

#include <ext/hash_set>
#include <sstream>

namespace polymake {
namespace topaz {
  
void suspension(Poly& p_out, Poly& p_in, const char* in_complex_section, const int k,
	   const std::list<std::string> L_in, const bool no_labels, const std::string& comment)
{
   Array< Set<int> > C = p_in.give(in_complex_section);
   const Array<std::string> L = p_in.give("VERTEX_LABELS");
   Set<int> V = accumulate(C, operations::add());
   
   // computing the new vertex label
   Array<std::string> new_L(V.size() + 2*k);
   if (!no_labels) {
      
      std_ext::hash_set<std::string> old_L(L.size());
      int count = 0;
      for (Entire< Set<int> >::const_iterator v=entire(V);
	   !v.at_end(); ++v, ++count) {
	 new_L[count] = L[*v];
	 old_L.insert(L[*v]);
      }
      
      for (Entire< std::list<std::string> >::const_iterator l=entire(L_in);
	   !l.at_end(); ++l, ++count) {
	 if (old_L.find(*l) != old_L.end())
	    throw std::runtime_error("suspension: Input label not unique.");
	 new_L[count] = *l;
      }
      
      for ( ; count < V.size()+2*k; ++count) {
	 std::ostringstream label;
	 label << "apex_" << (count-V.size())/2;
	 if ( (count-V.size())%2 == 0 )  label << "+";
	 else                            label << "-";
	 
	 std::string l=label.str(), ll=l;
	 
	 // test if l is unique
	 int i=0;
	 while (old_L.find(ll) != old_L.end()) {
	    ++i;
	    label.str("");
	    label << l << "_" << i;
	    ll=label.str();
	 }
	 
	 new_L[count] = ll;
      }
   }  // end compute labels
   
   const Set<int> new_V = sequence(V.back()+1,2*k);
   const int orig_size=C.size();
   C.resize(orig_size * (1<<k));
   
   Set<int>::const_iterator s_it=new_V.begin();
   for (int i=0; i<k; ++i) {
      Array< Set<int> > SUS(C.size());
      
      int v1=*s_it;  ++s_it;
      int v2=*s_it;  ++s_it;
      for (int j=0; j < orig_size * (1<<i); ++j) {
	 Set<int> facet1=C[j], facet2=C[j];
	 facet1 += v1;
	 facet2 += v2;
	 SUS[2*j] = facet1;
	 SUS[2*j+1] = facet2;
      }
      C=SUS;
   }
   
   // update V
   V+=new_V;
   adj_numbering(C, V);
   
   p_out.take("DESCRIPTION") << comment;
   p_out.take("FACETS") << C;
   
   if (!no_labels)
      p_out.take("VERTEX_LABELS") << new_L;
}
   
} }

using namespace polymake;

/** @file suspension
 *
 *  Produce the $k$-suspension over a given simplicial complex.
 *
 *  Default for the parameter $k$ is 1.
 *
 *  The labels of the apexes may be specified. In case too few
 *  apexes are specified the client labels the remaining ones
 *  <i>apex_0+, apex_0-, apex_1+, apex_1-, ... </i>. In case one of the labels exists
 *  already, the client chooses a unique one by appending <i>_i</i>
 *  where $i$ is the smallest integer which makes the label unique.
 *
 *  The @c -nol flag tells the client not to write any labels.
 *
 *  @synopsis suspension <out_file> <in_file> <in_complex_section> [ <k> ] [ -l <l_1+> <l_1-> <l_2+> <l_2-> ... ] [ -nol ]
 *
 *  @reading  <in_complex_section>, VERTEX_LABELS
 *  @writing  DESCRIPTION, FACETS, may write VERTEX_LABELS
 *
 *  @index clients Producing a new simplicial complex from others
 */


int main(int argc, const char* argv[])
{
   if (argc < 4) {
      cerr << "usage: " << argv[0] << " <out_file> <in_file> <in_complex_section> [ <k> ] [ -l <l_1+> <l_1-> <l_2+> <l_2-> ... ] [ -nol ]" << endl;
      return 1;
   }
   try {
      Poly p_in(argv[2], ios::in);
      Poly p_out(argv[1], ios::out | ios::trunc, p_in.type());

      // reading k and the vertices.
      int k=1;                                   // default k=1
      std::list<std::string> L_in;
      if (argc>4) {                              // options given
	 if (!strcmp(argv[4],"-l")) {             // no k given
	    L_in = topaz::read_str_args(argc, argv, 5);
	 } else {                                 // k given
	    k=atoi(argv[4]);
	    L_in = topaz::read_str_args(argc, argv,  6);
	 }
      }

      // checking parameters
      if (k<1) {
	 cerr << argv[0] << ": k < 1 " << endl;
	 return 1;
      }

      if (size_t(2*k) < L_in.size()) {
	 cerr << "too many vertices specified." << endl;
	 return 1;
      }
      
      std::ostringstream comment;
      comment << k << "-suspension of " << argv[2] << ".";
      
      topaz::suspension(p_out, p_in, argv[3], k, L_in, !strcmp(argv[argc-1],"-nol"), comment.str());      
   }
   catch (const std::exception& e) {
      cerr << e.what() << endl;
      return 1;
   }
   return 0;
}


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