| 1 | | % (c) 2009-2016 Lehrstuhl fuer Softwaretechnik und Programmiersprachen, |
| 2 | | % Heinrich Heine Universitaet Duesseldorf |
| 3 | | % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html) |
| 4 | | |
| 5 | | :- module(fd_utils_clpfd,[eq_fd/2, neq_fd/3, |
| 6 | | in_fd/3, in_fd_wf/4, |
| 7 | | /* neq_fdpair/4, not_in_fd/3, not used anymore */ |
| 8 | | enum_fd/3, enum_fd_linear/3]). |
| 9 | | |
| 10 | | :- use_module(module_information). |
| 11 | | :- module_info(group,kernel). |
| 12 | | :- module_info(description,'Basic checks for SET elements (equality, ...); maps to CLP(FD).'). |
| 13 | | |
| 14 | | /* File: fd_utils_clpfd.pl */ |
| 15 | | /* Created: 21/3/06 by Michael Leuschel */ |
| 16 | | |
| 17 | | |
| 18 | | :- use_module(self_check). |
| 19 | | |
| 20 | | :- use_module(library(clpfd)). |
| 21 | | |
| 22 | | :- assert_must_succeed(( fd_utils_clpfd:eq_fd(2,2) )). |
| 23 | | :- assert_must_fail(( fd_utils_clpfd:eq_fd(2,3) )). |
| 24 | | |
| 25 | ? | eq_fd(X,Y) :- X=Y. |
| 26 | | |
| 27 | | %eq_fd(X,Y) :- %print_message(informational,eq_fd(X,Y)), |
| 28 | | % %((var(X),frozen(X,G)) -> print_message(informational,frozen(X,G)) ; true), |
| 29 | | % X = Y, |
| 30 | | % print_message(informational,done_eq(X,Y)). |
| 31 | | |
| 32 | | |
| 33 | | :- assert_must_succeed(( fd_utils_clpfd:in_fd(X,1,3), |
| 34 | | fd_utils_clpfd:neq_fd(X,1,'Name'), fd_utils_clpfd:neq_fd(X,3,'Name'), X==2 )). |
| 35 | | |
| 36 | | :- assert_must_succeed(( fd_utils_clpfd:neq_fd(1,2,'Name') )). |
| 37 | | :- assert_must_fail(( fd_utils_clpfd:neq_fd(2,2,'Name') )). |
| 38 | | |
| 39 | | neq_fd(X,Y,_Type) :- %print(neq_fd(X,Y,_Type)),nl, |
| 40 | | % sometimes no CLP(FD) constraints set up for X or Y; can mean that we only detect inconsistencies much later |
| 41 | | %(var(X) -> b_global_sets:global_type(fd(X,_Type),_Type) ; true), % commenting it in causes test 496 to fail; |
| 42 | | %(var(Y) -> b_global_sets:global_type(fd(Y,_Type),_Type) ; true), % TO DO: investigate |
| 43 | | X #\= Y, |
| 44 | | ((var(X),var(Y)) -> dif(X,Y) ; true). % even for finite domains X in 1..10, Y in 1..10, X#\=Y, X=Y. does not fail; |
| 45 | | |
| 46 | | |
| 47 | | |
| 48 | | /* |
| 49 | | :- assert_must_succeed(( fd_utils_clpfd:neq_fdpair(2,3,2,4) )). |
| 50 | | :- assert_must_succeed(( fd_utils_clpfd:neq_fdpair(2,3,3,3) )). |
| 51 | | :- assert_must_fail(( fd_utils_clpfd:neq_fdpair(2,3,2,3) )). |
| 52 | | |
| 53 | | neq_fdpair(X1,Y1,X2,Y2) :- |
| 54 | | when((?=(X1,X2);?=(Y1,Y2)), |
| 55 | | (?=(X1,X2) -> (X1 \= X2 -> true ; dif(Y1,Y2)) |
| 56 | | ; (Y1 \= Y2 -> true ; dif(X1,X2)) |
| 57 | | )). |
| 58 | | */ |
| 59 | | |
| 60 | | :- use_module(kernel_waitflags,[add_fd_variable_for_labeling/2]). |
| 61 | | |
| 62 | | in_fd(X,Low,Up) :- number(Low), number(Up), !, X in Low..Up. |
| 63 | | in_fd(X,Low,Up) :- X #>=Low, X#=<Up. %when((ground(Low),ground(Up)), X in Low..Up). |
| 64 | | |
| 65 | | in_fd_wf(X,Low,Up,WF) :- number(Low), number(Up), !, X in Low..Up, |
| 66 | | in_fd_wf2(X,Low,Up,WF). |
| 67 | | in_fd_wf(X,Low,Up,WF) :- X #>=Low, X#=<Up, in_fd_wf2(X,Low,Up,WF). |
| 68 | | |
| 69 | | :- block in_fd_wf2(?,-,?,?), in_fd_wf2(?,?,-,?). |
| 70 | | in_fd_wf2(X,_Low,_Up,WF) :- |
| 71 | | (ground(X) -> true |
| 72 | | ; %Size is Up+1-Low, |
| 73 | | %fd_size(X,Size), |
| 74 | | add_fd_variable_for_labeling(X,WF) % will automatically do enumeration |
| 75 | | ). |
| 76 | | |
| 77 | | /* TO DO: check if we have to add FD variables to kernel_waitflags store using label_clpfd_vars |
| 78 | | in other circumstances; |
| 79 | | Provide support for x: {aa,bb,cc} ... constraints |
| 80 | | */ |
| 81 | | |
| 82 | | |
| 83 | | |
| 84 | | |
| 85 | | enum_fd(X,Low,Up) :- % we could use clpfd labeling |
| 86 | ? | preferences:get_preference(randomise_enumeration_order,true) |
| 87 | | -> %print(random_enum(X,Low,Up)),nl, |
| 88 | | enum_fd_random(X,Low,Up) |
| 89 | ? | ; enum_fd_linear(X,Low,Up). |
| 90 | | enum_fd_linear(X,Low,Up) :- |
| 91 | ? | Low =< Up |
| 92 | | -> ( %print(enum_fd(X,Low,Up)),translate:print_clpfd_variable(X),nl, |
| 93 | ? | X=Low %, tools:print_bt_message(done_enum_fd(X,Low,Up)) |
| 94 | | ; |
| 95 | | %print(continue(X,Low,Up)),nl, |
| 96 | | % TO DO: We could assert that X>Low and/or try to trigger all equalities for X=y with y<=Low |
| 97 | ? | L1 is Low+1, enum_fd_linear(X,L1,Up) |
| 98 | | ) |
| 99 | | ; fail. |
| 100 | | |
| 101 | | |
| 102 | | :- use_module(library(random)). |
| 103 | | :- use_module(extension('random_permutations/random_permutations')). |
| 104 | | enum_fd_random(Var,Low,Up) :- |
| 105 | | init_random_permutations, |
| 106 | | IntervalLength is Up - Low + 1, |
| 107 | | get_num_bits(IntervalLength,MaxIdx,NumBits), |
| 108 | | get_masks(NumBits,LeftMask,RightMask), |
| 109 | | % the seed relies on the random predicate, not on now/1, thus prob can be made deterministic by setting a central random seed |
| 110 | | random(TempSeed), |
| 111 | | Seed is floor(TempSeed * 10000), |
| 112 | | enum_fd_random_aux(Var,0,MaxIdx,Low,Up,Seed,NumBits,LeftMask,RightMask). |
| 113 | | |
| 114 | | enum_fd_random_aux(Var,CurIdx,MaxIdx,From,To,Seed,NumBits,LeftMask,RightMask) :- |
| 115 | | random_permutation_element(CurIdx,MaxIdx,From,To,Seed,NumBits,LeftMask,RightMask,Drawn,NextIdx), |
| 116 | | (Var=Drawn ; enum_fd_random_aux(Var,NextIdx,MaxIdx,From,To,Seed,NumBits,LeftMask,RightMask)). |
| 117 | | |
| 118 | | |
| 119 | | % not really required, would be a type error |
| 120 | | %:- block not_in_fd(-,?,?), not_in_fd(?,-,?), not_in_fd(?,?,-). |
| 121 | | %not_in_fd(X,Low,Up) :- |
| 122 | | % (X < Low ; X > Up),!. |