/*----------------------------------------------------------------*
 *
 * File : conflicts.c
 * Author : NTM
 * Created : 12/11/04
 *
 *
 * Copyright (C) Nicolas Thierry-Mieg, 2006.
 *
 *
 * This file is part of InterPool, written by 
 * Nicolas Thierry-Mieg (CNRS, France) Nicolas.Thierry-Mieg@imag.fr
 *
 * InterPool 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 of the License, or
 * (at your option) any later version.
 *
 * InterPool 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with InterPool; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *-----------------------------------------------------------------*/

#include <stdio.h> // for printing
#include <stdlib.h> // for memory access


#include "types.h" /* MOT */
#include "varia.h" /* buildInitialVV, updateVVNegPool, naivePosUpdate, hasANonNegVar */
#include "signa.h" /* signature, getsigvalue, setsigvalue, copysig, SIG_* */
#include "pools.h" /* pool */
#include "distance.h" /* DIST_XXX */

#include "conflicts.h"




/************************************************************************
 ******************* LOCAL FUNCTIONS ************************************
 ************************************************************************/

/////////////// DECLARATIONS ///////////////



//////////////// BODIES ///////////////////




/************************************************************************
 ******************* EXPORTED FUNCTIONS *********************************
 ************************************************************************/

/*!
  \brief sig0 is an observation: it can hold only SIG_NEG, SIG_FAINT, 
  SIG_WEAK or SIG_POS;<br>
  this function builds and returns a signature where conflicts are
  tagged: all conflicting pools get their sig values changed from
  SIG_XXX to SIG_XXXCONF.
 
  Algorithm:
  - 1. copy sig0 into sigConf;
  - 2. build a VV where the value of a var is 00 if the var is present
  in at least one neg or faint pool, 11 otherwise ;
  - 3. using hasANonNegVar with each pos pool and this VV, we can tag 
  each pos or weak pool as either conflicting or non-conflicting ;
  - 4. build another VV where vars are 11 if they appear in at least
  one conflicting pos or weak pool, 00 otherwise ;
  - 5. using hasANonNegVar with each neg or faint pool and this VV, we can
  tag each neg or faint pool as conflicting or not.
*/
signature* enrichSig(MOT* tabpool, signature* sig0, int n)
{
  int nbPools = sig0->nbPools ;
  {
    /* sanity check: sig0 should hold only values SIG_NEG, SIG_FAINT,
       SIG_WEAK or SIG_POS */
    int i ;
    for (i = 0 ; i < nbPools ; i++ )
      {
	int sigvalue = getsigvalue(sig0, i) ;
	
	if ( (sigvalue != SIG_POS) && (sigvalue != SIG_WEAK) &&
	     (sigvalue != SIG_FAINT) && (sigvalue != SIG_NEG))
	  {
	    fprintf(stderr, "in enrichSig, sig0 should have only SIG_NEG, SIG_FAINT, SIG_WEAK and SIG_POS, but this is not the case\n");
	    fprintf(stderr, "i is %d, value is %d\n\n", i, sigvalue) ;
	    exit(1);
	  }
      }
  }

  /* 1. copy sig0 into sigConf */
  signature* sigConf = copysig(sig0) ;
  
  /* 2. build a VV where the value of a var is 00 if the var is present
     in at least one neg or faint pool, 11 otherwise */
  // VVtab_11 is full of 11's (255 == 11111111)
  MOT* VVtab_11 = buildInitialVV(n, 255) ; 
  
  {
    /* in VVtab_11, set to 00 any var present in at least one neg or faint pool */
    int i ;
    for (i = 0 ; i < nbPools ; i++)
      {
	int sigvalue=getsigvalue(sigConf, i);
	if ((sigvalue == SIG_NEG) || (sigvalue == SIG_FAINT))
	  {
	    MOT* poolCourant = pool(tabpool, i, n) ;
	    updateVVNegPool(VVtab_11, poolCourant, n) ;
	  }
      }
  }


  /*   3. using hasANonNegVar with each pos pool and this VV, we can tag 
       each pos or weak pool as either conflicting or non-conflicting */
  {
    int i ;
    for (i = 0 ; i < nbPools ; i++)
      {
	int sigvalue = getsigvalue(sigConf, i);
	if (sigvalue == SIG_POS)
	  {		
	    MOT* poolCourant = pool(tabpool, i, n) ;
	    if (! hasANonNegVar(poolCourant, VVtab_11, n) )
	      setsigvalue(sigConf, i, SIG_POSCONF) ;
	  }
	else if (sigvalue == SIG_WEAK)
	  {		
	    MOT* poolCourant = pool(tabpool, i, n) ;
	    if (! hasANonNegVar(poolCourant, VVtab_11, n) )
	      setsigvalue(sigConf, i, SIG_WEAKCONF) ;
	  }
      }      
  }  
  
  free(VVtab_11) ;
  
  /* 4. build another VV where vars are 11 if they appear in at least
     one conflicting pos or weak pool, 00 otherwise */
  // initially, fill with 00's
  MOT* VVtab_00 = buildInitialVV(n,0) ;
  {
    /* in VVtab_00, set to 11 any var that appears in a conflicting pos or weak pool */
    int i ;
    for (i = 0 ; i < nbPools ; i++)
      {
	int sigvalue = getsigvalue(sigConf, i);
	if ((sigvalue == SIG_POSCONF) || (sigvalue == SIG_WEAKCONF))
	  {
	    MOT* poolCourant = pool(tabpool, i, n) ;
	    naivePosUpdate(VVtab_00, poolCourant, n) ;
	  }
      }
  }

  /* 5. using hasANonNegVar with each neg or faint pool and this VV, we can
     tag each neg or faint pool as conflicting or not */
  {
    int i ;
    for (i = 0 ; i < nbPools ; i++)
      {
	int sigvalue = getsigvalue(sigConf, i);
	if (sigvalue == SIG_NEG)
	{		
	  MOT* poolCourant = pool(tabpool, i, n) ;
	  if (hasANonNegVar(poolCourant, VVtab_00, n))
	    setsigvalue(sigConf, i, SIG_NEGCONF) ;
	}
	else if (sigvalue == SIG_FAINT)
	{		
	  MOT* poolCourant = pool(tabpool, i, n) ;
	  if (hasANonNegVar(poolCourant, VVtab_00, n))
	    setsigvalue(sigConf, i, SIG_FAINTCONF) ;
	}  
      }
  }

  free(VVtab_00) ;
  
  return(sigConf) ;
}


