34
38
39:- module(clpb, [
40 op(300, fy, ~),
41 op(500, yfx, #),
42 sat/1,
43 taut/2,
44 labeling/1,
45 sat_count/2,
46 weighted_maximum/3,
47 random_labeling/2
48 ]). 49
50:- use_module(library(error)). 51:- use_module(library(assoc)). 52:- use_module(library(apply_macros)). 53
54:- create_prolog_flag(clpb_monotonic, false, []). 55:- create_prolog_flag(clpb_residuals, default, []). 56
279
280
328
332
333is_sat(V) :- var(V), !, non_monotonic(V).
334is_sat(v(V)) :- var(V), !.
335is_sat(v(I)) :- integer(I), between(0, 1, I).
336is_sat(I) :- integer(I), between(0, 1, I).
337is_sat(A) :- atom(A).
338is_sat(~A) :- is_sat(A).
339is_sat(A*B) :- is_sat(A), is_sat(B).
340is_sat(A+B) :- is_sat(A), is_sat(B).
341is_sat(A#B) :- is_sat(A), is_sat(B).
342is_sat(A=:=B) :- is_sat(A), is_sat(B).
343is_sat(A=\=B) :- is_sat(A), is_sat(B).
344is_sat(A=<B) :- is_sat(A), is_sat(B).
345is_sat(A>=B) :- is_sat(A), is_sat(B).
346is_sat(A<B) :- is_sat(A), is_sat(B).
347is_sat(A>B) :- is_sat(A), is_sat(B).
348is_sat(+(Ls)) :- must_be(list, Ls), maplist(is_sat, Ls).
349is_sat(*(Ls)) :- must_be(list, Ls), maplist(is_sat, Ls).
350is_sat(X^F) :- var(X), is_sat(F).
351is_sat(card(Is,Fs)) :-
352 must_be(list(ground), Is),
353 must_be(list, Fs),
354 maplist(is_sat, Fs).
355
356non_monotonic(X) :-
357 ( var_index(X, _) ->
358 359 true
360 ; current_prolog_flag(clpb_monotonic, true) ->
361 instantiation_error(X)
362 ; true
363 ).
364
371
373sat_rewrite(V, V) :- var(V), !.
374sat_rewrite(I, I) :- integer(I), !.
375sat_rewrite(A, V) :- atom(A), !, clpb_atom_var(A, V).
376sat_rewrite(v(V), V).
377sat_rewrite(P0*Q0, P*Q) :- sat_rewrite(P0, P), sat_rewrite(Q0, Q).
378sat_rewrite(P0+Q0, P+Q) :- sat_rewrite(P0, P), sat_rewrite(Q0, Q).
379sat_rewrite(P0#Q0, P#Q) :- sat_rewrite(P0, P), sat_rewrite(Q0, Q).
380sat_rewrite(X^F0, X^F) :- sat_rewrite(F0, F).
381sat_rewrite(card(Is,Fs0), card(Is,Fs)) :-
382 maplist(sat_rewrite, Fs0, Fs).
384sat_rewrite(~P, R) :- sat_rewrite(1 # P, R).
385sat_rewrite(P =:= Q, R) :- sat_rewrite(~P # Q, R).
386sat_rewrite(P =\= Q, R) :- sat_rewrite(P # Q, R).
387sat_rewrite(P =< Q, R) :- sat_rewrite(~P + Q, R).
388sat_rewrite(P >= Q, R) :- sat_rewrite(Q =< P, R).
389sat_rewrite(P < Q, R) :- sat_rewrite(~P * Q, R).
390sat_rewrite(P > Q, R) :- sat_rewrite(Q < P, R).
391sat_rewrite(+(Ls), R) :- foldl(or, Ls, 0, F), sat_rewrite(F, R).
392sat_rewrite(*(Ls), R) :- foldl(and, Ls, 1, F), sat_rewrite(F, R).
393
394or(A, B, B + A).
395
396and(A, B, B * A).
397
398must_be_sat(Sat) :-
399 must_be(acyclic, Sat),
400 ( is_sat(Sat) -> true
401 ; no_truth_value(Sat)
402 ).
403
404no_truth_value(Term) :- domain_error(clpb_expr, Term).
405
406parse_sat(Sat0, Sat) :-
407 must_be_sat(Sat0),
408 sat_rewrite(Sat0, Sat),
409 term_variables(Sat, Vs),
410 maplist(enumerate_variable, Vs).
411
412enumerate_variable(V) :-
413 ( var_index_root(V, _, _) -> true
414 ; clpb_next_id('$clpb_next_var', Index),
415 put_attr(V, clpb, index_root(Index,_)),
416 put_empty_hash(V)
417 ).
418
419var_index(V, I) :- var_index_root(V, I, _).
420
421var_index_root(V, I, Root) :- get_attr(V, clpb, index_root(I,Root)).
422
423put_empty_hash(V) :-
424 empty_assoc(H0),
425 put_attr(V, clpb_hash, H0).
426
427sat_roots(Sat, Roots) :-
428 term_variables(Sat, Vs),
429 maplist(var_index_root, Vs, _, Roots0),
430 term_variables(Roots0, Roots).
431
435
436sat(Sat0) :-
437 ( phrase(sat_ands(Sat0), Ands), Ands = [_,_|_] ->
438 maplist(sat, Ands)
439 ; parse_sat(Sat0, Sat),
440 sat_bdd(Sat, BDD),
441 sat_roots(Sat, Roots),
442 roots_and(Roots, Sat0-BDD, And-BDD1),
443 maplist(del_bdd, Roots),
444 maplist(=(Root), Roots),
445 root_put_formula_bdd(Root, And, BDD1),
446 is_bdd(BDD1),
447 satisfiable_bdd(BDD1)
448 ).
449
459
460sat_ands(X) -->
461 ( { var(X) } -> [X]
462 ; { X = (A*B) } -> sat_ands(A), sat_ands(B)
463 ; { X = *(Ls) } -> sat_ands_(Ls)
464 ; { X = ~Y } -> not_ors(Y)
465 ; [X]
466 ).
467
468sat_ands_([]) --> [].
469sat_ands_([L|Ls]) --> [L], sat_ands_(Ls).
470
471not_ors(X) -->
472 ( { var(X) } -> [~X]
473 ; { X = (A+B) } -> not_ors(A), not_ors(B)
474 ; { X = +(Ls) } -> not_ors_(Ls)
475 ; [~X]
476 ).
477
478not_ors_([]) --> [].
479not_ors_([L|Ls]) --> [~L], not_ors_(Ls).
480
481del_bdd(Root) :- del_attr(Root, clpb_bdd).
482
483root_get_formula_bdd(Root, F, BDD) :- get_attr(Root, clpb_bdd, F-BDD).
484
485root_put_formula_bdd(Root, F, BDD) :- put_attr(Root, clpb_bdd, F-BDD).
486
487roots_and(Roots, Sat0-BDD0, Sat-BDD) :-
488 foldl(root_and, Roots, Sat0-BDD0, Sat-BDD),
489 rebuild_hashes(BDD).
490
491root_and(Root, Sat0-BDD0, Sat-BDD) :-
492 ( root_get_formula_bdd(Root, F, B) ->
493 Sat = F*Sat0,
494 bdd_and(B, BDD0, BDD)
495 ; Sat = Sat0,
496 BDD = BDD0
497 ).
498
499bdd_and(NA, NB, And) :-
500 apply(*, NA, NB, And),
501 is_bdd(And).
502
508
509taut(Sat0, T) :-
510 parse_sat(Sat0, Sat),
511 ( T = 0, \+ sat(Sat) -> true
512 ; T = 1, tautology(Sat) -> true
513 ; false
514 ).
515
535
536tautology(Sat) :-
537 ( phrase(sat_ands(Sat), Ands), Ands = [_,_|_] ->
538 maplist(tautology, Ands)
539 ; catch((sat_roots(Sat, Roots),
540 roots_and(Roots, _-1, _-Ands),
541 sat_bdd(1#Sat, BDD),
542 bdd_and(BDD, Ands, B),
543 B == 0,
544 545 throw(tautology)),
546 tautology,
547 true)
548 ).
549
550satisfiable_bdd(BDD) :-
551 ( BDD == 0 -> false
552 ; BDD == 1 -> true
553 ; ( bdd_nodes(var_unbound, BDD, Nodes) ->
554 bdd_variables_classification(BDD, Nodes, Classes),
555 partition(var_class, Classes, Eqs, Bs, Ds),
556 domain_consistency(Eqs, Goal),
557 aliasing_consistency(Bs, Ds, Goals),
558 maplist(unification, [Goal|Goals])
559 ; 560 561 true
562 )
563 ).
564
565var_class(_=_, <).
566var_class(further_branching(_,_), =).
567var_class(negative_decisive(_), >).
568
569unification(true).
570unification(A=B) :- A = B. 571
572var_unbound(Node) :-
573 node_var_low_high(Node, Var, _, _),
574 var(Var).
575
576universal_var(Var) :- get_attr(Var, clpb_atom, _).
577
594
595aliasing_consistency(Bs, Ds, Goals) :-
596 phrase(aliasings(Bs, Ds), Goals).
597
598aliasings([], _) --> [].
599aliasings([further_branching(B,Nodes)|Bs], Ds) -->
600 { var_index(B, BI) },
601 aliasings_(Ds, B, BI, Nodes),
602 aliasings(Bs, Ds).
603
604aliasings_([], _, _, _) --> [].
605aliasings_([negative_decisive(D)|Ds], B, BI, Nodes) -->
606 { var_index(D, DI) },
607 ( { DI > BI,
608 always_false(high, DI, Nodes),
609 always_false(low, DI, Nodes),
610 var_or_atom(D, DA), var_or_atom(B, BA) } ->
611 [DA=BA]
612 ; []
613 ),
614 aliasings_(Ds, B, BI, Nodes).
615
616var_or_atom(Var, VA) :-
617 ( get_attr(Var, clpb_atom, VA) -> true
618 ; VA = Var
619 ).
620
621always_false(Which, DI, Nodes) :-
622 phrase(nodes_always_false(Nodes, Which, DI), Opposites),
623 maplist(with_aux(unvisit), Opposites).
624
625nodes_always_false([], _, _) --> [].
626nodes_always_false([Node|Nodes], Which, DI) -->
627 { which_node_child(Which, Node, Child),
628 opposite(Which, Opposite) },
629 opposite_always_false(Opposite, DI, Child),
630 nodes_always_false(Nodes, Which, DI).
631
632which_node_child(low, Node, Child) :-
633 node_var_low_high(Node, _, Child, _).
634which_node_child(high, Node, Child) :-
635 node_var_low_high(Node, _, _, Child).
636
637opposite(low, high).
638opposite(high, low).
639
640opposite_always_false(Opposite, DI, Node) -->
641 ( { node_visited(Node) } -> []
642 ; { node_var_low_high(Node, Var, Low, High),
643 with_aux(put_visited, Node),
644 var_index(Var, VI) },
645 [Node],
646 ( { VI =:= DI } ->
647 { which_node_child(Opposite, Node, Child),
648 Child == 0 }
649 ; opposite_always_false(Opposite, DI, Low),
650 opposite_always_false(Opposite, DI, High)
651 )
652 ).
653
654further_branching(Node) :-
655 node_var_low_high(Node, _, Low, High),
656 Low \== 1,
657 High \== 1.
658
659negative_decisive(Node) :-
660 node_var_low_high(Node, _, Low, High),
661 ( Low == 0 -> true
662 ; High == 0 -> true
663 ; false
664 ).
665
675
676domain_consistency(Eqs, Goal) :-
677 maplist(eq_a_b, Eqs, Vs, Values),
678 Goal = (Vs = Values). 679
680eq_a_b(A=B, A, B).
681
682consistently_false_(Which, Node) :-
683 which_node_child(Which, Node, Child),
684 Child == 0.
685
700
701bdd_variables_classification(BDD, Nodes, Classes) :-
702 nodes_variables(Nodes, Vs0),
703 variables_in_index_order(Vs0, Vs),
704 ( partition(universal_var, Vs, [_|_], Es) ->
705 foldl(existential, Es, BDD, 1)
706 ; true
707 ),
708 phrase(variables_classification(Vs, [BDD]), Classes),
709 maplist(with_aux(unvisit), Nodes).
710
711variables_classification([], _) --> [].
712variables_classification([V|Vs], Nodes0) -->
713 { var_index(V, Index) },
714 ( { phrase(nodes_with_variable(Nodes0, Index), Nodes) } ->
715 ( { maplist(consistently_false_(low), Nodes) } -> [V=1]
716 ; { maplist(consistently_false_(high), Nodes) } -> [V=0]
717 ; []
718 ),
719 ( { maplist(further_branching, Nodes) } ->
720 [further_branching(V, Nodes)]
721 ; []
722 ),
723 ( { maplist(negative_decisive, Nodes) } ->
724 [negative_decisive(V)]
725 ; []
726 ),
727 { maplist(with_aux(unvisit), Nodes) },
728 variables_classification(Vs, Nodes)
729 ; variables_classification(Vs, Nodes0)
730 ).
731
732nodes_with_variable([], _) --> [].
733nodes_with_variable([Node|Nodes], VI) -->
734 { Node \== 1 },
735 ( { node_visited(Node) } -> nodes_with_variable(Nodes, VI)
736 ; { with_aux(put_visited, Node),
737 node_var_low_high(Node, OVar, Low, High),
738 var_index(OVar, OVI) },
739 { OVI =< VI },
740 ( { OVI =:= VI } -> [Node]
741 ; nodes_with_variable([Low,High], VI)
742 ),
743 nodes_with_variable(Nodes, VI)
744 ).
745
749
750make_node(Var, Low, High, Node) :-
751 ( Low == High -> Node = Low
752 ; low_high_key(Low, High, Key),
753 ( lookup_node(Var, Key, Node) -> true
754 ; clpb_next_id('$clpb_next_node', ID),
755 Node = node(ID,Var,Low,High,_Aux),
756 register_node(Var, Key, Node)
757 )
758 ).
759
760make_node(Var, Low, High, Node) -->
761 762 { make_node(Var, Low, High, Node) }.
763
764
767
768low_high_key(Low, High, node(LID,HID)) :-
769 node_id(Low, LID),
770 node_id(High, HID).
771
772
773rebuild_hashes(BDD) :-
774 bdd_nodes(nodevar_put_empty_hash, BDD, Nodes),
775 maplist(re_register_node, Nodes).
776
777nodevar_put_empty_hash(Node) :-
778 node_var_low_high(Node, Var, _, _),
779 empty_assoc(H0),
780 put_attr(Var, clpb_hash, H0).
781
782re_register_node(Node) :-
783 node_var_low_high(Node, Var, Low, High),
784 low_high_key(Low, High, Key),
785 register_node(Var, Key, Node).
786
787register_node(Var, Key, Node) :-
788 get_attr(Var, clpb_hash, H0),
789 put_assoc(Key, H0, Node, H),
790 put_attr(Var, clpb_hash, H).
791
792lookup_node(Var, Key, Node) :-
793 get_attr(Var, clpb_hash, H0),
794 get_assoc(Key, H0, Node).
795
796
797node_id(0, false).
798node_id(1, true).
799node_id(node(ID,_,_,_,_), ID).
800
801node_aux(Node, Aux) :- arg(5, Node, Aux).
802
803node_var_low_high(Node, Var, Low, High) :-
804 Node = node(_,Var,Low,High,_).
805
806
811
812sat_bdd(V, Node) :- var(V), !, make_node(V, 0, 1, Node).
813sat_bdd(I, I) :- integer(I), !.
814sat_bdd(V^Sat, Node) :- !, sat_bdd(Sat, BDD), existential(V, BDD, Node).
815sat_bdd(card(Is,Fs), Node) :- !, counter_network(Is, Fs, Node).
816sat_bdd(Sat, Node) :- !,
817 Sat =.. [F,A,B],
818 sat_bdd(A, NA),
819 sat_bdd(B, NB),
820 apply(F, NA, NB, Node).
821
822existential(V, BDD, Node) :-
823 var_index(V, Index),
824 bdd_restriction(BDD, Index, 0, NA),
825 bdd_restriction(BDD, Index, 1, NB),
826 apply(+, NA, NB, Node).
827
831
832counter_network(Cs, Fs, Node) :-
833 same_length([_|Fs], Indicators),
834 fill_indicators(Indicators, 0, Cs),
835 phrase(formulas_variables(Fs, Vars0), ExBDDs),
836 maplist(unvisit, Vars0),
837 838 839 variables_in_index_order(Vars0, Vars1),
840 reverse(Vars1, Vars),
841 counter_network_(Vars, Indicators, Node0),
842 foldl(existential_and, ExBDDs, Node0, Node).
843
848
849formulas_variables([], []) --> [].
850formulas_variables([F|Fs], [V|Vs]) -->
851 ( { var(F), \+ is_visited(F) } ->
852 { V = F,
853 put_visited(F) }
854 ; { enumerate_variable(V),
855 sat_rewrite(V =:= F, Sat),
856 sat_bdd(Sat, BDD) },
857 [V-BDD]
858 ),
859 formulas_variables(Fs, Vs).
860
861counter_network_([], [Node], Node).
862counter_network_([Var|Vars], [I|Is0], Node) :-
863 foldl(indicators_pairing(Var), Is0, Is, I, _),
864 counter_network_(Vars, Is, Node).
865
866indicators_pairing(Var, I, Node, Prev, I) :- make_node(Var, Prev, I, Node).
867
868fill_indicators([], _, _).
869fill_indicators([I|Is], Index0, Cs) :-
870 ( memberchk(Index0, Cs) -> I = 1
871 ; member(A-B, Cs), between(A, B, Index0) -> I = 1
872 ; I = 0
873 ),
874 Index1 is Index0 + 1,
875 fill_indicators(Is, Index1, Cs).
876
877existential_and(Ex-BDD, Node0, Node) :-
878 bdd_and(BDD, Node0, Node1),
879 existential(Ex, Node1, Node),
880 881 882 del_attrs(Ex).
883
890
891apply(F, NA, NB, Node) :-
892 empty_assoc(G0),
893 phrase(apply(F, NA, NB, Node), [G0], _).
894
895apply(F, NA, NB, Node) -->
896 ( { integer(NA), integer(NB) } -> { once(bool_op(F, NA, NB, Node)) }
897 ; { apply_shortcut(F, NA, NB, Node) } -> []
898 ; { node_id(NA, IDA), node_id(NB, IDB), Key =.. [F,IDA,IDB] },
899 ( state(G0), { get_assoc(Key, G0, Node) } -> []
900 ; apply_(F, NA, NB, Node),
901 state(G0, G),
902 { put_assoc(Key, G0, Node, G) }
903 )
904 ).
905
906apply_shortcut(+, NA, NB, Node) :-
907 ( NA == 0 -> Node = NB
908 ; NA == 1 -> Node = 1
909 ; NB == 0 -> Node = NA
910 ; NB == 1 -> Node = 1
911 ; false
912 ).
913
914apply_shortcut(*, NA, NB, Node) :-
915 ( NA == 0 -> Node = 0
916 ; NA == 1 -> Node = NB
917 ; NB == 0 -> Node = 0
918 ; NB == 1 -> Node = NA
919 ; false
920 ).
921
922
923apply_(F, NA, NB, Node) -->
924 { var_less_than(NA, NB),
925 !,
926 node_var_low_high(NA, VA, LA, HA) },
927 apply(F, LA, NB, Low),
928 apply(F, HA, NB, High),
929 make_node(VA, Low, High, Node).
930apply_(F, NA, NB, Node) -->
931 { node_var_low_high(NA, VA, LA, HA),
932 node_var_low_high(NB, VB, LB, HB),
933 VA == VB },
934 !,
935 apply(F, LA, LB, Low),
936 apply(F, HA, HB, High),
937 make_node(VA, Low, High, Node).
938apply_(F, NA, NB, Node) --> 939 { node_var_low_high(NB, VB, LB, HB) },
940 apply(F, NA, LB, Low),
941 apply(F, NA, HB, High),
942 make_node(VB, Low, High, Node).
943
944
945node_varindex(Node, VI) :-
946 node_var_low_high(Node, V, _, _),
947 var_index(V, VI).
948
949var_less_than(NA, NB) :-
950 ( integer(NB) -> true
951 ; node_varindex(NA, VAI),
952 node_varindex(NB, VBI),
953 VAI < VBI
954 ).
955
956bool_op(+, 0, 0, 0).
957bool_op(+, 0, 1, 1).
958bool_op(+, 1, 0, 1).
959bool_op(+, 1, 1, 1).
960
961bool_op(*, 0, 0, 0).
962bool_op(*, 0, 1, 0).
963bool_op(*, 1, 0, 0).
964bool_op(*, 1, 1, 1).
965
966bool_op(#, 0, 0, 0).
967bool_op(#, 0, 1, 1).
968bool_op(#, 1, 0, 1).
969bool_op(#, 1, 1, 0).
970
974
975state(S) --> state(S, S).
976
977state(S0, S), [S] --> [S0].
978
1003
1004attr_unify_hook(index_root(I,Root), Other) :-
1005 ( integer(Other) ->
1006 ( between(0, 1, Other) ->
1007 root_get_formula_bdd(Root, Sat, BDD0),
1008 bdd_restriction(BDD0, I, Other, BDD),
1009 root_put_formula_bdd(Root, Sat, BDD),
1010 satisfiable_bdd(BDD)
1011 ; no_truth_value(Other)
1012 )
1013 ; atom(Other) ->
1014 root_get_formula_bdd(Root, Sat0, _),
1015 parse_sat(Sat0, Sat),
1016 sat_bdd(Sat, BDD),
1017 root_put_formula_bdd(Root, Sat0, BDD),
1018 is_bdd(BDD),
1019 satisfiable_bdd(BDD)
1020 ; 1021 1022 root_get_formula_bdd(Root, Sat0, _),
1023 Sat = Sat0*OtherSat,
1024 ( var(Other), var_index_root(Other, _, OtherRoot),
1025 OtherRoot \== Root ->
1026 root_get_formula_bdd(OtherRoot, OtherSat, _),
1027 parse_sat(Sat, Sat1),
1028 sat_bdd(Sat1, BDD1),
1029 And = Sat,
1030 sat_roots(Sat, Roots)
1031 ; parse_sat(Other, OtherSat),
1032 sat_roots(Sat, Roots),
1033 maplist(root_rebuild_bdd, Roots),
1034 roots_and(Roots, 1-1, And-BDD1)
1035 ),
1036 maplist(del_bdd, Roots),
1037 maplist(=(NewRoot), Roots),
1038 root_put_formula_bdd(NewRoot, And, BDD1),
1039 is_bdd(BDD1),
1040 satisfiable_bdd(BDD1)
1041 ).
1042
1043root_rebuild_bdd(Root) :-
1044 ( root_get_formula_bdd(Root, F0, _) ->
1045 parse_sat(F0, Sat),
1046 sat_bdd(Sat, BDD),
1047 root_put_formula_bdd(Root, F0, BDD)
1048 ; true
1049 ).
1050
1064
1065project_attributes(QueryVars0, AttrVars) :-
1066 append(QueryVars0, AttrVars, QueryVars1),
1067 include(clpb_variable, QueryVars1, QueryVars),
1068 maplist(var_index_root, QueryVars, _, Roots0),
1069 sort(Roots0, Roots),
1070 maplist(remove_hidden_variables(QueryVars), Roots).
1071
1072clpb_variable(Var) :- var_index(Var, _).
1073
1080
1081remove_hidden_variables(QueryVars, Root) :-
1082 root_get_formula_bdd(Root, Formula, BDD0),
1083 maplist(put_visited, QueryVars),
1084 bdd_variables(BDD0, HiddenVars0),
1085 exclude(universal_var, HiddenVars0, HiddenVars),
1086 maplist(unvisit, QueryVars),
1087 foldl(existential, HiddenVars, BDD0, BDD),
1088 foldl(quantify_existantially, HiddenVars, Formula, ExFormula),
1089 root_put_formula_bdd(Root, ExFormula, BDD).
1090
1091quantify_existantially(E, E0, E^E0) :- put_attr(E, clpb_omit_boolean, true).
1092
1096
1097bdd_restriction(Node, VI, Value, Res) :-
1098 empty_assoc(G0),
1099 phrase(bdd_restriction_(Node, VI, Value, Res), [G0], _),
1100 is_bdd(Res).
1101
1102bdd_restriction_(Node, VI, Value, Res) -->
1103 ( { integer(Node) } -> { Res = Node }
1104 ; { node_var_low_high(Node, Var, Low, High) } ->
1105 ( { integer(Var) } ->
1106 ( { Var =:= 0 } -> bdd_restriction_(Low, VI, Value, Res)
1107 ; { Var =:= 1 } -> bdd_restriction_(High, VI, Value, Res)
1108 ; { no_truth_value(Var) }
1109 )
1110 ; { var_index(Var, I0),
1111 node_id(Node, ID) },
1112 ( { I0 =:= VI } ->
1113 ( { Value =:= 0 } -> { Res = Low }
1114 ; { Value =:= 1 } -> { Res = High }
1115 )
1116 ; { I0 > VI } -> { Res = Node }
1117 ; state(G0), { get_assoc(ID, G0, Res) } -> []
1118 ; bdd_restriction_(Low, VI, Value, LRes),
1119 bdd_restriction_(High, VI, Value, HRes),
1120 make_node(Var, LRes, HRes, Res),
1121 state(G0, G),
1122 { put_assoc(ID, G0, Res, G) }
1123 )
1124 )
1125 ; { domain_error(node, Node) }
1126 ).
1127
1136
1137bdd_nodes(BDD, Ns) :- bdd_nodes(ignore_node, BDD, Ns).
1138
1139ignore_node(_).
1140
1143
1144bdd_nodes(VPred, BDD, Ns) :-
1145 phrase(bdd_nodes_(VPred, BDD), Ns),
1146 maplist(with_aux(unvisit), Ns).
1147
1148bdd_nodes_(VPred, Node) -->
1149 ( { node_visited(Node) } -> []
1150 ; { call(VPred, Node),
1151 with_aux(put_visited, Node),
1152 node_var_low_high(Node, _, Low, High) },
1153 [Node],
1154 bdd_nodes_(VPred, Low),
1155 bdd_nodes_(VPred, High)
1156 ).
1157
1158node_visited(Node) :- integer(Node).
1159node_visited(Node) :- with_aux(is_visited, Node).
1160
1161bdd_variables(BDD, Vs) :-
1162 bdd_nodes(BDD, Nodes),
1163 nodes_variables(Nodes, Vs).
1164
1165nodes_variables(Nodes, Vs) :-
1166 phrase(nodes_variables_(Nodes), Vs),
1167 maplist(unvisit, Vs).
1168
1169nodes_variables_([]) --> [].
1170nodes_variables_([Node|Nodes]) -->
1171 { node_var_low_high(Node, Var, _, _) },
1172 ( { integer(Var) } -> []
1173 ; { is_visited(Var) } -> []
1174 ; { put_visited(Var) },
1175 [Var]
1176 ),
1177 nodes_variables_(Nodes).
1178
1179unvisit(V) :- del_attr(V, clpb_visited).
1180
1181is_visited(V) :- get_attr(V, clpb_visited, true).
1182
1183put_visited(V) :- put_attr(V, clpb_visited, true).
1184
1185with_aux(Pred, Node) :-
1186 node_aux(Node, Aux),
1187 call(Pred, Aux).
1188
1194
1195is_bdd(BDD) :-
1196 ( current_prolog_flag(clpb_validation, true) ->
1197 bdd_ites(BDD, ITEs),
1198 pairs_values(ITEs, Ls0),
1199 sort(Ls0, Ls1),
1200 ( same_length(Ls0, Ls1) -> true
1201 ; domain_error(reduced_ites, (ITEs,Ls0,Ls1))
1202 ),
1203 ( member(ITE, ITEs), \+ registered_node(ITE) ->
1204 domain_error(registered_node, ITE)
1205 ; true
1206 ),
1207 ( member(I, ITEs), \+ ordered(I) ->
1208 domain_error(ordered_node, I)
1209 ; true
1210 )
1211 ; true
1212 ).
1213
1214ordered(_-ite(Var,High,Low)) :-
1215 ( var_index(Var, VI) ->
1216 greater_varindex_than(High, VI),
1217 greater_varindex_than(Low, VI)
1218 ; true
1219 ).
1220
1221greater_varindex_than(Node, VI) :-
1222 ( integer(Node) -> true
1223 ; node_var_low_high(Node, Var, _, _),
1224 ( var_index(Var, OI) ->
1225 OI > VI
1226 ; true
1227 )
1228 ).
1229
1230registered_node(Node-ite(Var,High,Low)) :-
1231 ( var(Var) ->
1232 low_high_key(Low, High, Key),
1233 lookup_node(Var, Key, Node0),
1234 Node == Node0
1235 ; true
1236 ).
1237
1238bdd_ites(BDD, ITEs) :-
1239 bdd_nodes(BDD, Nodes),
1240 maplist(node_ite, Nodes, ITEs).
1241
1242node_ite(Node, Node-ite(Var,High,Low)) :-
1243 node_var_low_high(Node, Var, Low, High).
1244
1249
1250labeling(Vs0) :-
1251 must_be(list, Vs0),
1252 maplist(labeling_var, Vs0),
1253 variables_in_index_order(Vs0, Vs),
1254 maplist(indomain, Vs).
1255
1256labeling_var(V) :- var(V), !.
1257labeling_var(V) :- V == 0, !.
1258labeling_var(V) :- V == 1, !.
1259labeling_var(V) :- domain_error(clpb_variable, V).
1260
1261variables_in_index_order(Vs0, Vs) :-
1262 maplist(var_with_index, Vs0, IVs0),
1263 keysort(IVs0, IVs),
1264 pairs_values(IVs, Vs).
1265
1266var_with_index(V, I-V) :-
1267 ( var_index_root(V, I, _) -> true
1268 ; I = 0
1269 ).
1270
1271indomain(0).
1272indomain(1).
1273
1274
1301
1302sat_count(Sat0, N) :-
1303 catch((parse_sat(Sat0, Sat),
1304 sat_bdd(Sat, BDD),
1305 sat_roots(Sat, Roots),
1306 roots_and(Roots, _-BDD, _-BDD1),
1307 1308 term_variables(Sat0, Vs),
1309 maplist(put_visited, Vs),
1310 1311 bdd_variables(BDD1, Vs1),
1312 partition(universal_var, Vs1, Univs, Exis),
1313 1314 foldl(universal, Univs, BDD1, BDD2),
1315 foldl(existential, Exis, BDD2, BDD3),
1316 variables_in_index_order(Vs, IVs),
1317 foldl(renumber_variable, IVs, 1, VNum),
1318 bdd_count(BDD3, VNum, Count0),
1319 var_u(BDD3, VNum, P),
1320 1321 1322 N0 is 2^(P - 1)*Count0,
1323 1324 throw(count(N0))),
1325 count(N0),
1326 N = N0).
1327
1328universal(V, BDD, Node) :-
1329 var_index(V, Index),
1330 bdd_restriction(BDD, Index, 0, NA),
1331 bdd_restriction(BDD, Index, 1, NB),
1332 apply(*, NA, NB, Node).
1333
1334renumber_variable(V, I0, I) :-
1335 put_attr(V, clpb, index_root(I0,_)),
1336 I is I0 + 1.
1337
1338bdd_count(Node, VNum, Count) :-
1339 ( integer(Node) -> Count = Node
1340 ; node_aux(Node, Count),
1341 ( integer(Count) -> true
1342 ; node_var_low_high(Node, V, Low, High),
1343 bdd_count(Low, VNum, LCount),
1344 bdd_count(High, VNum, HCount),
1345 bdd_pow(Low, V, VNum, LPow),
1346 bdd_pow(High, V, VNum, HPow),
1347 Count is LPow*LCount + HPow*HCount
1348 )
1349 ).
1350
1351
1352bdd_pow(Node, V, VNum, Pow) :-
1353 var_index(V, Index),
1354 var_u(Node, VNum, P),
1355 Pow is 2^(P - Index - 1).
1356
1357var_u(Node, VNum, Index) :-
1358 ( integer(Node) -> Index = VNum
1359 ; node_varindex(Node, Index)
1360 ).
1361
1365
1372
1373single_bdd(Vars0) :-
1374 maplist(monotonic_variable, Vars0, Vars),
1375 1376 sat(+[1|Vars]).
1377
1378random_labeling(Seed, Vars) :-
1379 must_be(list, Vars),
1380 set_random(seed(Seed)),
1381 ( ground(Vars) -> true
1382 ; catch((single_bdd(Vars),
1383 once((member(Var, Vars),var(Var))),
1384 var_index_root(Var, _, Root),
1385 root_get_formula_bdd(Root, _, BDD),
1386 bdd_variables(BDD, Vs),
1387 variables_in_index_order(Vs, IVs),
1388 foldl(renumber_variable, IVs, 1, VNum),
1389 phrase(random_bindings(VNum, BDD), Bs),
1390 maplist(del_attrs, Vs),
1391 1392 throw(randsol(Vars, Bs))),
1393 randsol(Vars, Bs),
1394 true),
1395 maplist(call, Bs),
1396 1397 include(var, Vars, Remaining),
1398 maplist(maybe_zero, Remaining)
1399 ).
1400
1401maybe_zero(Var) :-
1402 ( maybe -> Var = 0
1403 ; Var = 1
1404 ).
1405
1406random_bindings(_, Node) --> { Node == 1 }, !.
1407random_bindings(VNum, Node) -->
1408 { node_var_low_high(Node, Var, Low, High),
1409 bdd_count(Node, VNum, Total),
1410 bdd_count(Low, VNum, LCount) },
1411 ( { maybe(LCount, Total) } ->
1412 [Var=0], random_bindings(VNum, Low)
1413 ; [Var=1], random_bindings(VNum, High)
1414 ).
1415
1419
1439
1440weighted_maximum(Ws, Vars, Max) :-
1441 must_be(list(integer), Ws),
1442 must_be(list(var), Vars),
1443 single_bdd(Vars),
1444 Vars = [Var|_],
1445 var_index_root(Var, _, Root),
1446 root_get_formula_bdd(Root, _, BDD0),
1447 bdd_variables(BDD0, Vs),
1448 1449 maplist(put_visited, Vars),
1450 exclude(is_visited, Vs, Unvisited),
1451 maplist(unvisit, Vars),
1452 foldl(existential, Unvisited, BDD0, BDD),
1453 maplist(var_with_index, Vars, IVs),
1454 pairs_keys_values(Pairs0, IVs, Ws),
1455 keysort(Pairs0, Pairs1),
1456 pairs_keys_values(Pairs1, IVs1, WeightsIndexOrder),
1457 pairs_values(IVs1, VarsIndexOrder),
1458 1459 pairs_keys_values(Pairs, VarsIndexOrder, WeightsIndexOrder),
1460 bdd_maximum(BDD, Pairs, Max),
1461 max_labeling(BDD, Pairs).
1462
1463max_labeling(1, Pairs) :- max_upto(Pairs, _, _).
1464max_labeling(node(_,Var,Low,High,Aux), Pairs0) :-
1465 max_upto(Pairs0, Var, Pairs),
1466 get_attr(Aux, clpb_max, max(_,Dir)),
1467 direction_labeling(Dir, Var, Low, High, Pairs).
1468
1469max_upto([], _, _).
1470max_upto([Var0-Weight|VWs0], Var, VWs) :-
1471 ( Var == Var0 -> VWs = VWs0
1472 ; Weight =:= 0 ->
1473 ( Var0 = 0 ; Var0 = 1 ),
1474 max_upto(VWs0, Var, VWs)
1475 ; Weight < 0 -> Var0 = 0, max_upto(VWs0, Var, VWs)
1476 ; Var0 = 1, max_upto(VWs0, Var, VWs)
1477 ).
1478
1479direction_labeling(low, 0, Low, _, Pairs) :- max_labeling(Low, Pairs).
1480direction_labeling(high, 1, _, High, Pairs) :- max_labeling(High, Pairs).
1481
1482bdd_maximum(1, Pairs, Max) :-
1483 pairs_values(Pairs, Weights0),
1484 include(<(0), Weights0, Weights),
1485 sum_list(Weights, Max).
1486bdd_maximum(node(_,Var,Low,High,Aux), Pairs0, Max) :-
1487 ( get_attr(Aux, clpb_max, max(Max,_)) -> true
1488 ; ( skip_to_var(Var, Weight, Pairs0, Pairs),
1489 ( Low == 0 ->
1490 bdd_maximum_(High, Pairs, MaxHigh, MaxToHigh),
1491 Max is MaxToHigh + MaxHigh + Weight,
1492 Dir = high
1493 ; High == 0 ->
1494 bdd_maximum_(Low, Pairs, MaxLow, MaxToLow),
1495 Max is MaxToLow + MaxLow,
1496 Dir = low
1497 ; bdd_maximum_(Low, Pairs, MaxLow, MaxToLow),
1498 bdd_maximum_(High, Pairs, MaxHigh, MaxToHigh),
1499 Max0 is MaxToLow + MaxLow,
1500 Max1 is MaxToHigh + MaxHigh + Weight,
1501 Max is max(Max0,Max1),
1502 ( Max0 =:= Max1 -> Dir = _Any
1503 ; Max0 < Max1 -> Dir = high
1504 ; Dir = low
1505 )
1506 ),
1507 store_maximum(Aux, Max, Dir)
1508 )
1509 ).
1510
1511bdd_maximum_(Node, Pairs, Max, MaxTo) :-
1512 bdd_maximum(Node, Pairs, Max),
1513 between_weights(Node, Pairs, MaxTo).
1514
1515store_maximum(Aux, Max, Dir) :- put_attr(Aux, clpb_max, max(Max,Dir)).
1516
1517between_weights(Node, Pairs0, MaxTo) :-
1518 ( Node == 1 -> MaxTo = 0
1519 ; node_var_low_high(Node, Var, _, _),
1520 phrase(skip_to_var_(Var, _, Pairs0, _), Weights0),
1521 include(<(0), Weights0, Weights),
1522 sum_list(Weights, MaxTo)
1523 ).
1524
1525skip_to_var(Var, Weight, Pairs0, Pairs) :-
1526 phrase(skip_to_var_(Var, Weight, Pairs0, Pairs), _).
1527
1528skip_to_var_(Var, Weight, [Var0-Weight0|VWs0], VWs) -->
1529 ( { Var == Var0 } ->
1530 { Weight = Weight0, VWs0 = VWs }
1531 ; ( { Weight0 =< 0 } -> []
1532 ; [Weight0]
1533 ),
1534 skip_to_var_(Var, Weight, VWs0, VWs)
1535 ).
1536
1540
1541attribute_goals(Var) -->
1542 { var_index_root(Var, _, Root) },
1543 ( { root_get_formula_bdd(Root, Formula, BDD) } ->
1544 { del_bdd(Root) },
1545 ( { current_prolog_flag(clpb_residuals, bdd) } ->
1546 { bdd_nodes(BDD, Nodes),
1547 phrase(nodes(Nodes), Ns) },
1548 [clpb:'$clpb_bdd'(Ns)]
1549 ; { prepare_global_variables(BDD),
1550 phrase(sat_ands(Formula), Ands0),
1551 ands_fusion(Ands0, Ands),
1552 maplist(formula_anf, Ands, ANFs0),
1553 sort(ANFs0, ANFs1),
1554 exclude(eq_1, ANFs1, ANFs2),
1555 variables_separation(ANFs2, ANFs) },
1556 sats(ANFs)
1557 ),
1558 ( { get_attr(Var, clpb_atom, Atom) } ->
1559 [clpb:sat(Var=:=Atom)]
1560 ; []
1561 ),
1562 1563 { bdd_variables(BDD, Vs),
1564 maplist(del_clpb, Vs),
1565 term_variables(Formula, RestVs0),
1566 include(clpb_variable, RestVs0, RestVs) },
1567 booleans(RestVs)
1568 ; boolean(Var) 1569 ).
1570
1571del_clpb(Var) :- del_attr(Var, clpb).
1572
1580
1581prepare_global_variables(BDD) :-
1582 clpb_next_id('$clpb_next_var', V0),
1583 clpb_next_id('$clpb_next_node', N0),
1584 bdd_nodes(BDD, Nodes),
1585 foldl(max_variable_node, Nodes, V0-N0, MaxV0-MaxN0),
1586 MaxV is MaxV0 + 1,
1587 MaxN is MaxN0 + 1,
1588 b_setval('$clpb_next_var', MaxV),
1589 b_setval('$clpb_next_node', MaxN).
1590
1591max_variable_node(Node, V0-N0, V-N) :-
1592 node_id(Node, N1),
1593 node_varindex(Node, V1),
1594 N is max(N0,N1),
1595 V is max(V0,V1).
1596
1600
1601ands_fusion(Ands0, Ands) :-
1602 maplist(with_variables, Ands0, Pairs0),
1603 keysort(Pairs0, Pairs),
1604 group_pairs_by_key(Pairs, Groups),
1605 pairs_values(Groups, Andss),
1606 maplist(list_to_conjunction, Andss, Ands).
1607
1608with_variables(F, Vs-F) :-
1609 term_variables(F, Vs0),
1610 variables_in_index_order(Vs0, Vs).
1611
1619
1620variables_separation(Fs0, Fs) :- separation_fixpoint(Fs0, [], Fs).
1621
1622separation_fixpoint(Fs0, Ds0, Fs) :-
1623 phrase(variables_separation_(Fs0, Ds0, Rest), Fs1),
1624 partition(anf_done, Fs1, Ds1, Fs2),
1625 maplist(arg(1), Ds1, Ds2),
1626 maplist(arg(1), Fs2, Fs3),
1627 append(Ds0, Ds2, Ds3),
1628 append(Rest, Fs3, Fs4),
1629 sort(Fs4, Fs5),
1630 sort(Ds3, Ds4),
1631 ( Fs5 == [] -> Fs = Ds4
1632 ; separation_fixpoint(Fs5, Ds4, Fs)
1633 ).
1634
1635anf_done(done(_)).
1636
1637variables_separation_([], _, []) --> [].
1638variables_separation_([F0|Fs0], Ds, Rest) -->
1639 ( { member(Done, Ds), F0 == Done } ->
1640 variables_separation_(Fs0, Ds, Rest)
1641 ; { sat_rewrite(F0, F),
1642 sat_bdd(F, BDD),
1643 bdd_variables(BDD, Vs0),
1644 exclude(universal_var, Vs0, Vs),
1645 maplist(existential_(BDD), Vs, Nodes),
1646 phrase(pairs(Nodes), Pairs),
1647 group_pairs_by_key(Pairs, Groups),
1648 phrase(groups_separation(Groups, BDD), ANFs) },
1649 ( { ANFs = [_|_] } ->
1650 list(ANFs),
1651 { Rest = Fs0 }
1652 ; [done(F0)],
1653 variables_separation_(Fs0, Ds, Rest)
1654 )
1655 ).
1656
1657
1658existential_(BDD, V, Node) :- existential(V, BDD, Node).
1659
1660groups_separation([], _) --> [].
1661groups_separation([BDD1-BDDs|Groups], OrigBDD) -->
1662 { phrase(separate_pairs(BDDs, BDD1, OrigBDD), Nodes) },
1663 ( { Nodes = [_|_] } ->
1664 nodes_anfs([BDD1|Nodes])
1665 ; []
1666 ),
1667 groups_separation(Groups, OrigBDD).
1668
1669separate_pairs([], _, _) --> [].
1670separate_pairs([BDD2|Ps], BDD1, OrigBDD) -->
1671 ( { apply(*, BDD1, BDD2, And),
1672 And == OrigBDD } ->
1673 [BDD2]
1674 ; []
1675 ),
1676 separate_pairs(Ps, BDD1, OrigBDD).
1677
1678nodes_anfs([]) --> [].
1679nodes_anfs([N|Ns]) --> { node_anf(N, ANF) }, [anf(ANF)], nodes_anfs(Ns).
1680
1681pairs([]) --> [].
1682pairs([V|Vs]) --> pairs_(Vs, V), pairs(Vs).
1683
1684pairs_([], _) --> [].
1685pairs_([B|Bs], A) --> [A-B], pairs_(Bs, A).
1686
1691
1692nodes([]) --> [].
1693nodes([Node|Nodes]) -->
1694 { node_var_low_high(Node, Var0, Low, High),
1695 var_or_atom(Var0, Var),
1696 maplist(node_projection, [Node,High,Low], [ID,HID,LID]),
1697 var_index(Var0, VI) },
1698 [ID-(v(Var,VI) -> HID ; LID)],
1699 nodes(Nodes).
1700
1701
1702node_projection(Node, Projection) :-
1703 node_id(Node, ID),
1704 ( integer(ID) -> Projection = node(ID)
1705 ; Projection = ID
1706 ).
1707
1712
1713sats([]) --> [].
1714sats([A|As]) --> [clpb:sat(A)], sats(As).
1715
1716booleans([]) --> [].
1717booleans([B|Bs]) --> boolean(B), { del_clpb(B) }, booleans(Bs).
1718
1719boolean(Var) -->
1720 ( { get_attr(Var, clpb_omit_boolean, true) } -> []
1721 ; [clpb:sat(Var =:= Var)]
1722 ).
1723
1727
1728formula_anf(Formula0, ANF) :-
1729 parse_sat(Formula0, Formula),
1730 sat_bdd(Formula, Node),
1731 node_anf(Node, ANF).
1732
1733node_anf(Node, ANF) :-
1734 node_xors(Node, Xors0),
1735 maplist(maplist(monotonic_variable), Xors0, Xors),
1736 maplist(list_to_conjunction, Xors, Conjs),
1737 ( Conjs = [Var,C|Rest], clpb_var(Var) ->
1738 foldl(xor, Rest, C, RANF),
1739 ANF = (Var =\= RANF)
1740 ; Conjs = [One,Var,C|Rest], One == 1, clpb_var(Var) ->
1741 foldl(xor, Rest, C, RANF),
1742 ANF = (Var =:= RANF)
1743 ; Conjs = [C|Cs],
1744 foldl(xor, Cs, C, ANF)
1745 ).
1746
1747monotonic_variable(Var0, Var) :-
1748 ( var(Var0), current_prolog_flag(clpb_monotonic, true) ->
1749 Var = v(Var0)
1750 ; Var = Var0
1751 ).
1752
1753clpb_var(Var) :- var(Var), !.
1754clpb_var(v(_)).
1755
1756list_to_conjunction([], 1).
1757list_to_conjunction([L|Ls], Conj) :- foldl(and, Ls, L, Conj).
1758
1759xor(A, B, B # A).
1760
1761eq_1(V) :- V == 1.
1762
1763node_xors(Node, Xors) :-
1764 phrase(xors(Node), Xors0),
1765 1766 maplist(sort, Xors0, Xors1),
1767 pairs_keys_values(Pairs0, Xors1, _),
1768 keysort(Pairs0, Pairs),
1769 group_pairs_by_key(Pairs, Groups),
1770 exclude(even_occurrences, Groups, Odds),
1771 pairs_keys(Odds, Xors2),
1772 maplist(exclude(eq_1), Xors2, Xors).
1773
1774even_occurrences(_-Ls) :- length(Ls, L), L mod 2 =:= 0.
1775
1776xors(Node) -->
1777 ( { Node == 0 } -> []
1778 ; { Node == 1 } -> [[1]]
1779 ; { node_var_low_high(Node, Var0, Low, High),
1780 var_or_atom(Var0, Var),
1781 node_xors(Low, Ls0),
1782 node_xors(High, Hs0),
1783 maplist(with_var(Var), Ls0, Ls),
1784 maplist(with_var(Var), Hs0, Hs) },
1785 list(Ls0),
1786 list(Ls),
1787 list(Hs)
1788 ).
1789
1790list([]) --> [].
1791list([L|Ls]) --> [L], list(Ls).
1792
1793with_var(Var, Ls, [Var|Ls]).
1794
1798
1799make_clpb_var('$clpb_next_var') :- nb_setval('$clpb_next_var', 0).
1800
1801make_clpb_var('$clpb_next_node') :- nb_setval('$clpb_next_node', 0).
1802
1803make_clpb_var('$clpb_atoms') :-
1804 empty_assoc(E),
1805 nb_setval('$clpb_atoms', E).
1806
1807:- multifile user:exception/3. 1808
1809user:exception(undefined_global_variable, Name, retry) :-
1810 make_clpb_var(Name), !.
1811
1812clpb_next_id(Var, ID) :-
1813 b_getval(Var, ID),
1814 Next is ID + 1,
1815 b_setval(Var, Next).
1816
1817clpb_atom_var(Atom, Var) :-
1818 b_getval('$clpb_atoms', A0),
1819 ( get_assoc(Atom, A0, Var) -> true
1820 ; put_attr(Var, clpb_atom, Atom),
1821 put_attr(Var, clpb_omit_boolean, true),
1822 put_assoc(Atom, A0, Var, A),
1823 b_setval('$clpb_atoms', A)
1824 ).
1825
1833
1834:- public
1835 clpb_hash:attr_unify_hook/2,
1836 clpb_bdd:attribute_goals//1,
1837 clpb_hash:attribute_goals//1,
1838 clpb_omit_boolean:attr_unify_hook/2,
1839 clpb_omit_boolean:attribute_goals//1,
1840 clpb_atom:attr_unify_hook/2,
1841 clpb_atom:attribute_goals//1. 1842
1843clpb_hash:attr_unify_hook(_,_). 1844
1850
1851clpb_atom:attr_unify_hook(_, _) :- false.
1852
1853clpb_omit_boolean:attr_unify_hook(_,_).
1854
1855clpb_bdd:attribute_goals(_) --> [].
1856clpb_hash:attribute_goals(_) --> [].
1857clpb_omit_boolean:attribute_goals(_) --> [].
1858clpb_atom:attribute_goals(_) --> [].
1859
1864
1867
1871
1872:- multifile prolog:message//1. 1873
1874prolog:message(clpb(bounded)) -->
1875 ['Using CLP(B) with bounded arithmetic may yield wrong results.'-[]].
1876
1877warn_if_bounded_arithmetic :-
1878 ( current_prolog_flag(bounded, true) ->
1879 print_message(warning, clpb(bounded))
1880 ; true
1881 ).
1882
1883:- initialization(warn_if_bounded_arithmetic). 1884
1888
1889:- multifile
1890 sandbox:safe_global_variable/1,
1891 sandbox:safe_primitive/1. 1892
1893sandbox:safe_global_variable('$clpb_next_var').
1894sandbox:safe_global_variable('$clpb_next_node').
1895sandbox:safe_global_variable('$clpb_atoms').
1896sandbox:safe_primitive(set_prolog_flag(clpb_residuals, _))