% -----------------------------------------------------------------------------
%  (C) Altran Praxis Limited
% -----------------------------------------------------------------------------
% 
%  The SPARK toolset is free software; you can redistribute it and/or modify it
%  under terms of the GNU General Public License as published by the Free
%  Software Foundation; either version 3, or (at your option) any later
%  version. The SPARK toolset is distributed in the hope that it will be
%  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
%  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
%  Public License for more details. You should have received a copy of the GNU
%  General Public License distributed with the SPARK toolset; see file
%  COPYING3. If not, go to http://www.gnu.org/licenses for a complete copy of
%  the license.
% 
% =============================================================================


%-------------------------------------------------------------------------------
% RULE FAMILIES CONTAINED HEREIN :-
%
% arith        : simple arithmetic simplification rules
% assoc        : associativity of + and *
% commut       : commutativity of + and *
% distrib      : distributivity of * over + and -
% minus        : rules for unary and binary minus
% intdiv       : rules for the integer div operator
%-------------------------------------------------------------------------------
% MODEL DECLARATIONS FOR THIS FILE :-
%
% rule_family arith:
%         X * Y   requires [ X:ir, Y:ir ] &
%         X + Y   requires [ X:ir, Y:ir ] &
%         X - Y   requires [ X:ir, Y:ir ] &
%         X div Y requires [ X:i,  Y:i  ] &
%         X / Y   requires [ X:ir, Y:ir ].
%
% rule_family assoc:
%         X + Y requires [ X:ir, Y:ir ] &
%         X * Y requires [ X:ir, Y:ir ].
%
% rule_family commut:
%         X + Y requires [ X:ir, Y:ir ] &
%         X * Y requires [ X:ir, Y:ir ].
%
% rule_family distrib:
%         X + Y requires [ X:ir, Y:ir ] &
%         X - Y requires [ X:ir, Y:ir ] &
%         X * Y requires [ X:ir, Y:ir ].
%
% rule_family minus:
%         - X   requires [ X:ir       ] &
%         X + Y requires [ X:ir, Y:ir ] &
%         X - Y requires [ X:ir, Y:ir ] &
%         X * Y requires [ X:ir, Y:ir ].
%
% rule_family intdiv:
%         X div Y requires [ X:i, Y:i ] &
%         X + Y   requires [ X:i, Y:i ] &
%         - X     requires [ X:i      ].
%-------------------------------------------------------------------------------


/*** SIMPLIFICATION OF ARITHMETIC EXPRESSIONS Rules ***/

arith(1):    X*1             may_be_replaced_by X.
arith(2):    1*X             may_be_replaced_by X.
arith(3):    X+0             may_be_replaced_by X.
arith(4):    0+X             may_be_replaced_by X.
arith(5):    X - 0           may_be_replaced_by X.
arith(6):    X*0             may_be_replaced_by 0.
arith(7):    0*X             may_be_replaced_by 0.
arith(8):    X div 1         may_be_replaced_by X.
arith(9):    (X*N) div N     may_be_replaced_by X        if [ N<>0 ].
arith(10):   (N*X) div N     may_be_replaced_by X        if [ N<>0 ].
arith(11):    X/1            may_be_replaced_by X.
arith(12):    (X/Y)*Y        may_be_replaced_by X        if [ Y<>0 ].
arith(13):    Y*(X/Y)        may_be_replaced_by X        if [ Y<>0 ].
arith(14):    (X*Y)/Y        may_be_replaced_by X        if [ Y<>0 ].
arith(15):    (Y*X)/Y        may_be_replaced_by X        if [ Y<>0 ].


/*** ASSOCIATIVITY of + & * Rules ***/

assoc(1):       (A+B)+C         may_be_replaced_by A+(B+C).
assoc(2):       A+(B+C)         may_be_replaced_by (A+B)+C.
assoc(3):       (A*B)*C         may_be_replaced_by A*(B*C).
assoc(4):       A*(B*C)         may_be_replaced_by (A*B)*C.


/*** COMMUTATIVITY of + & * Rules ***/

commut(1):      A+B             may_be_replaced_by B+A.
commut(2):      A*B             may_be_replaced_by B*A.


/*** DISTRIBUTIVITY of * over + & - Rules ***/

distrib(1):   A*(B+C) & A*B+A*C are_interchangeable.
distrib(2):   (B+C)*A & A*B+A*C are_interchangeable.
distrib(3):   A*(B-C) & A*B-A*C are_interchangeable.
distrib(4):   (B-C)*A & A*B-A*C are_interchangeable.


/*** Rules for manipulation of unary and binary MINUS operators ***/

minus(1):       X-X                      may_be_replaced_by 0.
minus(2):       -(0)                     may_be_replaced_by 0.
minus(3):       -(-X)                    may_be_replaced_by X.
minus(4):       -(A+B) & -A+(-B)         are_interchangeable.
minus(5):       -(A+B) & -A-B            are_interchangeable.
minus(6):       -A+(-B) & -A-B           are_interchangeable.
minus(7):       A+(-B) & A-B             are_interchangeable.
minus(8):       A+(-B) & -(B-A)          are_interchangeable.
minus(9):       A-B & -(B-A)             are_interchangeable.
minus(10):      -A*B & A*(-B)            are_interchangeable.
minus(11):      -A*B & -(A*B)            are_interchangeable.
minus(12):      -(A*B) & A*(-B)          are_interchangeable.
minus(13):      -A*(-B) & A*B            are_interchangeable.


/*** Some rules for INTEGER DIVISION ***/

intdiv(1):   (A+B) div C & A div C+B div C are_interchangeable if [B=K*C, A*B>=0].
intdiv(2):   (A+B) div C & A div C+B div C are_interchangeable if [B=C*K, A*B>=0].
intdiv(3):   (A+B) div C & A div C+B div C are_interchangeable if [A=K*C, A*B>=0].
intdiv(4):   (A+B) div C & A div C+B div C are_interchangeable if [A=C*K, A*B>=0].
intdiv(5):   (A+B) div C & A div C+D       are_interchangeable if
                          [goal(integer(B)), goal(integer(C)), goal(C\=0),
                           goal(D iss B div C), goal(B iss D*C), A*B>=0].
intdiv(6):   (A+B) div C & D+B div C       are_interchangeable if
                          [goal(integer(A)), goal(integer(C)), goal(C\=0),
                           goal(D iss A div C), goal(A iss D*C), A*B>=0].
intdiv(7):   -A div B    & A div (-B)      are_interchangeable.
intdiv(8):   -A div B    & -(A div B)      are_interchangeable.
intdiv(9):   A div (-B)  & -(A div B)      are_interchangeable.
intdiv(10):  -A div (-B) & A div B         are_interchangeable.
intdiv(11):  (A*B) div B                   may_be_replaced_by A if [B<>0].
intdiv(12):  (A*B) div (C*B)               may_be_replaced_by A div C if [B<>0].
