View source with raw comments or as raw
    1:- module(scasp_solve,
    2          [ solve/4                   % :Goals, +StackIn, -StackOut, -Model
    3          ]).    4:- use_module(clp/call_stack).    5:- use_module(predicates).    6:- use_module(clp/disequality).    7:- use_module(clp/clpq).    8:- use_module(verbose).    9
   10:- autoload(library(apply), [maplist/2, include/3]).   11:- autoload(library(assoc),
   12            [get_assoc/3, empty_assoc/1, get_assoc/5, put_assoc/4]).   13:- autoload(library(lists), [append/3, member/2]).   14:- autoload(library(terms), [variant/2, mapsubterms/3]).   15
   16:- meta_predicate
   17    solve(:, +, -, -).

The sCASP solver

*/

   22% Note:  The  Ciao  original  controls   forall  algorithm  using  three
   23% current_option/2 facts, `prev_forall`, `sasp_forall` and `all_forall`:
   24%
   25%   <no option>:    no current_option/2
   26%   --prev_forall:  prev_forall=on, sasp_forall=off
   27%   --all_c_forall: all_forall=on
   28%   --sasp_forall:  prev_forall=on sasp_forall=on
   29
   30:- create_prolog_flag(scasp_no_fail_loop, false, [keep(true)]).   31:- create_prolog_flag(scasp_assume,       false, [keep(true)]).   32:- create_prolog_flag(scasp_forall,       all,   [keep(true)]).   33:- create_prolog_flag(scasp_dcc,	  false, [keep(true)]).   34:- create_prolog_flag(scasp_trace_dcc,	  false, [keep(true)]).
 solve(:Goals, +StackIn, -StackOut, -Model)
Solve the list of sub-goals Goal where StackIn is the list of goals already visited and returns in StackOut the list of goals visited to prove the sub-goals and in Model the model that supports the sub-goals.
   43solve(M:Goals, StackIn, StackOut, Model) :-
   44    stack_parents(StackIn, Parents),
   45    stack_proved(StackIn, ProvedIn),
   46    solve(Goals, M, Parents, ProvedIn, _ProvedOut, StackIn, StackOut, Model).
   47
   48solve([], _, _, Proved, Proved, StackIn, [[]|StackIn], []).
   49solve([Goal|Goals], M, Parents, ProvedIn, ProvedOut, StackIn, StackOut, Model) :-
   50    verbose(print_check_calls_calling(Goal, StackIn)),
   51    check_goal(Goal, M, Parents, ProvedIn, ProvedMid, StackIn, StackMid, Modelx),
   52    Modelx = [AddGoal|JGoal],
   53    verbose(format('Success ~@\n', [print_goal(Goal)])),
   54    solve(Goals, M, Parents, ProvedMid, ProvedOut, StackMid, StackOut, Modelxs),
   55    Modelxs = JGoals,
   56    (   shown_predicate(M:Goal)
   57    ->  Model = [AddGoal, JGoal|JGoals]
   58    ;   Model = [JGoal|JGoals]
   59    ).
   60
   61
   62proved_relatives(not(Goal), Proved, Relatives) =>
   63    proved_relatives(Goal, Proved, Relatives).
   64proved_relatives(Goal, Proved, Relatives) =>
   65    functor(Goal, Name, Arity),
   66    get_assoc(Name/Arity, Proved, Relatives).
 check_goal(+Goal, +Module, +Parents, +ProvedIn, -ProvedOut, +StackIn, -StackOut, -Model)
Call check_CHS/3 to check the sub-goal Goal against the list of goals already visited StackIn to determine if it is a coinductive success, a coinductive failure, an already proved sub-goal, or if it has to be evaluated.
Arguments:
StackOut- is updated by prepending one or more elements to StackIn.
  • [], chs(Goal) Proved by co-induction
  • [], proved(Goal) Proved in a completed subtree
  • From solve_goal/5 Continued execution
   83check_goal(Goal, M, Parents, ProvedIn, ProvedOut, StackIn, StackOut, Model) :-
   84    check_CHS(Goal, M, Parents, ProvedIn, StackIn, Check),
   85    check_goal_(Check, Goal, M,
   86                Parents, ProvedIn, ProvedOut, StackIn, StackOut,
   87                Model),
   88    (   current_prolog_flag(scasp_dcc, true),
   89        (   Check == co_success
   90        ;   Check == cont
   91        )
   92    ->  dynamic_consistency_check(Goal, M, StackIn)
   93    ;   true
   94    ).
   95
   96% coinduction success <- cycles containing even loops may succeed
   97check_goal_(co_success, Goal, _M,
   98            _Parents, ProvedIn, ProvedOut, StackIn, StackOut,
   99            [AddGoal]) :-
  100    AddGoal = chs(Goal),
  101    add_proved(AddGoal, ProvedIn, ProvedOut),
  102    (   current_prolog_flag(scasp_assume, true)
  103    ->  mark_prev_goal(Goal, StackIn, StackMark),
  104        StackOut = [[],AddGoal|StackMark]
  105    ;   StackOut = [[],AddGoal|StackIn]
  106    ).
  107% already proved in the stack
  108check_goal_(proved, Goal, _M,
  109            _Parents, ProvedIn, ProvedOut, StackIn, StackOut,
  110            [AddGoal]) :-
  111    AddGoal = proved(Goal),
  112    add_proved(AddGoal, ProvedIn, ProvedOut),
  113    StackOut = [[], proved(Goal)|StackIn].
  114% coinduction does neither success nor fails <- the execution continues inductively
  115check_goal_(cont, Goal, M,
  116            Parents, ProvedIn, ProvedOut, StackIn, StackOut,
  117            Model) :-
  118    solve_goal(Goal, M,
  119               [Goal|Parents], ProvedIn, ProvedOut, StackIn, StackOut,
  120               Model).
  121% coinduction fails <- the negation of a call unifies with a call in the call stack
  122check_goal_(co_failure, _Goal, _M,
  123            _Parents, _ProvedIn, _ProvedOut, _StackIn, _StackOut,
  124            _Model) :-
  125    fail.
  126
  127mark_prev_goal(Goal, [I|In], [assume(Goal)|In]) :-  Goal == I, !.
  128mark_prev_goal(Goal, [I|In], [I|Mk]) :- mark_prev_goal(Goal,In,Mk).
  129mark_prev_goal(_Goal,[],[]).
 dynamic_consistency_check(+Goal, +Module, +StackIn) is semidet
