int IBFiltering3B(IBDomains d, IBDmodified *dmodified, IBLocalPropagation f2b)
/***************************************************************************
*  3B consistency, using the 2B consistency algorithm f2b
*
*  Returns - 0 if d is inconsistent
*          - 1 if d is consistent (and reduced or not)
*/
{
  int i, n, fixedPoint;
  double bound,
         wRatio = 5.0;     /* 5.0 originates from the experiments */
  IBDomains dcopy;

  IBDMnb(dmodified) = IBVnb(variables);
  if( !f2b(d,dmodified) )  /* reduction of d */
  {
    return( 0 );
  }

  /* Initialization of widths used for the precision at bounds */
  for( i=0; i<IBVnb(variables); i++ )
  {
    IBwidth3B[i] = IBWidthI(IBDomV(d,i));
  }

  dcopy = IBNewD(IBVnb(variables));
  fixedPoint = 0;
  while( (!fixedPoint) && (IBClockObserve(IBClockSolve)<=IBPragmaMaxTime) )
  {
    /* Detection of fixed-point: d is consistent and all the parameters
       IBwidth3B[i] are small enough, i.e., <= IBPragmaPrecision3B */

    fixedPoint = 1;

    if( !(n=IBFiltering3BOneStep(d,dmodified,f2b,dcopy,IBwidth3B)) )
    {
      IBFreeD(dcopy);
      return( 0 );         /* inconsistency */
    }
    else if( n==1 )
    {
      fixedPoint = 0;
    }
    else                   /* n==2: no reduction of d, n==1: reduction of d */
    {
      i = 0;
      while( fixedPoint && (i<IBVnb(variables)) )
      {
        if( IBwidth3B[i]>IBPragmaPrecision3B )
	{
          fixedPoint = 0;
	}
	else i++;
      }
    }
  }
  IBFreeD(dcopy);
  return( 1 );
}
int IBFiltering3BOneStep(IBDomains d, IBDmodified *dmodified, IBLocalPropagation f2b,
                         IBDomains dcopy, double *w)
