#include "VertexCoverProblem.h"

VertexCoverProblem::VertexCoverProblem( std::string filename ) : ProblemDomain() {
  adjacencyList = new AdjacencyList( AdjacencyMatrix( filename ) );
  if ( adjacencyList->isGood() ) {
    numberOfGenes = adjacencyList->getDimension();
    numberOfAlleles = new AlleleType[numberOfGenes];
    for ( unsigned i = 0; i < numberOfGenes; i++ )
      numberOfAlleles[i] = 2;
  }
}

VertexCoverProblem::~VertexCoverProblem() {
  delete [] numberOfAlleles;
  delete adjacencyList;
}

bool VertexCoverProblem::isGood() const {
  return adjacencyList->isGood();
}

void VertexCoverProblem::print( bool verbose ) const {
  if ( adjacencyList->isGood() ) {
    std::printf( "Vertex Cover Problem with %u genes; graph file: %s\n",
                 numberOfGenes, adjacencyList->getFilename().c_str() );
    if ( verbose ) {
      std::printf( "--------------------\n" );
      adjacencyList->print();
    }
  } else
    std::printf( "Vertex Cover Problem with INVALID graph file <%s>\n", adjacencyList->getFilename().c_str() );
}

FloatType VertexCoverProblem::getFitness( AlleleType *phenotype ) const {
  // Fetch the adjacency list
  const AdjacencyList::AdjListType * const adj = adjacencyList->getData();
  AdjacencyList::AdjListType::const_iterator vertexOuter;
  AdjacencyList::ListType::const_iterator vertexInner;
  unsigned vertexNumber = 0;
  FloatType fitnessValue = static_cast<FloatType>( numberOfGenes );
  FloatType fitnessDecrement = static_cast<FloatType>( 1.0 );
  // Loop through the adjacency list
  for ( vertexOuter = adj->begin(); vertexOuter != adj->end(); vertexOuter++ ) {
    if ( phenotype[vertexNumber] ) {
      /* The phenotype includes this vertex in the cover.
       * All edges attached to this vertex are covered, no need to check that.
       * So we just update the fitness and get on with our lives.
       */
      fitnessValue -= fitnessDecrement;
    } else {
      /* The phenotype does NOT include this vertex in the cover.
       * So we have to check that ALL neighboring vertices are included in the cover.
       * If at least one vertex isn't, the cover is invalid.
       */
      for ( vertexInner = vertexOuter->begin() ; vertexInner != vertexOuter->end(); vertexInner++ )
        if ( ! phenotype[*vertexInner] )
          return NEGATIVE_INFINITY;
    }
    vertexNumber += 1;
  }
  // By the time we get here, we know the cover is valid.
  return fitnessValue;
}