Check that the resulting literal is consistent with the nmr.
  135dynamic_consistency_check(Goal, M, StackIn) :-
  136    user_predicate(M:Goal),
  137    ground(Goal),
  138    M:pr_dcc_predicate(dcc(Goal), Body),
  139%   scasp_trace(scasp_trace_dcc, dcc_call(Goal, StackIn)),
  140    dynamic_consistency_eval(Body, M, StackIn),
  141    !,
  142    scasp_trace(scasp_trace_dcc, dcc_discard(Goal, Body)),
  143    fail.
  144dynamic_consistency_check(_, _, _).
  145
  146
  147dynamic_consistency_eval([], _, _).
  148dynamic_consistency_eval([SubGoal|Bs], M, StackIn) :-
  149    dynamic_consistency_eval_(SubGoal, M, StackIn),
  150    dynamic_consistency_eval(Bs, M, StackIn).
  151
  152dynamic_consistency_eval_(not(SubGoal), M, StackIn) :-
  153    user_predicate(M:SubGoal), !,
  154    member_stack(not(SubGoal), StackIn).
  155dynamic_consistency_eval_(SubGoal, M, StackIn) :-
  156    user_predicate(M:SubGoal), !,
  157    member_stack(SubGoal, StackIn).
  158dynamic_consistency_eval_(SubGoal, _, _) :-
  159    solve_goal_builtin(SubGoal, _).
 solve_goal(+Goal, +Module, +Parents, +ProvedIn, -ProvedOut, +StackIn, -StackOut, -Model)
Solve a simple sub-goal Goal where StackIn is the list of goals already visited and returns in StackOut the list of goals visited to prove the sub-goals and in Model the model with support the sub-goals
  171solve_goal(Goal, M, Parents, ProvedIn, ProvedOut, StackIn, StackOut, GoalModel) :-
  172    Goal = forall(_, _),
  173    !,
  174    (   current_prolog_flag(scasp_forall, Algo),
  175        ( Algo == prev -> true ; Algo == sasp )
  176        % Ciao version --prev_forall or --sasp_forall
  177    ->  solve_goal_forall(Goal, M,
  178                          Parents, ProvedIn, ProvedOut, [Goal|StackIn], StackOut,
  179                          Model)
  180    ;   solve_c_forall(Goal, M,
  181                       Parents, ProvedIn, ProvedOut, [Goal|StackIn], StackOut,
  182                       Model)
  183    ),
  184    GoalModel = [Goal|Model].
  185solve_goal(Goal, _M,
  186           _Parents, ProvedIn, ProvedOut, StackIn, [[], Goal|StackIn],
  187           GoalModel) :-
  188    Goal = not(is(V, Expresion)),
  189    add_proved(Goal, ProvedIn, ProvedOut),
  190    !,
  191    NV is Expresion,
  192    V .\=. NV,
  193    GoalModel = [Goal].
  194solve_goal(Goal, _, _, _, _, _, _, _) :-
  195    Goal = not(true),
  196    !,
  197    fail.
  198solve_goal(Goal, M, Parents, ProvedIn, ProvedOut, StackIn, StackOut, Model) :-
  199    table_predicate(M:Goal),
  200    !,
  201    verbose(format('Solve the tabled goal ~p\n', [Goal])),
  202    AttStackIn <~ stack([Goal|StackIn]),
  203    solve_goal_table_predicate(Goal, M, Parents, ProvedIn, ProvedOut,
  204                               AttStackIn, AttStackOut, AttModel),
  205    AttStackOut ~> stack(StackOut),
  206    AttModel ~> model(Model).
  207solve_goal(call(Goal), M, Parents, ProvedIn, ProvedOut, StackIn, StackOut,
  208           [call(Goal)|Model]) :-
  209    !,
  210    solve_goal(Goal, M, Parents, ProvedIn, ProvedOut, StackIn, StackOut, Model).
  211solve_goal(not(call(Goal)), M, Parents, ProvedIn, ProvedOut, StackIn, StackOut,
  212           [not(call(Goal))|Model]) :-
  213    !,
  214    solve_goal(not(Goal), M, Parents, ProvedIn, ProvedOut, StackIn, StackOut,
  215               Model).
  216solve_goal(Goal, M, Parents, ProvedIn, ProvedOut, StackIn, StackOut,
  217           [Goal|Model]) :-
  218    Goal = findall(_, _, _),
  219    !,
  220    exec_findall(Goal, M, Parents, ProvedIn, ProvedOut, StackIn, StackOut, Model).
  221solve_goal(not(Goal), M, Parents, ProvedIn, ProvedIn, StackIn, StackIn,
  222           [not(Goal)]) :-
  223    Goal = findall(_, _, _),
  224    !,
  225    exec_neg_findall(Goal, M, Parents, ProvedIn, StackIn).
  226solve_goal(Goal, M, Parents, ProvedIn, ProvedOut, StackIn, StackOut, Model) :-
  227    user_predicate(M:Goal),
  228    !,
  229    (   solve_goal_predicate(Goal, M, Parents, ProvedIn, ProvedOut,
  230                             StackIn, StackOut, Model)
  231    *-> true
  232    ;   verbose(format(' FAIL~n')),
  233        shown_predicate(M:Goal),
  234        scasp_trace(scasp_trace_failures,
  235                    trace_failure(Goal, [Goal|StackIn])),
  236        fail
  237    ).
  238solve_goal(Goal, _M, _Parents, ProvedIn, ProvedIn, StackIn, [[], Goal|StackIn],
  239           Model) :-
  240    solve_goal_builtin(Goal, Model).
  241
  242
  243mkgoal(Goal, generated(_), Goal                     ) :- !.
  244mkgoal(Goal, Origin      , goal_origin(Goal, Origin)).
 solve_goal_forall(+Forall, +Module, +Parents, +ProvedIn, -ProvedOut, +StackIn, -StackOut, -Model)
