# Fuzzy Prolog

Author(s): Claudio Vaucheret, Sergio Guadarrama, Francisco Bueno.

Version: 1.10#6 (2004/8/7, 21:46:39 CEST)

Version of last change: 1.9#339 (2004/4/22, 7:49:9 CEST)

This package impements an extension of prolog to deal with uncertainty. We implement a fuzzy prolog that models interval-valued fuzzy logic. This approach is more general than other fuzzy prologs in two aspects:

1. Truth values are sub-intervals on [0,1]. In fact, it could be a finite union of sub-intervals, as we will see below. Having a unique truth value is a particular case modeled with a unitary interval.
2. Truth values are propagated through the rules by means of a set of aggregation operators. The definition of an aggregation operator is a generalization that subsumes conjunctive operators (triangular norms as min, prod, etc.), disjunctive operators (triangular co-norms as max, sum, etc.), average operators (averages as arithmetic average, cuasi-linear average, etc.) and hybrid operators (combinations of previous operators).

We add uncertainty using CLP(R) instead of implementing a new fuzzy resolution as other fuzzy prologs. In this way, we use the original inference mechanism of Prolog, and we use the constraints and its operations provided by CLP(R) to handle the concept of partial truth. We represent intervals as constrains over real numbers and aggregation operators as operations with constraints.

Each fuzzy predicate has an additional argument which represents its truth value. We use ":~" instead of ":-" to distinguish fuzzy clauses from prolog clauses. In fuzzy clauses, truth values are obtained via an aggregation operator. There is also some syntactic sugar for defining fuzzy predicates with certain membership functions, the fuzzy counterparts of crisp predicates, and the fuzzy negation of a fuzzy predicate.

## Usage and interface (`fuzzy`)

• Library usage: `:- use_package(fuzzy).` or `:- module(...,...,[fuzzy]).`
• Exports:
• Predicates: `:#/2`, `fuzzy_predicate/1`, `fuzzy/1`, `fnot/1`, `:~/2`, `=>/4`.
• Properties: `fuzzybody/1`.
• Regular Types: `faggregator/1`.
• New operators defined: `:~/2` [1200,xfx], `:~/1` [1200,xf], `:=/2` [1200,xfx], `:=/1` [1200,xf], `:#/2` [1200,xfx], `=>/1` [1175,fx], `fnot/1` [1150,fx], `aggr/1` [1150,fx], `##/2` [1120,xfy], `<#/2` [1120,xfy], `#>/2` [1120,xfy], `fuzzy/1` [1150,fx], `fuzzy_predicate/1` [1190,fx], `fuzzy_discrete/1` [1190,fx].
• New declarations defined: `aggr/1`.

## Documentation on new declarations (`fuzzy`)

DECLARATION: aggr/1:

Usage: :- `aggr(Name)`.

• Description: Declares `Name` an aggregator. Its binary definition has to be provided. For example:
```:- aggr myaggr.

myaggr(X,Y,Z):- Z .=. X*Y.
```
defines an aggregator identical to `prod`.
• The following properties hold at call time: `Name` is an atomic term (an atom or a number). (`basic_props:constant/1`)

## Documentation on exports (`fuzzy`)

PREDICATE: :#/2:

Usage: `:#(Name, Decl)`

• Description: Defines fuzzy predicate `Name` from the declaration `Decl`.
• The following properties hold upon exit: `Name` is a Name/Arity structure denoting a predicate name:
```predname(P/A) :-
atm(P),
nnegint(A).
```
(`basic_props:predname/1`) `Decl` is one of the following three:
```fuzzydecl(fuzzy_predicate(_1)).
fuzzydecl(fuzzy(_1)).
fuzzydecl(fnot(_1)).
```
(`user(... /fuzzy_doc):fuzzydecl/1`)

PREDICATE: fuzzy_predicate/1:

Usage: `fuzzy_predicate(Domain)`

• Description: Defines a fuzzy predicate with piecewise linear continuous membership function. This is given by `Domain`, which is a list of pairs of domain-truth values, in increasing order and exhaustive. For example:
```young :# fuzzy_predicate([(0,1),(35,1),(45,0),(120,0)]).
```
defines the predicate:
```young(X,1):- X .>=. 0, X .<. 35.
young(X,M):- X .>=. 35, X .<. 45, 10*M .=. 45-X.
young(X,0):- X .>=. 45, X .=<. 120.
```
• The following properties should hold at call time: `Domain` is a list. (`basic_props:list/1`)

PREDICATE: fuzzy/1:

Usage: `fuzzy(Name)`

