//////////////////////////////////////////////////////////////////////////
//
// SymmetricExtensionGraphNode.cc
// produced: 03/12/2020 jr
//
/////////////////////////////////////////////////////////////////////////

#include "SymmetricExtensionGraphNode.hh"
#include "VertexFacetTable.hh"

namespace topcom {

  // static members:
  symmetry_table_type              SymmetricExtensionGraphNode::_symmetry_images_by_element;
  thread_local symmetry_cache_type SymmetricExtensionGraphNode::_symmetry_images_by_element_cache;

  // construct the root node with a given root partial triangulation
  // using the symmetry group to initialize the critical element table:

  SymmetricExtensionGraphNode::SymmetricExtensionGraphNode(const ConfData&       confdata,
							   const PartialTriang&  partial_triang,
							   const size_type       card) :
    _partial_triang(partial_triang),
    _card(card),
    _critsimpidx_table(),
    _seecount(0) {
    _populate_critsimpidx_table(confdata, partial_triang, card);
  }

  // the same, but with moving the passed partial triangulation:
  SymmetricExtensionGraphNode::SymmetricExtensionGraphNode(const ConfData& confdata,
							   PartialTriang&& partial_triang,
							   const size_type card) :
    _partial_triang(std::move(partial_triang)),
    _card(card),
    _critsimpidx_table(),
    _seecount(0) {
    _populate_critsimpidx_table(confdata, partial_triang, card);
  }

  // auxiliary function to avoid code duplication:
  void SymmetricExtensionGraphNode::_populate_critsimpidx_table(const ConfData& confdata,
								const PartialTriang& partial_triang,
								const size_type card) {
    if (CommandlineOptions::simpidx_symmetries()) {
      
      // here we use symmetries on simplex indices from simpidx_symmetries:
      try {
	_critsimpidx_table.resize(confdata.simpidx_symmetries().size(), std::numeric_limits<size_type>::max());
      }
      catch (...) {
	MessageStreams::forced() << message::lock
				 << "SymmetricExtensionGraphNode::SymmetricExtensionGraphNode(const SymmetryGroup&, const PartialTriang&): "
				 << "allocation of " << confdata.simpidx_symmetries().size() << " int elements failed - exiting"
				 << std::endl
				 << message::unlock;
	exit(1);
      }
      
      for (size_type symidx = 0; symidx < confdata.simpidx_symmetries().size(); ++symidx) {
	const Symmetry& g = confdata.simpidx_symmetries()[symidx];
	_critsimpidx_table.push_back(critical_simpidx(partial_triang, g, symidx));
      }
    }
    else {
      
      // here we use symmetries on points from valid_symmetries:
      try {
	_critsimpidx_table.resize(confdata.valid_symmetries().size(), std::numeric_limits<size_type>::max());
      }
      catch (...) {
	MessageStreams::forced() << message::lock
				 << "SymmetricExtensionGraphNode::SymmetricExtensionGraphNode(const SymmetryGroup&, const PartialTriang&): "
				 << "allocation of " << confdata.valid_symmetries().size() << " int elements failed - exiting"
				 << std::endl
				 << message::unlock;
	exit(1);
      }
      
      for (size_type symidx = 0; symidx < confdata.valid_symmetries().size(); ++symidx) {
	const Symmetry& g = confdata.valid_symmetries()[symidx];
	_critsimpidx_table.push_back(critical_simpidx_lean(partial_triang, g, symidx));
      }
    }
  }

  // functions:

