/*-------------------------------------------------------------------------*/
/* GNU Prolog                                                              */
/*                                                                         */
/* Part  : FD constraint solver                                            */
/* File  : fd_to_c.h                                                       */
/* Descr.: FD to C macros - header file                                    */
/* Author: Daniel Diaz                                                     */
/*                                                                         */
/* Copyright (C) 1999 Daniel Diaz                                          */
/*                                                                         */
/* GNU Prolog 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, or any later version.       */
/*                                                                         */
/* GNU Prolog 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 this program; if not, write to the Free Software Foundation, Inc.  */
/* 59 Temple Place - Suite 330, Boston, MA 02111, USA.                     */
/*-------------------------------------------------------------------------*/
#include <stdio.h>

#include "engine_pl.h"
#include "engine_fd.h"




/*---------------------------------*/
/* Constants                       */
/*---------------------------------*/



          /* Environment Frame */

#define Frame_Variable(fv)         ((WamWord *)(AF[fv]))
#define Frame_Range_Parameter(fp)  ((Range *)  (AF[fp]))
#define Frame_Term_Parameter(fp)   ((int)      (AF[fp]))
#define Frame_List_Parameter(fp)   ((WamWord *)(AF[fp]))


#define chain_min                  CHAIN_NB_MIN
#define chain_max                  CHAIN_NB_MAX
#define chain_min_max              CHAIN_NB_MIN_MAX
#define chain_dom                  CHAIN_NB_DOM
#define chain_val                  CHAIN_NB_VAL




/*---------------------------------*/
/* Type Definitions                */
/*---------------------------------*/

/*---------------------------------*/
/* Global Variables                */
/*---------------------------------*/

/*---------------------------------*/
/* Function Prototypes             */
/*---------------------------------*/

/*---------------------------------*/
/* Auxiliary engine macros         */
/*---------------------------------*/

#define DivDn(x,y)                 ((x)/(y))
#define DivUp(x,y)                 (((x)+(y)-1)/(y))


#define R(r_no)                    rr##r_no

          /* Interface with Prolog clauses instructions */

#define fd_create_a_frame(nb_arg)                                           \
     AF=CS;                                                                 \
     CS+=nb_arg;




