PrologJ Support for Fuzzy Logic

Overview

Standard Prolog is based on crisp logic, in which a proposition is either absolutely true or is not known to be true and is therefore assumed to be absolutely false. PrologJ offers the option of performing computations using the rules of fuzzy logic in which a proposition can be partially true, not just absolutely true or false.

A fuzzy proposition that is regarded as partially true has associated with it a "truth value", which is a real number in the range 0.0 < truth-value < 1.0. Sometimes it is useful to think of a proposition that is regarded as being absolutely true as having a truth value of 1.0.

Fuzzy logic can be used to model inexact concepts that are inherently fuzzy - e.g. "Joe is a tall person." - a statement which would probably be regarded as absolutely true if Joe is a 6'8" basketball player, or absolutely false if Joe is a 3'6" Hobbit. But what if Joe is exactly six feet tall? Is Joe a tall person? Crisp logic has no clean way of modelling propositions that are "sort of" true. Fuzzy logic can also be used to model reasoning under uncertainty - e.g. "The witness is 90% sure that the robber was male".

PrologJ provides optional support for using fuzzy logic. This support is implemented in such a way as to have no effect on computations unless fuzzy computation is explicitly specified by the user. Moreover, the fuzzy logic extension can be either enabled or disabled at system startup by making the various built-in predicates that support it be either available or unavailable. (Support for fuzzy logic is enabled by default.)

When the use of fuzzy logic is enabled, a "top-level" PrologJ computation can be explicitly specified to be fuzzy. A computation that is not specified to be fuzzy is crisp by default. A fuzzy computation can either fail, or it can succeed with a truth value lying in (0 .. 1.0], with 1.0 corresponding to absolute truth. Of course, a crisp computation can only fail or succeed absolutely.

Likewise, a PrologJ clause (appearing in a source file or asserted by asserta/1 or assertz/1) can be explicitly specified to be fuzzy. A clause that is not specified to be fuzzy is crisp by default. When a clause is crisp, its body is evaluated as a crisp computation; when it is fuzzy, its body is evaluated as a fuzzy computation.

Fuzzy Clauses

Clauses that are stored in the PrologJ database are either crisp or fuzzy. A clause that is asserted in the ordinary way (either as a fact, or a rule, or a grammar rule) is crisp. To assert a fuzzy clause, its head must be immediately followed by a colon and a number in the range (0.0 .. 1.0] - i.e. the number must be strictly greater than 0.0, and less than or equal to 1.0. This number is called the "inherent truth value" of the clause - it represents the truth value of a fact or the truth value that would be assigned to a computation using a rule if the body succeeds absolutely. The following examples illustrate the declaration of fuzzy facts, fuzzy rules, and fuzzy grammar rules.

secure(linux) : 0.95.   % Linux is a very secure operating system
secure(X) : 0.3 :-      % Any form of windows is moderately secure
    atom_concat(windows, _, X).
verb : 0.7 -->          % "Flies" is generally a verb
	[ flies ].

When a fuzzy fact is used to attempt proving a goal, the truth value of the computatation is the inherent truth value of the fact. When a fuzzy clause is used to attempt proving a goal, its body is evaluated according to the rules of fuzzy logic, and if the body (partially) succeeds, then the truth value for the attempt to satisfy the goal is computed as (inherent truth value of clause) * (truth value of body). Example: Suppose we had the following rule in the database:

desirable(OS) : 0.8     % A secure operating system is generally desirable
	:- secure(OS).

If we now pose the following as a fuzzy query:

desirable('windows xp') : C.

We would get a truth value of (0.8) * (0.3) = 0.24.

Note that it is possible to specify a fuzzy clause with an inherent truth value of 1.0, which connotes absolute truth; this differs from a crisp clause in that an attempt to prove a goal using that clause will be done using the rules of fuzzy logic, and so the truth value of the computation will be the truth value of the body, which could be less than 1.0.

Fuzzy Computations

Any PrologJ computation is classified as either crisp or fuzzy. The result of a crisp computation is always either absolute success or failure. The result of a fuzzy computation may be absolute success, partial success, or failure. Which type of computation is performed may depend on the context in which the goal occurs.