  // the following is the core function:
  // it checks whether the child node of this node by extending subset by a new element
  // is lex-minimal; it is assumed that the new element is larger than all the existing
  // elements of subset; the critical element table is updated during the checking process
  // and returned if the extended subset is lex minimal:
  bool SymmetricExtensionGraphNode::child_is_lexmin(const ConfData&              confdata,
						    const PartialTriang&         new_partial_triang,
						    const Simplex&               new_simp,
						    critical_simpidx_table_type* new_critsimpidx_tableptr,
						    size_type*                   new_stabilizer_cardptr) const {
    const bool local_debug = false;

    *new_stabilizer_cardptr = 0UL;
    
    //////////////////////////////////////////////////////////////////////////////
    // disable the technique by answering the question without any smartness:
    //////////////////////////////////////////////////////////////////////////////
    // try {
    //   new_critsimpidx_tableptr->reserve(_critsimpidx_table.size());
    // }
    // catch (...) {
    //   MessageStreams::forced() << "std::pair<bool, CriticalSimpidxTable> SymmetricExtensionGraphNode::child_is_lexmin(const Simplex&, CriticalSimpidxTable*) const: "
    // 	      << "allocation of " << _critsimpidx_table.size() << " int elements failed - exiting"
    // 	      << std::endl;
    //   exit(1);
    // }
    // for (size_type idx = 0; idx < _symmetriesptr->size(); ++idx) {
    //   // if ((*_symmetriesptr)[idx].lex_decreases((_partial_triang + new_simp).index_set(_partial_triang.rank()))) {
    //   // return false;
    //   // }
    //   new_critsimpidx_tableptr->push_back(std::numeric_limits<parameter_type>::max());
    // }
    // return true;
    //////////////////////////////////////////////////////////////////////////////
    // end disable
    //////////////////////////////////////////////////////////////////////////////

    MessageStreams::debug() << message::lock
			    << "SymmetricExtensionGraphNode::child_is_lexmin(const Simplex& new_simp):" << '\n'
			    << "checking extension of partial triangulation " << _partial_triang
			    << " in node " << *this
			    << " by new_element " << new_simp << " ..."
			    << std::endl
			    << message::unlock;
    const parameter_type rank = confdata.rank();
    const size_type new_simpidx = SimplicialComplex::index_of_simplex(new_simp, rank);

    // generate a table to save the updated critical elements:
    try {
      
      // new_critsimpidx_tableptr->insert(new_critsimpidx_tableptr->begin(), _critsimpidx_table.begin(), _critsimpidx_table.end());
      new_critsimpidx_tableptr->reserve(_critsimpidx_table.size());
    }
    catch (...) {
      MessageStreams::forced() << message::lock
			       << "bool SymmetricExtensionGraphNode::child_is_lexmin(const Simplex&, CriticalSimpidxTable*) const: "
			       << "allocation of " << _critsimpidx_table.size() << " int elements failed - exiting"
			       << std::endl;
      exit(1);
    }
    const std::vector<size_type>& img_of_elm_vec = _symmetry_images_by_element[new_simpidx];
    for (size_type symidx = 0; symidx < confdata.simpidx_symmetries().size(); ++symidx) {
      const Symmetry& g = confdata.valid_symmetries()[symidx];
      const size_type& critsimpidx = _critsimpidx_table[symidx];

      // here we take advantage of the special representation of the group:
      // no simplex has to be mapped, just read the image index from the array
      // representing the permutation on simplex indices:
      const size_type& new_simpidx_image = img_of_elm_vec[symidx];
      ++_seecount;
      // const parameter_type& new_simpidx_image = g[new_simpidx];

      if (critsimpidx == std::numeric_limits<size_type>::max()) {

	// in case g(S) = S, the new critical element is the new element itself:
	if (new_simpidx_image < new_simpidx) {
	  return false;
	}
	if (new_simpidx_image > new_simpidx) {
	  new_critsimpidx_tableptr->emplace_back(new_simpidx);
	  continue;
	}

	// the current symmetry is in the stabilizer of the new partial triangulation,
	// which therefore is not lex-decreased:
	new_critsimpidx_tableptr->emplace_back(std::numeric_limits<size_type>::max());
	++(*new_stabilizer_cardptr);
	continue;
      }

      // the order on simplices in the IndexTable has to be used:
      if (new_simpidx_image == critsimpidx) {

	// this case is the complicated case:
	// the image g(new_simpidx) of the new element under the symmetry g
	// is equal to the critical simplex index,
	// thus, there is a new critical simplex index for g w.r.t. partial_triang union new_simp,
	// and we have to compute the new critical element from scratch:
	const size_type& new_critsimpidx = critical_simpidx(new_partial_triang, g, symidx);
	if (new_critsimpidx == std::numeric_limits<size_type>::max()) {

	  // in this case, the new partial triangulation is fixed, thus it is lex minimal,
	  // and the critical-element table needs an update:
	  new_critsimpidx_tableptr->emplace_back(std::numeric_limits<size_type>::max());
	  ++(*new_stabilizer_cardptr);
	  continue;
	}
	else {
	  if (new_partial_triang.index_set_pure().contains(new_critsimpidx)) {
	    
	    // in this case, the critical simplex is in the new partial triang,
	    // thus it is lex minimal with new critical simplex,
	    // and the critical-element table needs an update:
	    new_critsimpidx_tableptr->emplace_back(new_critsimpidx);
	    continue;
	  }
	  
	  // in this case, neither the new subset is fixed nor the new critical element is
	  // in the image of the new subset, thus the new subset is not lex-minimal:
	  return false;
	}
      }
      if (new_simpidx_image > critsimpidx) {

	// the image g(new_simpidx) of the new simplex index under the symmetry g
	// is strictly larger than the critical simplex index,
	// thus, partial_triang union new_simp is lex-smaller than g(partial_triang union new_simp),
	// the critical simplex remains unchanged,
	// and we continue with the next symmetry:
	new_critsimpidx_tableptr->emplace_back(critsimpidx);
	continue;
      }

      // the image g(new_simpidx) of the new simplex index under the symmetry g
      // is strictly smaller than the critical simplex index,
      // thus, g(partial_triang union new_simp) is lex-smaller than partial_triang union new_simp,
      // we do not need updated critical simplex indices,
      // we return false, and the table built so far is irrelevant:
      
      return false;
    }

    // we have not found any lex-decreasing symmetry;
    // in that case, all symmetries have been scanned,
    // and therefore all critical elements have been updated:
    return true;
  }
  
