Did you know ... Search Documentation:
Pack logicmoo_base -- t/examples/pfc/trypfcall.pl.txt

% File : pfc % Author : Tim Finin, finin@umbc.edu % Updated: 10/11/87, ... % Purpose: consult system file for ensure

user:file_search_path(pack,'/devel/PrologMUD/pack'). :- attach_packs.

:- 'lmcode':ensure_loaded(logicmoo(logicmoo_utils)).

% not(P):- \+ P.

:- kill_term_expansion. %:- include(prologmud(mud_header)). :- thread_local t_l:pfcExpansion. :- thread_local t_l:pfcExpansionWas.

:- dynamic p. :- dynamic x. :- dynamic q. :- dynamic fly/1.

:- dynamic old_clausedb/0. :- dynamic old_assert/0. :- dynamic old_call/0. :- dynamic bugger_assert/0.

% old_clausedb. % old_assert. old_call. % bugger_assert:- current_predicate(ain/1).

db_retractall(X):-old_assert,!,retractall(X). db_retractall(X):-invoke_modify(retract(all),X). db_retract(X):- old_assert,!,retract(X). db_retract(X):-invoke_modify(retract(one),X). db_assertz(X):-old_assert,!,assertz(X). db_assertz(X):-invoke_modify(assert(z),X). db_asserta(X):-old_assert,!,asserta(X). db_asserta(X):-invoke_modify(assert(a),X). db_assert(X):-old_assert,!,assert(X). db_assert(X):-invoke_modify(assert(z),X).

db_clause(X,Y,Ref):-old_clausedb,!,clause(X,Y,Ref). db_clause(X,Y,Ref):-invoke_check(clause(_),clause_asserted(X,Y,Ref)). db_clause(X,Y):-old_clausedb,!,clause(X,Y). db_clause(X,Y):-invoke_check(clause(_),clause_asserted(X,Y)).

db_call(Y):-db_call(nonPfc,Y). db_call(_,Y):-old_call,!,predicate_property(Y,_),!, call(Y). db_call(What,X):-invoke_call(call(What),X).

ain(X):-ain(X). rem(X):-pfcRem(X).

invoke_call(_, B ):- var(B),!,fail. invoke_call(A, not(B)):- !, not(invoke_call(A,B)). invoke_call(A,\+(B)):- !, not(invoke_call(A,B)). invoke_call(A, call(B)):- !, invoke_call(A,B). invoke_call(_A, X ):- !, current_predicate(_,X),!,call(X). invoke_call(A, B ):- (invoke_op0(A,B)).

invoke_modify(A,B):-(invoke_op0(A,B)). invoke_check(A,B):-(invoke_op0(A,B)).

invoke_op0(assert(z),X):- bugger_assert,!,ainz(X). invoke_op0(assert(a),X):- bugger_assert,!,ain(X). invoke_op0(assert(_),X):- bugger_assert,!,ain(X). invoke_op0(assert(z),X):-!,assertz(X). invoke_op0(assert(a),X):-!,asserta(X). invoke_op0(assert(_),X):-!,assert(X). invoke_op0(retract(all),X):-!,retractall(X). invoke_op0(retract(_),X):-!,retract(X). invoke_op0(clause(_),(X)):-clause(X,true). invoke_op0(clause(_),clause_asserted(X,Y)):-!,clause(X,Y). invoke_op0(clause(_),clause_asserted(X,Y,Ref)):-!,clause(X,Y,Ref). invoke_op0(_,X):-nonvar(X),current_predicate(_,X),!,call(X).

% :- set_prolog_flag(unknown,fail). :- dynamic(go/0).

pfcVersion(1.2).

% pfcFile('pfcsyntax'). % operator declarations.

% File : pfcsyntax.pl % Author : Tim Finin, finin@prc.unisys.com % Purpose: syntactic sugar for Pfc - operator definitions and term expansions.

:- op(500,fx,'~'). :- op(1050,xfx,('==>')). :- op(1050,xfx,'<==>'). :- op(1050,xfx,('<-')). :- op(1100,fx,('==>')). :- op(1150,xfx,('::::')).

:- multifile('mpred_term_expansion'/2).

mpred_term_expansion((P==>Q),(:- ain((P==>Q)))). %mpred_term_expansion((P==>Q),(:- ain(('<-'(Q,P))))). % speed-up attempt mpred_term_expansion(('<-'(P,Q)),(:- ain(('<-'(P,Q))))). mpred_term_expansion((P<==>Q),(:- ain((P<==>Q)))). mpred_term_expansion((RuleName :::: Rule),(:- ain((RuleName :::: Rule)))). mpred_term_expansion((==>P),(:- ain(P))).

:- multifile(term_expansion/2). term_expansion(A,B):- once(true ; t_l:pfcExpansion), once(mpred_term_expansion(A,B)),A\=@=B.

:- asserta(t_l:pfcExpansion).

% pfcFile('pfccore'). % core of Pfc.

% File : pfccore.pl % Author : Tim Finin, finin@prc.unisys.com % Updated: 10/11/87, ... % 4/2/91 by R. McEntire: added calls to valid_dbref as a % workaround for the Quintus 3.1 % bug in the recorded database. % Purpose: core Pfc predicates.

:- use_module(library(lists)).

:- dynamic ('==>')/2. :- dynamic ('::::')/2. :- dynamic '<==>'/2. :- dynamic '<-'/2. :- dynamic 'pt'/2. :- dynamic 'nt'/3. :- dynamic 'bt'/2. :- dynamic pfcUndoMethod/2. :- dynamic (mpred_action)/1. %:- dynamic pfcTmsMode/1. :- dynamic mpred_queue/1. :- dynamic pfcDatabase/1. :- dynamic mpred_haltSignal/0. %:- dynamic pfcDebugging/0. %:- dynamic mpred_select/1. %:- dynamic mpred_search/1.

%%% initialization of global assertons

%% mpred_default/1 initialized a global assertion. %% mpred_default(P,Q) - if there is any fact unifying with P, then do %% nothing, else db_assert Q.

mpred_default(GeneralTerm,Default) :- db_clause(GeneralTerm,true) -> true ; db_assert(Default).

%% pfcTmsMode is one of {none,local,cycles} and controles the tms alg. :- mpred_default(mpred_settings(tmsMode,_), mpred_settings(tmsMode,cycles)).

% Pfc Search strategy. mpred_settings(searchMode,X) where X is one of {direct,depth,breadth} :- mpred_default(mpred_settings(searchMode,_), mpred_settings(searchMode,direct)).

%

%% add/2 and pfcPost/2 are the main ways to db_assert new clauses into the %% database and have forward reasoning done.

%% ain(P,S) asserts P into the dataBase with support from S.

ain(P) :- ain(P,(pcfUser,pcfUser)).

ain((==>P),S) :- ain(P,S).

ain(P,S) :- pfcPost(P,S), pfcRun.