Some goals are inherently crisp - e.g. most built-ins, all SQL predicates, or a predicate written in Prolog if a crisp clause is used to satisfy it. If an inherently crisp goal is called in a fuzzy context, then the goal can only succeed absolutely - which is taken as being success with a truth value of 1.0 - or fail. Partial success is not possible.

Likewise, some goals are inherently fuzzy - e.g. the built-ins fuzzy_best/1 and fuzzy_truth/1, or a predicate written in Prolog if a fuzzy clause is used to satisfy it. It is illegal to call an inherently fuzzy goal in a crisp context; doing so will result in the error permission_error(fuzzy_operation, Goal).

It is legal for a given predicate to be defined by a mixture of fuzzy and crisp clauses. Such a predicate should only be called in a fuzzy context, since an error would result if a fuzzy clause were used when the predicate is called in a crisp context.

The built-in predicate call_fuzzy/1 is added as part of the fuzzy extension to allow an inherently fuzzy goal to be called in a crisp context, with partial success treated as absolute success by a parent crisp computation. See the discussion of this built-in predicate below.

Note: the following built-ins call their subgoal in a fuzzy context, but are themselves inherently crisp - that is, in the end, the built-in succeeds absolutely or fails depending on whether or not its "list" argument unifies with the computed list.

Return Truth Value Variables

Any goal that appears in an initial context or a fuzzy context can be followed by a return truth value variable, which takes the form of a colon (:) followed by an uninstantiated variable. A fuzzy computation is performed, and if it succeeds (partially or absolutely) the variable is instantiated to the truth value resulting from the computation (1.0 meaning absolute success). (Note: it is an error for the variable to be instantiated before the computation, or to be instantiated by the computation itself.)

Example:

	?- tall(joe)  : V.          % Succeeds if the database contains a crisp or fuzzy
	                            % fact that joe is tall (or a rule that leads to this
	                            % conclusion);  if it succeeds, V is instantiated
	                            % to the truth value of the fact or rule if it is crisp,
	                            % or 1.0 if it is crisp.

Thresholds

The concept of a threshold is an important one in the PrologJ implementation of fuzzy logic. In a fuzzy computation, the threshold for a goal is the minimum truth value that will be considered to represent success for that goal. It is also possible to specify a threshold of 0.0 - which is taken to mean that a goal that succeeds with any degree of truth will be considered successful.

The default value for the threshold for a goal appearing in an initial context is 0.0. The default value for the threshold for a goal appearing in a fuzzy context is determined as follows:

A higher threshold for any fuzzy goal can be specified by following the goal with a double colon (::) and then a real number in the range [0.0 .. 1.0). (If it is desired to specify a variable to be unified with the truth value of the computation, then the variable comes first.) The effective threshold is the maximum of the default threshold, determined as discussed above, and the value specified. This mechanism can therefore only be used to specify a threshold at least as high as the default; it cannot be used to specify a lower value. It is also often used to specify the threshold for an initial goal (since the default is 0.0 in this case).

Examples:

	?- tall(Person) : V.        % Find all Persons such that tall(Person)
	                            % succeeds with any value - however small - in
	                            % each case unify the actual truth value with V.
	                            
	?- tall(Person) :: 0.5.     % Find all the Persons such that tall(Person) 
	                            % succeeds with truth value at least 0.5.
                
	?- tall(Person) : V :: 0.5. % Find all the Persons such that tall(Person)
	                            % succeeds with truth value at least 0.5; in
	                            % each case unify the actual truth value with V. 

PrologJ uses the threshold to avoid the potential for combinatorial explosion when dealing with alternate ways of satisfying a goal. In fuzzy logic, the truth value of "A or B" is defined as maximum(truth value of A, truth value of B). This implies that - unless A succeeds absolutely (with the maximum possible truth value - 1.0) both subgoals need to be tried.

In Prolog, the various clauses for a predicate are considered to be connected by "or". Thus, strict adherence to fuzzy logic would require that, when attempting a goal for which there are multiple clauses, each clause has to be tried in order to find the one with the maximum degree of success (unless one succeeds totally) - leading quickly to the possibility of combinatorial explosion. Moreover, Prolog programs typically assume that only the first clause that succeeds in satisfying a goal is tried - at least until the goal is redone during backtracking, and cut (!) can be used to prevent trying alternatives if a goal succeeds.

