210 lines
6.5 KiB
Perl
210 lines
6.5 KiB
Perl
|
% fougau.pl =================================================================
|
||
|
% constraint handling rules for linear arithmetic
|
||
|
% fouriers algorithm for inequalities and gaussian elemination for equalities
|
||
|
% thom fruehwirth 950405-06, 980312
|
||
|
% 961107 Christian Holzbaur, SICStus mods
|
||
|
|
||
|
% CHOOSE one of the propagation rules below and comment out the others!
|
||
|
% completeness and termination depends on propagation rule used
|
||
|
|
||
|
:- use_module( library(chr)).
|
||
|
:- use_module( library(lists), [append/3]).
|
||
|
:- ensure_loaded('math-utilities').
|
||
|
|
||
|
handler fougau.
|
||
|
|
||
|
% auxiliary constraint to delay a goal G until it is ground
|
||
|
constraints check/1.
|
||
|
check(G) <=> ground(G) | G.
|
||
|
|
||
|
constraints {}/1.
|
||
|
|
||
|
{ C,Cs } <=> { C }, { Cs }.
|
||
|
|
||
|
{A =< B} <=> ground(A),ground(B) | A=<B.
|
||
|
{A >= B} <=> ground(A),ground(B) | A>=B.
|
||
|
{A < B} <=> ground(A),ground(B) | A<B.
|
||
|
{A > B} <=> ground(A),ground(B) | A>B.
|
||
|
{A =\= B} <=> ground(A),ground(B) | A=\=B.
|
||
|
|
||
|
{A =< B} <=> normalize(B,A,P,C), eq(P,C,'>'('=')).
|
||
|
{A >= B} <=> normalize(A,B,P,C), eq(P,C,'>'('=')).
|
||
|
{A < B} <=> normalize(B,A,P,C), eq(P,C,'>'('>')).
|
||
|
{A > B} <=> normalize(A,B,P,C), eq(P,C,'>'('>')).
|
||
|
%{A < B} <=> normalize(B,A+1,P,C), eq(P,C,(>=)). % adopt to integer
|
||
|
%{A > B} <=> normalize(A,B+1,P,C), eq(P,C,(>=)). % adopt to integer
|
||
|
{A =\= B} <=> normalize(A+X,B,P,C), eq(P,C,(=:=)), check(X=\=0).
|
||
|
|
||
|
{A =:= B} <=> ground(A),ground(B) | X is A-B, zero(X). % handle imprecision of reals
|
||
|
{A =:= B} <=> var(A), ground(B) | A is B.
|
||
|
{B =:= A} <=> var(A), ground(B) | A is B.
|
||
|
{A =:= B} <=> unconstrained(A),var(B) | A=B.
|
||
|
{B =:= A} <=> unconstrained(A),var(B) | A=B.
|
||
|
{A =:= B} <=> normalize(A,B,P,C), eq(P,C,(=:=)).
|
||
|
|
||
|
constraints eq/3.
|
||
|
% eq(P,C,R)
|
||
|
% P is a polynomial (list of monomials variable*coefficient),
|
||
|
% C is a numeric constant and R is the relation between P and C
|
||
|
|
||
|
% simplify single equation
|
||
|
zero @ eq([],C1,(=:=)) <=> zero(C1).
|
||
|
zero @ eq([],C1,'>'('=')) <=> C1>=0.
|
||
|
zero @ eq([],C1,'>'('>')) <=> C1>0.
|
||
|
unify @ eq([X*C2],C1,(=:=)) <=> nonground(X),nonzero(C2) | is_div(C1,C2,X).
|
||
|
%, integer(X) % if integers only
|
||
|
simplify @ eq(P0,C1,R) <=> delete(X*C2,P0,P),ground(X) | % R any relation
|
||
|
%, integer(X), % if integers only
|
||
|
is_mul(X,C2,XC2),
|
||
|
C is XC2+C1,
|
||
|
eq(P,C,R).
|
||
|
/*
|
||
|
% must use if you unify variables of equations with each other
|
||
|
unified @ eq(P0,C1,R1) <=>
|
||
|
append(P1,[X*C2|P2],P0),var(X),delete(Y*C3,P2,P3),X==Y
|
||
|
|
|
||
|
C23 is C2+C3,
|
||
|
append(P1,[X*C23|P3],P4),
|
||
|
sort1(P4,P5),
|
||
|
eq(P5,C1,R1).
|
||
|
*/
|
||
|
|
||
|
%(1) remove redundant inequation
|
||
|
% -1 (change in number of constraints)
|
||
|
red_poly @ eq([X*C1X|P1],C1,'>'(R1)) \ eq([X*C2X|P2],C2,'>'(R2)) <=>
|
||
|
C is C2X/C1X, % explicit because of call_explicit bug
|
||
|
C>0, % same sign
|
||
|
C1C is C1*C,
|
||
|
C1C=<C2, % remove right one
|
||
|
stronger(C1X,C1C,R1,C2X,C2,R2), % remove right one if C1C=:= C2
|
||
|
same_poly(P1,P2,C)
|
||
|
|
|
||
|
true.
|
||
|
|
||
|
%(2) equate opposite inequations
|
||
|
% -1
|
||
|
opp_poly @ eq([X*C1X|P1],C1,'>'(R1)), eq([X*C2X|P2],C2,'>'(R2)) <=>
|
||
|
C is C2X/C1X,
|
||
|
C<0, % different sign
|
||
|
C1C is C1*C,
|
||
|
C1C>=C2, % applicable?
|
||
|
same_poly(P1,P2,C)
|
||
|
|
|
||
|
Z is C1C-C2, zero(Z), % must have identical constants
|
||
|
(R1)=('='), (R2)=('='), % fail if one of R's is ('>')
|
||
|
eq([X*C1X|P1],C1,(=:=)).
|
||
|
|
||
|
%(3) usual equation replacement (like math-gauss.chr)
|
||
|
% 0
|
||
|
/*
|
||
|
elimin_eager @ eq([X*C2X|PX],C1X,(=:=)) \ eq(P0,C1,R) <=> % R any relation
|
||
|
extract(X*C2,P0,P)
|
||
|
|
|
||
|
is_div(C2,C2X,CX),
|
||
|
mult_const(eq0(C1X,PX),CX,P2),
|
||
|
add_eq0(eq0(C1,P),P2,eq0(C3,P3)),
|
||
|
sort1(P3,P4),
|
||
|
eq(P4,C3,R).
|
||
|
*/
|
||
|
elimin_lazy @ eq([X*C2X|PX],C1X,(=:=)) \ eq([X*C2|P],C1,R) <=>
|
||
|
is_div(C2,C2X,CX),
|
||
|
mult_const(eq0(C1X,PX),CX,P2),
|
||
|
add_eq0(eq0(C1,P),P2,eq0(C3,P3)),
|
||
|
sort1(P3,P4),
|
||
|
eq(P4,C3,R).
|
||
|
|
||
|
% choose one of the propagation rules below and comment out the others!
|
||
|
% completeness and termination depends on propagation rule used
|
||
|
|
||
|
%(4) propagate, transitive closure of inequations, various versions
|
||
|
% +1
|
||
|
/*
|
||
|
% complete, but too costly, propagate_lazy is as good, can loop
|
||
|
propagate_eager @ eq([X*C2X|PX],C1X,'>'(R1)), eq(P0,C1,'>'(R2)) ==>
|
||
|
extract(X*C2,P0,P),
|
||
|
is_div(C2,C2X,CX),
|
||
|
CX>0 % different sign?
|
||
|
|
|
||
|
combine_ineqs(R1,R2,R3),
|
||
|
mult_const(eq0(C1X,PX),CX,P2),
|
||
|
add_eq0(eq0(C1,P),P2,eq0(C3,P3)),
|
||
|
sort1(P3,P4),
|
||
|
eq(P4,C3,'>'(R3)).
|
||
|
|
||
|
% complete, may loop
|
||
|
propagate_lazy @ eq([X*C2X|PX],C1X,'>'(R1)), eq([X*C2|P],C1,'>'(R2)) ==>
|
||
|
is_div(C2,C2X,CX),
|
||
|
CX>0 % different sign?
|
||
|
|
|
||
|
combine_ineqs(R1,R2,R3),
|
||
|
mult_const(eq0(C1X,PX),CX,P2),
|
||
|
add_eq0(eq0(C1,P),P2,eq0(C3,P3)),
|
||
|
sort1(P3,P4),
|
||
|
eq(P4,C3,'>'(R3)).
|
||
|
*/
|
||
|
/*
|
||
|
% incomplete, number of variables does not increase, may loop
|
||
|
propagate_pair @ eq([X*C2X|PX],C1X,'>'(R1)), eq(P0,C1,'>'(R2)) ==>
|
||
|
not(PX=[_,_,_|_]), % single variable or pair of variables only
|
||
|
extract(X*C2,P0,P),
|
||
|
is_div(C2,C2X,CX),
|
||
|
CX>0 % different sign?
|
||
|
|
|
||
|
combine_ineqs(R1,R2,R3),
|
||
|
mult_const(eq0(C1X,PX),CX,P2),
|
||
|
add_eq0(eq0(C1,P),P2,eq0(C3,P3)),
|
||
|
sort1(P3,P4),
|
||
|
eq(P4,C3,'>'(R3)).
|
||
|
*/
|
||
|
% incomplete, is interval reasoning, number of variables decreases, loop free
|
||
|
propagate_single @ eq([X*C2X],C1X,'>'(R1)), eq(P0,C1,'>'(R2)) ==> % single variable only
|
||
|
(P0=[V*C2|P],V==X ; P0=[VC,V*C2|PP],V==X,P=[VC|PP]), % only first or second variable
|
||
|
is_div(C2,C2X,CX),
|
||
|
CX>0 % different sign?
|
||
|
|
|
||
|
combine_ineqs(R1,R2,R3),
|
||
|
is_mul(C1X,CX,C1XCX),
|
||
|
C3 is C1+C1XCX,
|
||
|
eq(P,C3,'>'(R3)).
|
||
|
/*
|
||
|
% incomplete, ignore inequations until they are sufficiently simplified
|
||
|
%propagate_never @ eq([X*C2X|PX],C1X,'>'(R1)), eq([X*C2|P],C1,'>'(R2)) ==>
|
||
|
% fail | true.
|
||
|
*/
|
||
|
|
||
|
% handle nonlinear equations ------------------------------------------------
|
||
|
operator(450,xfx,eqnonlin).
|
||
|
constraints (eqnonlin)/2.
|
||
|
non_linear @ X eqnonlin A <=> ground(A) | A1 is A, {X=:=A1}.
|
||
|
non_linear @ X eqnonlin A*B <=> ground(A) | A1 is A, {X=:=A1*B}.
|
||
|
non_linear @ X eqnonlin B*A <=> ground(A) | A1 is A, {X=:=A1*B}.
|
||
|
|
||
|
|
||
|
% labeling, useful really only for integers ---------------------------------
|
||
|
%label_with eq([XC],C1,'>'('=')) if true.
|
||
|
%eq([XC],C1,'>'('=')) :- eq([XC],C1,(=:=)) ; eq([XC],C1,'>'('>')).
|
||
|
|
||
|
|
||
|
% auxiliary predicates --------------------------------------------------------
|
||
|
|
||
|
% combine two inequalities
|
||
|
combine_ineqs(('='),('='),('=')):- !.
|
||
|
combine_ineqs(_,_,('>')).
|
||
|
|
||
|
same_poly([],[],C).
|
||
|
same_poly([X*C1|P1],[X*C2|P2],C) ?-
|
||
|
%X==Y,
|
||
|
C4 is C*C1-C2, zero(C4),
|
||
|
same_poly(P1,P2,C).
|
||
|
|
||
|
stronger(C1X,C1C,R1,C2X,C2,R2):-
|
||
|
C1C=:=C2 ->
|
||
|
\+ (R1=('='),R2=('>')),
|
||
|
C1A is abs(C1X)+1/abs(C1X), C2A is abs(C2X)+1/abs(C2X),
|
||
|
C1A=<C2A
|
||
|
;
|
||
|
true.
|
||
|
|
||
|
|
||
|
/* end of file math-fougau.chr ----------------------------------------------*/
|