%ain(_,_). %ain(P,S) :- mpred_warn("ain(~w,~w) failed",[P,S]).

% pfcPost(+Ps,+S) tries to add a fact or set of fact to the database. For % each fact (or the singelton) pfcPost1 is called. It always succeeds.

pfcPost([H|T],S) :- !, pfcPost1(H,S), pfcPost(T,S). pfcPost([],_) :- !. pfcPost(P,S) :- pfcPost1(P,S).

% pfcPost1(+P,+S) tries to add a fact to the database, and, if it succeeded, % adds an entry to the pfc queue for subsequent forward chaining. % It always succeeds.

pfcPost1(P,S) :- %% db ainDbToHead(P,P2), % pfcRemoveOldVersion(P), ainSupport(P,S), pfcUnique(P), db_assert(P), pfcTraceAdd(P,S), !, pfcEnqueue(P,S), !.

pfcPost1(_,_). %%pfcPost1(P,S) :- mpred_warn("ain(~w,~w) failed",[P,S]).

%% %% ainDbToHead(+P,-NewP) talkes a fact P or a conditioned fact %% (P:-C) and adds the Db context. %%

ainDbToHead(P,NewP) :- pfcCurrentDb(Db), (Db=true -> NewP = P; P=(Head:-Body) -> NewP = (Head :- (Db,Body)); otherwise -> NewP = (P :- Db)).

% pfcUnique(X) is true if there is no assertion X in the prolog db.

pfcUnique((Head:-Tail)) :- !, \+ db_clause(Head,Tail). pfcUnique(P) :- !, \+ db_clause(P,true).

pfcEnqueue(P,S) :- mpred_settings(searchMode,Mode) -> (Mode=direct -> pfcFwd(P) ; Mode=depth -> pfcAsserta(mpred_queue(P),S) ; Mode=breadth -> pfcAssert(mpred_queue(P),S) ; else -> mpred_warn("Unrecognized mpred_search mode: ~w", Mode)) ; mpred_warn("No mpred_search mode").

% if there is a rule of the form Identifier ::: Rule then delete it.

pfcRemoveOldVersion((Identifier::::Body)) :- % this should never happen. var(identifier), !, mpred_warn("variable used as an rule name in ~w :::: ~w", [Identifier,Body]).

pfcRemoveOldVersion((Identifier::::Body)) :- nonvar(Identifier), db_clause((Identifier::::OldBody),_), \+(Body=OldBody), pfcRem((Identifier::::OldBody)), !. pfcRemoveOldVersion(_).

%

% pfcRun compute the deductive closure of the current database. % How this is done depends on the searching mode: % direct - fc has already done the job. % depth or breadth - use the mpred_queue mechanism.

pfcRun :- ( \+ mpred_settings(searchMode,direct)), mpred_step, pfcRun. pfcRun.

% mpred_step removes one entry from the mpred_queue and reasons from it.

mpred_step :- % if mpred_haltSignal is true, reset it and fail, thereby stopping inferencing. pfcRetract(mpred_haltSignal), !, fail.

mpred_step :- % draw immediate conclusions from the next fact to be considered. % fails iff the queue is empty. get_next_fact(P), pfcdo(pfcFwd(P)), !.

get_next_fact(P) :- %identifies the nect fact to fc from and removes it from the queue. select_next_fact(P), remove_selection(P).

remove_selection(P) :- pfcRetract(mpred_queue(P)), pfcRemoveSupportsQuietly(mpred_queue(P)), !. remove_selection(P) :- brake(format("~Npfc:get_next_fact - selected fact not on Queue: ~w", [P])).

% select_next_fact(P) identifies the next fact to reason from. % It tries the pcfUser defined predicate first and, failing that, % the default mechanism.

select_next_fact(P) :- mpred_select(P), !. select_next_fact(P) :- defaultmpred_select(P), !.

% the default selection predicate takes the item at the froint of the queue. defaultmpred_select(P) :- mpred_queue(P),!.

% mpred_halt stops the forward chaining. mpred_halt :- mpred_halt("",[]).

mpred_halt(Format) :- mpred_halt(Format,[]).

mpred_halt(Format,Args) :- format(Format,Args), mpred_haltSignal -> mpred_warn("mpred_halt finds mpred_haltSignal already set") ; db_assert(mpred_haltSignal).

%% %% %% predicates for manipulating triggers %%

ainTrigger(pt(Trigger,Body),Support) :- !, mpred_trace_msg('~n Adding positive trigger ~q~n', [pt(Trigger,Body)]), pfcAssert(pt(Trigger,Body),Support), copy_term(pt(Trigger,Body),Tcopy), pfcBC(Trigger), pfcEvalLHS(Body,(Trigger,Tcopy)), fail.
ainTrigger(nt(Trigger,Test,Body),Support) :- !, mpred_trace_msg('~n Adding negative trigger: ~q~n test: ~q~n body: ~q~n', [Trigger,Test,Body]), copy_term(Trigger,TriggerCopy), pfcAssert(nt(TriggerCopy,Test,Body),Support), \+Test, pfcEvalLHS(Body,(( \+Trigger),nt(TriggerCopy,Test,Body))).

ainTrigger(bt(Trigger,Body),Support) :- !, pfcAssert(bt(Trigger,Body),Support), pfcBtPtCombine(Trigger,Body).

ainTrigger(X,_Support) :- mpred_warn("Unrecognized trigger to aintrigger: ~w",[X]).

pfcBtPtCombine(Head,Body,Support) :- %% a backward trigger (bt) was just added with head and Body and support Support %% find any pt's with unifying heads and add the instantied bt body. pfcGetTriggerQuick(pt(Head,_PtBody)), pfcEvalLHS(Body,Support), fail. pfcBtPtCombine(_,_,_) :- !.

pfcGetTriggerQuick(Trigger) :- db_clause(Trigger,true).

pfcGetTrigger(Trigger):-pfcGetTriggerQuick(Trigger).

%% %% %% predicates for manipulating action traces. %%

ainActionTrace(Action,Support) :- % adds an action trace and it's support. ainSupport(mpred_action(Action),Support).

pfcRemActionTrace(mpred_action(A)) :- pfcUndoMethod(A,M), M, !.

%% %% predicates to remove pfc facts, triggers, action traces, and queue items %% from the database. %%

pfcRetract(X) :- %% db_retract an arbitrary thing. mpred_db_type(X,Type), pfcRetractType(Type,X), !.

pfcRetractType(fact,X) :- %% db ainDbToHead(X,X2), db_retract(X2). db_retract(X).

pfcRetractType(rule,X) :- %% db ainDbToHead(X,X2), db_retract(X2). db_retract(X). pfcRetractType(trigger,X) :- db_retract(X) -> unFc(X) ; mpred_warn("Trigger not found to db_retract: ~w",[X]).

pfcRetractType(action,X) :- pfcRemActionTrace(X).

%% ainSome(X) adds item X to some database