Solve a sub-goal of the form forall(Var,Goal) and success if Var success in all its domain for the goal Goal. It calls solve/4
Arguments:
Forall- is a term forall(?Var, ?Goal)
  255solve_goal_forall(forall(Var, Goal), M,
  256                  Parents, ProvedIn, ProvedOut, StackIn, [[]|StackOut],
  257                  Model) :-
  258    my_copy_term(Var, Goal, NewVar, NewGoal),
  259    my_copy_term(Var, Goal, NewVar2, NewGoal2),
  260    solve([NewGoal], M, Parents, ProvedIn, ProvedMid, StackIn, [[]|StackMid],
  261          ModelMid),
  262    verbose(format('\tSuccess solve ~@\n\t\t for the ~@\n',
  263                   [print_goal(NewGoal), print_goal(forall(Var, Goal))])),
  264    check_unbound(NewVar, List),
  265    (   List == ground
  266    ->  verbose(format('The var ~p is grounded so try with other clause\n',
  267                       [NewVar])),
  268        fail
  269    ;   List == []
  270    ->  ProvedOut = ProvedMid,
  271        StackOut = StackMid,
  272        Model = ModelMid
  273    ;   List = clpq(NewVar3, Constraints)
  274    ->  findall(dual(NewVar3, ConDual),
  275                dual_clpq(Constraints, ConDual),
  276                DualList),
  277        verbose(format('Executing ~@ with clpq ConstraintList = ~p\n',
  278                       [print_goal(Goal), DualList])),
  279        exec_with_clpq_constraints(NewVar2, NewGoal2, M,
  280                                   entry(NewVar3, []),
  281                                   DualList,
  282                                   Parents, ProvedMid, ProvedOut,
  283                                   StackMid, StackOut, ModelList),
  284        !,
  285        append(ModelMid, ModelList, Model)
  286    ;   verbose(format('Executing ~@ with clp_disequality list = ~p\n',
  287                       [print_goal(Goal), List])),
  288        (   current_prolog_flag(scasp_forall, prev)
  289        ->  !  % Ciao --prev_forall: remove answers in max.lp
  290        ;   true
  291        ),
  292        exec_with_neg_list(NewVar2, NewGoal2, M,
  293                           List, Parents, ProvedMid, ProvedOut,
  294                           StackMid, StackOut, ModelList),
  295        (   current_prolog_flag(scasp_forall, sasp)
  296        ->  !  % Ciao --sasp_forall: remove answers in hamcycle_two.lp
  297               % Without cuts the evaluation may loop - e.g. queens.lp
  298        ;   true
  299        ),
  300        append(ModelMid, ModelList, Model)
  301    ).
  302
  303check_unbound(Var, ground) :-
  304    ground(Var), !.
  305check_unbound(Var, List) :-
  306    get_neg_var(Var, List), !.
  307check_unbound(Var, 'clpq'(NewVar, Constraints)) :-
  308    dump_clpq_var([Var], [NewVar], Constraints),
  309    Constraints \== [], !.
  310check_unbound(Var, []) :-
  311    var(Var), !.
  312
  313exec_with_clpq_constraints(_Var, _Goal, _M, _, [],
  314                           _Parents, ProvedIn, ProvedIn, StackIn, StackIn, []).
  315exec_with_clpq_constraints(Var, Goal, M, entry(ConVar, ConEntry),
  316                           [dual(ConVar, ConDual)|Duals],
  317                           Parents, ProvedIn, ProvedOut, StackIn, StackOut,
  318                           Model) :-
  319    my_copy_term(Var,   [Goal,   Parents,   StackIn,   ProvedIn],
  320                 Var01, [Goal01, Parents01, StackIn01, ProvedIn01]),
  321    append(ConEntry, ConDual, Con),
  322    my_copy_term(ConVar, Con, ConVar01, Con01),
  323    my_copy_term(Var, Goal, Var02, Goal02),
  324    my_copy_term(ConVar, ConEntry, ConVar02, ConEntry02),
  325    Var01 = ConVar,
  326    (   apply_clpq_constraints(Con)
  327    ->  verbose(format('Executing ~p with clpq_constrains ~p\n',
  328                       [Goal01, Con])),
  329        solve([Goal01], M, Parents01, ProvedIn01, ProvedOut01, StackIn01, [[]|StackOut01], Model01),
  330        verbose(format('Success executing ~p with constrains ~p\n',
  331                       [Goal01, Con])),
  332        verbose(format('Check entails Var = ~p with const ~p and ~p\n',
  333                       [Var01, ConVar01, Con01])),
  334        (   entails([Var01], ([ConVar01], Con01))
  335        ->  verbose(format('\tOK\n', [])),
  336            StackOut02 = StackOut01,
  337            Model03 = Model01
  338        ;   verbose(format('\tFail\n', [])),
  339            dump_clpq_var([Var01], [ConVar01], ExitCon),
  340            findall(dual(ConVar01, ConDual01),
  341                    dual_clpq(ExitCon, ConDual01),
  342                    DualList),
  343            verbose(format('Executing ~p with clpq ConstraintList = ~p\n',
  344                           [Goal, DualList])),
  345            exec_with_clpq_constraints(Var, Goal, M, entry(ConVar01, Con01),
  346                                       DualList,
  347                                       Parents01, ProvedOut01, ProvedOut02,
  348                                       StackOut01, StackOut02, Model02),
  349            append(Model01, Model02, Model03)
  350        )
  351    ;   verbose(format('Skip execution of an already checked \c
  352                        constraint ~p (it is inconsitent with ~p)\n',
  353                       [ConDual, ConEntry])),
  354        StackOut02 = StackIn01,
  355        Model03 = []
  356    ),
  357    verbose(format('Executing ~p with clpq ConstraintList = ~p\n',
  358                   [Goal, Duals])),
  359    exec_with_clpq_constraints(Var02, Goal02, M,
  360                               entry(ConVar02, ConEntry02),
  361                               Duals, Parents, ProvedOut02, ProvedOut,
  362                               StackOut02, StackOut, Model04),
  363    append(Model03, Model04, Model).
  364
  365exec_with_neg_list(_, _, _, [], _, ProvedIn, ProvedIn, StackIn, StackIn, []).
  366exec_with_neg_list(Var, Goal, M, [Value|Vs],
  367                   Parents, ProvedIn, ProvedOut, StackIn, StackOut,
  368                   Model) :-
  369    my_copy_term(Var, [Goal, StackIn], NewVar, [NewGoal, NewStackIn]),
  370    NewVar = Value,
  371    verbose(format('Executing ~p with value ~p\n', [NewGoal, Value])),
  372    solve([NewGoal], M, Parents,
  373          ProvedIn, ProvedMid, NewStackIn, [[]|NewStackMid], ModelMid),
  374    verbose(format('Success executing ~p with value ~p\n',
  375                   [NewGoal, Value])),
  376    exec_with_neg_list(Var, Goal, M, Vs, Parents,
  377                       ProvedMid, ProvedOut, NewStackMid, StackOut, Models),
  378    append(ModelMid, Models, Model).
 solve_goal_table_predicate(+Goal, +Module, +Parents, +ProvedIn, -ProvedOut, +AttStackIn, -AttStackOut, -AttModel)
Used to evaluate predicates under tabling. This predicates should be defined in the program using the directive _#table pred/n._
  386solve_goal_table_predicate(Goal, M, Parents, ProvedIn, ProvedOut, AttStackIn, AttStackOut, AttModel) :-
  387    M:pr_rule(Goal, Body, _Origin),
  388    AttStackIn ~> stack(StackIn),
  389    solve(Body, M, Parents, ProvedIn, ProvedOut, StackIn, StackOut, Model),
  390    AttStackOut <~ stack(StackOut),
  391    AttModel <~ model([Goal|Model]).
 solve_goal_predicate(+Goal, +Module, +Parents, +ProvedIn, -ProvedOut, +StackIn, -StackOut, -Model)