  bool SymmetricExtensionGraphNode::child_is_lexmin_lean(const ConfData&              confdata,
							 const PartialTriang&         new_partial_triang,
							 const Simplex&               new_simp,
							 critical_simpidx_table_type* new_critsimpidx_tableptr,
							 size_type*                   new_stabilizer_cardptr) const {
    const bool local_debug = false;
    *new_stabilizer_cardptr = 0UL;

    MessageStreams::debug() << message::lock
			    << "SymmetricExtensionGraphNode::child_is_lexmin_lean(const Simplex& new_simp):" << '\n'
			    << "checking extension of partial triangulation " << _partial_triang
			    << " in node " << *this
			    << " by new_element " << new_simp << " ..."
			    << std::endl
			    << message::unlock;
    
    // first, we compute the extended partial triangulation
    // (without all the expensive auxiliary data in PartialTriang):
    const parameter_type rank = confdata.rank();
    const size_type new_simpidx = SimplicialComplex::index_of_simplex(new_simp, rank);

    // generate a table to save the updated critical elements:
    try {
      new_critsimpidx_tableptr->reserve(_critsimpidx_table.size());
    }
    catch (...) {
      MessageStreams::forced() << message::lock
			       << "bool SymmetricExtensionGraphNode::child_is_lexmin_lean(const Simplex&, CriticalSimpidxTable*) const: "
			       << "allocation of " << _critsimpidx_table.size() << " int elements failed - exiting"
			       << std::endl
			       << message::unlock;
      exit(1);
    }

    // in the lean version, the symmetries in the node are the original symmetries on points;
    // this is a very tight loop so that if-statements independent on the loop variable
    // are evaluated outside the loop:
    if (CommandlineOptions::memopt()) {
      for (size_type symidx = 0; symidx < confdata.valid_symmetries().size(); ++symidx) {
	const Symmetry& g = confdata.valid_symmetries()[symidx];
	const size_type critsimpidx = _critsimpidx_table[symidx];
	size_type new_simpidx_image;
	if (CommandlineOptions::localcache() == 0) {
	  
	  // choose this branch if cache administration does not pay off:
	  new_simpidx_image = SimplicialComplex::index_of_simplex(g.map(new_simp), rank);
	  _seecount += rank;
	}
	else {

	  // choose this branch if non-zero thread-local cache is used:
	  const IndexPair index_pair(new_simpidx, symidx);
	  const size_type hash_value = Hash<IndexPair>()(index_pair);
	  const size_type cache_idx  = hash_value % _symmetry_images_by_element_cache.size();
	  symmetry_cache_entry_type& cache_entry_reference = _symmetry_images_by_element_cache[cache_idx];
	  if (cache_entry_reference.first == index_pair) {
	    new_simpidx_image = cache_entry_reference.second;
	    ++_seecount;
	  }
	  else {
	    new_simpidx_image = SimplicialComplex::index_of_simplex(g.map(new_simp), rank);
	    _seecount += rank;
	    cache_entry_reference = std::move(symmetry_cache_entry_type(index_pair, new_simpidx_image));
	  }
	}   

	// identical functionality from this point on:
	if (critsimpidx == std::numeric_limits<size_type>::max()) {
	  if (new_simpidx_image < new_simpidx) {
	    return false;
	  }
	  if (new_simpidx_image > new_simpidx) {
	    new_critsimpidx_tableptr->emplace_back(new_simpidx);
	    continue;
	  }
	  new_critsimpidx_tableptr->emplace_back(std::numeric_limits<size_type>::max());
	  ++(*new_stabilizer_cardptr);
	  continue;
	}
	if (new_simpidx_image == critsimpidx) {
	  const size_type new_critsimpidx = critical_simpidx_lean(new_partial_triang, g, symidx);
	  if (new_critsimpidx == std::numeric_limits<size_type>::max()) {
	    new_critsimpidx_tableptr->emplace_back(std::numeric_limits<size_type>::max());
	    ++(*new_stabilizer_cardptr);
	    continue;
	  }
	  else {
	    if (new_partial_triang.index_set_pure().contains(new_critsimpidx)) {
	      new_critsimpidx_tableptr->emplace_back(new_critsimpidx);
	      continue;
	    }
	    return false;
	  }
	}
	if (new_simpidx_image > critsimpidx) {
	  new_critsimpidx_tableptr->emplace_back(critsimpidx);
	  continue;
	}
	return false;
      }
    }
    else {
      for (size_type symidx = 0; symidx < confdata.valid_symmetries().size(); ++symidx) {

	// this branch is chosen if simplex indices can be stored on the fly completely:
	const Symmetry& g = confdata.valid_symmetries()[symidx];
	const size_type critsimpidx = _critsimpidx_table[symidx];
	size_type new_simpidx_image;
	if (_symmetry_images_by_element[new_simpidx][symidx] == std::numeric_limits<size_type>::max()) {
	  
	  // bring requested value into the table:
	  _symmetry_images_by_element[new_simpidx][symidx] = SimplicialComplex::index_of_simplex(g.map(new_simp), rank);
	  _seecount += rank;
	}

	// retrieve requested value from table:
	new_simpidx_image = _symmetry_images_by_element[new_simpidx][symidx];
	++_seecount;
	if (critsimpidx == std::numeric_limits<size_type>::max()) {
	  if (new_simpidx_image < new_simpidx) {
	    return false;
	  }
	  if (new_simpidx_image > new_simpidx) {
	    new_critsimpidx_tableptr->emplace_back(new_simpidx);
	    continue;
	  }
	  new_critsimpidx_tableptr->emplace_back(std::numeric_limits<size_type>::max());
	  ++(*new_stabilizer_cardptr);
	  continue;
	}
	
	// identical functionality from this point on:
	if (new_simpidx_image == critsimpidx) {
	  const size_type new_critsimpidx = critical_simpidx_lean(new_partial_triang, g, symidx);
	  if (new_critsimpidx == std::numeric_limits<size_type>::max()) {
	    new_critsimpidx_tableptr->emplace_back(std::numeric_limits<size_type>::max());
	    ++(*new_stabilizer_cardptr);
	    continue;
	  }
	  else {
	    if (new_partial_triang.index_set_pure().contains(new_critsimpidx)) {
	      new_critsimpidx_tableptr->emplace_back(new_critsimpidx);
	      continue;
	    }
	    return false;
	  }
	}
	
	if (new_simpidx_image > critsimpidx) {
	  new_critsimpidx_tableptr->emplace_back(critsimpidx);
	  continue;
	}
	return false;
      }
    }
    return true;
  }