ainSome(X) :- % what type of X do we have? mpred_db_type(X,Type), % db_call the appropriate predicate. ainType(Type,X).

ainType(fact,X) :- pfcUnique(X), db_assert(X),!. ainType(rule,X) :- pfcUnique(X), db_assert(X),!. ainType(trigger,X) :- db_assert(X). ainType(action,_Action) :- !.

%% pfcRem(P,S) removes support S from P and checks to see if P is still supported. %% If it is not, then the fact is retreactred from the database and any support %% relationships it participated in removed.

pfcRem(List) :- % iterate down the list of facts to be pfcRem'ed. nonvar(List), List=[_|_], pfcRem_L(List).

pfcRem(P) :- % pfcRem/1 is the pcfUser's interface - it withdraws pcfUser support for P. pfcRem(P,(pcfUser,pcfUser)).

pfcRem_L([H|T]) :- % pfcRem each element in the list. pfcRem(H,(pcfUser,pcfUser)), pfcRem_L(T).

pfcRem(P,S) :- % pfcDebug(format("~Nremoving support ~w from ~w",[S,P])), mpred_trace_msg('~n Removing support: ~q from ~q~n',[S,P]), pfcRemSupport(P,S) -> pcfRemoveIfUnsupported(P) ; mpred_warn("pfcRem/2 Could not find support ~w to remove from fact ~w", [S,P]).

%% %% mpred_rem2 is like pfcRem, but if P is still in the DB after removing the %% pcfUser's support, it is retracted by more forceful means (e.g. remove). %%

mpred_rem2(P) :- % mpred_rem2/1 is the pcfUser's interface - it withdraws pcfUser support for P. mpred_rem2(P,(pcfUser,pcfUser)).

mpred_rem2(P,S) :- pfcRem(P,S), pfcBC(P) -> remove(P) ; true.

%% %% remove(+F) retracts fact F from the DB and removes any dependent facts */ %%

remove(F) :- pfcRemoveSupports(F), pfcUndo(F).

% removes any remaining supports for fact F, complaining as it goes.

pfcRemoveSupports(F) :- pfcRemSupport(F,S), mpred_warn("~w was still supported by ~w",[F,S]), fail. pfcRemoveSupports(_).

pfcRemoveSupportsQuietly(F) :- pfcRemSupport(F,_), fail. pfcRemoveSupportsQuietly(_).

% pfcUndo(X) undoes X.

pfcUndo(mpred_action(A)) :- % undo an action by finding a method and successfully executing it. !, pfcRemActionTrace(mpred_action(A)).

pfcUndo(pfcPT3(Key,Head,Body)) :- % undo a positive trigger. % !, (db_retract(pfcPT3(Key,Head,Body)) -> unFc(pt(Head,Body)) ; mpred_warn("Trigger not found to db_retract: ~w",[pt(Head,Body)])).
pfcUndo(nt(Head,Condition,Body)) :- % undo a negative trigger. !, (db_retract(nt(Head,Condition,Body)) -> unFc(nt(Head,Condition,Body)) ; mpred_warn("Trigger not found to db_retract: ~w",[nt(Head,Condition,Body)])).

pfcUndo(Fact) :- % undo a random fact, printing out the trace, if relevant. db_retract(Fact), pfcTraceRem(Fact), unFc1(Fact).

%% unFc(P) "un-forward-chains" from fact f. That is, fact F has just %% been removed from the database, so remove all support relations it %% participates in and check the things that they support to see if they %% should stayu in the database or should also be removed.

unFc(F) :- pfcRetractSupportRelations(F), unFc1(F).

unFc1(F) :- pfcUnFcCheckTriggers(F), % is this really the right place for pfcRun<? pfcRun.

pfcUnFcCheckTriggers(F) :- mpred_db_type(F,fact), copy_term(F,Fcopy), nt(Fcopy,Condition,Action), ( \+ Condition), pfcEvalLHS(Action,(( \+F),nt(F,Condition,Action))), fail. pfcUnFcCheckTriggers(_).

pfcRetractSupportRelations(Fact) :- mpred_db_type(Fact,Type), (Type=trigger -> pfcRemSupport(P,(_,Fact)) ; pfcRemSupport(P,(Fact,_))), pcfRemoveIfUnsupported(P), fail. pfcRetractSupportRelations(_).

%% pcfRemoveIfUnsupported(+P) checks to see if P is supported and removes %% it from the DB if it is not.

pcfRemoveIfUnsupported(P) :- mpred_tms_supported(P) -> true ; pfcUndo(P).

%% mpred_tms_supported(+P) succeeds if P is "supported". What this means %% depends on the TMS mode selected.

mpred_tms_supported(P) :- mpred_settings(tmsMode,Mode), mpred_tms_supported(Mode,P).

mpred_tms_supported(local,P) :- !, pfcGetSupport(P,_). mpred_tms_supported(cycles,P) :- !, wellFounded(P). mpred_tms_supported(_,_P) :- true.

%% %% a fact is well founded if it is supported by the pcfUser %% or by a set of facts and a rules, all of which are well founded. %%

wellFounded(Fact) :- pfcWFF(Fact,[]).

pfcWFF(F,_) :- % supported by pcfUser (pfcAxiom) or an "absent" fact (pfcAssumptionBase). (pfcAxiom(F) ; pfcAssumptionBase(F)), !.

pfcWFF(F,Descendants) :- % first make sure we aren't in a loop. ( \+ memberchk(F,Descendants)), % find a pfcJustificationDB. supports(F,Supporters), % all of whose members are well founded. pfcWFF_L(Supporters,[F|Descendants]), !.

%% pfcWFF_L(L) simply maps pfcWFF over the list.

pfcWFF_L([],_). pfcWFF_L([X|Rest],L) :- pfcWFF(X,L), pfcWFF_L(Rest,L).

% supports(+F,-ListofSupporters) where ListOfSupports is a list of the % supports for one pfcJustificationDB for fact F -- i.e. a list of facts which, % together allow one to deduce F. One of the facts will typically be a rule. % The supports for a pcfUser-defined fact are: [pcfUser].

supports(F,[Fact|MoreFacts]) :- pfcGetSupport(F,(Fact,Trigger)), triggerSupports(Trigger,MoreFacts).

triggerSupports(pcfUser,[]) :- !. triggerSupports(Trigger,[Fact|MoreFacts]) :- pfcGetSupport(Trigger,(Fact,AnotherTrigger)), triggerSupports(AnotherTrigger,MoreFacts).

%% %% %% pfcFwd(X) forward chains from a fact or a list of facts X. %%

pfcFwd([H|T]) :- !, pfcFwd1(H), pfcFwd(T). pfcFwd([]) :- !. pfcFwd(P) :- pfcFwd1(P).

% pfcFwd1(+P) forward chains for a single fact.

% pfcFwd1(Fact) :- map_if_list(pfcFwd1,List),!. pfcFwd1(Fact) :- fc_rule_check(Fact), copy_term(Fact,F), % check positive triggers pfcRunPT(Fact,F), % check negative triggers pfcRunNT(Fact,F).

