Fuzzy Logic IF-THEN Rules in Amzi! Prolog
(Scalable Monotonic Chaining Version)
Cox's Case Study: A Project Risk Assesment Model
Reported in "The Fuzzy Systems Handbook", AP Professional, 1994, pp. 436-447.
Alberto Pacheco © 1997
/*
RISK.PRO:
Developed by Alberto Pacheco, 1996-1997
e-mail: apacheco@campus.chi.itesm.mx
This version supports:
- One-goal, one-sample-at-a-time
- Linear Fuzzy Membership Representations
--------> Sigmoid Curve Membership Function (S-Curve Fuzzy Set) (as/ds)
- Zadeh Fuzzy Set Operators
--------> Mapping from Membreship Degree to I/O Domain (member_to_domain)
--------> Scalable Monotonic Chaining (monotonic_scaling)
To run, type:
?- main.
Test results:
--- SAMPLE #1: OUTPUT FOR A LOW RISK ASSESMENT MODEL ---
proj_duration: 8.000000
proj_staffing: 12.000000
proj_funding: 40.000000
proj_priority: 3.000000
project_risk : amount = 142.222244 membership = 0.142222
project_risk : amount = 500.000000 membership = 0.500000
project_risk : amount = 600.000000 membership = 0.600000
project_risk : amount = 700.000000 membership = 0.700000
Cummulative Risk is 1942.222168
project_risk = 388.444427
--- SAMPLE #2: OUTPUT FOR A HIGH RISK ASSESMENT MODEL ---
proj_duration: 25.000000
proj_staffing: 19.000000
proj_funding: 10.000000
proj_priority: 1.000000
project_risk : amount = 944.444397 membership = 0.944444
project_risk : amount = 791.666687 membership = 0.791667
project_risk : amount = 900.000000 membership = 0.900000
project_risk : amount = 900.000000 membership = 0.900000
Cummulative Risk is 3536.111084
project_risk = 707.222229
--- END OF SAMPLE'S OUTPUT ---
---> ..HERE ARE COX'S RESULTS FOR THE SAME INPUT STREAM <---
--- SAMPLE #1: COX'S OUTPUT FOR A LOW RISK ASSESMENT MODEL ---
proj_duration: 8.000000
proj_staffing: 12.000000
proj_funding: 40.000000
proj_priority: 3.000000
project_risk : amount = 292.97 membership = 0.141
project_risk : amount = 515.62 membership = 0.498
project_risk : amount = 574.22 membership = 0.603
project_risk : amount = 632.81 membership = 0.704
Cummulative Risk is 2015.62
project_risk = 323.76
--- SAMPLE #2: COX'S OUTPUT FOR A HIGH RISK ASSESMENT MODEL ---
proj_duration: 25.000000
proj_staffing: 19.000000
proj_funding: 10.000000
proj_priority: 1.000000
project_risk : amount = 839.84 membership = 0.944
project_risk : amount = 687.50 membership = 0.786
project_risk : amount = 792.97 membership = 0.903
project_risk : amount = 792.97 membership = 0.903
Cummulative Risk is 3113.28
project_risk = 712.86
*/
% Operator Definitions
:- op(700, xfx, is).
:- op(720, xfy, and).
:- op(740, xfy, or).
:- op(760, xfx, then).
:- op(780, fx, if).
% Main Procedure:
% 1) Initialization;
% 2) Goal with Output Variable
main :-
init(project_risk),
one_goal(project_risk).
% Initialization: Clear global working memory
init(Var) :-
retractall(_),
assert(sum1(Var,0.0)),
nl,write('Fuzzy Project Risk Assesment Model'),
nl,write('Example taken from: Cox, E. "The Fuzzy Systems Handbook",'),
write(' AP Professional, 1994, pp. 436-447.'),nl,nl,
input_value( _, Input_Variable, Value ),
write(Input_Variable),write(': '),write(Value),nl,
fail.
init(_):-nl,!.
% Probes all rules with conclusion 'Var'
one_goal(Var) :-
prove( Var is X ),
fail.
% Reports the composite solution
one_goal(Var) :-
output_value(Var,X),
nl, write(Var), write(' = '), write(X), nl.
/*
::: PRODUCTION RULES (FUZZY MODEL'S RULES) :::
A Project Risk Assesment Model
Based on Earl Cox's Case Study
Book:
Cox, E. "The Fuzzy Systems Handbook", AP Professional, 1994
pp. 436-447.
*/
% R-1
if proj_duration is long
then project_risk is increased.
% R-2
if proj_staffing is large
then project_risk is increased.
% R-3
if proj_funding is low
then project_risk is increased.
% R-4
if proj_priority is high
then project_risk is increased.
%::: FUZZY SETS DEFINITIONS :::
% Note: The Maximun Domain Limit acts as a Weighted Measure for its corresponding set
fuzzy_set( proj_duration, long, as, 0.0, 15.0, 30.0, 0.0 ).
fuzzy_set( proj_staffing, large, at, 0.0, 24.0, 0.0, 0.0 ).
fuzzy_set( proj_funding, low, dt, 0.0, 100.0, 0.0, 0.0 ). % Greatest Weight
fuzzy_set( proj_priority, high, dt, 0.0, 10.0, 0.0, 0.0 ). % Lowest Weight
%::: OUTPUT FUZZY SETS :::
fuzzy_set( project_risk, increased, as, 0.0, 1000.0, 0.0, 0.0 ).
fuzzy_set( project_risk, high_risk, at, 0.0, 5000.0, 0.0, 0.0 ).
%::: INPUT VALUES :::
% SAMPLE #1: A LOW RISK ASSESMENT MODEL INPUT
input_value( 1, proj_duration, 8.0 ).
input_value( 1, proj_staffing, 12.0 ).
input_value( 1, proj_funding, 40.0 ).
input_value( 1, proj_priority, 3.0 ).
/*
% SAMPLE #2: A HIGH RISK ASSESMENT MODEL INPUT
input_value( 1, proj_duration, 25.0 ).
input_value( 1, proj_staffing, 19.0 ).
input_value( 1, proj_funding, 10.0 ).
input_value( 1, proj_priority, 1.0 ).
*/
/***************************************************************
Prolog Interpreter in Prolog
Based on Dennis Merrit's Article
"Building Custom Rule Engines," PC AI, Mar/Apr 1996.
****************************************************************/
prove(ATTR is VALUE and REST) :- % AND
getav(ATTR, VALUE),
prove(REST),
apply_fuzzy_oper(and_z).
prove(ATTR is VALUE or REST) :- % OR
getav(ATTR, VALUE),
prove(REST),
apply_fuzzy_oper(or_z).
prove(ATTR is VALUE) :- % IS
getav(ATTR,VALUE).
getav(ATTR,VALUE) :- % IF/THEN's CONCLUSION
if CONDITIONS then ATTR is VALUE,
prove(CONDITIONS),
retract(prem(Mx)),
monotonic_scaling(ATTR,VALUE,Mx).
getav(ATTR,VALUE) :-
not(if _ then ATTR is _),
rule_translation(ATTR,VALUE).
%::: IS A BOOLEAN OR A FUZZY RULE? :::
% FUZZY RULE PROCESSING
rule_translation( T, Cj ) :-
clause( fuzzy_set(T,_,_,_,_,_,_), _ ), !,
input_value( _, T, X ), !,
fuzzification( T, Cj, X ).
% DISCRETE INFERENCE RULE PROCESSING
rule_translation( T, Cj ) :-
input_value( _, T, Cj ), !,
is_true.
rule_translation( T, Cj ) :-
is_false,
nl,write('Error in rule_translation(): Undefined set'),nl,write(T),nl,write(Cj).
%::: FUZZIFICACION :::
fuzzification( Name, Set, X_Value ) :-
fuzzy_set( Name, Set, Type, A, B, C, D ),
degree_of_membership( Type, A, B, C, D, X_Value, Membership ),
assert( prem(Membership) ), !.
/*
LINEAR DECREASING FUZZY SET (i,i,i,i,i,i,o)
dt
A - Minimum Value
B - Maximum Value
*/
degree_of_membership( dt, A, _, _, _, X, 1.0 ) :-
X =< A, !.
degree_of_membership( dt, _, B, _, _, X, 0.0 ) :-
X >= B, !.
degree_of_membership( dt, A, B, _, _, X, M ) :-
line_eq( dt, A, B, X, M ), !.
/*
LINEAR INCREASING FUZZY SET
at
A - Minimum Value
B - Maximum Value
*/
degree_of_membership( at, A, _, _, _, X, 0.0 ) :-
X =< A, !.
degree_of_membership( at, _, B, _, _, X, 1.0 ) :-
X >= B, !.
degree_of_membership( at, A, B, _, _, X, M ) :-
line_eq( at, A, B, X, M ), !.
/*
TRAPEZOIDAL OR TRIANGULAR FUZZY SET
tp -- TRAPEZOIDAL -- -- TRIANGULAR --
A - Minimum Value A - Minimum Value
B - Left Shoulder B - Center
C - Right Shoulder C - Center
D - Maximum Value D - Maximum Value
*/
degree_of_membership( tp, A, _, _, _, X, 0.0 ) :-
X =< A, !.
degree_of_membership( tp, A, B, _, _, X, M ) :-
X > A, X =< B,
line_eq( at, A, B, X, M ), !.
degree_of_membership( tp, _, B, C, _, X, 1.0 ) :-
X > B, X < C, !.
degree_of_membership( tp, _, _, C, D, X, M ) :-
X > C, X < D,
line_eq( dt, C, D, X, M ), !.
degree_of_membership( tp, _, _, _, _, _, 0.0 ). % X>D
/*
INCREASING S-CURVE FUZZY SET
as
A - Minimum Value
B - Inflexion Point (point at wich the domain value is 50% true
C - Maximum Value
*/
degree_of_membership( as, A, _, _, _, X, 0.0 ) :-
X =< A, !.
degree_of_membership( as, A, B, C, _, X, M ) :-
X > A, X =< B,
M is (2.0 * ((X-A)/(C-A))**2.0), !.
degree_of_membership( as, A, B, C, _, X, M ) :-
X > B, X < C,
M is (1.0 - 2.0*(((C-X)/(C-A))**2.0)), !. % Cox's Bug? Eq. 3.2 p.52
/*
degree_of_membership( as, A, B, C, _, X, M ) :-
X > B, X < C,
M is (1.0 - 2.0*((X-C)/(C-A))**2.0), !.
*/
degree_of_membership( as, _, _, _, _, _, 1.0 ). % X>=C
% FINDS THE EXPECTED OUTPUT VALUE OF THE FUZZY SET GIVEN ITS DEGREE OF MEMBERSHIP
% === member_to_domain( A, B, Membership-Degree, X-Domain-Value ) - (i,i,i,o) ===
member_to_domain( X1, X2, Memb, X ) :-
X is ( Memb * (X2 - X1) + X1 ), !.
%::: FUZZY OPERATORS :::
apply_fuzzy_oper( and_z ) :-
retract(prem(M1)),
write(M1),
retract(prem(M2)), !,
write(' and '), write(M2), nl,
min(M1,M2,M),
assert(prem(M)), !.
apply_fuzzy_oper( or_z ) :-
retract(prem(M1)),
write(M1),
retract(prem(M2)),!,
write(' or '), write(M2), nl,
max(M1,M2,M),
assert(prem(M)), !.
%::: MONOTONIC SCALING CHAINING MODEL - (i,i,i) :::
monotonic_scaling( Var, OutSet, Memb ) :-
fuzzy_set( Var, OutSet, _, X1, X2, _, _ ), !,
member_to_domain( X1, X2, Memb, X ),
retract( sum1(Var,Q) ),
R is ( X + Q ),
assert( sum1(Var,R) ),
write(Var),write(' : amount = '),write(X),
write(' membership = '),write(Memb),nl,!.
%::: END OF DEFUZZIFICATION METHOD ::::
output_value( Var, X ) :-
retract( sum1( Var, Cummulative_Risk ) ),
nl, write('Cummulative Risk is '),write(Cummulative_Risk),nl,
fuzzification( Var, high_risk, Cummulative_Risk ),
retract( prem( Memb ) ),
X is (Memb * 1000.0).
%::: LINEAR INTERPOLATION :::
line_eq( dt, X1, X2, X, Y ) :-
Y is (X2 - X) / (X2 - X1).
line_eq( at, X1, X2, X, Y ) :-
Y is (X - X1) / (X2 - X1).
%::: BOOLEAN VALUES :::
is_true :- assert(prem(1.0)), !.
is_false :- assert(prem(0.0)), !.
%::: FUZZY FUNCTION PRIMITIVES :::
min( X, Y, X ) :- X < Y, !.
min( _, Y, Y ).
max( X, Y, X ) :- X > Y, !.
max( _, Y, Y ).