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

#include <Poly.h>
#include <Array.h>
#include <Set.h>
#include <complex_tools.h>

namespace polymake {
namespace topaz {
  
void is_vert_dec(std::ostream& os, Poly& p, const char* shedding_vertices_section)
{
   const Array< Set<int> > C = p.give("FACETS");
   int d; 
   p.give("DIM") >> d;
   const Array<int> ShedVert = p.give(shedding_vertices_section);

   if (ShedVert.empty()) {
      std::ostringstream e;
      e << "is_vert_dec: " << shedding_vertices_section << " is empty.";
      throw std::runtime_error(e.str());
   }
      
   // checking case d==0
   if (d==0) {
      Set<int> V = accumulate(C, operations::add());
      if (V.size() < ShedVert.size()) {
	 os << shedding_vertices_section << " is NOT a vertex decomposition.\nToo many shedding vertices specified." << endl;
	 return;
      }
      
      for (int i=0; i<ShedVert.size(); ++i)  V -= ShedVert[i];
      if (V.empty())
	 os << shedding_vertices_section << " is a vertex decomposition." << endl;
      else
	 os << shedding_vertices_section << " is NOT a vertex decomposition.\nThe complex is not completely decomposed." << endl;
      return;
   }

   // test whether C is a manifold
   bool is_MF=false;
   
   if (d>3)
      throw std::runtime_error("is_vert_dec: Dimension of the complex must be smaller 4.");
   
   if (d==1)
      is_MF=C1_is_manifold(C);
   if (d==2)
      is_MF=C2_is_manifold(C);
   if (d==3)
      is_MF=C3_is_manifold(os,C);
   if (!is_MF)
      throw std::runtime_error("is_vert_dec: Complex is not a manifold.");
   
   // compute the hasse diagram
   HasseDiagram<> HD = pure_hasse_diagram(C);
   
   // for all v in ShedVert
   os << "testing vertex:";
   for (int i=0; i<ShedVert.size(); ++i) {
      const int v=ShedVert[i];
      os << " " << v;
      
      // if the remaining complex consists of v only -> complex is decomposed
      if (HD.nodes_of_dim(0).size()==1) {
	 if (i!=ShedVert.size()-1)
	    os << "\n" << shedding_vertices_section << " is NOT a vertex decomposition.\n"
	       << "Too many shedding vertices specified." << endl;
	 else
	    os << "\n" << shedding_vertices_section << " is a vertex decomposition." << endl;
	 return;
      }
      
      // compute the vertices of link(v) and remove star(v) from HD
      const Set<int> V_of_link = vert_of_vertexLink(HD,v);
      remove_vertex_star(HD,v);
      
      // check the invariant:
      // dim == 0 -> true
      // dim > 0  -> HD is a manifold.
      const int dim = HD.dim()-1;
      if (dim==0)  continue;
      
      // it suffices to check the link for all vertices of link(v)
      for (Entire< Set<int> >::const_iterator it=entire(V_of_link); !it.at_end(); ++it) {
	 const int w=*it;
	 std::list< Set<int> > link = vertexLink_of_HD(HD,w);
	 
	 if (dim==1 && !link.empty() && link.size()<3) continue;
	 if (dim==2 && !link.empty() && C1_is_BOS(link)) continue;
	 if (dim==3 && !link.empty() && C2_is_BOS(link)) continue;
	 
	 os << "\n" << shedding_vertices_section << " is NOT a vertex decomposition.\n" 
	    << "The remaining complex is not a manifold." << endl;
	 return;
      }
   }  // end for all v in ShedVert
   
   os << "\n" << shedding_vertices_section << " is NOT a vertex decomposition.\n"
      << "The complex is not completely decomposed." << endl;
}
   
} }

using namespace polymake;

/** @file is_vert_dec
 *
 *  Check whether a given ordered subset of the vertex set is a vertex decomposition.
 *
 *  The client works for 1-, 2- and 3-manifolds only!
 *
 *  @synopsis is_vert_dec <file> <shedding_vertices_section>
 *
 *  @reading  FACETS, <shedding_vertices_section>, DIM
 *
 *  @index clients Other
 */ 

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


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