%% %% fc_rule_check(P) does some special, built in forward chaining if P is %% a rule. %%

fc_rule_check((P==>Q)) :- !, pfcProcessRule(P,Q,(P==>Q)). fc_rule_check((Name::::P==>Q)) :- !, pfcProcessRule(P,Q,(Name::::P==>Q)). fc_rule_check((P<==>Q)) :- !, pfcProcessRule(P,Q,(P<==>Q)), pfcProcessRule(Q,P,(P<==>Q)). fc_rule_check((Name::::P<==>Q)) :- !, pfcProcessRule(P,Q,((Name::::P<==>Q))), pfcProcessRule(Q,P,((Name::::P<==>Q))).

fc_rule_check(('<-'(P,Q))) :- !, pfcDefineBcRule(P,Q,('<-'(P,Q))).

fc_rule_check(_).

pfcRunPT(Fact,F) :- pfcGetTriggerQuick(pt(F,Body)), mpred_trace_msg('~n Found positive trigger: ~q~n body: ~q~n', [F,Body]), pfcEvalLHS(Body,(Fact,pt(F,Body))), fail.

%pfcRunPT(Fact,F) :- % pfcGetTriggerQuick(pt(presently(F),Body)), % pfcEvalLHS(Body,(presently(Fact),pt(presently(F),Body))), % fail.

pfcRunPT(_,_).

pfcRunNT(_Fact,F) :- support3(nt(F,Condition,Body),X,_), Condition, pfcRem(X,(_,nt(F,Condition,Body))), fail. pfcRunNT(_,_).

%% %% pfcDefineBcRule(+Head,+Body,+ParentRule) - defines a backeard %% chaining rule and adds the corresponding bt triggers to the database. %%

pfcDefineBcRule(Head,_Body,ParentRule) :- ( \+ mpred_literal(Head)), mpred_warn("Malformed backward chaining rule. ~w not atomic.",[Head]), mpred_warn("rule: ~w",[ParentRule]), !, fail.

pfcDefineBcRule(Head,Body,ParentRule) :- copy_term(ParentRule,ParentRuleCopy), pfcBuildRhs(Head,Rhs), foreach(mpred_nf(Body,Lhs), (pfcBuildTrigger(Lhs,rhs(Rhs),Trigger), ain(bt(Head,Trigger),(ParentRuleCopy,pcfUser)))).

%% %% %% eval something on the LHS of a rule. %%

pfcEvalLHS((Test->Body),Support) :- !, (db_call(nonPfC,Test) -> pfcEvalLHS(Body,Support)), !.

pfcEvalLHS(rhs(X),Support) :- !, mpred_eval_rhs(X,Support), !.

pfcEvalLHS(X,Support) :- mpred_db_type(X,trigger), !, ainTrigger(X,Support), !.

%pfcEvalLHS(snip(X),Support) :- % snip(Support), % pfcEvalLHS(X,Support).

pfcEvalLHS(X,_) :- mpred_warn("Unrecognized item found in trigger body, namely ~w.",[X]).

%% %% eval something on the RHS of a rule. %%

mpred_eval_rhs([],_) :- !. mpred_eval_rhs([Head|Tail],Support) :- mpred_eval_rhs1(Head,Support), mpred_eval_rhs(Tail,Support).

mpred_eval_rhs1({Action},Support) :- % evaluable Prolog code. !, pfcEvalAction(Action,Support).

mpred_eval_rhs1(P,_Support) :- % predicate to remove. pfcNegatedLiteral(P), !, pfcRem(P).

mpred_eval_rhs1([X|Xrest],Support) :- % embedded sublist. !, mpred_eval_rhs([X|Xrest],Support).

mpred_eval_rhs1(Assertion,Support) :- % an assertion to be added. pfcPost1(Assertion,Support).

mpred_eval_rhs1(X,_) :- mpred_warn("Malformed rhs of a rule: ~w",[X]).

%% %% evaluate an action found on the rhs of a rule. %%

pfcEvalAction(Action,Support) :- db_call(nonPfC,Action), (pfcUndoable(Action) -> ainActionTrace(Action,Support) ; true).

%% %% %%

mpred_trigger_the_trigger(Trigger,Body,_Support) :- trigger_trigger1(Trigger,Body). mpred_trigger_the_trigger(_,_,_).

%trigger_trigger1(presently(Trigger),Body) :- % !, % copy_term(Trigger,TriggerCopy), % pfcBC(Trigger), % pfcEvalLHS(Body,(presently(Trigger),pt(presently(TriggerCopy),Body))), % fail.

trigger_trigger1(Trigger,Body) :- copy_term(Trigger,TriggerCopy), pfcBC(Trigger), pfcEvalLHS(Body,(Trigger,pt(TriggerCopy,Body))), fail.

%% %% pfcBC(F) is true iff F is a fact available for forward chaining. %% Note that this has the side effect of catching unsupported facts and %% assigning them support from God. %%

pfcBC(P) :- % trigger any bc rules. bt(P,Trigger), pfcGetSupport(bt(P,Trigger),S), pfcEvalLHS(Trigger,S), fail.

pfcBC(F) :- %% this is probably not advisable due to extreme inefficiency. var(F) -> pfcFact(F) ; otherwise -> db_clause(F,Condition),db_call(nonPfC,Condition).

%%pfcBC(F) :- %% %% we really need to check for system predicates as well. %% % current_predicate(_,F) -> db_call(nonPfC,F). %% db_clause(F,Condition),db_call(nonPfC,Condition).

% an action is pfcUndoable if there exists a method for undoing it. pfcUndoable(A) :- pfcUndoMethod(A,_).

%% %% %% defining fc rules %%

%% mpred_nf(+In,-Out) maps the LHR of a pfc rule In to one normal form %% Out. It also does certain optimizations. Backtracking into this %% predicate will produce additional clauses.

mpred_nf(LHS,List) :- mpred_nf1(LHS,List2), mpred_nf_negations(List2,List).

%% mpred_nf1(+In,-Out) maps the LHR of a pfc rule In to one normal form %% Out. Backtracking into this predicate will produce additional clauses.

% handle a variable.

mpred_nf1(P,[P]) :- var(P), !.

% these next two rules are here for upward compatibility and will go % away eventually when the P/Condition form is no longer used anywhere.

mpred_nf1(P/Cond,[( \+P)/Cond]) :- pfcNegatedLiteral(P), !.

mpred_nf1(P/Cond,[P/Cond]) :- mpred_literal(P), !.

%% handle a negated form

mpred_nf1(NegTerm,NF) :- mpred_negation(NegTerm,Term), !, mpred_nf1_negation(Term,NF).

%% disjunction.

mpred_nf1((P;Q),NF) :- !, (mpred_nf1(P,NF) ; mpred_nf1(Q,NF)).

%% conjunction.