Used to evaluate a user predicate
  399solve_goal_predicate(Goal, M, Parents, ProvedIn, ProvedOut, StackIn, StackOut,
  400                     GoalModel) :-
  401    M:pr_rule(Goal, Body, Origin),
  402    mkgoal(Goal, Origin, StackGoal),
  403    solve(Body, M, Parents, ProvedIn, ProvedMid, [StackGoal|StackIn], StackOut, BodyModel),
  404    add_proved(Goal, ProvedMid, ProvedOut),
  405    GoalModel = [Goal|BodyModel].
 solve_goal_builtin(+Goal, -Model)
Used to evaluate builtin predicates predicate
  411solve_goal_builtin(is(X, Exp), Model) :-
  412    exec_goal(is(X, Exp)),
  413    Model = [is(X, Exp)]. 
  414solve_goal_builtin(builtin(Goal), Model) :- !,
  415    exec_goal(Goal),
  416    Model = [builtin(Goal)].
  417solve_goal_builtin(Goal, Model) :-
  418    clp_builtin(Goal), !,
  419    exec_goal(apply_clpq_constraints(Goal)),
  420    Model = [Goal].
  421solve_goal_builtin(Goal, Model) :-
  422    clp_interval(Goal), !,
  423    exec_goal(Goal),
  424    Model = [Goal].
  425solve_goal_builtin(not(Goal), _Model) :-
  426    clp_interval(Goal), !,
  427    scasp_warning(scasp(failure_calling_negation(Goal))),
  428    fail.
  429solve_goal_builtin(Goal, Model) :-
  430    clp_builtin(Goal),
  431    !,
  432    exec_goal(apply_clpq_constraints(Goal)),
  433    Model = [Goal].
  434solve_goal_builtin(Goal, Model) :-
  435    prolog_builtin(Goal), !,
  436    exec_goal(Goal),
  437    Model = [Goal].
  438% The predicate is not defined as user_predicates neither builtin
  439solve_goal_builtin(Goal, Model) :-
  440    verbose(format('The predicate ~p is not user_defined / builtin\n', [Goal])),
  441    (   Goal = not(_)
  442    ->  Model = [Goal]
  443    ;   fail
  444    )
  444.
  445
  446exec_goal(A \= B) :- !,
  447    verbose(format('exec ~@\n', [print_goal(A \= B)])),
  448    A .\=. B,
  449    verbose(format('ok   ~@\n', [print_goal(A \= B)])).
  450exec_goal(Goal) :-
  451    (   current_prolog_flag(scasp_verbose, true)
  452    ->  E = error(_,_),
  453        verbose(format('exec goal ~@ \n', [print_goal(Goal)])),
  454        catch(call(Goal), E, (print_message(warning, E), fail)),
  455        verbose(format('ok   goal ~@ \n', [print_goal(Goal)]))
  456    ;   catch(call(Goal), error(_,_), fail)
  457    ).
  458
  459% TODO: Pending StackOut to carry the literal involved in the findall
  460% (if needed)
  461% TODO: Handling of ProvedIn/ProvedOut
 exec_findall(+Findall, +Module, +ProvedIn, -ProvedOut, +StackIn, -StackOut, -Model)
  466exec_findall(findall(Var, Call, List), M,
  467             Parents, ProvedIn, ProvedOut, StackIn, StackOut, Model) :-
  468    verbose(format('execution of findall(~p, ~p, _) \n', [Var, Call])),
  469    findall(t(Var, S, Mdl), (
  470            solve([Call], M, Parents, ProvedIn, _ProvedOut, StackIn, S0, Mdl),
  471            append(S, StackIn, S0)
  472        ), VSMList),
  473    process_vsmlist(VSMList, List, SOut, Model),
  474    append(SOut, [findall(Var, Call, List)|StackIn], StackOut),
  475    stack_proved(StackOut, ProvedOut),
  476    verbose(format('Result execution = ~p \n', [List])).
  477
  478process_vsmlist(VSMList, List, [[]|StackOut], Model) :-
  479    process_vsmlist_(VSMList, List, StackOut, Model).
  480
  481process_vsmlist_([], [], [], []).
  482process_vsmlist_([t(V, [[]|S], M)|Rs], [V|Vs], S1, M1) :-
  483    process_vsmlist_(Rs, Vs, S0, M0),
  484    append(S0, S, S1),
  485    append(M, M0, M1).
  486
  487% TODO: What to do with the negation of findall/3 (if required)
  488exec_neg_findall(Goal, _, _, _, _) :-
  489    verbose(format('PENDING: execution of not ~p \n', [Goal])),
  490    fail.
 check_CHS(+Goal, +Module, +Parents, +ProvedIn, +StackIn, -Result) is det
Checks the StackIn and returns in Result if the goal Goal is a coinductive success, a coinductive failure or an already proved goal. Otherwise it is constraint against its negation atoms already visited.
  500:- det(check_CHS/6).  501
  502check_CHS(Goal, M, Parents, Proved, I, Result) :-
  503    (   user_predicate(M:Goal)
  504    ->  check_CHS_(Goal, M, Parents, Proved, I, Result)
  505    ;   Result = cont
  506    ).
  507
  508% inmediate success if the goal has already been proved.
  509check_CHS_(Goal, _M, _Parents, Proved, _Stack, proved) :-
  510    ground(Goal),
  511    proved_in_stack(Goal, Proved),
  512    !.
  513% coinduction success <- cycles containing even loops may succeed
  514check_CHS_(Goal, _M, Parents, _Proved, _I, co_success) :-
  515    check_parents(Goal, Parents, even),
  516    !.
  517% coinduction fails <- the goal is entailed by its negation in the
  518% call stack
  519check_CHS_(Goal, _M, Parents, Proved, _Stack, co_failure) :-
  520    neg_in_stack(Goal, Parents, Proved), !,
  521    verbose(format('Negation of the goal in the stack, failling (Goal = ~w)\n', [Goal])).
  522% coinduction fails <- cycles containing positive loops can be solved
  523% using tabling
  524check_CHS_(Goal, M, Parents, _Proved, _Stask, co_failure) :-
  525    \+ table_predicate(M:Goal),
  526    \+ current_prolog_flag(scasp_no_fail_loop, true),
  527    \+ \+ (
  528        check_parents(Goal, Parents, fail_pos(S)),
  529        verbose(format('Positive loop, failing (Goal == ~w)\n', [Goal])),
  530        scasp_warning(scasp_warn_pos_loops, pos_loop(fail, Goal, S))
  531    ), !.
  532check_CHS_(Goal, M, Parents, _Proved, _Stack, _Cont) :-
  533    \+ table_predicate(M:Goal),
  534    \+ \+ (
  535        check_parents(Goal, Parents, pos(S)),
  536        verbose(format('Positive loop, continuing (Goal = ~w)\n', [Goal])),
  537        scasp_info(scasp_warn_pos_loops, pos_loop(continue, Goal, S))
  538    ), fail.
  539% coinduction does not succeed or fail <- the execution continues inductively
  540check_CHS_(Goal, _M, Parents, Proved, _Stack, cont) :-
  541    (   ground(Goal)
  542    ->  constrained_neg_in_stack(Goal, Parents, Proved)
  543    ;   ground_neg_in_stack(Goal, Parents, Proved)
  544    ).
 neg_in_stack(+Goal, +Parents, +Proved) is semidet