To deal with these problem, PrologJ handles the evaluation of a predicate for which there are multiple fuzzy clauses as follows: each clause is tried, in turn, until one succeeds with truth value at least equal to the threshold. If the clause contains redoable subgoals, each way of proving the clause may be tried until one such solution is found. Cut (!) can be used to cut off alternatives if the truth value at the point the cut is executed is at least equal to the threshold, even though a later term may push the truth value below the threshold and force failure (in the same way that !, ..., fail can be used to force a crisp computation to fail.) As soon as any clause succeeds with truth value at least equal to the threshold, the goal is declared to be satisfied at once. Subsequent clauses may be tried during backtracking - but again, only until a clause that succeeds with truth value at least equal to the threshold is found.

Truth Values and Control Structures

When one of the control structure predicates listed earlier is called in a fuzzy context, its truth value is based on the truth value of its subgoal(s) according to the following rules.

Accessing and Retracting Fuzzy Clauses

Fuzzy clauses can be accessed or deleted in the same way as crisp clauses, using the built-in predicates clause/2, retract/1 and retractall/1. When these predicates are used in the standard way, the inherent truth value of the clause is ignored, as is any threshold if they are called in the context of a fuzzy computation. (That is, a fuzzy clause is handled in exactly the same way as a crisp clause by default.)

However, it is possible to take into account the inherent truth value of a fuzzy clause when one of these built-in predicate is used, by following the head of the clause with one of the following. (This only affects clause selection; it has no affect on the outcome of the overall goal, which is always crisp).

Note that, when entering one of these goals to the interpreter, the truth value and/or threshold specifier(s) appear inside the goal, not outside it. Example: to access clauses for a tall fact in such a way as to find out the inherent truth value of each, and to only consider clauses with inherent truth value at least 0.5, one would write:

	clause(tall(Person) : V :: 0.5, B).

not

	clause(tall(Person), B) : V :: 0.5.

(The latter would find all clauses, and would report 1.0 as the value of V in every case, since it is considering the truth of the proposition "there exists a clause ...")

When listing/1 or listing/2 lists a fuzzy clause, its inherent truth value is printed as part of the listing in the same way it would be specified when inputting the clause.

Special Built-in Predicates for Fuzzy Computations

Several built-in predicates are added to facilitate fuzzy computations. In the discussions that follow, the following sample database will be used:

	tall(joe) : 0.5.
	tall(ralph) : 0.3.
	tall(john) : 0.8.
	tall(george) : 0.4.

Fuzzy Sets

In conjunction with the set processing extension, PrologJ incorporates support for working with fuzzy sets. A fuzzy set is represented by a list, whose elements are of the form :/2, where the first argument is a set element and the second argument is a real number in the range (0.0 .. 1.0] representing its degree of membership in the set. (Note that 0.0 is not allowed - since such an element would be definitely not a part of the set, and therefore would not be listed. However, 1.0 is allowed - representing an element that is absolutely part of the set.) A fuzzy set may also include an element that is not of the form :/2, which is taken to represent an element with degree of membership 1.0 (and it is converted to a form that explicitly specifies this in the resultant set).

The standard set operations (set_difference/3, etc) should not be used with fuzzy sets, since they treat the truth value specifier as part of the set element. Instead, the following should be used. All of these allow the first and second arguments to be either a bag or a set; however, if the first argument is a bag it is first converted to a set in which each element's degree of membership is the largest degree of membership associated with that element in the bag. The result is always a fuzzy set, with each element having its degree of membership specified explicitly (even if 1.0).

Although these operations are intended for use with fuzzy sets, they can also be used with crisp sets. In this case, each member of a crisp set is considered to have degree of membership 1.0 in that set. The result is always a fuzzy set, with each element having its degree of membership specified explicitly (even if 1.0).

All of these predicates are considered crisp, in the sense that they succeed or fail solely on the basis of whether the set they compute unifies with the final argument. If they are called in a fuzzy context, the threshold of their context is ignored.

This documentation here describes the way these predicates differ from their crisp counterparts. This documentation should therefore be read in conjunction with the documentation for the built-in set-processing-extension predicates.

Copyright © 2005 - Russell C. Bjork. See the file See file COPYING in the root directory for copyright information.

Valid XHTML 1.0!