mpred_nf1((P,Q),NF) :- !, mpred_nf1(P,NF1), mpred_nf1(Q,NF2), append(NF1,NF2,NF).

%% handle a random atom.

mpred_nf1(P,[P]) :- mpred_literal(P), !.

%%% shouln't we have something to catch the rest as errors? mpred_nf1(Term,[Term]) :- mpred_warn("mpred_nf doesn't know how to normalize ~w",[Term]).

%% mpred_nf1_negation(P,NF) is true if NF is the normal form of \+P. mpred_nf1_negation((P/Cond),[( \+(P))/Cond]) :- !.

mpred_nf1_negation((P;Q),NF) :- !, mpred_nf1_negation(P,NFp), mpred_nf1_negation(Q,NFq), append(NFp,NFq,NF).

mpred_nf1_negation((P,Q),NF) :- % this code is not correct! twf. !, mpred_nf1_negation(P,NF) ; (mpred_nf1(P,Pnf), mpred_nf1_negation(Q,Qnf), append(Pnf,Qnf,NF)).

mpred_nf1_negation(P,[\+P]).

%% mpred_nf_negations(List2,List) sweeps through List2 to produce List, %% changing ~{...} to {\+...} %%% ? is this still needed? twf 3/16/90

mpred_nf_negations(X,X) :- !. % I think not! twf 3/27/90

mpred_nf_negations([],[]).

mpred_nf_negations([H1|T1],[H2|T2]) :- mpred_nf_negation(H1,H2), mpred_nf_negations(T1,T2).

mpred_nf_negation(Form,{\+ X}) :- nonvar(Form), Form=(~({X})), !. mpred_nf_negation(X,X).

%% %% pfcBuildRhs(+Conjunction,-Rhs) %%

pfcBuildRhs(X,[X]) :- var(X), !.

pfcBuildRhs((A,B),[A2|Rest]) :- !, pfcCompileRhsTerm(A,A2), pfcBuildRhs(B,Rest).

pfcBuildRhs(X,[X2]) :- pfcCompileRhsTerm(X,X2).

pfcCompileRhsTerm((P/C),((P:-C))) :- !.

pfcCompileRhsTerm(P,P).

%% mpred_negation(N,P) is true if N is a negated term and P is the term %% with the negation operator stripped.

mpred_negation((~P),P). mpred_negation((-P),P). mpred_negation(( \+(P)),P).

pfcNegatedLiteral(P) :- mpred_negation(P,Q), pfcPositiveAtom(Q).

mpred_literal(X) :- pfcNegatedLiteral(X). mpred_literal(X) :- pfcPositiveAtom(X).

pfcPositiveAtom(X) :- functor(X,F,_), \+ pfcConnective(F).

pfcConnective(';'). pfcConnective(','). pfcConnective('/'). pfcConnective('|'). pfcConnective(('==>')). pfcConnective(('<-')). pfcConnective('<==>').

pfcConnective('-'). pfcConnective('~'). pfcConnective(('\\+')).

pfcProcessRule(Lhs,Rhs,ParentRule) :- copy_term(ParentRule,ParentRuleCopy), pfcBuildRhs(Rhs,Rhs2), foreach(mpred_nf(Lhs,Lhs2), pfcBuild1Rule(Lhs2,rhs(Rhs2),(ParentRuleCopy,pcfUser))).

pfcBuild1Rule(Lhs,Rhs,Support) :- pfcBuildTrigger(Lhs,Rhs,Trigger), pfcEvalLHS(Trigger,Support).

pfcBuildTrigger([],Consequent,Consequent).

pfcBuildTrigger([V|Triggers],Consequent,pt(V,X)) :- var(V), !, pfcBuildTrigger(Triggers,Consequent,X).

pfcBuildTrigger([(T1/Test)|Triggers],Consequent,nt(T2,Test2,X)) :- mpred_negation(T1,T2), !, pfcBuildNtTest(T2,Test,Test2), pfcBuildTrigger(Triggers,Consequent,X).

pfcBuildTrigger([(T1)|Triggers],Consequent,nt(T2,Test,X)) :- mpred_negation(T1,T2), !, pfcBuildNtTest(T2,true,Test), pfcBuildTrigger(Triggers,Consequent,X).

pfcBuildTrigger([{Test}|Triggers],Consequent,(Test->X)) :- !, pfcBuildTrigger(Triggers,Consequent,X).

pfcBuildTrigger([T/Test|Triggers],Consequent,pt(T,X)) :- !, pfcBuildTest(Test,Test2), pfcBuildTrigger([{Test2}|Triggers],Consequent,X).

%pfcBuildTrigger([snip|Triggers],Consequent,snip(X)) :- % !, % pfcBuildTrigger(Triggers,Consequent,X).

pfcBuildTrigger([T|Triggers],Consequent,pt(T,X)) :- !, pfcBuildTrigger(Triggers,Consequent,X).

%% %% pfcBuildNtTest(+,+,-). %% %% builds the test used in a negative trigger (nt/3). This test is a %% conjunction of the check than no matching facts are in the db and any %% additional test specified in the rule attached to this ~ term. %%

pfcBuildNtTest(T,Testin,Testout) :- pfcBuildTest(Testin,Testmid), pfcConjoin((pfcBC(T)),Testmid,Testout).

% this just strips away any currly brackets.

pfcBuildTest({Test},Test) :- !. pfcBuildTest(Test,Test).

%%

%% simple typeing for pfc objects

mpred_db_type(('==>'(_,_)),Type) :- !, Type=rule. mpred_db_type(('<==>'(_,_)),Type) :- !, Type=rule. mpred_db_type(('<-'(_,_)),Type) :- !, Type=rule. mpred_db_type(pfcPT3(_,_,_),Type) :- !, Type=trigger. mpred_db_type(pt(_,_),Type) :- !, Type=trigger. mpred_db_type(nt(_,_,_),Type) :- !, Type=trigger. mpred_db_type(bt(_,_),Type) :- !, Type=trigger. mpred_db_type(mpred_action(_),Type) :- !, Type=action. mpred_db_type((('::::'(_,X))),Type) :- !, mpred_db_type(X,Type). mpred_db_type(_,fact) :- %% if it's not one of the above, it must be a fact! !.

pfcAssert(P,Support) :- (mpred_clause(P) ; db_assert(P)), !, ainSupport(P,Support).

pfcAsserta(P,Support) :- (mpred_clause(P) ; db_asserta(P)), !, ainSupport(P,Support).

pfcAssertz(P,Support) :- (mpred_clause(P) ; db_assertz(P)), !, ainSupport(P,Support).

mpred_clause((Head :- Body)) :- !, copy_term(Head,Head_copy), copy_term(Body,Body_copy), db_clause(Head,Body), variant(Head,Head_copy), variant(Body,Body_copy).

mpred_clause(Head) :- % find a unit db_clause identical to Head by finding one which unifies, % and then checking to see if it is identical copy_term(Head,Head_copy), db_clause(Head_copy,true), variant(Head,Head_copy).

