% Figure 20.8 A simulation program for qualitative differential equations. % The program uses the usual list predicates member/2 and conc/3. :- op( 900, fy, not). % not Goal): negation as failure; % Note: This is often available as a built-in predicate, % often written as prefix operator "\+", e.g. \+ likes(mary,snakes) not Goal :- Goal, !, fail ; true. % An interpreter for Qualitative Differential Equations :- op( 100, xfx, ..). :- op( 500, xfx, :). % landmarks( Domain, [ Land1, Land2, ... ] % Land1, Land2 etc. are landmarks for domain Domain % This is part of qualitative model definition, user-defined % correspond( Constraint): % Constraint specifies corresponding values for a type of constr. correspond( sum( Dom1:zero, Dom2:zero, Dom3:zero)). correspond( sum( Dom1:L, Dom2:zero, Dom1:L)) :- qmag( Dom1:L), L \== zero, not (L = _.._). % L is nonzero landmark in Dom1 correspond( sum( Dom1:zero, Dom2:L, Dom2:L)) :- qmag( Dom2:L), L \== zero, not (L = _.._). % L is nonzero landmark in Dom2 correspond( sum( V1, V2, V3)) :- correspond( V1, V2, V3). % User-defined corr. values % The following is a dummy definition of correspond/3 % just to avoid undefined-predicate error with some Prologs correspond( dummy, dummy, dummy). % qmag( Domain:QualMagnitude) qmag( Domain:Qm) :- landmarks( Domain, Lands), qmag( Lands, Qm). qmag( Lands, L) :- member( L, Lands), L \== minf, L \== inf. % A finite landmark qmag( Lands, L1..L2) :- % Interval conc( _, [L1,L2 | _], Lands). % Two adjacent landmarks % relative_qmag( Domain1:QM, Domain2:Landmark, Sign): % Sign is the sign of the difference between QM and Landmark % if QM < Landmark then Sign = neg, etc. relative_qmag( Domain:Ma..Mb, Domain:Land, Sign) :- !, landmarks( Domain, Lands), ( compare_lands( Ma, Land, Lands, neg), Sign = neg, ! ; Sign = pos ). relative_qmag( Domain:M1, Domain:M2, Sign) :- landmarks( Domain, Lands), compare_lands( M1, M2, Lands, Sign), !. % qdir( Qdir, Sign): % Qdir is qualitative direction of change with sign Sign qdir( dec, neg). qdir( std, zero). qdir( inc, pos). % Laws of qualitative summation % qsum( Q1, Q2, Q3): % Q3 = Q1 + Q2, qualitative sum over domain [pos,zero,neg] qsum( pos, pos, pos). qsum( pos, zero, pos). qsum( pos, neg, pos). qsum( pos, neg, zero). qsum( pos, neg, neg). qsum( zero, pos, pos). qsum( zero, zero, zero). qsum( zero, neg, neg). qsum( neg, pos, pos). qsum( neg, pos, zero). qsum( neg, pos, neg). qsum( neg, zero, neg). qsum( neg, neg, neg). % qdirsum( D1, D2, D3): % qualitative sum over directions of change qdirsum( D1, D2, D3) :- qdir( D1, Q1), qdir( D2, Q2), qdir( D3, Q3), qsum( Q1, Q2, Q3). % sum( QV1, QV2, QV3): % QV1 = QV2 + QV3, % qualitative sum over qualitative values of form Domain:Qmag/Dir % When called, this predicate assumes that the % domains of all three arguments are instantiated sum( D1:QM1/Dir1, D2:QM2/Dir2, D3:QM3/Dir3) :- qdirsum( Dir1, Dir2, Dir3), % Directions of change: Dir1 + Dir2 = Dir3 qmag( D1:QM1), qmag( D2:QM2), qmag( D3:QM3), % QM1+QM2=QM3 must be consistent with all corresponding values: not ( correspond( sum( D1:V1, D2:V2, D3:V3)), % V1 + V2 = V3 relative_qmag( D1:QM1, D1:V1, Sign1), relative_qmag( D2:QM2, D2:V2, Sign2), relative_qmag( D3:QM3, D3:V3, Sign3), not qsum( Sign1, Sign2, Sign3) ). % mplus( X, Y): % Y is a monotonically increasing function of X mplus( D1:QM1/Dir, D2:QM2/Dir) :- % Equal directions of change qmag( D1:QM1), qmag( D2:QM2), % QM1, QM2 consistent with all corresponding values between D1, D2: not ( correspond( D1:V1, D2:V2), relative_qmag( D1:QM1, D1:V1, Sign1), relative_qmag( D2:QM2, D2:V2, Sign2), Sign1 \== Sign2 ). % deriv( Var1, Var2): % time derivative of Var1 is qualitatively equal Var2 deriv( Dom1:Qmag1/Dir1, Dom2:Qmag2/Dir2) :- qdir( Dir1, Sign1), qmag( Dom2:Qmag2), relative_qmag( Dom2:Qmag2, Dom2:zero, Sign2), % Sign2 = sign of Qmag2 Sign1 = Sign2. % transition( Domain:Qmag1/Dir1, Domain:Qmag2/Dir2): % Variable state transitions between "close" time points transition( Dom:L1..L2/std, Dom:L1..L2/Dir2) :- qdir( Dir2, AnySign). transition( Dom:L1..L2/inc, Dom:L1..L2/inc). transition( Dom:L1..L2/inc, Dom:L1..L2/std). transition( Dom:L1..L2/inc, Dom:L2/inc) :- L2 \== inf. transition( Dom:L1..L2/inc, Dom:L2/std) :- L2 \== inf. transition( Dom:L1..L2/dec, Dom:L1..L2/dec). transition( Dom:L1..L2/dec, Dom:L1..L2/std). transition( Dom:L1..L2/dec, Dom:L1/dec) :- L1 \== minf. transition( Dom:L1..L2/dec, Dom:L1/std) :- L1 \== minf. transition( Dom:L1/std, Dom:L1/std) :- L1 \== A..B. % L1 not an interval transition( Dom:L1/std, Dom:L1..L2/inc) :- qmag( Dom:L1..L2). transition( Dom:L1/std, Dom:L0..L1/dec) :- qmag( Dom:L0..L1). transition( Dom:L1/inc, Dom:L1..L2/inc) :- qmag( Dom:L1..L2). transition( Dom:L1/dec, Dom:L0..L1/dec) :- qmag( Dom:L0..L1). % system_trans( State1, State2): % System state transition; % system state is a list of variable values system_trans( [], []). system_trans( [Val1 | Vals1], [Val2 | Vals2]) :- transition( Val1, Val2), system_trans( Vals1, Vals2). % legal_trans( State1, State2): % possible transition between states according to model legal_trans( State1, State2) :- system_trans( State1, State2), State1 \== State2, % Qualitatively different next state legalstate( State2). % Legal according to model % simulate( SystemStates, MaxLength): % SystemStates is a sequence of states of simulated system % not longer than MaxLength simulate( [State], MaxLength) :- ( MaxLength = 1 % Max length reached ; not legal_trans( State, _) % No legal next state ) , !. simulate( [State1,State2 | Rest], MaxLength) :- MaxLength > 1, NewMaxL is MaxLength - 1, legal_trans( State1, State2), simulate( [State2 | Rest], NewMaxL). % simulate( InitialState, QualBehaviour, MaxLength) simulate( InitialState, [InitialState | Rest], MaxLength) :- legalstate( InitialState), % Satisfy system's model simulate( [InitialState | Rest], MaxLength). % compare_lands( X1, X2, List, Sign): % if X1 before X2 in List then Sign = neg % if X2 before X1 then Sign = pos else Sign = zero compare_lands( X1, X2, [First | Rest], Sign) :- X1 = X2, !, Sign = zero ; X1 = First, !, Sign = neg ; X2 = First, !, Sign = pos ; compare_lands( X1, X2, Rest, Sign). % member( X, List): X is a member of List member(X,[X | _]). % X is head of list member( X, [_ | Rest]) :- member( X, Rest). % X is in body of list % conc(L1,L2,L3): list L3 is th econcatenation of lists L1 and L2 conc( [], L, L). conc( [X | L1], L2, [X | L3]) :- conc( L1, L2, L3).