/* 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: t_signature.cc,v 1.2 2005/10/04 17:19:58 witte Exp $"

#include <Poly.h>
#include <Matrix.h>
#include <Vector.h>
#include <Set.h>
#include <Graph.h>
#include <Array.h>
#include <linalg.h>
#include <Rational.h>

#include <list>


namespace polymake { namespace topaz {

void t_signature(Poly& p)
{
  const Graph<> DG=p.give("DUAL_GRAPH");
  Matrix<Rational> GR=p.give("GEOMETRIC_REALIZATION");
  Vector<Rational> homogenization(GR.rows(),Rational(1));
  GR = homogenization | GR;

  const int dim=p.give("DIM");
  const int g_dim=p.give("G_DIM");
  if (dim != g_dim)
    throw std::runtime_error("t_signature: DIM != G_DIM");

  const Array< Set<int> > F=p.give("FACETS");
  
  const int nodes=DG.nodes();
  bool bipartite = true;
  Array<int> color(nodes,0);  // coloring the nodes: 0 = not visited, -1/1 = colors
  std::list<int> node_queue;
  
  int sign = 0;
  //  Rational volume = Rational(0); 
  color[0] = -1;
  node_queue.push_back(0);
  
  while (!node_queue.empty()) {
    const int n=node_queue.front();
    node_queue.pop_front();
    
    //    volume += std::abs( det(GR.minor(F[n],All)) );

    if ( std::abs( (int)det(GR.minor(F[n],All)) )%2 == 1 )
      sign += color[n];

    for (Entire<Graph<>::out_edge_list>::const_iterator e=entire(DG.out_edges(n));
	 !e.at_end(); ++e) {
      const int nn=e.to_node();
      if (!color[nn]) {
	color[nn] = -color[n];
	node_queue.push_back(nn);
      } else
	if (color[nn]==color[n]) {
	  bipartite = false;
	  node_queue.clear();
	  break;
	}
    }
  }
  
  sign= bipartite ? std::abs(sign) : -1;
  
  //  cout << "\nSIGNATURE: " << sign
  //       << "\nVOLUME: " << volume << endl;
  p.take("SIGNATURE") << sign;
}
  
} }

using namespace polymake;

/** @file t_signature
 *
 *  Determine the signature of a embedded simplicial complex.
 *
 *  @synopsis t_signature <file>
 *
 *  @reading  DUAL_GRAPH, GEOMETRIC_REALIZATION, FACETS, DIM, G_DIM
 *  @writing  SIGNATURE
 *
 *  @author Niko Witte <witte@math.tu-berlin.de>
 */

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