True when the nagation of Goal is in Stack. If so we have a coinductive failure. Check on variants which requires tabling for proper results.
  552neg_in_stack(Goal, _Parents, Proved) :-
  553    proved_relatives(Goal, Proved, Relatives),
  554    member(Relative, Relatives),
  555    is_negated_goal(Goal, Relative),
  556    !.
  557neg_in_stack(Goal, Parents, _) :-
  558    member(Relative, Parents),
  559    is_negated_goal(Goal, Relative),
  560    !.
  561
  562is_negated_goal(Goal, Head) :-
  563    (   Goal = not(G)
  564    ->  (   G == Head
  565        ->  true
  566        ;   G =@= Head
  567        ->  scasp_warning(co_failing_in_negated_loop(G, Head))
  568        )
  569    ;   Head = not(NegGoal)
  570    ->  (   Goal == NegGoal
  571        ->  true
  572        ;   Goal =@= NegGoal
  573        ->  scasp_warning(co_failing_in_negated_loop(Goal, NegGoal))
  574        )
  575    ).
 ground_neg_in_stack(++Goal, +Parents, +Proved) is det
Propagate disequality constraints of Goal through matching goals on the stack.
  582:- det(ground_neg_in_stack/3).  583
  584ground_neg_in_stack(Goal, Parents, Proved) :-
  585    verbose(format('Enter ground_neg_in_stack for ~@\n', [print_goal(Goal)])),
  586    (   proved_relatives(Goal, Proved, Relatives)
  587    ->  maplist(ground_neg_in_stack_(Flag, Goal), Relatives)
  588    ;   true
  589    ),
  590    maplist(ground_neg_in_stack_(Flag, Goal), Parents),
  591    (   Flag == found
  592    ->  verbose(format('\tThere exit the negation of ~@\n\n', [print_goal(Goal)]))
  593    ;   true
  594    ).
  595
  596ground_neg_in_stack_(found, TGoal, SGoal) :-
  597    gn_match(TGoal, SGoal, Goal, NegGoal),
  598    \+ Goal \= NegGoal,
  599    verbose(format('\t\tCheck disequality of ~@ and ~@\n',
  600                   [print_goal(TGoal), print_goal(SGoal)])),
  601    loop_term(Goal, NegGoal),
  602    !.
  603ground_neg_in_stack_(_, _, _).
  604
  605gn_match(Goal, chs(not(NegGoal)), Goal, NegGoal) :- !.
  606gn_match(not(Goal), chs(NegGoal), Goal, NegGoal) :- !.
  607gn_match(not(Goal), NegGoal,      Goal, NegGoal) :- !.
 constrained_neg_in_stack(+Goal, +Parents, +Proved) is det
Propagate the fact that we accept Goal into all other accepted goals in the stack.
  615:- det(constrained_neg_in_stack/3).  616
  617constrained_neg_in_stack(Goal, Parents, Proved) :-
  618    (   proved_relatives(Goal, Proved, Relatives)
  619    ->  maplist(contrained_neg(Goal), Relatives)
  620    ;   true
  621    ),
  622    maplist(contrained_neg(Goal), Parents).
  623
  624contrained_neg(not(Goal), NegGoal) :-
  625    is_same_functor(Goal, NegGoal),
  626    verbose(format('\t\tCheck if not(~@) is consistent with ~@\n',
  627                   [print_goal(Goal), print_goal(NegGoal)])), !,
  628    loop_term(Goal, NegGoal),
  629    !,
  630    verbose(format('\t\tOK\n', [])).
  631contrained_neg(Goal, not(NegGoal)) :-
  632    is_same_functor(Goal, NegGoal),
  633    verbose(format('\t\tCheck if not(~@) is consistent with ~@\n',
  634                   [print_goal(Goal), print_goal(NegGoal)])), !,
  635    loop_term(Goal, NegGoal),
  636    !,
  637    verbose(format('\t\tOK\n', [])).
  638contrained_neg(_,_).
  639
  640is_same_functor(Term1, Term2) :-
  641    functor(Term1, Name, Arity, Type),
  642    functor(Term2, Name, Arity, Type).
 proved_in_stack(+Goal, +Proved) is semidet
True when Goal appears in one of the finished branches of the proof tree, i.e., it appears in Stack, but not as direct parent.
  649proved_in_stack(Goal, Proved) :-
  650    proved_relatives(Goal, Proved, Relatives),
  651    member(Relative, Relatives),
  652    (   Goal == Relative
  653    ;   Goal == chs(Relative)
  654    ),
  655    !.
 check_parents(+Goal, +Parents, -Type) is semidet
Type is the coinductive result. This is even if we have an even loop through negation or a simple positive match.
  662check_parents(not(Goal), Parents, Type) :-
  663    !,
  664    check_parents(not(Goal), 1, Parents, Type).
  665check_parents(Goal, Parents, Type) :-
  666    check_parents(Goal, 0, Parents, Type).
  667
  668check_parents(Goal, 0, [Parent|_Parents], Type) :-
  669    (   \+ \+ type_loop_fail_pos(Goal, Parent)
  670    ->  Type = fail_pos(Parent)
  671    ;   \+ Goal \= Parent
  672    ->  Type = pos(Parent)
  673    ),
  674    !.
  675check_parents(Goal, N, [Parent|Parents], Type) :-
  676    (   even_loop(Goal, Parent, N)
  677    ->  Type = even
  678    ;   Goal \== Parent
  679    ->  (  Parent = not(_)
  680        ->  NewN is N + 1,
  681            check_parents(Goal, NewN, Parents, Type)
  682        ;   check_parents(Goal, N, Parents, Type)
  683        )
  684    ).
  685
  686even_loop(not(Goal), not(Parent), _) :-
  687    Goal =@= Parent,
  688    !,
  689    Goal = Parent.
  690even_loop(Goal, Parent, N) :-
  691    Goal \= not(_),
  692    Goal == Parent,
  693    N > 0,
  694    0 =:= mod(N, 2).
  695
  696type_loop_fail_pos(Goal, S) :-
  697    Goal == S, !.
  698type_loop_fail_pos(Goal, S) :-
  699    variant(Goal, S), !,
  700    scasp_warning(variant_loop(Goal, S)).
  701type_loop_fail_pos(Goal, S) :-
  702    entail_terms(Goal, S),
  703    scasp_warning(subsumed_loop(Goal, S)).
 stack_parents(+Stack, -Parents) is det