foreach(Binder,Body) :- Binder,pfcdo(Body),fail. foreach(_,_).

% pfcdo(X) executes X once and always succeeds. pfcdo(X) :- X,!. pfcdo(_).

%% pfcUnion(L1,L2,L3) - true if set L3 is the result of appending sets %% L1 and L2 where sets are represented as simple lists.

pfcUnion([],L,L). pfcUnion([Head|Tail],L,Tail2) :- memberchk(Head,L), !, pfcUnion(Tail,L,Tail2). pfcUnion([Head|Tail],L,[Head|Tail2]) :- pfcUnion(Tail,L,Tail2).

%% pfcConjoin(+Conjunct1,+Conjunct2,?Conjunction). %% arg3 is a simplified expression representing the conjunction of %% args 1 and 2.

pfcConjoin(true,X,X) :- !. pfcConjoin(X,true,X) :- !. pfcConjoin(C1,C2,(C1,C2)).

% pfcFile('pfcsupport'). % support maintenance

%% %% %% predicates for manipulating support relationships %%

%:-dynamic(support2/3). :- dynamic(spft/3). :- dynamic(support3/3).

%% ainSupport(+Fact,+Support)

ainSupport(P,(Fact,Trigger)) :- db_assert(spft(P,Fact,Trigger)), %db_assert(support2(Fact,Trigger,P)), db_assert(support3(Trigger,P,Fact)).

pfcGetSupport(P,(Fact,Trigger)) :- nonvar(P) -> spft(P,Fact,Trigger) % ; nonvar(Fact) -> support2(Fact,Trigger,P) ; nonvar(Trigger) -> support3(Trigger,P,Fact) ; otherwise -> spft(P,Fact,Trigger).

% There are three of these to try to efficiently handle the cases % where some of the arguments are not bound but at least one is.

pfcRemSupport(P,(Fact,Trigger)) :- nonvar(P), !, pfcRetractOrWarn(spft(P,Fact,Trigger)), %pfcRetractOrWarn(support2(Fact,Trigger,P)), pfcRetractOrWarn(support3(Trigger,P,Fact)).

pfcRemSupport(P,(Fact,Trigger)) :- nonvar(Fact), !, %pfcRetractOrWarn(support2(Fact,Trigger,P)), pfcRetractOrWarn(spft(P,Fact,Trigger)), pfcRetractOrWarn(support3(Trigger,P,Fact)).

pfcRemSupport(P,(Fact,Trigger)) :- pfcRetractOrWarn(support3(Trigger,P,Fact)), pfcRetractOrWarn(spft(P,Fact,Trigger)). % pfcRetractOrWarn(support2(Fact,Trigger,P)).

mpred_collect_supports(Tripples) :- bagof(Tripple, mpred_support_relation(Tripple), Tripples), !. mpred_collect_supports([]).

mpred_support_relation((P,F,T)) :- spft(P,F,T).

mpred_make_supports((P,S1,S2)) :- ainSupport(P,(S1,S2),_), (ainSome(P); true), !.

%% pfcTriggerKey(+Trigger,-Key) %% %% Arg1 is a trigger. Key is the best term to index it on.

pfcTriggerKey(pt(Key,_),Key). pfcTriggerKey(pfcPT3(Key,_,_),Key). pfcTriggerKey(nt(Key,_,_),Key). pfcTriggerKey(Key,Key).

%%^L %% Get a key from the trigger that will be used as the first argument of %% the trigger pfcBase1 db_clause that stores the trigger. %%

mpred_trigger_key(X,X) :- var(X), !. mpred_trigger_key(chart(word(W),_L),W) :- !. mpred_trigger_key(chart(stem([Char1|_Rest]),_L),Char1) :- !. mpred_trigger_key(chart(Concept,_L),Concept) :- !. mpred_trigger_key(X,X).

% pfcFile('t_l'). % predicates to manipulate database.