/*!
  \brief Given an enriched observation, return the distance to the 
  coherent interpretation where all conflicting pos and weak pools
  are changed to neg. This can be seen as the "cost" of Pc+Wc.
*/
int costOfConflictingPosWeak(signature* sig)
{
  int nbPools = sig->nbPools ;
  int cost = 0 ;
  int i ;
  for (i=0; i<nbPools; i++)
    {
      int sigvalue = getsigvalue(sig, i);
      if (sigvalue == SIG_POSCONF)
	cost += DIST_POS ;
      else if (sigvalue == SIG_WEAKCONF)
	cost += DIST_WEAK ;
    }
  return cost ;
}


/*
  Given an enriched signature, build and return a vector
  of n bools: value [i] is true if variable i is a
  conflicting var (ie var appears in at least one
  conflicting pos or weak pool).
*/
bool* buildConflictingVars(MOT* tabpool, signature* sig, int n)
{
  bool* conflictingVars = (bool*)malloc(n*sizeof(bool)) ;
  if (conflictingVars==NULL)
    {
      fprintf(stderr, "in buildConflictingVars, no more memory.\n") ;
      exit(1) ;
    }

  /* The code is identical to step 4 in enrichSig:
     We build a VV where vars are 11 if they appear in at least
     one conflicting pos pool, 00 otherwise */
  // initially, fill with 00's
  MOT* VVtab_00 = buildInitialVV(n,0) ;
  {
    /* in VVtab_00, set to 11 any var that appears in a conflicting pos pool */
    int nbPools = sig->nbPools ;
    int i ;
    for (i = 0 ; i < nbPools ; i++)
      {
	int sigvalue = getsigvalue(sig, i);
	if (sigvalue == SIG_POSCONF || sigvalue == SIG_WEAKCONF)
	  {
	    MOT* poolCourant = pool(tabpool, i, n) ;
	    naivePosUpdate(VVtab_00, poolCourant, n) ;
	  }
      }
  }
  {
    /* now read VVtab_00 one var at a time and update conflictingVars */
    int var ;
    for (var=0; var<n; var++)
      {
	if (getpoolvalue(VVtab_00, var) == 00)
	  conflictingVars[var] = FALSE ;
	else
	  conflictingVars[var] = TRUE ;
      }
  }

  free(VVtab_00) ;
  return(conflictingVars) ;
}