• Description: Defines a fuzzy predicate as the fuzzy counterpart of a crisp predicate `Name`. For example,
```p_f :# fuzzy p/2
```
defines a new fuzzy predicate `p_f/3` (the last argument is the truth value) with truth value equal to 0 if `p/2` fails and 1 otherwise.
• The following properties should hold at call time: `Name` is a Name/Arity structure denoting a predicate name:
```predname(P/A) :-
atm(P),
nnegint(A).
```
(`basic_props:predname/1`)

PREDICATE: fnot/1:

Usage: `fnot(Name)`

• Description: Defines a fuzzy predicate as the fuzzy negation of another fuzzy predicate `Name`. For example,
```notp_f :# fnot p_f/3
```
defines the predicate:
```notp_f(X,Y,M) :-
p_f(X,Y,Mp),
M .=. 1 - Mp.
```
• The following properties should hold at call time: `Name` is a Name/Arity structure denoting a predicate name:
```predname(P/A) :-
atm(P),
nnegint(A).
```
(`basic_props:predname/1`)

PREDICATE: :~/2:

Usage: `:~(Head, Body)`

• Description: Defines a fuzzy clause for a fuzzy predicate. The clause contains calls to either fuzzy or crisp predicates. Calls to crisp predicates are automatically fuzzified. The last argument of `Head` is the truth value of the clause, which is obtained as the aggregation of the truth values of the body goals. An example:
```:- module(young2,_,[fuzzy]).

young_couple(X,Y,Mu) :~ min
age(X,X1),
age(Y,Y1),
young(X1,MuX),
young(Y1,MuY).

age(john,37).
age(rose,39).

young :# fuzzy_predicate([(0,1),(35,1),(45,0),(120,0)]).

```
so that:
```?- young_couple(john,rose,M).

M .=. 0.6 ?
```
• The following properties should hold at call time: `Head` is a term which represents a goal, i.e., an atom or a structure. (`basic_props:callable/1`) `Body` is a clause body plus an optional aggregation operator. (`user(... /fuzzy_doc):fuzzybody/1`)

PROPERTY: fuzzybody/1:

A clause body, optionally prefixed by the name of an aggregation operator. The agregators currently provided are listed under `faggregator/1`. By default, the aggregator used is `min`.

Usage: `fuzzybody(B)`

• Description: `B` is a clause body plus an optional aggregation operator.

REGTYPE: faggregator/1:

The first three are, respectively, the T-norms: minimum, product, and Lukasiewicz's. The last three are their corresponding T-conorms. Aggregators can be defined by the user, see `aggr/1`.

```faggregator(min).
faggregator(prod).
faggregator(luka).
faggregator(max).
faggregator(dprod).
faggregator(dluka).
```

Usage: `faggregator(Aggr)`

• Description: `Aggr` is an aggregator which is cumulative, i.e., its application to several values by iterating pairwise the binary operation is safe.

PREDICATE: =>/4:

Usage: `=>(Aggr, A, B, Truth)`

• Description: The fuzzy implication `A => B` defined by aggregator `Aggr`, resulting in the truth value `Truth`.
• The following properties should hold at call time: `Aggr` is an aggregator which is cumulative, i.e., its application to several values by iterating pairwise the binary operation is safe. (`user(... /fuzzy_doc):faggregator/1`) `A` is a term which represents a goal, i.e., an atom or a structure. (`basic_props:callable/1`) `B` is a term which represents a goal, i.e., an atom or a structure. (`basic_props:callable/1`) `Truth` is a free variable. (`term_typing:var/1`)

## Other information (`fuzzy`)

An example program:

```:- module(dicesum5,_,[fuzzy]).

% this example tries to measure which is the possibility
% that a couple of values, obtained throwing two loaded dice, sum 5. Let
% us suppose we only know that one die is loaded to obtain a small value
% and the other is loaded to obtain a large value.
%
% the query is  ? sum(5,M)
%

small :# fuzzy_predicate([(1,1),(2,1),(3,0.7),(4,0.3),(5,0),(6,0)]).
large :# fuzzy_predicate([(1,0),(2,0),(3,0.3),(4,0.7),(5,1),(6,1)]).

die1(X,M) :~
small(X,M).

die2(X,M) :~
large(X,M).

two_dice(X,Y,M):~ prod
die1(X,M1),
die2(Y,M2).

sum(2,M) :~
two_dice(1,1,M1).

sum(5,M) :~ dprod
two_dice(4,1,M1),
two_dice(1,4,M2),
two_dice(3,2,M3),
two_dice(2,3,M4).

```

There are more examples in the subdirectory `fuzzy/examples` of the distribution.

## Known bugs and planned improvements (`fuzzy`)

• General aggregations defined by users.
• Inconsistent behaviour of meta-calls in fuzzy clauses.
• Some meta-predicate constructions need be added, specially for 'disjunctive' fuzzy clauses, e.g., `sum/2` in the dice example.