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.