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
261
262
310
314
315is_sat(V) :- var(V), !, non_monotonic(V).
316is_sat(v(V)) :- var(V), !.
317is_sat(v(I)) :- integer(I), between(0, 1, I).
318is_sat(I) :- integer(I), between(0, 1, I).
319is_sat(A) :- atom(A).
320is_sat(~A) :- is_sat(A).
321is_sat(A*B) :- is_sat(A), is_sat(B).
322is_sat(A+B) :- is_sat(A), is_sat(B).
323is_sat(A#B) :- is_sat(A), is_sat(B).
324is_sat(A=:=B) :- is_sat(A), is_sat(B).
325is_sat(A=\=B) :- is_sat(A), is_sat(B).
326is_sat(A=<B) :- is_sat(A), is_sat(B).
327is_sat(A>=B) :- is_sat(A), is_sat(B).
328is_sat(A<B) :- is_sat(A), is_sat(B).
329is_sat(A>B) :- is_sat(A), is_sat(B).
330is_sat(+(Ls)) :- must_be(list, Ls), maplist(is_sat, Ls).
331is_sat(*(Ls)) :- must_be(list, Ls), maplist(is_sat, Ls).
332is_sat(X^F) :- var(X), is_sat(F).
333is_sat(card(Is,Fs)) :-
334 must_be(list(ground), Is),
335 must_be(list, Fs),
336 maplist(is_sat, Fs).
337
338non_monotonic(X) :-
339 ( var_index(X, _) ->
340 341 true
342 ; current_prolog_flag(clpb_monotonic, true) ->
343 instantiation_error(X)
344 ; true
345 ).
346
353
355sat_rewrite(V, V) :- var(V), !.
356sat_rewrite(I, I) :- integer(I), !.
357sat_rewrite(A, V) :- atom(A), !, clpb_atom_var(A, V).
358sat_rewrite(v(V), V).
359sat_rewrite(P0*Q0, P*Q) :- sat_rewrite(P0, P), sat_rewrite(Q0, Q).
360sat_rewrite(P0+Q0, P+Q) :- sat_rewrite(P0, P), sat_rewrite(Q0, Q).
361sat_rewrite(P0#Q0, P#Q) :- sat_rewrite(P0, P), sat_rewrite(Q0, Q).
362sat_rewrite(X^F0, X^F) :- sat_rewrite(F0, F).
363sat_rewrite(card(Is,Fs0), card(Is,Fs)) :-
364 maplist(sat_rewrite, Fs0, Fs).
366sat_rewrite(~P, R) :- sat_rewrite(1 # P, R).
367sat_rewrite(P =:= Q, R) :- sat_rewrite(~P # Q, R).
368sat_rewrite(P =\= Q, R) :- sat_rewrite(P # Q, R).
369sat_rewrite(P =< Q, R) :- sat_rewrite(~P + Q, R).
370sat_rewrite(P >= Q, R) :- sat_rewrite(Q =< P, R).
371sat_rewrite(P < Q, R) :- sat_rewrite(~P * Q, R).
372sat_rewrite(P > Q, R) :- sat_rewrite(Q < P, R).
373sat_rewrite(+(Ls), R) :- foldl(or, Ls, 0, F), sat_rewrite(F, R).
374sat_rewrite(*(Ls), R) :- foldl(and, Ls, 1, F), sat_rewrite(F, R).
375
376or(A, B, B + A).
377
378and(A, B, B * A).
379
380must_be_sat(Sat) :-
381 must_be(acyclic, Sat),
382 ( is_sat(Sat) -> true
383 ; no_truth_value(Sat)
384 ).
385
386no_truth_value(Term) :- domain_error(clpb_expr, Term).
387
388parse_sat(Sat0, Sat) :-
389 must_be_sat(Sat0),
390 sat_rewrite(Sat0, Sat),
391 term_variables(Sat, Vs),
392 maplist(enumerate_variable, Vs).
393
394enumerate_variable(V) :-
395 ( var_index_root(V, _, _) -> true
396 ; clpb_next_id('$clpb_next_var', Index),
397 put_attr(V, clpb, index_root(Index,_)),
398 put_empty_hash(V)
399 ).
400
401var_index(V, I) :- var_index_root(V, I, _).
402
403var_index_root(V, I, Root) :- get_attr(V, clpb, index_root(I,Root)).
404
405put_empty_hash(V) :-
406 empty_assoc(H0),
407 put_attr(V, clpb_hash, H0).
408
409sat_roots(Sat, Roots) :-
410 term_variables(Sat, Vs),
411 maplist(var_index_root, Vs, _, Roots0),
412 term_variables(Roots0, Roots).
413
417
418sat(Sat0) :-
419 ( phrase(sat_ands(Sat0), Ands), Ands = [_,_|_] ->
420 maplist(sat, Ands)
421 ; parse_sat(Sat0, Sat),
422 sat_bdd(Sat, BDD),
423 sat_roots(Sat, Roots),
424 roots_and(Roots, Sat0-BDD, And-BDD1),
425 maplist(del_bdd, Roots),
426 maplist(=(Root), Roots),
427 root_put_formula_bdd(Root, And, BDD1),
428 is_bdd(BDD1),
429 satisfiable_bdd(BDD1)
430 ).
431
441
442sat_ands(X) -->
443 ( { var(X) } -> [X]
444 ; { X = (A*B) } -> sat_ands(A), sat_ands(B)
445 ; { X = *(Ls) } -> sat_ands_(Ls)
446 ; { X = ~Y } -> not_ors(Y)
447 ; [X]
448 ).
449
450sat_ands_([]) --> [].
451sat_ands_([L|Ls]) --> [L], sat_ands_(Ls).
452
453not_ors(X) -->
454 ( { var(X) } -> [~X]
455 ; { X = (A+B) } -> not_ors(A), not_ors(B)
456 ; { X = +(Ls) } -> not_ors_(Ls)
457 ; [~X]
458 ).
459
460not_ors_([]) --> [].
461not_ors_([L|Ls]) --> [~L], not_ors_(Ls).
462
463del_bdd(Root) :- del_attr(Root, clpb_bdd).
464
465root_get_formula_bdd(Root, F, BDD) :- get_attr(Root, clpb_bdd, F-BDD).
466
467root_put_formula_bdd(Root, F, BDD) :- put_attr(Root, clpb_bdd, F-BDD).
468
469roots_and(Roots, Sat0-BDD0, Sat-BDD) :-
470 foldl(root_and, Roots, Sat0-BDD0, Sat-BDD),
471 rebuild_hashes(BDD).
472
473root_and(Root, Sat0-BDD0, Sat-BDD) :-
474 ( root_get_formula_bdd(Root, F, B) ->
475 Sat = F*Sat0,
476 bdd_and(B, BDD0, BDD)
477 ; Sat = Sat0,
478 BDD = BDD0
479 ).
480
481bdd_and(NA, NB, And) :-
482 apply(*, NA, NB, And),
483 is_bdd(And).
484
490
491taut(Sat0, T) :-
492 parse_sat(Sat0, Sat),
493 ( T = 0, \+ sat(Sat) -> true
494 ; T = 1, tautology(Sat) -> true
495 ; false
496 ).
497
517
518tautology(Sat) :-
519 ( phrase(sat_ands(Sat), Ands), Ands = [_,_|_] ->
520 maplist(tautology, Ands)
521 ; catch((sat_roots(Sat, Roots),
522 roots_and(Roots, _-1, _-Ands),
523 sat_bdd(1#Sat, BDD),
524 bdd_and(BDD, Ands, B),
525 B == 0,
526 527 throw(tautology)),
528 tautology,
529 true)
530 ).
531
532satisfiable_bdd(BDD) :-
533 ( BDD == 0 -> false
534 ; BDD == 1 -> true
535 ; ( bdd_nodes(var_unbound, BDD, Nodes) ->
536 bdd_variables_classification(BDD, Nodes, Classes),
537 partition(var_class, Classes, Eqs, Bs, Ds),
538 domain_consistency(Eqs, Goal),
539 aliasing_consistency(Bs, Ds, Goals),
540 maplist(unification, [Goal|Goals])
541 ; 542 543 true
544 )
545 ).
546
547var_class(_=_, <).
548var_class(further_branching(_,_), =).
549var_class(negative_decisive(_), >).
550
551unification(true).
552unification(A=B) :- A = B. 553
554var_unbound(Node) :-
555 node_var_low_high(Node, Var, _, _),
556 var(Var).
557
558universal_var(Var) :- get_attr(Var, clpb_atom, _).
559
576
577aliasing_consistency(Bs, Ds, Goals) :-
578 phrase(aliasings(Bs, Ds), Goals).
579
580aliasings([], _) --> [].
581aliasings([further_branching(B,Nodes)|Bs], Ds) -->
582 { var_index(B, BI) },
583 aliasings_(Ds, B, BI, Nodes),
584 aliasings(Bs, Ds).
585
586aliasings_([], _, _, _) --> [].
587aliasings_([negative_decisive(D)|Ds], B, BI, Nodes) -->
588 { var_index(D, DI) },
589 ( { DI > BI,
590 always_false(high, DI, Nodes),
591 always_false(low, DI, Nodes),
592 var_or_atom(D, DA), var_or_atom(B, BA) } ->
593 [DA=BA]
594 ; []
595 ),
596 aliasings_(Ds, B, BI, Nodes).
597
598var_or_atom(Var, VA) :-
599 ( get_attr(Var, clpb_atom, VA) -> true
600 ; VA = Var
601 ).
602
603always_false(Which, DI, Nodes) :-
604 phrase(nodes_always_false(Nodes, Which, DI), Opposites),
605 maplist(with_aux(unvisit), Opposites).
606
607nodes_always_false([], _, _) --> [].
608nodes_always_false([Node|Nodes], Which, DI) -->
609 { which_node_child(Which, Node, Child),
610 opposite(Which, Opposite) },
611 opposite_always_false(Opposite, DI, Child),
612 nodes_always_false(Nodes, Which, DI).
613
614which_node_child(low, Node, Child) :-
615 node_var_low_high(Node, _, Child, _).
616which_node_child(high, Node, Child) :-
617 node_var_low_high(Node, _, _, Child).
618
619opposite(low, high).
620opposite(high, low).
621
622opposite_always_false(Opposite, DI, Node) -->
623 ( { node_visited(Node) } -> []
624 ; { node_var_low_high(Node, Var, Low, High),
625 with_aux(put_visited, Node),
626 var_index(Var, VI) },
627 [Node],
628 ( { VI =:= DI } ->
629 { which_node_child(Opposite, Node, Child),
630 Child == 0 }
631 ; opposite_always_false(Opposite, DI, Low),
632 opposite_always_false(Opposite, DI, High)
633 )
634 ).
635
636further_branching(Node) :-
637 node_var_low_high(Node, _, Low, High),
638 Low \== 1,
639 High \== 1.
640
641negative_decisive(Node) :-
642 node_var_low_high(Node, _, Low, High),
643 ( Low == 0 -> true
644 ; High == 0 -> true
645 ; false
646 ).
647
657
658domain_consistency(Eqs, Goal) :-
659 maplist(eq_a_b, Eqs, Vs, Values),
660 Goal = (Vs = Values). 661
662eq_a_b(A=B, A, B).
663
664consistently_false_(Which, Node) :-
665 which_node_child(Which, Node, Child),
666 Child == 0.
667
682
683bdd_variables_classification(BDD, Nodes, Classes) :-
684 nodes_variables(Nodes, Vs0),
685 variables_in_index_order(Vs0, Vs),
686 ( partition(universal_var, Vs, [_|_], Es) ->
687 foldl(existential, Es, BDD, 1)
688 ; true
689 ),
690 phrase(variables_classification(Vs, [BDD]), Classes),
691 maplist(with_aux(unvisit), Nodes).
692
693variables_classification([], _) --> [].
694variables_classification([V|Vs], Nodes0) -->
695 { var_index(V, Index) },
696 ( { phrase(nodes_with_variable(Nodes0, Index), Nodes) } ->
697 ( { maplist(consistently_false_(low), Nodes) } -> [V=1]
698 ; { maplist(consistently_false_(high), Nodes) } -> [V=0]
699 ; []
700 ),
701 ( { maplist(further_branching, Nodes) } ->
702 [further_branching(V, Nodes)]
703 ; []
704 ),
705 ( { maplist(negative_decisive, Nodes) } ->
706 [negative_decisive(V)]
707 ; []
708 ),
709 { maplist(with_aux(unvisit), Nodes) },
710 variables_classification(Vs, Nodes)
711 ; variables_classification(Vs, Nodes0)
712 ).
713
714nodes_with_variable([], _) --> [].
715nodes_with_variable([Node|Nodes], VI) -->
716 { Node \== 1 },
717 ( { node_visited(Node) } -> nodes_with_variable(Nodes, VI)
718 ; { with_aux(put_visited, Node),
719 node_var_low_high(Node, OVar, Low, High),
720 var_index(OVar, OVI) },
721 { OVI =< VI },
722 ( { OVI =:= VI } -> [Node]
723 ; nodes_with_variable([Low,High], VI)
724 ),
725 nodes_with_variable(Nodes, VI)
726 ).
727
731
732make_node(Var, Low, High, Node) :-
733 ( Low == High -> Node = Low
734 ; low_high_key(Low, High, Key),
735 ( lookup_node(Var, Key, Node) -> true
736 ; clpb_next_id('$clpb_next_node', ID),
737 Node = node(ID,Var,Low,High,_Aux),
738 register_node(Var, Key, Node)
739 )
740 ).
741
742make_node(Var, Low, High, Node) -->
743 744 { make_node(Var, Low, High, Node) }.
745
746
749
750low_high_key(Low, High, node(LID,HID)) :-
751 node_id(Low, LID),
752 node_id(High, HID).
753
754
755rebuild_hashes(BDD) :-
756 bdd_nodes(nodevar_put_empty_hash, BDD, Nodes),
757 maplist(re_register_node, Nodes).
758
759nodevar_put_empty_hash(Node) :-
760 node_var_low_high(Node, Var, _, _),
761 empty_assoc(H0),
762 put_attr(Var, clpb_hash, H0).
763
764re_register_node(Node) :-
765 node_var_low_high(Node, Var, Low, High),
766 low_high_key(Low, High, Key),
767 register_node(Var, Key, Node).
768
769register_node(Var, Key, Node) :-
770 get_attr(Var, clpb_hash, H0),
771 put_assoc(Key, H0, Node, H),
772 put_attr(Var, clpb_hash, H).
773
774lookup_node(Var, Key, Node) :-
775 get_attr(Var, clpb_hash, H0),
776 get_assoc(Key, H0, Node).
777
778
779node_id(0, false).
780node_id(1, true).
781node_id(node(ID,_,_,_,_), ID).
782
783node_aux(Node, Aux) :- arg(5, Node, Aux).
784
785node_var_low_high(Node, Var, Low, High) :-
786 Node = node(_,Var,Low,High,_).
787
788
793
794sat_bdd(V, Node) :- var(V), !, make_node(V, 0, 1, Node).
795sat_bdd(I, I) :- integer(I), !.
796sat_bdd(V^Sat, Node) :- !, sat_bdd(Sat, BDD), existential(V, BDD, Node).
797sat_bdd(card(Is,Fs), Node) :- !, counter_network(Is, Fs, Node).
798sat_bdd(Sat, Node) :- !,
799 Sat =.. [F,A,B],
800 sat_bdd(A, NA),
801 sat_bdd(B, NB),
802 apply(F, NA, NB, Node).
803
804existential(V, BDD, Node) :-
805 var_index(V, Index),
806 bdd_restriction(BDD, Index, 0, NA),
807 bdd_restriction(BDD, Index, 1, NB),
808 apply(+, NA, NB, Node).
809
813
814counter_network(Cs, Fs, Node) :-
815 same_length([_|Fs], Indicators),
816 fill_indicators(Indicators, 0, Cs),
817 phrase(formulas_variables(Fs, Vars0), ExBDDs),
818 maplist(unvisit, Vars0),
819 820 821 variables_in_index_order(Vars0, Vars1),
822 reverse(Vars1, Vars),
823 counter_network_(Vars, Indicators, Node0),
824 foldl(existential_and, ExBDDs, Node0, Node).
825
830
831formulas_variables([], []) --> [].
832formulas_variables([F|Fs], [V|Vs]) -->
833 ( { var(F), \+ is_visited(F) } ->
834 { V = F,
835 put_visited(F) }
836 ; { enumerate_variable(V),
837 sat_rewrite(V =:= F, Sat),
838 sat_bdd(Sat, BDD) },
839 [V-BDD]
840 ),
841 formulas_variables(Fs, Vs).
842
843counter_network_([], [Node], Node).
844counter_network_([Var|Vars], [I|Is0], Node) :-
845 foldl(indicators_pairing(Var), Is0, Is, I, _),
846 counter_network_(Vars, Is, Node).
847
848indicators_pairing(Var, I, Node, Prev, I) :- make_node(Var, Prev, I, Node).
849
850fill_indicators([], _, _).
851fill_indicators([I|Is], Index0, Cs) :-
852 ( memberchk(Index0, Cs) -> I = 1
853 ; member(A-B, Cs), between(A, B, Index0) -> I = 1
854 ; I = 0
855 ),
856 Index1 is Index0 + 1,
857 fill_indicators(Is, Index1, Cs).
858
859existential_and(Ex-BDD, Node0, Node) :-
860 bdd_and(BDD, Node0, Node1),
861 existential(Ex, Node1, Node),
862 863 864 del_attrs(Ex).
865
872
873apply(F, NA, NB, Node) :-
874 empty_assoc(G0),
875 phrase(apply(F, NA, NB, Node), [G0], _).
876
877apply(F, NA, NB, Node) -->
878 ( { integer(NA), integer(NB) } -> { once(bool_op(F, NA, NB, Node)) }
879 ; { apply_shortcut(F, NA, NB, Node) } -> []
880 ; { node_id(NA, IDA), node_id(NB, IDB), Key =.. [F,IDA,IDB] },
881 ( state(G0), { get_assoc(Key, G0, Node) } -> []
882 ; apply_(F, NA, NB, Node),
883 state(G0, G),
884 { put_assoc(Key, G0, Node, G) }
885 )
886 ).
887
888apply_shortcut(+, NA, NB, Node) :-
889 ( NA == 0 -> Node = NB
890 ; NA == 1 -> Node = 1
891 ; NB == 0 -> Node = NA
892 ; NB == 1 -> Node = 1
893 ; false
894 ).
895
896apply_shortcut(*, NA, NB, Node) :-
897 ( NA == 0 -> Node = 0
898 ; NA == 1 -> Node = NB
899 ; NB == 0 -> Node = 0
900 ; NB == 1 -> Node = NA
901 ; false
902 ).
903
904
905apply_(F, NA, NB, Node) -->
906 { var_less_than(NA, NB),
907 !,
908 node_var_low_high(NA, VA, LA, HA) },
909 apply(F, LA, NB, Low),
910 apply(F, HA, NB, High),
911 make_node(VA, Low, High, Node).
912apply_(F, NA, NB, Node) -->
913 { node_var_low_high(NA, VA, LA, HA),
914 node_var_low_high(NB, VB, LB, HB),
915 VA == VB },
916 !,
917 apply(F, LA, LB, Low),
918 apply(F, HA, HB, High),
919 make_node(VA, Low, High, Node).
920apply_(F, NA, NB, Node) --> 921 { node_var_low_high(NB, VB, LB, HB) },
922 apply(F, NA, LB, Low),
923 apply(F, NA, HB, High),
924 make_node(VB, Low, High, Node).
925
926
927node_varindex(Node, VI) :-
928 node_var_low_high(Node, V, _, _),
929 var_index(V, VI).
930
931var_less_than(NA, NB) :-
932 ( integer(NB) -> true
933 ; node_varindex(NA, VAI),
934 node_varindex(NB, VBI),
935 VAI < VBI
936 ).
937
938bool_op(+, 0, 0, 0).
939bool_op(+, 0, 1, 1).
940bool_op(+, 1, 0, 1).
941bool_op(+, 1, 1, 1).
942
943bool_op(*, 0, 0, 0).
944bool_op(*, 0, 1, 0).
945bool_op(*, 1, 0, 0).
946bool_op(*, 1, 1, 1).
947
948bool_op(#, 0, 0, 0).
949bool_op(#, 0, 1, 1).
950bool_op(#, 1, 0, 1).
951bool_op(#, 1, 1, 0).
952
956
957state(S) --> state(S, S).
958
959state(S0, S), [S] --> [S0].
960
985
986attr_unify_hook(index_root(I,Root), Other) :-
987 ( integer(Other) ->
988 ( between(0, 1, Other) ->
989 root_get_formula_bdd(Root, Sat, BDD0),
990 bdd_restriction(BDD0, I, Other, BDD),
991 root_put_formula_bdd(Root, Sat, BDD),
992 satisfiable_bdd(BDD)
993 ; no_truth_value(Other)
994 )
995 ; atom(Other) ->
996 root_get_formula_bdd(Root, Sat0, _),
997 parse_sat(Sat0, Sat),
998 sat_bdd(Sat, BDD),
999 root_put_formula_bdd(Root, Sat0, BDD),
1000 is_bdd(BDD),
1001 satisfiable_bdd(BDD)
1002 ; 1003 1004 root_get_formula_bdd(Root, Sat0, _),
1005 Sat = Sat0*OtherSat,
1006 ( var(Other), var_index_root(Other, _, OtherRoot),
1007 OtherRoot \== Root ->
1008 root_get_formula_bdd(OtherRoot, OtherSat, _),
1009 parse_sat(Sat, Sat1),
1010 sat_bdd(Sat1, BDD1),
1011 And = Sat,
1012 sat_roots(Sat, Roots)
1013 ; parse_sat(Other, OtherSat),
1014 sat_roots(Sat, Roots),
1015 maplist(root_rebuild_bdd, Roots),
1016 roots_and(Roots, 1-1, And-BDD1)
1017 ),
1018 maplist(del_bdd, Roots),
1019 maplist(=(NewRoot), Roots),
1020 root_put_formula_bdd(NewRoot, And, BDD1),
1021 is_bdd(BDD1),
1022 satisfiable_bdd(BDD1)
1023 ).
1024
1025root_rebuild_bdd(Root) :-
1026 ( root_get_formula_bdd(Root, F0, _) ->
1027 parse_sat(F0, Sat),
1028 sat_bdd(Sat, BDD),
1029 root_put_formula_bdd(Root, F0, BDD)
1030 ; true
1031 ).
1032
1046
1047project_attributes(QueryVars0, AttrVars) :-
1048 append(QueryVars0, AttrVars, QueryVars1),
1049 include(clpb_variable, QueryVars1, QueryVars),
1050 maplist(var_index_root, QueryVars, _, Roots0),
1051 sort(Roots0, Roots),
1052 maplist(remove_hidden_variables(QueryVars), Roots).
1053
1054clpb_variable(Var) :- var_index(Var, _).
1055
1062
1063remove_hidden_variables(QueryVars, Root) :-
1064 root_get_formula_bdd(Root, Formula, BDD0),
1065 maplist(put_visited, QueryVars),
1066 bdd_variables(BDD0, HiddenVars0),
1067 exclude(universal_var, HiddenVars0, HiddenVars),
1068 maplist(unvisit, QueryVars),
1069 foldl(existential, HiddenVars, BDD0, BDD),
1070 foldl(quantify_existantially, HiddenVars, Formula, ExFormula),
1071 root_put_formula_bdd(Root, ExFormula, BDD).
1072
1073quantify_existantially(E, E0, E^E0) :- put_attr(E, clpb_omit_boolean, true).
1074
1078
1079bdd_restriction(Node, VI, Value, Res) :-
1080 empty_assoc(G0),
1081 phrase(bdd_restriction_(Node, VI, Value, Res), [G0], _),
1082 is_bdd(Res).
1083
1084bdd_restriction_(Node, VI, Value, Res) -->
1085 ( { integer(Node) } -> { Res = Node }
1086 ; { node_var_low_high(Node, Var, Low, High) } ->
1087 ( { integer(Var) } ->
1088 ( { Var =:= 0 } -> bdd_restriction_(Low, VI, Value, Res)
1089 ; { Var =:= 1 } -> bdd_restriction_(High, VI, Value, Res)
1090 ; { no_truth_value(Var) }
1091 )
1092 ; { var_index(Var, I0),
1093 node_id(Node, ID) },
1094 ( { I0 =:= VI } ->
1095 ( { Value =:= 0 } -> { Res = Low }
1096 ; { Value =:= 1 } -> { Res = High }
1097 )
1098 ; { I0 > VI } -> { Res = Node }
1099 ; state(G0), { get_assoc(ID, G0, Res) } -> []
1100 ; bdd_restriction_(Low, VI, Value, LRes),
1101 bdd_restriction_(High, VI, Value, HRes),
1102 make_node(Var, LRes, HRes, Res),
1103 state(G0, G),
1104 { put_assoc(ID, G0, Res, G) }
1105 )
1106 )
1107 ; { domain_error(node, Node) }
1108 ).
1109
1118
1119bdd_nodes(BDD, Ns) :- bdd_nodes(ignore_node, BDD, Ns).
1120
1121ignore_node(_).
1122
1125
1126bdd_nodes(VPred, BDD, Ns) :-
1127 phrase(bdd_nodes_(VPred, BDD), Ns),
1128 maplist(with_aux(unvisit), Ns).
1129
1130bdd_nodes_(VPred, Node) -->
1131 ( { node_visited(Node) } -> []
1132 ; { call(VPred, Node),
1133 with_aux(put_visited, Node),
1134 node_var_low_high(Node, _, Low, High) },
1135 [Node],
1136 bdd_nodes_(VPred, Low),
1137 bdd_nodes_(VPred, High)
1138 ).
1139
1140node_visited(Node) :- integer(Node).
1141node_visited(Node) :- with_aux(is_visited, Node).
1142
1143bdd_variables(BDD, Vs) :-
1144 bdd_nodes(BDD, Nodes),
1145 nodes_variables(Nodes, Vs).
1146
1147nodes_variables(Nodes, Vs) :-
1148 phrase(nodes_variables_(Nodes), Vs),
1149 maplist(unvisit, Vs).
1150
1151nodes_variables_([]) --> [].
1152nodes_variables_([Node|Nodes]) -->
1153 { node_var_low_high(Node, Var, _, _) },
1154 ( { integer(Var) } -> []
1155 ; { is_visited(Var) } -> []
1156 ; { put_visited(Var) },
1157 [Var]
1158 ),
1159 nodes_variables_(Nodes).
1160
1161unvisit(V) :- del_attr(V, clpb_visited).
1162
1163is_visited(V) :- get_attr(V, clpb_visited, true).
1164
1165put_visited(V) :- put_attr(V, clpb_visited, true).
1166
1167with_aux(Pred, Node) :-
1168 node_aux(Node, Aux),
1169 call(Pred, Aux).
1170
1176
1177is_bdd(BDD) :-
1178 ( current_prolog_flag(clpb_validation, true) ->
1179 bdd_ites(BDD, ITEs),
1180 pairs_values(ITEs, Ls0),
1181 sort(Ls0, Ls1),
1182 ( same_length(Ls0, Ls1) -> true
1183 ; domain_error(reduced_ites, (ITEs,Ls0,Ls1))
1184 ),
1185 ( member(ITE, ITEs), \+ registered_node(ITE) ->
1186 domain_error(registered_node, ITE)
1187 ; true
1188 ),
1189 ( member(I, ITEs), \+ ordered(I) ->
1190 domain_error(ordered_node, I)
1191 ; true
1192 )
1193 ; true
1194 ).
1195
1196ordered(_-ite(Var,High,Low)) :-
1197 ( var_index(Var, VI) ->
1198 greater_varindex_than(High, VI),
1199 greater_varindex_than(Low, VI)
1200 ; true
1201 ).
1202
1203greater_varindex_than(Node, VI) :-
1204 ( integer(Node) -> true
1205 ; node_var_low_high(Node, Var, _, _),
1206 ( var_index(Var, OI) ->
1207 OI > VI
1208 ; true
1209 )
1210 ).
1211
1212registered_node(Node-ite(Var,High,Low)) :-
1213 ( var(Var) ->
1214 low_high_key(Low, High, Key),
1215 lookup_node(Var, Key, Node0),
1216 Node == Node0
1217 ; true
1218 ).
1219
1220bdd_ites(BDD, ITEs) :-
1221 bdd_nodes(BDD, Nodes),
1222 maplist(node_ite, Nodes, ITEs).
1223
1224node_ite(Node, Node-ite(Var,High,Low)) :-
1225 node_var_low_high(Node, Var, Low, High).
1226
1231
1232labeling(Vs0) :-
1233 must_be(list, Vs0),
1234 maplist(labeling_var, Vs0),
1235 variables_in_index_order(Vs0, Vs),
1236 maplist(indomain, Vs).
1237
1238labeling_var(V) :- var(V), !.
1239labeling_var(V) :- V == 0, !.
1240labeling_var(V) :- V == 1, !.
1241labeling_var(V) :- domain_error(clpb_variable, V).
1242
1243variables_in_index_order(Vs0, Vs) :-
1244 maplist(var_with_index, Vs0, IVs0),
1245 keysort(IVs0, IVs),
1246 pairs_values(IVs, Vs).
1247
1248var_with_index(V, I-V) :-
1249 ( var_index_root(V, I, _) -> true
1250 ; I = 0
1251 ).
1252
1253indomain(0).
1254indomain(1).
1255
1256
1283
1284sat_count(Sat0, N) :-
1285 catch((parse_sat(Sat0, Sat),
1286 sat_bdd(Sat, BDD),
1287 sat_roots(Sat, Roots),
1288 roots_and(Roots, _-BDD, _-BDD1),
1289 1290 term_variables(Sat0, Vs),
1291 maplist(put_visited, Vs),
1292 1293 bdd_variables(BDD1, Vs1),
1294 partition(universal_var, Vs1, Univs, Exis),
1295 1296 foldl(universal, Univs, BDD1, BDD2),
1297 foldl(existential, Exis, BDD2, BDD3),
1298 variables_in_index_order(Vs, IVs),
1299 foldl(renumber_variable, IVs, 1, VNum),
1300 bdd_count(BDD3, VNum, Count0),
1301 var_u(BDD3, VNum, P),
1302 1303 1304 N0 is 2^(P - 1)*Count0,
1305 1306 throw(count(N0))),
1307 count(N0),
1308 N = N0).
1309
1310universal(V, BDD, Node) :-
1311 var_index(V, Index),
1312 bdd_restriction(BDD, Index, 0, NA),
1313 bdd_restriction(BDD, Index, 1, NB),
1314 apply(*, NA, NB, Node).
1315
1316renumber_variable(V, I0, I) :-
1317 put_attr(V, clpb, index_root(I0,_)),
1318 I is I0 + 1.
1319
1320bdd_count(Node, VNum, Count) :-
1321 ( integer(Node) -> Count = Node
1322 ; node_aux(Node, Count),
1323 ( integer(Count) -> true
1324 ; node_var_low_high(Node, V, Low, High),
1325 bdd_count(Low, VNum, LCount),
1326 bdd_count(High, VNum, HCount),
1327 bdd_pow(Low, V, VNum, LPow),
1328 bdd_pow(High, V, VNum, HPow),
1329 Count is LPow*LCount + HPow*HCount
1330 )
1331 ).
1332
1333
1334bdd_pow(Node, V, VNum, Pow) :-
1335 var_index(V, Index),
1336 var_u(Node, VNum, P),
1337 Pow is 2^(P - Index - 1).
1338
1339var_u(Node, VNum, Index) :-
1340 ( integer(Node) -> Index = VNum
1341 ; node_varindex(Node, Index)
1342 ).
1343
1347
1354
1355single_bdd(Vars0) :-
1356 maplist(monotonic_variable, Vars0, Vars),
1357 1358 sat(+[1|Vars]).
1359
1360random_labeling(Seed, Vars) :-
1361 must_be(list, Vars),
1362 set_random(seed(Seed)),
1363 ( ground(Vars) -> true
1364 ; catch((single_bdd(Vars),
1365 once((member(Var, Vars),var(Var))),
1366 var_index_root(Var, _, Root),
1367 root_get_formula_bdd(Root, _, BDD),
1368 bdd_variables(BDD, Vs),
1369 variables_in_index_order(Vs, IVs),
1370 foldl(renumber_variable, IVs, 1, VNum),
1371 phrase(random_bindings(VNum, BDD), Bs),
1372 maplist(del_attrs, Vs),
1373 1374 throw(randsol(Vars, Bs))),
1375 randsol(Vars, Bs),
1376 true),
1377 maplist(call, Bs),
1378 1379 include(var, Vars, Remaining),
1380 maplist(maybe_zero, Remaining)
1381 ).
1382
1383maybe_zero(Var) :-
1384 ( maybe -> Var = 0
1385 ; Var = 1
1386 ).
1387
1388random_bindings(_, Node) --> { Node == 1 }, !.
1389random_bindings(VNum, Node) -->
1390 { node_var_low_high(Node, Var, Low, High),
1391 bdd_count(Node, VNum, Total),
1392 bdd_count(Low, VNum, LCount) },
1393 ( { maybe(LCount, Total) } ->
1394 [Var=0], random_bindings(VNum, Low)
1395 ; [Var=1], random_bindings(VNum, High)
1396 ).
1397
1401
1421
1422weighted_maximum(Ws, Vars, Max) :-
1423 must_be(list(integer), Ws),
1424 must_be(list(var), Vars),
1425 single_bdd(Vars),
1426 Vars = [Var|_],
1427 var_index_root(Var, _, Root),
1428 root_get_formula_bdd(Root, _, BDD0),
1429 bdd_variables(BDD0, Vs),
1430 1431 maplist(put_visited, Vars),
1432 exclude(is_visited, Vs, Unvisited),
1433 maplist(unvisit, Vars),
1434 foldl(existential, Unvisited, BDD0, BDD),
1435 maplist(var_with_index, Vars, IVs),
1436 pairs_keys_values(Pairs0, IVs, Ws),
1437 keysort(Pairs0, Pairs1),
1438 pairs_keys_values(Pairs1, IVs1, WeightsIndexOrder),
1439 pairs_values(IVs1, VarsIndexOrder),
1440 1441 pairs_keys_values(Pairs, VarsIndexOrder, WeightsIndexOrder),
1442 bdd_maximum(BDD, Pairs, Max),
1443 max_labeling(BDD, Pairs).
1444
1445max_labeling(1, Pairs) :- max_upto(Pairs, _, _).
1446max_labeling(node(_,Var,Low,High,Aux), Pairs0) :-
1447 max_upto(Pairs0, Var, Pairs),
1448 get_attr(Aux, clpb_max, max(_,Dir)),
1449 direction_labeling(Dir, Var, Low, High, Pairs).
1450
1451max_upto([], _, _).
1452max_upto([Var0-Weight|VWs0], Var, VWs) :-
1453 ( Var == Var0 -> VWs = VWs0
1454 ; Weight =:= 0 ->
1455 ( Var0 = 0 ; Var0 = 1 ),
1456 max_upto(VWs0, Var, VWs)
1457 ; Weight < 0 -> Var0 = 0, max_upto(VWs0, Var, VWs)
1458 ; Var0 = 1, max_upto(VWs0, Var, VWs)
1459 ).
1460
1461direction_labeling(low, 0, Low, _, Pairs) :- max_labeling(Low, Pairs).
1462direction_labeling(high, 1, _, High, Pairs) :- max_labeling(High, Pairs).
1463
1464bdd_maximum(1, Pairs, Max) :-
1465 pairs_values(Pairs, Weights0),
1466 include(<(0), Weights0, Weights),
1467 sum_list(Weights, Max).
1468bdd_maximum(node(_,Var,Low,High,Aux), Pairs0, Max) :-
1469 ( get_attr(Aux, clpb_max, max(Max,_)) -> true
1470 ; ( skip_to_var(Var, Weight, Pairs0, Pairs),
1471 ( Low == 0 ->
1472 bdd_maximum_(High, Pairs, MaxHigh, MaxToHigh),
1473 Max is MaxToHigh + MaxHigh + Weight,
1474 Dir = high
1475 ; High == 0 ->
1476 bdd_maximum_(Low, Pairs, MaxLow, MaxToLow),
1477 Max is MaxToLow + MaxLow,
1478 Dir = low
1479 ; bdd_maximum_(Low, Pairs, MaxLow, MaxToLow),
1480 bdd_maximum_(High, Pairs, MaxHigh, MaxToHigh),
1481 Max0 is MaxToLow + MaxLow,
1482 Max1 is MaxToHigh + MaxHigh + Weight,
1483 Max is max(Max0,Max1),
1484 ( Max0 =:= Max1 -> Dir = _Any
1485 ; Max0 < Max1 -> Dir = high
1486 ; Dir = low
1487 )
1488 ),
1489 store_maximum(Aux, Max, Dir)
1490 )
1491 ).
1492
1493bdd_maximum_(Node, Pairs, Max, MaxTo) :-
1494 bdd_maximum(Node, Pairs, Max),
1495 between_weights(Node, Pairs, MaxTo).
1496
1497store_maximum(Aux, Max, Dir) :- put_attr(Aux, clpb_max, max(Max,Dir)).
1498
1499between_weights(Node, Pairs0, MaxTo) :-
1500 ( Node == 1 -> MaxTo = 0
1501 ; node_var_low_high(Node, Var, _, _),
1502 phrase(skip_to_var_(Var, _, Pairs0, _), Weights0),
1503 include(<(0), Weights0, Weights),
1504 sum_list(Weights, MaxTo)
1505 ).
1506
1507skip_to_var(Var, Weight, Pairs0, Pairs) :-
1508 phrase(skip_to_var_(Var, Weight, Pairs0, Pairs), _).
1509
1510skip_to_var_(Var, Weight, [Var0-Weight0|VWs0], VWs) -->
1511 ( { Var == Var0 } ->
1512 { Weight = Weight0, VWs0 = VWs }
1513 ; ( { Weight0 =< 0 } -> []
1514 ; [Weight0]
1515 ),
1516 skip_to_var_(Var, Weight, VWs0, VWs)
1517 ).
1518
1522
1523attribute_goals(Var) -->
1524 { var_index_root(Var, _, Root) },
1525 ( { root_get_formula_bdd(Root, Formula, BDD) } ->
1526 { del_bdd(Root) },
1527 ( { current_prolog_flag(clpb_residuals, bdd) } ->
1528 { bdd_nodes(BDD, Nodes),
1529 phrase(nodes(Nodes), Ns) },
1530 [clpb:'$clpb_bdd'(Ns)]
1531 ; { prepare_global_variables(BDD),
1532 phrase(sat_ands(Formula), Ands0),
1533 ands_fusion(Ands0, Ands),
1534 maplist(formula_anf, Ands, ANFs0),
1535 sort(ANFs0, ANFs1),
1536 exclude(eq_1, ANFs1, ANFs2),
1537 variables_separation(ANFs2, ANFs) },
1538 sats(ANFs)
1539 ),
1540 ( { get_attr(Var, clpb_atom, Atom) } ->
1541 [clpb:sat(Var=:=Atom)]
1542 ; []
1543 ),
1544 1545 { bdd_variables(BDD, Vs),
1546 maplist(del_clpb, Vs),
1547 term_variables(Formula, RestVs0),
1548 include(clpb_variable, RestVs0, RestVs) },
1549 booleans(RestVs)
1550 ; boolean(Var) 1551 ).
1552
1553del_clpb(Var) :- del_attr(Var, clpb).
1554
1562
1563prepare_global_variables(BDD) :-
1564 clpb_next_id('$clpb_next_var', V0),
1565 clpb_next_id('$clpb_next_node', N0),
1566 bdd_nodes(BDD, Nodes),
1567 foldl(max_variable_node, Nodes, V0-N0, MaxV0-MaxN0),
1568 MaxV is MaxV0 + 1,
1569 MaxN is MaxN0 + 1,
1570 b_setval('$clpb_next_var', MaxV),
1571 b_setval('$clpb_next_node', MaxN).
1572
1573max_variable_node(Node, V0-N0, V-N) :-
1574 node_id(Node, N1),
1575 node_varindex(Node, V1),
1576 N is max(N0,N1),
1577 V is max(V0,V1).
1578
1582
1583ands_fusion(Ands0, Ands) :-
1584 maplist(with_variables, Ands0, Pairs0),
1585 keysort(Pairs0, Pairs),
1586 group_pairs_by_key(Pairs, Groups),
1587 pairs_values(Groups, Andss),
1588 maplist(list_to_conjunction, Andss, Ands).
1589
1590with_variables(F, Vs-F) :-
1591 term_variables(F, Vs0),
1592 variables_in_index_order(Vs0, Vs).
1593
1601
1602variables_separation(Fs0, Fs) :- separation_fixpoint(Fs0, [], Fs).
1603
1604separation_fixpoint(Fs0, Ds0, Fs) :-
1605 phrase(variables_separation_(Fs0, Ds0, Rest), Fs1),
1606 partition(anf_done, Fs1, Ds1, Fs2),
1607 maplist(arg(1), Ds1, Ds2),
1608 maplist(arg(1), Fs2, Fs3),
1609 append(Ds0, Ds2, Ds3),
1610 append(Rest, Fs3, Fs4),
1611 sort(Fs4, Fs5),
1612 sort(Ds3, Ds4),
1613 ( Fs5 == [] -> Fs = Ds4
1614 ; separation_fixpoint(Fs5, Ds4, Fs)
1615 ).
1616
1617anf_done(done(_)).
1618
1619variables_separation_([], _, []) --> [].
1620variables_separation_([F0|Fs0], Ds, Rest) -->
1621 ( { member(Done, Ds), F0 == Done } ->
1622 variables_separation_(Fs0, Ds, Rest)
1623 ; { sat_rewrite(F0, F),
1624 sat_bdd(F, BDD),
1625 bdd_variables(BDD, Vs0),
1626 exclude(universal_var, Vs0, Vs),
1627 maplist(existential_(BDD), Vs, Nodes),
1628 phrase(pairs(Nodes), Pairs),
1629 group_pairs_by_key(Pairs, Groups),
1630 phrase(groups_separation(Groups, BDD), ANFs) },
1631 ( { ANFs = [_|_] } ->
1632 list(ANFs),
1633 { Rest = Fs0 }
1634 ; [done(F0)],
1635 variables_separation_(Fs0, Ds, Rest)
1636 )
1637 ).
1638
1639
1640existential_(BDD, V, Node) :- existential(V, BDD, Node).
1641
1642groups_separation([], _) --> [].
1643groups_separation([BDD1-BDDs|Groups], OrigBDD) -->
1644 { phrase(separate_pairs(BDDs, BDD1, OrigBDD), Nodes) },
1645 ( { Nodes = [_|_] } ->
1646 nodes_anfs([BDD1|Nodes])
1647 ; []
1648 ),
1649 groups_separation(Groups, OrigBDD).
1650
1651separate_pairs([], _, _) --> [].
1652separate_pairs([BDD2|Ps], BDD1, OrigBDD) -->
1653 ( { apply(*, BDD1, BDD2, And),
1654 And == OrigBDD } ->
1655 [BDD2]
1656 ; []
1657 ),
1658 separate_pairs(Ps, BDD1, OrigBDD).
1659
1660nodes_anfs([]) --> [].
1661nodes_anfs([N|Ns]) --> { node_anf(N, ANF) }, [anf(ANF)], nodes_anfs(Ns).
1662
1663pairs([]) --> [].
1664pairs([V|Vs]) --> pairs_(Vs, V), pairs(Vs).
1665
1666pairs_([], _) --> [].
1667pairs_([B|Bs], A) --> [A-B], pairs_(Bs, A).
1668
1673
1674nodes([]) --> [].
1675nodes([Node|Nodes]) -->
1676 { node_var_low_high(Node, Var0, Low, High),
1677 var_or_atom(Var0, Var),
1678 maplist(node_projection, [Node,High,Low], [ID,HID,LID]),
1679 var_index(Var0, VI) },
1680 [ID-(v(Var,VI) -> HID ; LID)],
1681 nodes(Nodes).
1682
1683
1684node_projection(Node, Projection) :-
1685 node_id(Node, ID),
1686 ( integer(ID) -> Projection = node(ID)
1687 ; Projection = ID
1688 ).
1689
1694
1695sats([]) --> [].
1696sats([A|As]) --> [clpb:sat(A)], sats(As).
1697
1698booleans([]) --> [].
1699booleans([B|Bs]) --> boolean(B), { del_clpb(B) }, booleans(Bs).
1700
1701boolean(Var) -->
1702 ( { get_attr(Var, clpb_omit_boolean, true) } -> []
1703 ; [clpb:sat(Var =:= Var)]
1704 ).
1705
1709
1710formula_anf(Formula0, ANF) :-
1711 parse_sat(Formula0, Formula),
1712 sat_bdd(Formula, Node),
1713 node_anf(Node, ANF).
1714
1715node_anf(Node, ANF) :-
1716 node_xors(Node, Xors0),
1717 maplist(maplist(monotonic_variable), Xors0, Xors),
1718 maplist(list_to_conjunction, Xors, Conjs),
1719 ( Conjs = [Var,C|Rest], clpb_var(Var) ->
1720 foldl(xor, Rest, C, RANF),
1721 ANF = (Var =\= RANF)
1722 ; Conjs = [One,Var,C|Rest], One == 1, clpb_var(Var) ->
1723 foldl(xor, Rest, C, RANF),
1724 ANF = (Var =:= RANF)
1725 ; Conjs = [C|Cs],
1726 foldl(xor, Cs, C, ANF)
1727 ).
1728
1729monotonic_variable(Var0, Var) :-
1730 ( var(Var0), current_prolog_flag(clpb_monotonic, true) ->
1731 Var = v(Var0)
1732 ; Var = Var0
1733 ).
1734
1735clpb_var(Var) :- var(Var), !.
1736clpb_var(v(_)).
1737
1738list_to_conjunction([], 1).
1739list_to_conjunction([L|Ls], Conj) :- foldl(and, Ls, L, Conj).
1740
1741xor(A, B, B # A).
1742
1743eq_1(V) :- V == 1.
1744
1745node_xors(Node, Xors) :-
1746 phrase(xors(Node), Xors0),
1747 1748 maplist(sort, Xors0, Xors1),
1749 pairs_keys_values(Pairs0, Xors1, _),
1750 keysort(Pairs0, Pairs),
1751 group_pairs_by_key(Pairs, Groups),
1752 exclude(even_occurrences, Groups, Odds),
1753 pairs_keys(Odds, Xors2),
1754 maplist(exclude(eq_1), Xors2, Xors).
1755
1756even_occurrences(_-Ls) :- length(Ls, L), L mod 2 =:= 0.
1757
1758xors(Node) -->
1759 ( { Node == 0 } -> []
1760 ; { Node == 1 } -> [[1]]
1761 ; { node_var_low_high(Node, Var0, Low, High),
1762 var_or_atom(Var0, Var),
1763 node_xors(Low, Ls0),
1764 node_xors(High, Hs0),
1765 maplist(with_var(Var), Ls0, Ls),
1766 maplist(with_var(Var), Hs0, Hs) },
1767 list(Ls0),
1768 list(Ls),
1769 list(Hs)
1770 ).
1771
1772list([]) --> [].
1773list([L|Ls]) --> [L], list(Ls).
1774
1775with_var(Var, Ls, [Var|Ls]).
1776
1780
1781make_clpb_var('$clpb_next_var') :- nb_setval('$clpb_next_var', 0).
1782
1783make_clpb_var('$clpb_next_node') :- nb_setval('$clpb_next_node', 0).
1784
1785make_clpb_var('$clpb_atoms') :-
1786 empty_assoc(E),
1787 nb_setval('$clpb_atoms', E).
1788
1789:- multifile user:exception/3. 1790
1791user:exception(undefined_global_variable, Name, retry) :-
1792 make_clpb_var(Name), !.
1793
1794clpb_next_id(Var, ID) :-
1795 b_getval(Var, ID),
1796 Next is ID + 1,
1797 b_setval(Var, Next).
1798
1799clpb_atom_var(Atom, Var) :-
1800 b_getval('$clpb_atoms', A0),
1801 ( get_assoc(Atom, A0, Var) -> true
1802 ; put_attr(Var, clpb_atom, Atom),
1803 put_attr(Var, clpb_omit_boolean, true),
1804 put_assoc(Atom, A0, Var, A),
1805 b_setval('$clpb_atoms', A)
1806 ).
1807
1815
1816:- public
1817 clpb_hash:attr_unify_hook/2,
1818 clpb_bdd:attribute_goals//1,
1819 clpb_hash:attribute_goals//1,
1820 clpb_omit_boolean:attr_unify_hook/2,
1821 clpb_omit_boolean:attribute_goals//1,
1822 clpb_atom:attr_unify_hook/2,
1823 clpb_atom:attribute_goals//1. 1824
1825clpb_hash:attr_unify_hook(_,_). 1826
1832
1833clpb_atom:attr_unify_hook(_, _) :- false.
1834
1835clpb_omit_boolean:attr_unify_hook(_,_).
1836
1837clpb_bdd:attribute_goals(_) --> [].
1838clpb_hash:attribute_goals(_) --> [].
1839clpb_omit_boolean:attribute_goals(_) --> [].
1840clpb_atom:attribute_goals(_) --> [].
1841
1846
1849
1853
1854:- multifile prolog:message//1. 1855
1856prolog:message(clpb(bounded)) -->
1857 ['Using CLP(B) with bounded arithmetic may yield wrong results.'-[]].
1858
1859warn_if_bounded_arithmetic :-
1860 ( current_prolog_flag(bounded, true) ->
1861 print_message(warning, clpb(bounded))
1862 ; true
1863 ).
1864
1865:- initialization(warn_if_bounded_arithmetic). 1866
1870
1871:- multifile
1872 sandbox:safe_global_variable/1,
1873 sandbox:safe_primitive/1. 1874
1875sandbox:safe_global_variable('$clpb_next_var').
1876sandbox:safe_global_variable('$clpb_next_node').
1877sandbox:safe_global_variable('$clpb_atoms').
1878sandbox:safe_primitive(set_prolog_flag(clpb_residuals, _))