Get the direct callers from Stack. Stack contains both previous proved stacks as well as the current list of parents.
  710:- det(stack_parents/2).  711stack_parents(Stack, Parents) :-
  712    stack_parents(Stack, 0, Parents).
  713
  714stack_parents([], _, []).
  715stack_parents([[]|T], N, Parents) :-
  716    !,
  717    N1 is N-1,
  718    stack_parents(T, N1, Parents).
  719stack_parents([_|T], N, Parents) :-
  720    N < 0,
  721    !,
  722    N1 is N+1,
  723    stack_parents(T, N1, Parents).
  724stack_parents([goal_origin(H, _)|T], N, [H|TP]) :-
  725    !,
  726    stack_parents(T, N, TP).
  727stack_parents([H|T], N, [H|TP]) :-
  728    stack_parents(T, N, TP).
 stack_proved(Stack, Proved:assoc) is det
True when Proved is an assoc holding all goals that have already been proved in Stack. This excludes the direct parents of in the stack, i.e. only adds goals from already completed branches.

The code is based on the old proved_in_stack/2. Effectively this extracts the other half than stack_parents/2, so possibly we should sync the code with that.

  740:- det(stack_proved/2).  741
  742stack_proved(Stack, Proved) :-
  743    empty_assoc(Proved0),
  744    stack_proved(Stack, 0, -1, Proved0, Proved).
  745
  746stack_proved([], _, _, Proved, Proved).
  747stack_proved([Top|Ss], Intervening, MaxInter, Proved0, Proved) :-
  748    (   Top == []
  749    ->  NewInter is Intervening - 1,
  750        stack_proved(Ss, NewInter, MaxInter, Proved0, Proved)
  751    ;   Intervening > MaxInter
  752    ->  NewMaxInter is max(MaxInter, Intervening),
  753        NewInter is Intervening + 1,
  754        stack_proved(Ss, NewInter, NewMaxInter, Proved0, Proved)
  755    ;   add_proved(Top, Proved0, Proved1),
  756        stack_proved(Ss, Intervening, MaxInter, Proved1, Proved)
  757    ).
  758
  759add_proved(goal_origin(Goal, _), Assoc0, Assoc) =>
  760    add_proved(Goal, Goal, Assoc0, Assoc).
  761add_proved(Goal, Assoc0, Assoc) =>
  762    add_proved(Goal, Goal, Assoc0, Assoc).
  763
  764add_proved(not(Term), Goal, Assoc0, Assoc) =>
  765    add_proved(Term, Goal, Assoc0, Assoc).
  766add_proved(chs(Term), Goal, Assoc0, Assoc) =>
  767    add_proved(Term, Goal, Assoc0, Assoc).
  768add_proved(forall(_,_), _Goal, Assoc0, Assoc) =>
  769    Assoc = Assoc0.
  770add_proved(Term, Goal, Assoc0, Assoc) =>
  771    functor(Term, Name, Arity),
  772    (   get_assoc(Name/Arity, Assoc0, List, Assoc, [Goal|List])
  773    ->  true
  774    ;   put_assoc(Name/Arity, Assoc0, [Goal], Assoc)
  775    ).
 solve_c_forall(+Forall, +Module, +Parents, +ProvedIn, -ProvedOut, +StackIn, -StackOut, -Model)