/***************************************************************************
*  One step of 3B consistency for each variable bound
*  Returns - 0 if d is inconsistent
*          - 1 if d is reduced and it is not 3B(w) consistent
*          - 2 if d is reduced and it is 3B(w) consistent
*/
{
  int i,
      n,
    result = 2;   /* a priori, d is 3B(w) consistent */
  double bound,
         wRatio = 5.0;

  /* Contraction of all domains */
  for( i=0; i<IBVnb(variables) && (IBClockObserve(IBClockSolve)<=IBPragmaMaxTime); i++ )
  {
    w[i] /= wRatio;
    if( w[i]<IBPragmaPrecision3B ) w[i] = IBPragmaPrecision3B;

    /* Copy of d in dcopy, d must not be modified by the call to IB3BReviseLeft */
    IBCopyD(dcopy,d,IBVnb(variables));
    if( !(n=IB3BReviseLeft(dcopy,i,dmodified,f2b,IBwidth3B[i],&bound)) )
    {
      return 0;       /* d is inconsistent */
    }
    else if( n==1 )
    {
      IBMinI(IBDomV(d,i)) = bound;
      result = 1;     /* modification, left bound not 3B(w) consistent */
    }
    else
    {
      IBMinI(IBDomV(d,i)) = bound;  /* optimization */
    }

    IBCopyD(dcopy,d,IBVnb(variables));
    if( !(n=IB3BReviseRight(dcopy,i,dmodified,f2b,IBwidth3B[i],&bound)) )
    {
      return 0;       /* d is inconsistent */
    }
    else if( n==1 )
    {
      IBMaxI(IBDomV(d,i)) = bound;
      result = 1;     /* modification, right bound not 3B(w) consistent */
    }
    else
    {
      IBMaxI(IBDomV(d,i)) = bound;  /* optimization */
    }
  }
  return( result );
}
int IBFilteringBC4(IBDomains d, IBDmodified *dmodified)
/***************************************************************************
 *  Propagation algorithm BC4 that enforces box consistency
 *    => combination of BC3revise and HC4revise narrowing operators
 *
 *  IBDmodified contains the variable domains previously modified
 *  and it is used to intialize the propagation
 */
{
    int notfixedpoint;
    int dom, i;
    IBDomains dsave = IBNewD(IBVnb(variables));
    
    IBCopyD(dsave,d,IBVnb(variables));    /* domains are saved */
    if( IBDMnb(dmodified)==1 )
        dom = IBDMdom(dmodified,0);      /* one domain modified */
    else dom = -1;                        /* all domains modified */
    
    /* first application of HC4 (3rd argument=1 since only the constraints
     containing at least one variable occurring once are considered) )*/
    if( IBFilteringHC4in(d,dmodified,1) )
    {
        if( dom==-1 )
        {
            IBDMnb(dmodified) = IBVnb(variables);  /* initialization used for BC3 */
        }
        else
        {
            IBDMnb(dmodified) = 1;
            IBDMdom(dmodified,0) = 0;
        }
        
        /* first application of BC3 (3rd argument=0 since only the constraint
         projections (c,x) s.t. x occurs one in c are considered */
        if( !IBFilteringBC3in(d,dmodified,0) )
        {
            IBFreeD(dsave);
            return( 0 );  /* FAILURE OF FILTERING from BC3 */
        }
    }
    else
    {
        IBFreeD(dsave);
        return( 0 );  /* FAILURE OF FILTERING from HC4 */
    }
    
    /* Creation of the list of modified domains */
    IBDMnb(dmodified) = 0;
    for( i=0; i<IBVnb(variables); i++ )
    {
        if( IBIdiffI(IBDomV(d,i),IBDomV(dsave,i)) )
        {
            IBDMdom(dmodified,IBDMnb(dmodified)) = i;
            IBDMnb(dmodified)++;
        }
    }
    
    while( IBDMnb(dmodified) && (IBClockObserve(IBClockSolve)<=IBPragmaMaxTime) )
    {
        IBCopyD(dsave,d,IBVnb(variables));     /* domains are saved */
        
        /* Call of HC4 */
        if( IBFilteringHC4in(d,dmodified,1) )
        {
            /* Creation of dmodified */
            IBDMnb(dmodified) = 0;
            for( i=0; i<IBVnb(variables); i++ )
            {
                if( IBIdiffI(IBDomV(d,i),IBDomV(dsave,i)) )
                {
                    IBDMdom(dmodified,IBDMnb(dmodified)) = i;
                    IBDMnb(dmodified)++;
                }
            }
            
            if( IBDMnb(dmodified) )
            {
                IBCopyD(dsave,d,IBVnb(variables));
                
                /* Call of BC3 */
                if( IBFilteringBC3in(d,dmodified,0) )
                {
                    /* Creation of dmodified */
                    IBDMnb(dmodified) = 0;
                    for( i=0; i<IBVnb(variables); i++ )
                    {
                        if( IBIdiffI(IBDomV(d,i),IBDomV(dsave,i)) )
                        {
                            IBDMdom(dmodified,IBDMnb(dmodified)) = i;
                            IBDMnb(dmodified)++;
                        }
                    }
                }
                else
                {
                    IBFreeD(dsave);
                    return( 0 );  /* FAILURE OF FILTERING from BC3 */
                }
            }
        }
        else
        {
            IBFreeD(dsave);
            return( 0 );      /* FAILURE OF FILTERING from HC4 */
        }
    }
    IBFreeD(dsave);
    return( 1 );          /* SUCCESS OF FILTERING */
}
int IBFilteringHC3(IBDomains d, IBDmodified *dmodified)
/***************************************************************************
 *  Propagation algorithm HC4 that enforces hull consistency
 *
 *  IBDmodified contains the variable domains previously modified
 *  and it is used to intialize the propagation
 *
 *  Equivalent to HC4 where HC4revise is replaced with HC3revise
 *  HC4revise uses unions of intervals while HC3revise uses only intervals
 */
{
    IBConstraint *ctr;
    int i, j, globvar;
    int onlyoccone = 0;
    IBDomains dsave = IBNewD(IBVnb(variables));
    
#if SOFTWARE_PROFILE
    IBClockBegin(IBClockHC3);
#endif
    
    /* Propagation wrt. all the constraints */
    IBFPropagationHC4(IBpropaglistctr,dmodified,1,onlyoccone);
    
    while( IBPLCnbelem(IBpropaglistctr) && (IBClockObserve(IBClockSolve)<=IBPragmaMaxTime) )
    {
        ctr = IBPLCctr(IBpropaglistctr,IBPLCfirst(IBpropaglistctr));
        
        IBCopyD(dsave,d,IBVnb(variables));   /* domains are saved */
        
        /* HC3revise narrowing operator */
        if( IBNarrowHC3revise(ctr,d) )
        {
            /* which domains have been modified ? */
            i = j = 0;
            for( i=0; i<IBCNbVar(ctr); i++ )
            {
                globvar = IBCVglobvar(ctr,i);
                if( IBIdiffI(IBDomV(dsave,globvar),IBDomV(d,globvar)) )
                {
                    if( ((IBWidthI(IBDomV(d,globvar)) < IBPragmaImprovement*IBWidthI(IBDomV(dsave,globvar)))
                         || (IBInfiniteI(IBDomV(d,globvar))))
                       && ( (!onlyoccone) || (onlyoccone && (IBCVnbocc(ctr,i)==1))) )
                    {
                        IBDMdom(dmodified,j) = globvar;
                        j++;
                    }
                }
            }
            IBDMnb(dmodified) = j;
            
            /* PROPAGATION */
            if( IBDMnb(dmodified) )
            {
                /* ctr is not added in the list since is is already in the list */
                IBFPropagationHC4(IBpropaglistctr,dmodified,0,onlyoccone);
                
                /* ctr is removed from the list */
                IBPLCfirst(IBpropaglistctr) =
                (IBPLCfirst(IBpropaglistctr)+1) % IBPLCsize(IBpropaglistctr);
                
                /* ctr is added at the end of the list since HC4revise is not idempotent */
                
                IBCctrAsleep(ctr) = 0;
                IBPLCend(IBpropaglistctr) = (IBPLCend(IBpropaglistctr)+1) % IBPLCsize(IBpropaglistctr);
                IBPLCctr(IBpropaglistctr,IBPLCend(IBpropaglistctr)) = ctr;
                
                /* Remark: the number of elements does not change */
                
            }
            else  /* no domain modified, then no propagation */
            {
                IBPLCnbelem(IBpropaglistctr)--;
                IBPLCfirst(IBpropaglistctr) =
                (IBPLCfirst(IBpropaglistctr)+1) % IBPLCsize(IBpropaglistctr);
                
                IBCctrAsleep(ctr) = 1;
            }
        }
        else
        {
#if SOFTWARE_PROFILE
            IBClockEnd(IBClockHC3);
#endif
            
            IBFreeD(dsave);
            return( 0 ); /* FAILURE OF FILTERING */
        }
    }
#if SOFTWARE_PROFILE
    IBClockEnd(IBClockHC3);
#endif
    
    IBFreeD(dsave);
    return( 1 );      /* SUCCESS OF FILTERING */
}
int IBFilteringHC4in(IBDomains d, IBDmodified *dmodified, int onlyoccone)
/***************************************************************************
 *  Propagation algorithm HC4 that enforces hull consistency
 *
 *  IBDmodified contains the variable domains previously modified
 *  and it is used to initialize the propagation
 *
 *  onlyoccone=1 if only the constraints with at least one variable occurring
 *  once are considered => in this case, propagation is stopped when no domain
 *  of such a variable is contracted
 
 *  onlyoccone=0 if all constraints are considered
 */
{
    IBConstraint *ctr;
    int i, j, globvar;
    IBDomains dsave = IBNewD(IBVnb(variables));
    
#if SOFTWARE_PROFILE
    IBClockBegin(IBClockHC4);
#endif
    
    IBFPropagationHC4(IBpropaglistctr,dmodified,1,onlyoccone);
    
    while( IBPLCnbelem(IBpropaglistctr) && (IBClockObserve(IBClockSolve)<=IBPragmaMaxTime) )
    {
        ctr = IBPLCctr(IBpropaglistctr,IBPLCfirst(IBpropaglistctr));
        
        IBCopyD(dsave,d,IBVnb(variables));   /* domains are saved */
        
        /* HC4revise narrowing operator */
        if( IBNarrowHC4revise(ctr,d) )
        {
            /* which domains have been modified ? */
            i = j = 0;
            for( i=0; i<IBCNbVar(ctr); i++ )
            {
                globvar = IBCVglobvar(ctr,i);
                if( IBIdiffI(IBDomV(dsave,globvar),IBDomV(d,globvar)) )
                {
                    /* propagation only if the width of domain has been reduced enough, i.e.,
                     improvement factor = e.g. 10%  => domain 10% tighter
                     the improvement factor can be used only if the domain is finite, otherwise
                     the width is infinite and the test below does not succeed */
                    if( ((IBWidthI(IBDomV(d,globvar)) < IBPragmaImprovement*IBWidthI(IBDomV(dsave,globvar)))
                         || (IBInfiniteI(IBDomV(d,globvar))))
                       && ( (!onlyoccone) || (onlyoccone && (IBCVnbocc(ctr,i)==1))) )
                    {
                        IBDMdom(dmodified,j) = globvar;
                        j++;
                    }
                }
            }
            IBDMnb(dmodified) = j;   /* number of modified domains */
            
            /* Propagation */
            if( IBDMnb(dmodified) )
            {
                /* ctr is not added in the list since it is already in the list */
                IBFPropagationHC4(IBpropaglistctr,dmodified,0,onlyoccone);
                
                /* ctr is removed from the list */
                IBPLCfirst(IBpropaglistctr) =
                (IBPLCfirst(IBpropaglistctr)+1) % IBPLCsize(IBpropaglistctr);
                
                /* whether ctr is kept in the list ? */
                if( IBCNbProjMul(ctr)>0 )  /* HC4revise is not idempotent */
                {
                    IBCctrAsleep(ctr) = 0;
                    IBPLCend(IBpropaglistctr) = (IBPLCend(IBpropaglistctr)+1) % IBPLCsize(IBpropaglistctr);
                    IBPLCctr(IBpropaglistctr,IBPLCend(IBpropaglistctr)) = ctr;
                }
                else                       /* HC4revise is idempotent */
                {
                    IBPLCnbelem(IBpropaglistctr)--;
                    IBCctrAsleep(ctr) = 1;
                }
                /* Remark: the number of elements does not change */
                
            }
            else  /* no domain modified, then no propagation */
            {
                IBPLCnbelem(IBpropaglistctr)--;
                IBPLCfirst(IBpropaglistctr) =
                (IBPLCfirst(IBpropaglistctr)+1) % IBPLCsize(IBpropaglistctr);
                
                IBCctrAsleep(ctr) = 1;
            }
        }
        else
        {
#if SOFTWARE_PROFILE
            IBClockEnd(IBClockHC4);
#endif
            
            IBFreeD(dsave);
            return( 0 ); /* FAILURE OF FILTERING */
        }
    }
    
#if SOFTWARE_PROFILE
    IBClockEnd(IBClockHC4);
#endif
    
    IBFreeD(dsave);
    return( 1 );      /* SUCCESS OF FILTERING */
}
int IBFilteringBC3in(IBDomains d, IBDmodified *dmodified, int allproj)
/***************************************************************************
 *  Propagation algorithm BC3 for box consistency: this algorithm is
 *  an adaptation of AC3 using box consistency narrowing operators
 *
 *  IBDmodified contains the variable domains previously modified and
 *  it is used to initialize propagation
 */
{
    IBItv out;
    int locvar, globvar;
    IBConstraint *ctr;
    
#if SOFTWARE_PROFILE
    IBClockBegin(IBClockBC3);
#endif
    
    IBFPropagationBC3(IBpropaglist,dmodified,1,allproj);
    IBDMnb(dmodified) = 1;  /* during propagation in BC3, only one domain
                             is modified at each step */
    
    while( IBPLnbelem(IBpropaglist) && (IBClockObserve(IBClockSolve)<=IBPragmaMaxTime) )
    {
        ctr     = IBCCtr(constraints,IBCPctr(IBPLproj(IBpropaglist,IBPLfirst(IBpropaglist))));
        locvar  = IBCPvar(IBPLproj(IBpropaglist,IBPLfirst(IBpropaglist)));
        globvar = IBCVglobvar(ctr,locvar);
        
        /* BC3revise over projection (ctr,globvar/locvar) */
        if( IBNarrowBC3revise(ctr,locvar,globvar,d,out,IBPragmaPrecisionShrink) )
        {
            if( IBIdiffI(IBDomV(d,globvar),out) )          /* the domain has changed */
            {
                /* Improvement factor, e.g. 10% (1-0.9) ; can be used only if out is finite */
                if( (IBWidthI(out) < IBPragmaImprovement*IBWidthI(IBDomV(d,globvar))) ||
                   (IBInfiniteI(out)) )
                {
                    IBDMdom(dmodified,0) = globvar;                 /* then propagation */
                    IBFPropagationBC3(IBpropaglist,dmodified,0,allproj);
                }
                IBCopyI(IBDomV(d,globvar),out);    /* copy of new domain */
                if (IBPragmaPrecisionShrink==0.0)  /* idempotent narrowing operator */
                {
                    IBCPasleep(IBPLproj(IBpropaglist,IBPLfirst(IBpropaglist))) = 1;
                }
            }
            else  /* no contraction */
            {
                IBCPasleep(IBPLproj(IBpropaglist,IBPLfirst(IBpropaglist))) = 1;
            }
            IBPLnbelem(IBpropaglist)--;
            IBPLfirst(IBpropaglist) = (IBPLfirst(IBpropaglist)+1) % IBPLsize(IBpropaglist);
        }
        else
        {
#if SOFTWARE_PROFILE
            IBClockEnd(IBClockBC3);
#endif
            
            return( 0 ); /* FAILURE OF FILTERING */
        }
    }
    
#if SOFTWARE_PROFILE
    IBClockEnd(IBClockBC3);
#endif
    
    return( 1 );        /* SUCCESS OF FILTERING */
}