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 IBFilteringBC5(IBDomains d, IBDmodified *dmodified)
/***************************************************************************
 *  Propagation algorithm BC5 than enforces box consistency
 *  and the interval Newton method
 *
 *  It does not compute a fixed-point
 *
 *  IBDmodified contains the variable domains previously modified
 *  and it is used to intialize the propagation
 */
{
    int dom, i, isin;
    IBDomains dsave = IBNewD(IBVnb(variables));
    
    IBCopyD(dsave,d,IBVnb(variables));
    if( IBDMnb(dmodified)==1 )
        dom = IBDMdom(dmodified,0);      /* one domain modified */
    else dom = -1;                        /* all domains modified */
    
    
    /* HEURISTICS: (HC4,BC3,NEWTON) MORE EFFICIENT THAN (BC4,NEWTON),
     i.e., the computation of a fixed-point of (HC4,BC3) in BC4
     may be too long, and a bisection step may be more efficient */
    /* Call of BC4 */
    /*
     if( IBFilteringBC4(d,dmodified) )
     {
     if( IBComputableIntervalNewton )
     {
     if( !IBNarrowIntervalNewton(d) )
     {
     IBFreeD(dsave);
     return( 0 );
     }
     }
     }
     else
     {
     IBFreeD(dsave);
     return( 0 );
     }
     IBFreeD(dsave);
     return( 1 );
     */
    
    
    /* Call of HC4 */
    if( IBFilteringHC4in(d,dmodified,1) )
    {
        if( dom==-1 ) IBDMnb(dmodified) = IBVnb(variables);
        else
        {
            /* Creation of dmodified before BC3 */
            IBDMnb(dmodified) = 0; isin = 0;
            for( i=0; i<IBVnb(variables); i++ )
            {
                if( IBIdiffI(IBDomV(d,i),IBDomV(dsave,i)) )
                {
                    IBDMdom(dmodified,IBDMnb(dmodified)) = i;
                    IBDMnb(dmodified)++;
                    if( i==dom ) isin = 1;
                }
            }
            if( !isin )  /* domain dom has not been modified by HC4
                          but dom belongs to the argument dmodified */
            {
                IBDMdom(dmodified,IBDMnb(dmodified)) = dom;
                IBDMnb(dmodified)++;
            }
        }
        
        /* Call of BC3 */
        if( IBFilteringBC3in(d,dmodified,0) )
        {
            if( IBComputableIntervalNewton )
            {
                /* Call of Interval Newton */
                if( !IBNarrowIntervalNewton(d) )
                {
                    IBFreeD(dsave);
                    return( 0 );
                }
            }
        }
        else
        {
            IBFreeD(dsave);
            return( 0 );    /* failure of filtering in BC3 */
        }
    }
    else
    {
        IBFreeD(dsave);
        return( 0 );      /* failure of filtering in HC4 */
    }
    IBFreeD(dsave);
    return( 1 );         /* success of filtering */
}
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 */
}