/* Copyright (c) 1997-2010
   Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Darmstadt, Germany)
   http://www.polymake.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.
--------------------------------------------------------------------------------
   $Project: polymake $$Id: is_sphere_h_impl.cc 10012 2011-01-12 23:19:57Z gawrilow $
*/

#include "polymake/topaz/is_sphere_h.h"

namespace polymake { namespace topaz {

bool is_sphere_h(const HasseDiagram& HD, const pm::SharedRandomState& random_source, int strategy, const int n_stable_rounds)
{
   const int dim = HD.dim()-1;

   // strategic options
   int max_relax=0, heating=0, preheat=0;
  
   if (strategy == 0) {
      max_relax= 70;
      heating= 30;
      preheat= 30;
   }
  
   if (strategy == 1) {
      max_relax= 120;
      heating= 50;
      preheat= 70;
   }
  
   BistellarComplex BC(HD,random_source,false,true);
  
   int stable_rounds = 0;
   int relax = 0;
   int neg_relax = 0;
   int full_dim_move = preheat;
   int chilly_moves = 0;
   int up_moves = 0;
   int warm_moves = preheat;
   int min_facets = BC.n_facets();
  
   for ( ; stable_rounds<n_stable_rounds; ++stable_rounds) {
      //    cerr << "stable_rounds: " << stable_rounds << "     min_facets: " << min_facets << endl;

      const int facets = BC.n_facets();
      if (facets < min_facets) {
         min_facets = facets;
         stable_rounds = 0;
      }

      if (facets == dim+2)  // is sphere
         return true;
    
      if (relax < neg_relax)
         relax = 0;
    
      if (relax > max_relax) {  // heating up
         relax = 0;
         up_moves = heating;
         warm_moves = heating;
         if (strategy == 1)
            chilly_moves = heating;
      }
    
      if (full_dim_move > 0) {
         --full_dim_move;  
         BC.zero_move();
         continue;
      }
    
      if (chilly_moves > 0) {
         --chilly_moves;   
         BC.min_rev_move(dim-1);  // very hot move indeed
         continue;
      }
    
      if (up_moves > 0) {
         --up_moves;       
         BC.min_rev_move(dim/2 + 1);  // up move
         continue;
      }
    
      if (warm_moves > 0) {
         --warm_moves;
         BC.min_rev_move(dim/2);  // up or eaven move
         continue;
      }
    
      // make smallest reversed move
      const int move = BC.min_rev_move();
    
      if ( move >= (dim+1)/2 && move != 0 ) {  // up or eaven move
         neg_relax = 0;
         ++relax;
      }
    
      else
         ++neg_relax;
   }
  
   return false;
}  

bool is_ball_or_sphere_h(const HasseDiagram& HD, const pm::SharedRandomState& random_source, const int strategy, const int n_stable_rounds)
{
  const Boundary_of_PseudoManifold B=boundary_of_pseudo_manifold(HD);
  if (B.empty())
    return is_sphere_h(HD, random_source, strategy, n_stable_rounds);

  // compute C + cone(bound(C))
  std::list< Set<int> > S;
  int v=0;
  
  for (Entire<HasseDiagram::nodes_of_dim_set>::const_iterator f=entire(HD.nodes_of_dim(HD.dim()-1));
       !f.at_end(); ++f) {
    S.push_back(HD.face(*f));
    const int w=HD.face(*f).back();
    if (w>=v)
      v=w+1;
  }
  
  for (Entire<Boundary_of_PseudoManifold>::const_iterator b=entire(B);
       !b.at_end(); ++b)
    S.push_back(*b+v);
  
  return is_sphere_h(S, random_source, strategy, n_stable_rounds);
}

} }

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