  // auxiliary function to compute critical element from scratch for a symmetry on simplex indices:
  size_type SymmetricExtensionGraphNode::critical_simpidx(const SimplicialComplex& sc,
							  const Symmetry& g,
							  const size_type symidx) const {
    // const SimplicialComplex::IndexSet symdiff_idxset(sc.index_set_pure() ^ g.map(sc.index_set_pure()));
    // if (symdiff_idxset.empty()) {
    //   return std::numeric_limits<size_type>::max(); // an encoding for infinity
    // }
    // else {
    //   return symdiff_idxset.min_elem();
    // }

    // new algorithm: for explanations, see below
    const SimplicialComplex::IndexSet& scidxset(sc.index_set_pure());
    SimplicialComplex::IndexSet::const_iterator miniter = scidxset.begin();
    LabelSet imgset;
    size_type imgminidx = std::numeric_limits<size_type>::max();
    for (SimplicialComplex::IndexSet::const_iterator isiter = scidxset.begin();
	 isiter != scidxset.end();
	 ++isiter) {
      
      // const size_type imgidx = g.map(*isiter);
      const size_type imgidx = _symmetry_images_by_element[*isiter][symidx];
      ++_seecount;
      if (imgidx < *miniter) {
	return imgidx;
      }
      else if (imgidx == *miniter) {
	do {
	  ++miniter;
	  if (miniter == scidxset.end()) {
	    return std::numeric_limits<size_type>::max();
	  }
	  else if (imgminidx < *miniter) {
	    return imgminidx;
	  }
	} while (imgset.contains(*miniter));
      }
      else if (!scidxset.contains(imgidx)) {
	if (imgidx < imgminidx) {
	  imgminidx = imgidx;
	}
      }
      imgset += imgidx;
    }
    if (*miniter < imgminidx) {
      return *miniter;
    }
    else {
      return imgminidx;
    }
  }

