% -----------------------------------------------------------------------------
%  (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 :-
%
% modular : modular arithmetic
%-------------------------------------------------------------------------------
% MODEL DECLARATIONS FOR THIS FILE :-
%
% rule_family modular:
%         X mod Y requires [X : i, Y : i] &
%         X <= Y  requires [X : i, Y : i] &
%         X <> Y  requires [X : i, Y : i] &
%         X < Y   requires [X : i, Y : i] &
%         X = Y   requires [X : i, Y : i].
%-------------------------------------------------------------------------------


/*** Definition of mod (modulo) ***/

modular(1):  X mod Y = X - N * Y may_be_deduced_from
                                            [ N * Y <= X, X < (N + 1)* Y,  0 < Y ].
modular(2):  X mod Y = X - N * Y may_be_deduced_from
                                            [ X <= N * Y, (N + 1) * Y < X, Y < 0 ].

/*** Bounds for 0 < Y ***/
modular(10):   0 <= (X * Y + Z) mod Y may_be_deduced_from [ 0 <= Z, Z < Y ].
modular(11):   (X * Y + Z) mod Y < Y  may_be_deduced_from [ 0 <= Z, Z < Y ].

/*** Bounds for Y < 0 ***/
modular(20):   Y < (X * Y + Z) mod Y  may_be_deduced_from [ Y < Z, Z <= 0 ].
modular(21):  (X * Y + Z) mod Y <= 0  may_be_deduced_from [ Y < Z, Z <= 0 ].

/** Properties ***/
modular(30):   (X * Y + Z) mod Y = Z  may_be_deduced_from [ 0 <= Z, Z < Y ].
modular(31):   (X * Y + Z) mod Y = Z  may_be_deduced_from [ Z <= 0, Y < Z ].

modular(32):   N mod N       may_be_replaced_by  0     if [ N <> 0 ].
modular(33):   N mod N       may_be_replaced_by  0     if [ N > 0 ].
modular(34):   N mod N       may_be_replaced_by  0     if [ N < 0 ].

modular(40):   X * Y mod Y   may_be_replaced_by  0     if [ Y <> 0 ].
modular(41):   X mod Y       may_be_replaced_by  X     if [ 0 <= X, X < Y ].
modular(42):   X mod Y       may_be_replaced_by  X     if [ Y < X,  X <= 0 ].

modular(50):   X mod Y mod Z = X mod Y may_be_deduced_from
                                            [ 0 <= B, B < Y, Y <= Z, X = A*Y + B ].
modular(51):   X mod Y mod Z = X mod Y may_be_deduced_from
                                            [ Z <= Y, Y < B, B <= 0, X = A*Y + B ].

modular(52):   X mod Y mod Z = X mod Z may_be_deduced_from
                             [ X = A * Y + B, B = C * Z + D, Y = Z * E,
                               0 <= B, B < Y,  0 <= D, D < Z ].

modular(53):   X mod Y mod Z = X mod Z may_be_deduced_from
                             [ X = A * Y + B, B = C * Z + D, Y = Z * E,
                               0 <= B, B < Y,  D <= 0, Z < D ].

modular(54):   X mod Y mod Z = X mod Z may_be_deduced_from
                             [ X = A * Y + B, B = C * Z + D, Y = Z * E,
                               B <= 0, Y < B,  0 <= D, D < Z ].

modular(55):   X mod Y mod Z = X mod Z may_be_deduced_from
                             [ X = A * Y + B, B = C * Z + D, Y = Z * E,
                               B <= 0, Y < B,  D <= 0, Z < 0 ].

modular(60):   X mod Y = -((-X) mod (-Y)) may_be_deduced_from
                                            [ 0 <= B, B < Y, X = A * Y + B ].
modular(61):   X mod Y = -((-X) mod (-Y)) may_be_deduced_from
                                            [ Y < B, B <= 0, X = A * Y + B ].
