////////////////////////////////////////////////////////////////////////////////
// 
// CheckSymmetries.hh 
//
//    produced: 18 July, 2025 jr
//
////////////////////////////////////////////////////////////////////////////////
#ifndef CHECKSYMMETRIES_HH
#define CHECKSYMMETRIES_HH

#include "ConfData.hh"
#include "SimplicialComplex.hh"
#include "Circuits.hh"
#include "Cocircuits.hh"
#include "Symmetry.hh"

namespace topcom {
  
  class CheckSymmetries {
  private:
    const ConfData&             _confdata;   // data of problem instance
    const SymmetryGroup&        _symmetries; // symmetries to check
  private:
    CheckSymmetries() = delete;
    CheckSymmetries(const CheckSymmetries&) = delete;
  public:
    inline CheckSymmetries(const ConfData& confdata,
			   const SymmetryGroup& symmetries) :
      _confdata(confdata),
      _symmetries(symmetries) {}
  public:
    inline bool operator()() const;
  };

  // in case we have [co]circuits already, we can short-cut:
  bool CheckSymmetries::operator()() const {
    if (_confdata.has_cocircuits()) {
      for (Cocircuits::const_iterator cocirciter = _confdata.cocircuits().begin();
	   cocirciter != _confdata.cocircuits().end();
	   ++cocirciter) {
	const Cocircuit& cocircuit(cocirciter->second);
	const dependent_set_type& pospart(cocircuit.positive_part()); 
	const dependent_set_type& negpart(cocircuit.negative_part());
	const dependent_set_type support(cocircuit.support());
	for (symmetry_collectordata::const_iterator symiter = _symmetries.generators().begin();
	     symiter != _symmetries.generators().end();
	     ++symiter) {
	  const Symmetry& g(*symiter);
	  const dependent_set_type pospartimg(g.map(pospart));
	  const dependent_set_type negpartimg(g.map(negpart));
	  const dependent_set_type supportimg(pospartimg + negpartimg);
	  Cocircuits::const_iterator finditer = _confdata.cocircuits().find(supportimg);
	  if (finditer == _confdata.cocircuits().end()) {
	    MessageStreams::forced() << message::lock
				     << "image " << supportimg
				     << " of support " << support
				     << " under given symmetry generator " << g
				     << " is not a support of cocircuits in " << _confdata.cocircuits()
				     << " ...\n"
				     << message::unlock;
	    return false;
	  }
	  else {
	    const Cocircuit& signature = finditer->second;
	    if (((signature.positive_part() != pospartimg) || (signature.negative_part() != negpartimg))
		&&
		((signature.positive_part() != negpartimg) || (signature.negative_part() != pospartimg))) {
	      MessageStreams::forced() << message::lock
				       << "image " << "(" << pospart << ", " << negpart << ")"
				       << " of cocircuit " << cocircuit
				       << " under given symmetry generator " << g
				       << " is not equal or inverse to signature " << signature
				       << " in cocircuits " << _confdata.cocircuits()
				       << " ...\n"
				       << message::unlock;
	      return false;
	    }
	  }
	}
      }
    }
    else if (_confdata.has_circuits()) {
      for (Circuits::const_iterator circiter = _confdata.circuits().begin();
	   circiter != _confdata.circuits().end();
	   ++circiter) {
	const Circuit& circuit(circiter->second);
	const dependent_set_type& pospart(circuit.positive_part()); 
	const dependent_set_type& negpart(circuit.negative_part());
	const dependent_set_type support(circuit.support());
	for (symmetry_collectordata::const_iterator symiter = _symmetries.generators().begin();
	     symiter != _symmetries.generators().end();
	     ++symiter) {
	  const Symmetry& g(*symiter);
	  const dependent_set_type pospartimg(g.map(pospart));
	  const dependent_set_type negpartimg(g.map(negpart));
	  const dependent_set_type supportimg(pospartimg + negpartimg);
	  Circuits::const_iterator finditer = _confdata.circuits().find(supportimg);
	  if (finditer == _confdata.circuits().end()) {
	    MessageStreams::forced() << message::lock
				     << "image " << supportimg
				     << " of support " << support
				     << " under given symmetry generator " << g
				     << " is not a support of circuits in " << _confdata.circuits()
				     << " ...\n"
				     << message::unlock;
	    return false;
	  }
	  else {
	    const Circuit& signature = finditer->second;
	    if (((signature.positive_part() != pospartimg) || (signature.negative_part() != negpartimg))
		&&
		((signature.positive_part() != negpartimg) || (signature.negative_part() != pospartimg))) {
	      MessageStreams::forced() << message::lock
				       << "image " << "(" << pospart << ", " << negpart << ")"
				       << " of circuit " << circuit
				       << " under given symmetry generator " << g
				       << " is not equal or inverse to signature " << signature
				       << " in circuits " << _confdata.circuits()
				       << " ...\n"
				       << message::unlock;
	      return false;
	    }
	  }
	}
      }
    }
    else {
      MessageStreams::forced() << message::lock
			       << "CheckSymmetries::operator()(): "
			       << "neither circuits nor cocircuits available for symmetries check - exiting." << std::endl
			       << message::unlock;
      exit(1);
    }
    return true;
  }

}; // namespace topcom

#endif
// eof CheckSymmetries.hh