  // auxiliary function to compute critical element from scratch for a symmetry on points:
  size_type SymmetricExtensionGraphNode::critical_simpidx_lean(const SimplicialComplex& sc,
							       const Symmetry& g,
							       const size_type symidx) const {
    // return (sc.index_set_pure() ^ g.map(sc).index_set_pure()).min_elem();

    const parameter_type rank = sc.rank();
    if (CommandlineOptions::memopt()) {

      // here, the cache value of the index of the image simplices under g might not be present,
      // and we need to compute the critical element from scratch by mapping all of sc:
      const SimplicialComplex::IndexSet symdiff_idxset(sc.index_set_pure() ^ g.map(sc).index_set_pure());
      _seecount += rank;
      if (symdiff_idxset.empty()) {
	return std::numeric_limits<size_type>::max(); // an encoding for infinity
      }
      else {
	return symdiff_idxset.min_elem();
      }
    }
    else {

      // use the cache to speed-up the map function:

      // new algorithm:
      // let S be sc's index set and g(S) its image under g;
      // the following iterator is updated to the min of S \ g(s_1, s_2, ..., s_k);
      // while iterating over the elements s_1, s_2, ..., s_k, ..., s_n of S:
      SimplicialComplex::IndexSet::const_iterator miniter = sc.index_set_pure().begin();
      LabelSet imgset;

      // the following index is the updated to the minimal index in g(s_1, s_2, ..., s_k) / S
      size_type imgminidx = std::numeric_limits<size_type>::max();
      const SimplicialComplex::IndexSet& scidxset(sc.index_set_pure());
      for (SimplicialComplex::IndexSet::const_iterator isiter = scidxset.begin();
	   isiter != scidxset.end();
	   ++isiter) {

	if (CommandlineOptions::read_status()) {
	  
	  // if we have read data from a file, the value may not be in the cache:
	  if (_symmetry_images_by_element[*isiter][symidx] == std::numeric_limits<size_type>::max()) {
	    
	    // bring requested value into the table:
	    _symmetry_images_by_element[*isiter][symidx]
	      = SimplicialComplex::index_of_simplex(g.map(SimplicialComplex::simplex_of_index(*isiter, rank)), rank);
	    _seecount += rank;
	  }
	}
	
	// we know at this point that the images of
	// simplex indices for all simplices in the partial triangulation
	// have been cached already (either in the calling function or right above):
	// sc_image_indexset += _symmetry_images_by_element[*isiter][symidx];
	const size_type imgidx = _symmetry_images_by_element[*isiter][symidx];
	++_seecount;
	if (imgidx < *miniter) {

	  // g(s_k) is already smaller than min S / g(s_1, s_2, ..., s_k);
	  // we return this element though it is not necessarily the critical element
	  // because in this case g(S) < S, and the critical-element table is not needed;
	  // the caller will notice that imgidx is not in S and
	  // return that S is not lex-min in its orbit:
	  return imgidx;
	}
        else if (imgidx == *miniter) {

	  // in this case, neither imgidx nor *miniter are
	  // in the symmetric difference; thus, miniter has
	  // to be shifted to the next element not in g(s_1, s_2, ..., s_k),
	  // and imgidx will not update imgminidx:
	  do {
	    ++miniter;
	    if (miniter == scidxset.end()) {

	      // this can only happen if S = g(S):
	      return std::numeric_limits<size_type>::max();
	    }
	    else if (imgminidx < *miniter) {
	      
	      // the minimal index in g(s_1, s_2, ..., s_k) \ S is already
	      // smaller than min S \ g(s_1, s_2, ..., s_k);
	      // again, this means g(S) < S
	      return imgminidx;
	    }
	  } while (imgset.contains(*miniter));
	}
	else if (!scidxset.contains(imgidx)) {

	  // in this case, imgidx is not in S, and the min of
	  // g(s_1, s_2, ..., s_k) \ S must be updated:
	  if (imgidx < imgminidx) {
	    imgminidx = imgidx;
	  }
	}
	imgset += imgidx;
      }
      if (*miniter < imgminidx) {
	return *miniter;
      }
      else {
	return imgminidx;
      }
    }
  }