Solve a sub-goal of the form c_forall(Vars,Goal) and succeeds if the goal Goal succeeds covering the domain of all the vars in the list of vars `Vars. It calls solve/4
Arguments:
Forall- is a term forall(Var, Goal).
To be done
- Improve the efficiency by removing redundant justifications w.o. losing solutions.
  789solve_c_forall(Forall, M, Parents, ProvedIn, ProvedOut, StackIn, [[]|StackOut],
  790               Model) :-
  791    collect_vars(Forall, c_forall(Vars0, Goal0)),    % c_forall([F,G], not q_1(F,G))
  792
  793    verbose(format('\nc_forall(~p,\t~@)\n\n',[Vars0, print_goal(Goal0)])),
  794
  795    my_copy_vars(Vars0, Goal0, Vars1, Goal1),        % Vars should remain free
  796    my_diff_term(Goal1, Vars1, OtherVars),
  797    Initial_Const = [],                              % Constraint store = top
  798    (   current_prolog_flag(scasp_forall, all_c)     % Ciao --all_c_forall
  799    ->  solve_var_forall_(Goal1, M, Parents, ProvedIn, ProvedOut,
  800                          entry(Vars1, Initial_Const),
  801                          dual(Vars1, [Initial_Const]),
  802                          OtherVars, StackIn, StackOut, Model)
  803    ;   solve_other_forall(Goal1, M, Parents, ProvedIn, ProvedOut,
  804                           entry(Vars1, Initial_Const),
  805                           dual(Vars1, [Initial_Const]),
  806                           OtherVars, StackIn, StackOut, Model)
  807    ).
  808
  809solve_other_forall(Goal, M, Parents, ProvedIn, ProvedOutExit,
  810                   entry(Vars, Initial_Const),
  811                   dual(Vars, [Initial_Const]),
  812                   OtherVars, StackIn, StackOutExit, ModelExit) :-
  813    append(Vars,OtherVars,AllVars),
  814    my_copy_vars(AllVars,   [Goal,  Parents,  ProvedIn,  StackIn,  OtherVars,  Vars],
  815                 _AllVars1, [Goal1, Parents1, ProvedIn1, StackIn1, OtherVars1, Vars1]),
  816    my_copy_vars(AllVars,   [Goal,  Parents,  ProvedIn,  StackIn,  OtherVars,  Vars],
  817                 _AllVars2, [Goal2, Parents2, ProvedIn2, StackIn2, OtherVars2, Vars2]),
  818
  819    verbose(format("solve other forall:\n\c
  820                           \t Goal \t~p\n\c
  821                           \t Vars1       \t~p\n\c
  822                           \t OtherVars   \t~p\n\c
  823                           \t StackIn     \t~p\n\n",
  824                          ['G'(Goal),'G'(Vars1),
  825                           'G'(OtherVars),'G'(StackIn)])),
  826
  827    % disequality and clp for numbers
  828    dump_constraint(OtherVars, OtherVars1, Dump, []-[], Pending-Pending1), !,
  829    clpqr_dump_constraints(Pending, Pending1, CLP),
  830    append(CLP, Dump, Constraints1),
  831    my_copy_vars(OtherVars1, Constraints1, OtherVars2, Constraints2),
  832
  833    verbose(format("solve other forall:\n\c
  834                          \t OtherVars1   \t~p\n\c
  835                          \t OtherVars2   \t~p\n\c
  836                          \t Constraints1 \t~p\n\c
  837                          \t Constraints2 \t~p\n\n",
  838                          ['G'(OtherVars1), 'G'(OtherVars2),
  839                           'G'(Constraints1), 'G'(Constraints2)])),
  840
  841    apply_const_store(Constraints1),
  842    !,
  843
  844    solve_var_forall_(Goal1, M, Parents1, ProvedIn1, ProvedOut,
  845                      entry(Vars1, Initial_Const),
  846                      dual(Vars1, [Initial_Const]), OtherVars1,
  847                      StackIn1, StackOut, Model),
  848    !,
  849    (   OtherVars = OtherVars1,
  850        StackOutExit = StackOut,
  851        ModelExit = Model,
  852        ProvedOutExit = ProvedOut
  853    ;   \+ ground(OtherVars),
  854        apply_const_store(Constraints2),
  855        % disequality and clp for numbers
  856        dump_constraint(OtherVars1, OtherVars2, Dump1, []-[], Pend-Pend1), !,
  857        clpqr_dump_constraints(Pend, Pend1, CLP1),
  858        append(CLP1, Dump1, AnsConstraints2),
  859        make_duals(AnsConstraints2, Duals),
  860        member(Dual, Duals),
  861        apply_const_store(Dual),
  862        solve_other_forall(Goal2, M, Parents2, ProvedIn2, ProvedOutExit,
  863                           entry(Vars2, Initial_Const),
  864                           dual(Vars2, [Initial_Const]),
  865                           OtherVars2, StackIn2, StackOutExit, ModelExit), !,
  866        OtherVars = OtherVars2
  867    ).
 solve_var_forall_(+Goal, +Module, +Parents, +ProvedIn, -ProvedOut, +Entry, +Duals, +OtherVars, +StackIn, -StackOut, -Model) is nondet
Implements the forall algorithm as described in section 2.3 from "Constraint Answer Set Programming without Grounding" by Joaquin Arias et all. It works different though.

Note that the constraints on the forall variables are maintained explicitly.

  885solve_var_forall_(_Goal, _M, _Parents, Proved, Proved, _, dual(_, []),
  886                  _OtherVars, StackIn, StackIn, []) :- !.
  887solve_var_forall_(Goal, M, Parents, ProvedIn, ProvedOut,
  888                  entry(C_Vars, Prev_Store),
  889                  dual(C_Vars, [C_St|C_Stores]),
  890                  OtherVars, StackIn, StackOut, Model) :-
  891    verbose(format("solve forall:\n\c
  892                          \tPrev_Store \t~p\n\c
  893                          \tC_St       \t~p\n\c
  894                          \tC_Stores   \t~p\n\c
  895                          \tStackIn    \t~p\n\n",
  896                          ['G'(Prev_Store),'G'(C_St),
  897                           'G'(C_Stores),'G'(StackIn)])),
  898
  899    my_copy_vars(C_Vars,  [Goal,Prev_Store,C_St],
  900                 C_Vars1, [Goal1,Prev_Store1,C_St1]),
  901    my_copy_vars(C_Vars,  [Goal,Prev_Store,C_Stores],
  902                 C_Vars2, [Goal2,Prev_Store2,C_Stores2]),
  903
  904    apply_const_store(Prev_Store),
  905    (   %verbose(format('apply_const_store ~@\n',[print_goal(C_St)])),
  906        apply_const_store(C_St) % apply a Dual
  907    ->  solve([Goal], M, Parents, ProvedIn, ProvedOut1, StackIn, [[]|StackOut1], Model1),
  908        find_duals(C_Vars, C_Vars1, OtherVars, Duals),
  909        verbose(format('Duals = \t ~p\n',[Duals])),
  910        append_set(Prev_Store1, C_St1, Current_Store1),
  911        solve_var_forall_(Goal1, M, Parents, ProvedOut1, ProvedOut2,
  912                          entry(C_Vars1, Current_Store1),
  913                          dual(C_Vars1, Duals),
  914                          OtherVars, StackOut1, StackOut2, Model2),
  915        append(Model1,Model2,Model3)
  916    ;   verbose(format('Entail: Fail  applying \t ~p\n', ['G'(C_St)])),
  918        ProvedOut2 = ProvedIn,
  919        StackOut2 = StackIn,
  920        Model3 = []
  921    )
  921,
  922    solve_var_forall_(Goal2, M, Parents, ProvedOut2, ProvedOut,
  923                      entry(C_Vars2, Prev_Store2),
  924                      dual(C_Vars2, C_Stores2),
  925                      OtherVars, StackOut2, StackOut, Model4),
  926    append(Model3, Model4, Model)
  926.
  927
  928append_set([],X,X):- !.
  929append_set([A|As],Bs,Cs) :-
  930    \+ \+ memberchk_oc(A, Bs),
  931    !,
  932    append_set(As,Bs,Cs).
  933append_set([A|As],Bs,[A|Cs]) :-
  934    append_set(As,Bs,Cs).
  935
  936memberchk_oc(Term, [H|T]) :-
  937    (   unify_with_occurs_check(Term, H)
  938    ->  true
  939    ;   memberchk_oc(Term, T)
  940    ).
  941
  942apply_const_store([]) :- !.
  943apply_const_store([C|Cs]) :-
  944    apply_constraint(C),
  945    apply_const_store(Cs).
  946
  947apply_constraint(A \= B) =>
  948    A .\=. B.
  949apply_constraint(A = B) =>
  950    A = B.
  951apply_constraint(CLPConstraint) =>
  952    apply_clpq_constraints(CLPConstraint).
 find_duals(+C_Vars, +C_Vars1, +OtherVars, -Duals)
C_Vars is the list of forall variables after solve/4. C_Vars1 is a copy of this list before calling solve/4. Our task is to create a dual model from the instantiation. If subsequently we can prove the dual model to be true then we proved the forall is true. For example, if solve succeeded with [X] --> [q], it created the instantiation X=q. It we now can prove X\=q, we proved solve is true for all X.
See also
- Section 2.3 from "Constraint Answer Set Programming without Grounding" by Joaquin Arias et all.
To be done
- JW: it is not clear to me why OtherVars is needed and why it is not copied.
  969find_duals(C_Vars, C_Vars1, OtherVars, Duals) :-
  970    % disequality and clp for numbers
  971    dump_constraint(C_Vars, C_Vars1, Dump, []-[], Pending-Pending1), !,
  972    clp_vars_in(OtherVars, OtherCLPVars),		% clp(Q) vars
  973    append(Pending, OtherCLPVars, CLPVars),
  974    append(Pending1, OtherCLPVars, CLPVars1),
  975    clpqr_dump_constraints(CLPVars, CLPVars1, CLP),
  976    append(CLP, Dump, Constraints),
  977    make_duals(Constraints,Duals), !.
  978
  979make_duals(Ls,Ds) :-
  980    make_duals_([],Ls,[],Ds).
  981
  982make_duals_(_,[],Ds,Ds).
  983make_duals_(Prev,[A|As],D0,Ds) :-
  984    append(Prev,[A],Prev1),
  985    make_duals_(Prev1,As,D0,D1),
  986    dual(A,Duals_A),
  987    combine(Duals_A,Prev,As,Ls),
  988    append(Ls,D1,Ds).
  989
  990combine([A],Prev,Post,[Rs]) :-
  991    append(Prev,[A|Post],Rs).
  992combine([A,B|As],Prev,Post,[RA|RAs]) :-
  993    append(Prev,[A|Post],RA),
  994    combine([B|As],Prev,Post,RAs).
  995
  996:- det(dual/2).  997
  998dual(#=(A,B), [#<(A,B), #>(A,B)]).
  999dual(#<(A,B), [#>=(A,B)]).
 1000dual(#>(A,B), [#=<(A,B)]).
 1001dual(#=<(A,B), [#>(A,B)]).
 1002dual(#>=(A,B), [#<(A,B)]).
 1003
 1004dual(=(A,B), [\=(A,B)]).
 1005dual(\=(A,B), [=(A,B)]).
 dump_constraint(+C_Vars, +C_Vars1, -Dump, +Pending0, -Pending) is det
Arguments:
Dump- is a list of V1=B and V1\=B, where V1 is a variable from C_Vars1.
Pending- is a pair of lists with variables from C_Vars and C_Vars1 that are not processed (in reverse order, why?)
 1015:- det(dump_constraint/5). 1016dump_constraint([], [], [], Pending, Pending).
 1017dump_constraint([V|Vs], [V1|V1s], [V1 = V | Vs_Dump], P0, P1) :-
 1018    ground(V), !,
 1019    dump_constraint(Vs, V1s, Vs_Dump, P0, P1).
 1020dump_constraint([V|Vs], [V1|V1s], Rs_Dump, P0, P1) :-
 1021    get_neg_var(V, List),
 1022    List \== [], !,
 1023    dump_neg_list(V1, List, V_Dump),
 1024    dump_constraint(Vs, V1s, Vs_Dump, P0, P1),
 1025    append(V_Dump, Vs_Dump, Rs_Dump).
 1026dump_constraint([V|Vs], [V1|V1s], Vs_Dump, PV-PV1, P1) :-
 1027    dump_constraint(Vs, V1s, Vs_Dump, [V|PV]-[V1|PV1], P1).
 1028
 1029dump_neg_list(_,[],[]) :- !.
 1030dump_neg_list(V,[L|Ls],[V \= L|Rs]) :- dump_neg_list(V,Ls,Rs).
 1031
 1032clp_vars_in(Vars, ClpVars) :-
 1033    include(is_clpq_var, Vars, ClpVars).
 collect_vars(?Forall, ?CollectForall)
Forall Vars in a list
 1039collect_vars(Forall, c_forall(Vars, Goal)) :-
 1040    collect_vars_(Forall, [], Vars, Goal).
 1041
 1042collect_vars_(forall(Var, Goal), Vars, [Var|Vars], Goal) :-
 1043    Goal \= forall(_, _), !.
 1044collect_vars_(forall(Var, Forall), V0, V1, Goal) :-
 1045    collect_vars_(Forall, [Var|V0], V1, Goal).
 1046
 1047
 1048		 /*******************************
 1049		 *     AUXILIAR PREDICATES      *
 1050		 *******************************/
 my_copy_term(+Var, +Term, -NewVar, -NewTerm) is det
Its behaviour is similar to copy_term/2. It returns in NewTerm a copy of the term Term but it only replaces with a fresh variable NewVar the occurrences of Var
 1058:- if(current_predicate(copy_term_nat/4)). 1059
 1060my_copy_term(Var0, Term0, Var, Term) :-
 1061    copy_term_nat(Var0, Term0, Var, Term).
 1062
 1063my_copy_vars(Vars0, Term0, Vars, Term) :-
 1064    copy_term_nat(Vars0, Term0, Vars, Term).
 1065
 1066:- else. 1067
 1068my_copy_term(Var0, Term0, Var, Term) :-
 1069    term_variables(Term0, AllVars),
 1070    delete_var(AllVars, Var0, Share0),
 1071    copy_term_nat(t(Var0,Share0,Term0), t(Var,Share,Term)),
 1072    Share = Share0.
 1073
 1074delete_var([], _, []).
 1075delete_var([H|T0], V, List) :-
 1076    (   H == V
 1077    ->  List = T0
 1078    ;   List = [H|T],
 1079        delete_var(T0, V, T)
 1080    ).
 1081
 1082my_copy_vars(Vars0, Term0, Vars, Term) :-
 1083    term_variables(Term0, AllVars),
 1084    sort(AllVars, AllVarsSorted),
 1085    sort(Vars0, Vars0Sorted),
 1086    ord_subtract(AllVarsSorted, Vars0Sorted, Share0),
 1087    copy_term_nat(t(Vars0,Share0,Term0), t(Vars,Share,Term)),
 1088    Share = Share0.
 1089
 1090:- endif.
 my_diff_term(+Term, +Vars, -Others) is det
Others are variables in Term that do not appear in Vars.
 1096my_diff_term(Term, Vars, Others) :-
 1097    term_variables(Term, Set),
 1098    diff_vars(Set, Vars, Others).
 1099
 1100diff_vars([], _, []).
 1101diff_vars([H|T0], Vars, List) :-
 1102    (   member_var(Vars, H)
 1103    ->  diff_vars(T0, Vars, List)
 1104    ;   List = [H|T],
 1105        diff_vars(T0, Vars, T)
 1106    ).
 1107
 1108member_var(Vars, Var) :-
 1109    member(V, Vars),
 1110    Var == V,
 1111    !.
 1112
 1113member_stack(Goal, Stack) :- member(goal_origin(Goal, _), Stack).
 1114member_stack(Goal, Stack) :- member(Goal, Stack)