#define fd_int_in_a_frame(arg,offset)                                       \
     AF[offset]=(WamWord) Fd_Prolog_To_Value(fd_##arg);




#define fd_range_in_a_frame(arg,offset)                                     \
     AF[offset]=(WamWord) Fd_Prolog_To_Range(fd_##arg);




#define fd_fdv_in_a_frame(arg,offset)                                       \
     AF[offset]=(WamWord) Fd_Prolog_To_Fd_Var(fd_##arg,TRUE);




#define fd_fdv_in_a_frame(arg,offset)                                       \
     AF[offset]=(WamWord) Fd_Prolog_To_Fd_Var(fd_##arg,TRUE);




#define fd_any_in_a_frame(arg,offset)                                       \
     AF[offset]=(WamWord) fd_##arg;




#define fd_l_int_in_a_frame(arg,offset)                                     \
     AF[offset]=(WamWord) Fd_Prolog_To_Array_Int(fd_##arg);




#define fd_l_range_in_a_frame(arg,offset)                                   \
     printf("fd_l_range_in_a_frame  not yet implemented...\n");




#define fd_l_fdv_in_a_frame(arg,offset)                                     \
     AF[offset]=(WamWord) Fd_Prolog_To_Array_Fdv(fd_##arg,TRUE);




#define fd_l_any_in_a_frame(arg,offset)                                     \
     AF[offset]=(WamWord) Fd_Prolog_To_Array_Any(fd_##arg);




#define fd_cf_in_a_frame(offset)                                            \
     AF[offset]=(WamWord) CF;




#define fd_call_internal(fct_name)                                          \
     if (!fct_name(AF))                                                     \
        {                                                                   \
         ret_val=FALSE;                                                     \
         goto lab_exit;                                                     \
        }




#define fd_call_internal_and_test_switch_simple(fct_name)                   \
    {                                                                       \
     long (*fct)()=(long (*)()) fct_name(AF);                               \
                                                                            \
     if (fct==(long(*)()) FALSE)                                            \
        {                                                                   \
         ret_val=FALSE;                                                     \
         goto lab_exit;                                                     \
        }                                                                   \
     if (fct!=(long(*)()) TRUE)              /* FD switch case triggered */ \
        {                                                                   \
         if ((*fct)(AF)==FALSE)                                             \
            {                                                               \
             ret_val=FALSE;                                                 \
             goto lab_exit;                                                 \
            }                                                               \
        }                                                                   \
    }




#define fd_call_internal_and_test_switch(fct_name)                          \
    {                                                                       \
     long (*fct)()=(long (*)()) fct_name(AF);                               \
                                                                            \
     if (fct==(long(*)()) FALSE)                                            \
        {                                                                   \
         ret_val=FALSE;                                                     \
         goto lab_exit;                                                     \
        }                                                                   \
     if (fct!=(long(*)()) TRUE)              /* FD switch case triggered */ \
        {                                                                   \
         if ((*fct)(AF)==FALSE)                                             \
            {                                                               \
             ret_val=FALSE;                                                 \
             goto lab_exit;                                                 \
            }                                                               \
                                                                            \
         Fd_Stop_Constraint(CF);                                            \
        }                                                                   \
    }






#define fd_stop_constraint(offset)                                          \
     if (AF[offset])                                                        \
         Fd_Stop_Constraint((WamWord *) (AF[offset]));




          /* Install instructions */

#define fd_create_c_frame(fct_name,tell_fv,optim2)                          \
     CF=Fd_Create_C_Frame(fct_name,AF,(tell_fv== -1) ? NULL : Frame_Variable(tell_fv),optim2);




#define fd_add_dependency(fv,ch)                                            \
     Fd_Add_Dependency(Frame_Variable(fv),chain_##ch,CF);




#define fd_add_list_dependency(fv,ch)                                       \
     Fd_Add_List_Dependency(Frame_Variable(fv),chain_##ch,CF);




          /* Constraint instructions */

#define fd_before_add_constraint                                            \
     Fd_Before_Add_Cstr();




#define fd_after_add_constraint                                             \
     if (!Fd_After_Add_Cstr())                                              \
        {                                                                   \
         ret_val=FALSE;                                                     \
         goto lab_exit;                                                     \
        }



#define fd_allocate                                                         \
    {                                                                       \
     WamWord *save_CS=CS;                                                   \
     CS+=vec_size;




#define fd_deallocate                                                       \
     CS=save_CS;                                                            \
    }




#define fd_tell_value(fv,t)                                                 \
    {                                                                       \
     fdv_adr=Frame_Variable(fv);                                            \
     if (!Fd_Tell_Value(fdv_adr,t))                                         \
        {                                                                   \
         ret_val=FALSE;                                                     \
         goto lab_exit;                                                     \
        }                                                                   \
    }




#define fd_tell_not_value(fv,t)                                             \
    {                                                                       \
     fdv_adr=Frame_Variable(fv);                                            \
     if (!Fd_Tell_Not_Value(fdv_adr,t))                                     \
        {                                                                   \
         ret_val=FALSE;                                                     \
         goto lab_exit;                                                     \
        }                                                                   \
    }




#define fd_tell_interval(fv,t_min,t_max)                                    \
    {                                                                       \
     fdv_adr=Frame_Variable(fv);                                            \
     if (Fd_Variable_Is_Ground(fdv_adr))                                    \
        {                                                                   \
         int n=Min(fdv_adr);                                                \
         if (n<(t_min) || n>(t_max))    /* detects also if the initial   */ \
            {                                                               \
             ret_val=FALSE;                                                 \
             goto lab_exit;                                                 \
            }                                                               \
        }                                                                   \
      else                                                                  \
         if (Is_Sparse(Range(fdv_adr)))                                     \
            {                                                               \
             Range range;                                                   \
             Range_Init_Interval(&range,t_min,t_max);                       \
                                                                            \
             if (!Fd_Tell_Range_Range(fdv_adr,&range))                      \
                {                                                           \
                 ret_val=FALSE;                                             \
                 goto lab_exit;                                             \
                }                                                           \
            }                                                               \
          else                                                              \
             if (!Fd_Tell_Interv_Interv(fdv_adr,t_min,t_max))               \
                {                                                           \
                 ret_val=FALSE;                                             \
                 goto lab_exit;                                             \
                }                                                           \
    }




#define fd_tell_range(fv,r)                                                 \
    {                                                                       \
     fdv_adr=Frame_Variable(fv);                                            \
     if (Fd_Variable_Is_Ground(fdv_adr))                                    \
        {                                                                   \
         if (!Fd_Tell_Int_Range(fdv_adr,&R(r)))                             \
            {                                                               \
             ret_val=FALSE;                                                 \
             goto lab_exit;                                                 \
            }                                                               \
        }                                                                   \
      else                                                                  \
         if (!Fd_Tell_Range_Range(fdv_adr,&R(r)))                           \
            {                                                               \
             ret_val=FALSE;                                                 \
             goto lab_exit;                                                 \
            }                                                               \
    }




#define fd_check_fct(fct)                                                   \
     if (!fct)                                                              \
        {                                                                   \
         ret_val=FALSE;                                                     \
         goto lab_exit;                                                     \
        }


          /* Tests */

#define fd_test_exit_condition(t)                                           \
     if (t)                                                                 \
         goto lab_exit;



#define fd_test_fail_condition(t)                                           \
     if (!t)                                                                \
        {                                                                   \
         ret_val=FALSE;                                                     \
         goto lab_exit;                                                     \
        }




#define fd_test_switch_condition(t,fct_name)                                \
     if (t)                                                                 \
        {                                                                   \
         ret_val=(long) fct_name;                                           \
         goto lab_exit;                                                     \
        }




          /* Range */

#define fd_range_interval(r,t_min,t_max)                                    \
     Range_Init_Interval(&R(r),t_min,t_max);




#define fd_load_range(r,fp)                                                 \
     R(r).vec=NULL;                                                         \
     Range_Copy(&R(r),Frame_Range_Parameter(fp));




#define fd_load_dom(r,fv)                                                   \
     fdv_adr=Frame_Variable(fv);                                            \
     R(r).vec=NULL;                                                         \
     Range_Copy(&R(r),Range(fdv_adr));




#define fd_range_union(r,r1)                                                \
     Range_Union(&R(r),&R(r1));




#define fd_range_inter(r,r1)                                                \
     Range_Inter(&R(r),&R(r1));




#define fd_range_compl(r)                                                   \
     Range_Compl(&R(r));




#define fd_range_empty(r)                                                   \
     R(r).vec=NULL;                                                         \
     Set_To_Empty(&R(r));




#define fd_range_full(r)                                                    \
     Range_Init_Interval(&R(r),0,INTERVAL_MAX_INTEGER);




#define fd_range_set_value(r,t)                                             \
     Range_Set_Value(&R(r),t);




#define fd_range_reset_value(r,t)                                           \
     Range_Reset_Value(&R(r),t);




#define fd_range_add_range(r,r1)                                            \
     Range_Add_Range(&R(r),&R(r1));




#define fd_range_sub_range(r,r1)                                            \
     Range_Sub_Range(&R(r),&R(r1));




#define fd_range_mul_range(r,r1)                                            \
     Range_Mul_Range(&R(r),&R(r1));




#define fd_range_div_range(r,r1)                                            \
     Range_Div_Range(&R(r),&R(r1));




#define fd_range_mod_range(r,r1)                                            \
     Range_Mod_Range(&R(r),&R(r1));




#define fd_range_add_value(r,t)                                             \
     Range_Add_Value(&R(r),t);




#define fd_range_sub_value(r,t)                                             \
     Range_Add_Value(&R(r),-(t));




#define fd_range_mul_value(r,t)                                             \
     Range_Mul_Value(&R(r),t);




#define fd_range_div_value(r,t)                                             \
     Range_Div_Value(&R(r),t);




#define fd_range_mod_value(r,t)                                             \
     Range_Mod_Value(&R(r),t);




#define fd_range_copy(r,r1)                                                 \
     R(r).vec=NULL;                                                         \
     Range_Copy(&R(r),&R(r1));




#define fd_range_fct(fct_name,r,args)                                       \
    {                                                                       \
     void fct_name();                                                       \
     R(r).vec=NULL;                                                         \
     fct_name(&R(r),args);                                                  \
    }



          /* term */

#define fd_load_int(var_name,fp)                                            \
     var_name=Frame_Term_Parameter(fp);




#define fd_load_min(var_name,fv)                                            \
     fdv_adr=Frame_Variable(fv);                                            \
     var_name=Min(fdv_adr);




#define fd_load_max(var_name,fv)                                            \
     fdv_adr=Frame_Variable(fv);                                            \
     var_name=Max(fdv_adr);




#define fd_load_min_max(var_name_min,var_name_max,fv)                       \
     fdv_adr=Frame_Variable(fv);                                            \
     var_name_min=Min(fdv_adr);                                             \
     var_name_max=Max(fdv_adr);




#define fd_load_val(var_name,fv)                                            \
     fdv_adr=Frame_Variable(fv);                                            \
     if (Fd_Variable_Is_Ground(fdv_adr))                                    \
         var_name=Min(fdv_adr);                                             \
      else                                                                  \
         { goto lab_exit; };




#define fd_min_of_range(var_name,r)                                         \
    var_name=R(r).min;




#define fd_max_of_range(var_name,r)                                         \
    var_name=R(r).max;




#define fd_value_copy(t,t1)                                                 \
    (t)=(t1);




#define fd_load_l_int(var_name,fp)                                          \
     var_name=Frame_List_Parameter(fp);




#define fd_load_l_fdv(var_name,fp)                                          \
     var_name=Frame_List_Parameter(fp);




#define fd_load_l_any(var_name,fp)                                          \
     var_name=Frame_List_Parameter(fp);




#define arg_1(a1)                          a1
#define arg_2(a1,a2)                       a1,a2
#define arg_3(a1,a2,a3)                    a1,a2,a3
#define arg_4(a1,a2,a3,a4)                 a1,a2,a3,a4
#define arg_5(a1,a2,a3,a4,a5)              a1,a2,a3,a4,a5
#define arg_6(a1,a2,a3,a4,a5,a6)           a1,a2,a3,a4,a5,a6
#define arg_7(a1,a2,a3,a4,a5,a6,a7)        a1,a2,a3,a4,a5,a6,a7
#define arg_8(a1,a2,a3,a4,a5,a6,a7,a8)     a1,a2,a3,a4,a5,a6,a7,a8
#define arg_9(a1,a2,a3,a4,a5,a6,a7,a8,a9)  a1,a2,a3,a4,a5,a6,a7,a8,a9




#define range_arg(r)              &R(r)                      /* by address */




/*---------------------------------*/
/* Interface with C files          */
/*---------------------------------*/

#define max_integer                   INTERVAL_MAX_INTEGER




#define FdArg(arg) WamWord fd_##arg




#define fd_begin_user_constraint(name_args)                                 \
                                                                            \
    Bool name_args                                                          \
    {                                                                       \
     WamWord *AF;                                                           \
     long ret_val=TRUE;




#define fd_end_user_constraint                                              \
    }




#define fd_begin_internal(fct_name)                                         \
                                                                            \
    static long fct_name(WamWord *AF)                                       \
    {                                                                       \
     long ret_val=TRUE;




#define fd_end_internal                                                     \
    }




#define fd_exit_point                                                       \
     lab_exit:



#define fd_return                                                           \
     return ret_val;




#define fd_local_value_var(var_name)                                        \
     int var_name;




#define fd_local_range_var(r)                                               \
     Range R(r)  /*  ={FALSE,0,0,NULL} init should be useless  */;




#define fd_local_l_int_var(var_name)                                        \
     WamWord *var_name;




#define fd_local_l_fdv_var(var_name)                                        \
     WamWord *var_name;




#define fd_local_l_any_var(var_name)                                        \
     WamWord *var_name;




#define fd_local_cf_pointer                                                 \
     WamWord *CF;



#define fd_local_fdv_adr                                                    \
     WamWord *fdv_adr;




#define fd_init_local_value_var(var_name,term)                              \
     var_name=(term);