% File : t_l.pl % Author : Tim Finin, finin@prc.unisys.com % Author : Dave Matuszek, dave@prc.unisys.com % Author : Dan Corpron % Updated: 10/11/87, ... % Purpose: predicates to manipulate a pfc database (e.g. save, %% restore, reset, etc.0

% pfcDatabaseTerm(P/A) is true iff P/A is something that pfc adds to % the database and should not be present in an empty pfc database

pfcDatabaseTerm(spft/3). %pfcDatabaseTerm(support2/3). pfcDatabaseTerm(support3/3). pfcDatabaseTerm(pt/2). pfcDatabaseTerm(bt/2). pfcDatabaseTerm(nt/3). pfcDatabaseTerm('==>'/2). pfcDatabaseTerm('<==>'/2). pfcDatabaseTerm('<-'/2). pfcDatabaseTerm(mpred_queue/1).

% removes all forward chaining rules and pfcJustification_L from db.

pfcReset :- db_clause(spft(P,F,Trigger),true), pfcRetractOrWarn(P), pfcRetractOrWarn(spft(P,F,Trigger)), % pfcRetractOrWarn(support2(F,Trigger,P)), pfcRetractOrWarn(support3(Trigger,P,F)), fail. pfcReset :- pfcDatabaseItem(T), pfcError("Pfc database not empty after pfcReset, e.g., ~p.~n",[T]). pfcReset.

% true if there is some pfc crud still in the database. pfcDatabaseItem(Term) :- pfcDatabaseTerm(P/A), functor(Term,P,A), db_clause(Term,_).

pfcRetractOrWarn(X) :- db_retract(X), !. pfcRetractOrWarn(X) :- mpred_warn("Couldn't db_retract ~p.",[X]).

% pfcFile('pfcdebug'). % debugging aids (e.g. tracing).

% File : pfcdebug.pl % Author : Tim Finin, finin@prc.unisys.com % Author : Dave Matuszek, dave@prc.unisys.com % Updated: % Purpose: provides predicates for examining the database and debugginh % for Pfc.

:- dynamic mpred_settings/2. :- dynamic mpred_settings/3.

:- mpred_default(mpred_settings(warnings,_), mpred_settings(warnings,true)).

%% predicates to examine the state of pfc

mpred_queue :- listing(mpred_queue/1).

pfcPrintDB :- pfcPrintFacts, pfcPrintRules, pfcPrintTriggers, pfcPrintSupports, mpred_queue,!.

pfcPrintDB :- must_det_l([ pfcPrintFacts, pfcPrintRules, pfcPrintTriggers, pfcPrintSupports, mpred_queue]).

%% pfcPrintFacts ..

pfcPrintFacts :- pfcPrintFacts(_,true).

pfcPrintFacts(Pattern) :- pfcPrintFacts(Pattern,true).

pfcPrintFacts(P,C) :- pfcFacts(P,C,L), pfcClassifyFacts(L,User,Pfc,_Rule), format("~n~nUser added facts:",[]), pfcPrintitems(User), format("~n~nPfc added facts:",[]), pfcPrintitems(Pfc).

%% printitems clobbers it's arguments - beware!

pfcPrintitems([]). pfcPrintitems([H|T]) :- numbervars(H,0,_), format("~n ~w",[H]), pfcPrintitems(T).

pfcClassifyFacts([],[],[],[]).

pfcClassifyFacts([H|T],User,Pfc,[H|Rule]) :- mpred_db_type(H,rule), !, pfcClassifyFacts(T,User,Pfc,Rule).

pfcClassifyFacts([H|T],[H|User],Pfc,Rule) :- pfcGetSupport(H,(pcfUser,pcfUser)), !, pfcClassifyFacts(T,User,Pfc,Rule).

pfcClassifyFacts([H|T],User,[H|Pfc],Rule) :- pfcClassifyFacts(T,User,Pfc,Rule).

pfcPrintRules :- bagof((P==>Q),db_clause((P==>Q),true),R1), pfcPrintitems(R1), bagof((P<==>Q),db_clause((P<==>Q),true),R2), pfcPrintitems(R2), bagof((P<-Q),db_clause((P<-Q),true),R3), pfcPrintitems(R3).

pfcPrintTriggers :- format("Positive triggers...~n",[]), bagof(pt(T,B),pfcGetTrigger(pt(T,B)),Pts), pfcPrintitems(Pts), format("Negative triggers...~n",[]), bagof(nt(A,B,C),pfcGetTrigger(nt(A,B,C)),Nts), pfcPrintitems(Nts), format("Goal triggers...~n",[]), bagof(bt(A,B),pfcGetTrigger(bt(A,B)),Bts), pfcPrintitems(Bts).

pfcPrintSupports :- % temporary hack. setof((S > P), pfcGetSupport(P,S),L), pfcPrintitems(L).

%% pfcFact(P) is true if fact P was asserted into the database via add.

pfcFact(P) :- pfcFact(P,true).

%% pfcFact(P,C) is true if fact P was asserted into the database via %% add and contdition C is satisfied. For example, we might do: %% %% pfcFact(X,mpred_user_fact(X)) %%

pfcFact(P,C) :- pfcGetSupport(P,_), mpred_db_type(P,fact), db_call(nonPfC,C).

%% pfcFacts(-ListofPfcFacts) returns a list of facts added.

pfcFacts(L) :- pfcFacts(_,true,L).

pfcFacts(P,L) :- pfcFacts(P,true,L).

%% pfcFacts(Pattern,Condition,-ListofPfcFacts) returns a list of facts added.

pfcFacts(P,C,L) :- setof(P,pfcFact(P,C),L).

brake(X) :- X, break.

%% %% %% predicates providing a simple tracing facility %%

pfcTraceAdd(P) :- % this is here for upward compat. - should go away eventually. pfcTraceAdd(P,(o,o)).

pfcTraceAdd(pt(_,_),_) :- % hack for now - never trace triggers. !. pfcTraceAdd(nt(_,_),_) :- % hack for now - never trace triggers. !.

pfcTraceAdd(P,S) :- pfcTraceAddPrint(P,S), pfcTraceBreak(P,S).
pfcTraceAddPrint(P,S) :- mpred_settings(traced,P), !, copy_term(P,Pcopy), numbervars(Pcopy,0,_), (S=(pcfUser,pcfUser) -> format("~nAdding (u) ~w",[Pcopy]) ; format("~nAdding (g) ~w",[Pcopy])).

pfcTraceAddPrint(_,_).

pfcTraceBreak(P,_S) :- mpred_settings(spied,P,add) -> (copy_term(P,Pcopy), numbervars(Pcopy,0,_), format("~nBreaking on ain(~w)",[Pcopy]), break) ; true.

pfcTraceRem(pt(_,_)) :- % hack for now - never trace triggers. !. pfcTraceRem(nt(_,_)) :- % hack for now - never trace triggers. !.

pfcTraceRem(P) :- (mpred_settings(traced,P) -> format('~nRemoving ~w.',[P]) ; true), (mpred_settings(spied,P,pfcRem) -> (format("~nBreaking on pfcRem(~w)",[P]), break) ; true).

mpred_trace :- mpred_trace(_).

mpred_trace(Form) :- db_assert(mpred_settings(traced,Form)).

mpred_trace(Form,Condition) :- db_assert((mpred_settings(traced,Form) :- Condition)).

mpred_spy(Form) :- mpred_spy(Form,[add,pfcRem],true).

mpred_spy(Form,Modes) :- mpred_spy(Form,Modes,true).

mpred_spy(Form,[add,pfcRem],Condition) :- !, mpred_spy1(Form,add,Condition), mpred_spy1(Form,pfcRem,Condition).

mpred_spy(Form,Mode,Condition) :- mpred_spy1(Form,Mode,Condition).

mpred_spy1(Form,Mode,Condition) :- db_assert((mpred_settings(spied,Form,Mode) :- Condition)).

pfcNospy :- pfcNospy(_,_,_).

pfcNospy(Form) :- pfcNospy(Form,_,_).

pfcNospy(Form,Mode,Condition) :- db_clause(mpred_settings(spied,Form,Mode), Condition, Ref), erase(Ref), fail. pfcNospy(_,_,_).

pfcNoTrace :- pfcUntrace. pfcUntrace :- pfcUntrace(_). pfcUntrace(Form) :- db_retractall(mpred_settings(traced,Form)).

% needed: pfcTraceRule(Name) ...

% if the correct flag is set, trace exection of Pfc mpred_trace_msg(Msg,Args) :- mpred_settings(trace_exec,true), !, format(user_output, Msg, Args). mpred_trace_msg(_Msg,_Args).

pfcWatch :- db_assert(mpred_settings(trace_exec,true)).

pfcNoWatch :- db_retractall(mpred_settings(trace_exec,true)).

pfcError(Msg) :- pfcError(Msg,[]).

pfcError(Msg,Args) :- format("~nERROR/Pfc: ",[]), format(Msg,Args).

%% %% These control whether or not warnings are printed at all. %% mpred_warn. %% nompred_warn. %% %% These print a warning message if the flag mpred_warnings is set. %% mpred_warn(+Message) %% mpred_warn(+Message,+ListOfArguments) %%

mpred_warn :- db_retractall(mpred_settings(warnings,_)), db_assert(mpred_settings(warnings,true)).

nompred_warn :- db_retractall(mpred_settings(warnings,_)), db_assert(mpred_settings(warnings,false)).

mpred_warn(Msg) :- mpred_warn(Msg,[]).

mpred_warn(Msg,Args) :- mpred_settings(warnings,true), !, format("~nWARNING/Pfc: ",[]), format(Msg,Args). mpred_warn(_,_).

%% %% mpred_warnings/0 sets flag to cause pfc warning messages to print. %% pfcNoWarnings/0 sets flag to cause pfc warning messages not to print. %%

mpred_warnings :- db_retractall(mpred_settings(warnings,_)), db_assert(mpred_settings(warnings,true)).

pfcNoWarnings :- db_retractall(mpred_settings(warnings,_)).

% pfcFile('pfcjust'). % predicates to manipulate pfcJustification_L.

% File : pfcjust.pl % Author : Tim Finin, finin@prc.unisys.com % Author : Dave Matuszek, dave@prc.unisys.com % Updated: % Purpose: predicates for accessing Pfc Justifications. % Status: more or less working. % Bugs:

%% *** predicates for exploring supports of a fact *****

:- use_module(library(lists)).

pfcJustificationDB(F,J) :- justSupports(F,J).

pfcJustification_L(F,Js) :- bagof(J,pfcJustificationDB(F,J),Js).

% justSupports(F,J):- support2(F,J).

%% pfcBase1(P,L) - is true iff L is a list of "pfcBase1" facts which, taken %% together, allows us to deduce P. A pfcBase1 fact is an pfcAxiom (a fact %% added by the pcfUser or a raw Prolog fact (i.e. one w/o any support)) %% or an pfcAssumptionBase.

pfcBase1(F,[F]) :- (pfcAxiom(F) ; pfcAssumptionBase(F)),!.

pfcBase1(F,L) :- % i.e. (reduce 'append (map 'pfcBase1 (pfcJustificationDB f))) pfcJustificationDB(F,Js), pfcBases(Js,L).

