According to Wikipedia, "Well Founded Semantics is one definition of how we can make conclusions from a set of logical rules". Well Founded Semantics (WFS) defines a three valued logic representing true, false and something that is neither true or false. This latter value is often referred to as bottom, undefined or unknown. SWI-Prolog uses undefined/0.
Well Founded Semantics allows for reasoning about programs with contradictions or multiple answer sets. It allows for obtaining true/false results for literals that do not depend on the sub program that has no unambiguous solution, propagating the notion of undefined to literals that cannot be resolved otherwise and obtaining the residual program that expresses why an answer is not unambiguous.
The notion of Well Founded Semantics is only relevant if the program uses negation as implemented by tnot/1. The argument of tnot/1, as the name implies, must be a goal associated with a tabled predicate (see table/1). In a nutshell, resolving a goal that implies tnot/1 is implemented as follows:
Consider the following partial body term:
..., tnot(p), q.
tnot(p)
. If executing the continuation results in an answer
for some tabled predicate, record this answer as a
conditional answer, in this case with the condition
tnot(p)
.
tnot(g)
is true.
This conclusion is propagated by simplifying the conditions for all
answers that depend on tnot(g)
. This may result in a
definite false condition, in which case the answer is removed
or a definite true condition in which case the answer is made
unconditional. Both events can make other conditional answers definitely
true or false, etc.
The above process may complete without any remaining conditional answers, in which case we are back in the normal Prolog world. It is also possible that some answers remain conditional. The most obvious case is represented by undefined/0. The toplevel responds with undefined instead of true if an answer is conditional.
true
nor false
in
the well formed model. It is implemented as
:- table undefined/0. undefined :- tnot(undefined).
Solving a set of predicates under well formed semantics results in a residual program. This program contains clauses for all tabled predicates with condition answers where each clause head represents and answer and each clause body its condition. The condition is a disjunction of conjunctions where each literal is either a tabled goal or tnot/1 of a tabled goal. The remaining model has at least a cycle through a negative literal (tnot/1) and has no single solution in the stable model semantics, i.e., it either expresses a contradiction (as undefined/0, i.e., there is no stable model) or a multiple stable models as in the program below, where both {p} and {q} are stable models.
:- table p/0, q/0. p :- tnot(q). q :- tnot(p).
Note that it is possible that some literals have the same truth value in all stable models but are still undefined under the stable model semantics.
The residual program is an explanation of why an answer is undefined. SWI-Prolog offers the following predicates to access the residual program.
true
, Answer
is unconditional. Otherwise it is a conjunction of goals, each of which
is associated with a tabled predicate.tnot(Goal)
or a plain Goal. Each
Goal is associated with a tabled predicate. The program
always contains at least one cycle that involves tnot/1.
The toplevel supports two modes for reporting that it is undefined
whether the current answer is true. The mode is selected by the Prolog
flag
toplevel_list_wfs_residual_program.
If true
, the toplevel uses call_delays/2
and delays_residual_program/2
to find the conditional answers used and the residual program
associated with these answers. It then prints the residual program,
followed by the answer and the conditional answers. For undefined/0,
this results in the following output:
?- undefined. % WFS residual program undefined :- tnot(undefined). undefined.
If the toplevel_list_wfs_residual_program is false, any undefined answer is a conjunction with undefined/0. See the program and output below.
:- table p/0, q/0. p :- tnot(q). q :- tnot(p).
?- p. % WFS residual program p :- tnot(q). q :- tnot(p). p. ?- set_prolog_flag(toplevel_list_wfs_residual_program, false). true. ?- p. undefined.