  // the following is used for an incremental check whether or not a partial triangulation
  // is potentially extendable to a flag triangulation:
  bool SymmetricExtensionGraphNode::child_is_flagfeasible(const ConfData& confdata,
							  const PartialTriang& new_partial_triang,
							  const Simplex& simp,
							  uncovered_cliques_type* new_uncovered_cliquesptr) const {

    const SimplicialComplex& new_admissibles(new_partial_triang.admissibles());

    // copy coverable uncovered cliques that are not a face of simp:
    new_uncovered_cliquesptr->clear();
    for (uncovered_cliques_type::const_iterator sciter = _uncovered_cliques.begin();
	 sciter != _uncovered_cliques.end();
	 ++sciter) {
      const Simplex& old_clique(*sciter);
      if (simp.superset(old_clique)) {

	// clique is a face of simp - skip: 
	continue;
      }
      else if (new_admissibles.empty() || old_clique.lexsmaller(*new_admissibles.begin())) {

	// clique cannot be covered in the future:
	return false;
      }
      else {
	new_uncovered_cliquesptr->push_back(old_clique);
      }
    }
    
    // form all triples with pairs of simplices and simp:
    std::set<Simplex> doneset;
    SimplicialComplex::const_iterator iter1 = _partial_triang.begin();
    Simplex new_clique; // keep a result simplex in order to avoid too much memory allocation
    while (iter1 != _partial_triang.end()) {
      const Simplex& simp1(*iter1);
      SimplicialComplex intersecting_simps = confdata.admtable().find(simp1)->second.second;
      intersecting_simps *= _partial_triang;
      SimplicialComplex::const_iterator iter2 = intersecting_simps.begin();
      while (iter2 != intersecting_simps.end()) {
	const Simplex& simp2(*iter2);
	++iter2;
	new_clique = simp1;
	new_clique *= simp2;
	if (simp.intersection_nonempty(simp1)) {
	  new_clique += (simp * simp1);	  
	}
	else {
	  continue;
	}
	if (simp.intersection_nonempty(simp2)) {
	  new_clique += (simp * simp2);
	}
	else {
	  continue;
	}

	// first check whether this test-clique is too large:
	if (new_clique.card() > confdata.rank()) {
	  return false;
	}
	
	// then check whether this test-clique is at most an edge:
	if (new_clique.card() <= 2) {
	  continue;
	}

	// fast check for face in constituting simplices:
	if (simp.superset(new_clique)
	    || simp1.superset(new_clique)
	    || simp2.superset(new_clique)) {
	  continue;
	}

	// check if test-clique was already processed:
	if (doneset.find(new_clique) != doneset.end()) {
	  continue;
	}
	doneset.insert(new_clique);

	// check whether or not this test-clique is a face already:
	if (new_partial_triang.contains(new_clique) || new_partial_triang.contains_face(new_clique)) {
	  continue;
	}

	// check whether or not this test-clique is uncoverable in the future (lex-cover check):
	if (new_admissibles.empty()) {
	  return false;
	}
	else if (new_clique.lexsmaller(*new_admissibles.begin())) {
	  return false;
	}
	else {
	  new_uncovered_cliquesptr->push_back(new_clique);
	}
      }
      ++iter1;
    }
    return true;    
  }

}; // namespace topcom

// eof SymmetricExtensionGraphNode.cc