%% pfcBases(L1,L2) is true if list L2 represents the union of all of the %% facts on which some conclusion in list L1 is based.

pfcBases([],[]). pfcBases([X|Rest],L) :- pfcBase1(X,Bx), pfcBases(Rest,Br), pfcUnion(Bx,Br,L).

pfcAxiom(F) :- pfcGetSupport(F,(pcfUser,pcfUser)); pfcGetSupport(F,(pfcGod,pfcGod)).

%% an pfcAssumptionBase is a failed goal, i.e. were assuming that our failure to %% prove P is a proof of not(P)

pfcAssumptionBase(P) :- mpred_negation(P,_).

%% pfcAssumptionsSet(X,As) if As is a set of pfcAssumptionsSet which underly X.

pfcAssumptionsSet(X,[X]) :- pfcAssumptionBase(X). pfcAssumptionsSet(X,[]) :- pfcAxiom(X). pfcAssumptionsSet(X,L) :- pfcJustificationDB(X,Js), pfcAssumption1(Js,L).

pfcAssumption1([],[]). pfcAssumption1([X|Rest],L) :- pfcAssumptionsSet(X,Bx), pfcAssumption1(Rest,Br), pfcUnion(Bx,Br,L).

%% pfcProofTree(P,T) the proof tree for P is T where a proof tree is %% of the form %% %% [P , J1, J2, ;;; Jn] each Ji is an independent P justifier. %% ^ and has the form of %% [J11, J12,... J1n] a list of proof trees.

% pfcChild(P,Q) is true iff P is an immediate justifier for Q. % mode: pfcChild(+,?)

pfcChild(P,Q) :- pfcGetSupport(Q,(P,_)).

pfcChild(P,Q) :- pfcGetSupport(Q,(_,Trig)), mpred_db_type(Trig,trigger), pfcChild(P,Trig).

pfcChildren(P,L) :- bagof(C,pfcChild(P,C),L).

% pfcDescendant(P,Q) is true iff P is a justifier for Q.

pfcDescendant(P,Q) :- pfcDescendant1(P,Q,[]).

pfcDescendant1(P,Q,Seen) :- pfcChild(X,Q), ( \+ member(X,Seen)), (P=X ; pfcDescendant1(P,X,[X|Seen])).

pfcDescendants(P,L) :- bagof(Q,pfcDescendant1(P,Q,[]),L).

% pfcFile('pfcwhy'). % interactive exploration of pfcJustification_L.

% File : pfcwhy.pl % Author : Tim Finin, finin@prc.unisys.com % Updated: % Purpose: predicates for interactively exploring Pfc pfcJustification_L.

% ***** predicates for brousing pfcJustification_L *****

:- use_module(library(lists)).

pfcWhy :- pfcWhyMemory1(P,_), pfcWhy(P).

pfcWhy(N) :- number(N), !, pfcWhyMemory1(P,Js), pfcWhyCommand(N,P,Js).

pfcWhy(P) :- pfcJustification_L(P,Js), db_retractall(pfcWhyMemory1(_,_)), db_assert(pfcWhyMemory1(P,Js)), pfcWhyBrouse(P,Js).

pfcWhy1(P) :- pfcJustification_L(P,Js), pfcWhyBrouse(P,Js).

pfcWhyBrouse(P,Js) :- mpred_showJustifications(P,Js), pfcAskUser(' >> ',Answer), pfcWhyCommand(Answer,P,Js).

pfcWhyCommand(q,_,_) :- !. pfcWhyCommand(h,_,_) :- !, format("~n Justification Brouser Commands: q quit. N focus on Nth pfcJustificationDB. N.M brouse step M of the Nth pfcJustificationDB u up a level ",[]).

pfcWhyCommand(N,_P,Js) :- float(N), !, mpred_selectJustificationNode(Js,N,Node), pfcWhy1(Node).

pfcWhyCommand(u,_,_) :- % u=up !.

pfcCommand(N,_,_) :- integer(N), !, format("~n~w is a yet unimplemented command.",[N]), fail.

pfcCommand(X,_,_) :- format("~n~w is an unrecognized command, enter h. for help.",[X]), fail.

mpred_showJustifications(P,Js) :- format("~nJustifications for ~w:",[P]), mpred_showJustification1(Js,1).

mpred_showJustification1([],_).

mpred_showJustification1([J|Js],N) :- % show one pfcJustificationDB and recurse. nl, mpred_showJustifications2(J,N,1), N2 is N+1, mpred_showJustification1(Js,N2).

mpred_showJustifications2([],_,_).

mpred_showJustifications2([C|Rest],JustNo,StepNo) :- copy_term(C,CCopy), numbervars(CCopy,0,_), format("~n ~w.~w ~w",[JustNo,StepNo,CCopy]), StepNext is 1+StepNo, mpred_showJustifications2(Rest,JustNo,StepNext).

pfcAskUser(Msg,Ans) :- format("~n~w",[Msg]), read(Ans).

mpred_selectJustificationNode(Js,Index,Step) :- JustNo is integer(Index), nth(JustNo,Js,Justification), StepNo is 1+ integer(Index*10 - JustNo*10), nth(StepNo,Justification,Step).

:- mpred_trace.

:- ain([(faz(X), ~baz(Y)/{X=:=Y} ==> fazbaz(X)), (fazbaz(X), go ==> found(X)), (found(X), {X>=100} ==> big(X)), (found(X), {X>=10,X<100} ==> medium(X)), (found(X), {X<10} ==> little(X)), faz(1), goAhead, baz(2), baz(1) ]).

:- include(mpred_tests).

:- run_tests.