             %%%%%%%%%%%%%%%%%%%%%%%%%%%% CODIFICA %%%%%%%%%%%%%%%%%%%%%%%%%%%%


%% In questo file e' contenuta la codifica dell'operazione modulare "f*f mod n"
%% nel linguaggio accettato da Lparse, il front-end utilizzato per Smodels.
%% La struttura del moltiplicatore modulare, a cui si e' fatto riferimento, e' 
%% basata sul nuovo metodo di calcolo del prodotto modulare, proposto da 
%% Giuseppe Alia ed Enrico Martinelli.


%% Definizione dei dominii

const range1 = b.
const range2 =(2*b).
const range3 =(b+1).

bits1(0..range1-1).
bits2(0..range2-1).
bits3(0..range3-1).

%% ADD1 : p(I)+c(I) = d(I) , 0<=I<b+1 .

d(I) :- bits3(I),   
         p(I), not c(I), not q(I). 
d(I) :- bits3(I),   
         not p(I), c(I), not q(I). 
d(I) :- bits3(I),   
         not p(I), not c(I), q(I). 
d(I) :- bits3(I),   
         p(I), c(I), q(I). 
 
false :- q(0). 
 
q(I+1) :- bits3(I),   
             p(I), c(I). 
q(I+1) :- bits3(I),   
             p(I), not c(I), q(I). 
q(I+1) :- bits3(I),   
             not p(I), c(I), q(I). 

 
%% Test atto a verificare che il numero rappresentato dal vettore d sia minore
%% di n: in caso contrario sara' necessario sottrarvi n.
%% ADD2 : d(I)+e(I) = x(I) ,  0<=I<b+1 .
%% Il vettore "e" rappresenta il complemento a due di "n".

x(I) :- bits3(I),   
         d(I), not e(I), not u(I). 
x(I) :- bits3(I),   
         not d(I), e(I), not u(I). 
x(I) :- bits3(I),   
         not d(I), not e(I), u(I). 
x(I) :- bits3(I),   
         d(I), e(I), u(I). 
 
false :- u(0). 
 
u(I+1) :- bits3(I),   
             d(I), e(I). 
u(I+1) :- bits3(I),   
             d(I), not e(I), u(I). 
u(I+1) :- bits3(I),   
             not d(I), e(I), u(I). 

%% Il vettore m rappresenta il risultato di "f*f mod n".  
%% x(b)=sign bit=1 -> zero=0 ->  m(I)=d(I) ,  0<=I<b .
%% x(b)=sign bit=0 -> zero=1 ->  m(I)=x(I)=d(I)+e(I)=d(I)-n(I)  ,  0<=I<b .
 
m(I) :- bits1(I),  
         x(I), zero. 
m(I) :- bits1(I),   
         d(I), not zero. 

zero:- not x(b).

%% MUL1 : f(I)*f(I) = p(I) , 0<=I<b .

p(0) :- g(0,0). 
p(I) :- bits1(I),I>0, 
          s(I-1,0). 
p(I+range1) :- bits1(I),   I<=(range1-2), 
               s(range1-1,I). 
p(2*range1-1) :- h(range1-1,range1-2). 

g(I,J) :- bits1(I), bits1(J), 
                   f(I), f(J). 
 
s(0,J) :- bits1(J),  J<(range1-1), 
             g(0,J+1), not g(J+1,0). 
s(0,J) :- bits1(J), J<(range1-1), 
             g(J+1,0), not g(0,J+1). 
 
s(I,J) :- bits1(I), bits1(J), I>0, I<=(range1-2),J<=(range1-3),
            h(I-1,J), not s(I-1,J+1), not g(J+1,I). 
s(I,J) :- bits1(I), bits1(J), I>0,  I<=(range1-2),J<=(range1-3),
            not h(I-1,J), s(I-1,J+1), not g(J+1,I). 
s(I,J) :- bits1(I), bits1(J), I>0, I<=(range1-2),J<=(range1-3),
            not h(I-1,J), not s(I-1,J+1), g(J+1,I). 
s(I,J) :- bits1(I), bits1(J), I>0,  I<=(range1-2),J<=(range1-3),
            h(I-1,J), s(I-1,J+1), g(J+1,I). 

s(I,range1-2) :- bits1(I), I>0, I<=(range1-2),
                 h(I-1,range1-2), not g(I,range1-1), not g(range1-1,I). 
s(I,range1-2) :- bits1(I),  I>0, I<=(range1-2),
                 not h(I-1,range1-2), g(I,range1-1), not g(range1-1,I). 
s(I,range1-2) :- bits1(I), I>0, I<=(range1-2), 
                 not h(I-1,range1-2), not g(I,range1-1), g(range1-1,I). 
s(I,range1-2) :- bits1(I), I>0, I<=(range1-2),
                 h(I-1,range1-2), g(I,range1-1), g(range1-1,I). 

s(range1-1,0) :- h(range1-2,0), not s(range1-2,1). 
s(range1-1,0) :- not h(range1-2,0), s(range1-2,1).

s(range1-1,J) :- bits1(J),  J>0, J!=(range1-2),
                 h(range1-2,J), not s(range1-2,J+1), not h(range1-1,J-1). 
s(range1-1,J) :- bits1(J),  J>0, J!=(range1-2), 
                 not h(range1-2,J), s(range1-2,J+1), not h(range1-1,J-1). 
s(range1-1,J) :- bits1(J),   J>0, J!=(range1-2),
                 not h(range1-2,J), not s(range1-2,J+1), h(range1-1,J-1). 
s(range1-1,J) :- bits1(J),   J>0, J!=(range1-2),
                 h(range1-2,J), s(range1-2,J+1), h(range1-1,J-1). 
 
s(range1-1,range1-2) :- h(range1-2,range1-2), not g(range1-1,range1-1), not h(range1-1,range1-3). 
s(range1-1,range1-2) :- not h(range1-2,range1-2), g(range1-1,range1-1), not h(range1-1,range1-3).
s(range1-1,range1-2) :- not h(range1-2,range1-2), not g(range1-1,range1-1), h(range1-1,range1-3). 
s(range1-1,range1-2) :- h(range1-2,range1-2), g(range1-1,range1-1), h(range1-1,range1-3). 

h(0,J) :- bits1(J),  J<=(range1-2), 
             g(0,J+1), g(J+1,0).
 
h(I+1,J) :- bits1(I), bits1(J), I<range1-2, J<range1-2,
                 g(J+1,I+1), h(I,J). 
h(I+1,J) :- bits1(I), bits1(J), I<range1-2,J<range1-2,
                 g(J+1,I+1), s(I,J+1).
h(I+1,J) :- bits1(I), bits1(J), I<range1-2,J<range1-2,
                 h(I,J), s(I,J+1). 

h(I,range1-2) :- bits1(I), I>0, I<=(range1-2),
            h(I-1,range1-2), g(I,range1-1).
h(I,range1-2) :- bits1(I), I>0, I<=(range1-2),
            h(I-1,range1-2), g(range1-1,I). 
h(I,range1-2) :- bits1(I), I>0, I<=(range1-2),
            g(I,range1-1), g(range1-1,I). 

h(range1-1,0) :- h(range1-2,0), s(range1-2,1).

h(range1-1,J) :- bits1(J),  J>0, J!=(range1-2),
            h(range1-2,J), s(range1-2,J+1).
h(range1-1,J) :- bits1(J),  J>0, J!=(range1-2),
            h(range1-2,J), h(range1-1,J-1).
h(range1-1,J) :- bits1(J),  J>0, J!=(range1-2),
            s(range1-2,J+1), h(range1-1,J-1).

h(range1-1,range1-2) :- h(range1-2,range1-2), g(range1-1,range1-1). 
h(range1-1,range1-2) :- h(range1-2,range1-2), h(range1-1,range1-3).
h(range1-1,range1-2) :- g(range1-1,range1-1), h(range1-1,range1-3). 


 
%% MUL2 : p(I)*t(I) = r(I) , 0<=I<2*b .
%% Il vettore "t", fornito in input, rappresenta "1/n", troncato ai primi 2*b
%% bits.

l(I,J) :- bits2(I),bits2(J), 
                   p(I), t(J).
 
r(0) :- l(0,0).
r(I) :- bits2(I), I>0, 
          w(I-1,0).
r(I+range2) :- bits2(I), I<=b,
               w(range2-1,I). 

false :- bits2(I), I>=((3*b)+1), 
           r(I).  

w(0,J) :- bits2(J), J<(range2-1),  
             l(0,J+1), not l(J+1,0). 
w(0,J) :- bits2(J), J<(range2-1),  
             l(J+1,0), not l(0,J+1). 
 
w(I,J) :- bits2(I), bits2(J), I>0, I<=(range2-2), J<=(range2-3),
             v(I-1,J), not w(I-1,J+1), not l(J+1,I). 
w(I,J) :- bits2(I),bits2(J), I>0, I<=(range2-2), J<=(range2-3),
            not v(I-1,J), w(I-1,J+1), not l(J+1,I). 
w(I,J) :- bits2(I),bits2(J), I>0, I<=(range2-2), J<=(range2-3), 
            not v(I-1,J), not w(I-1,J+1), l(J+1,I). 
w(I,J) :- bits2(I),bits2(J), I>0, I<=(range2-2), J<=(range2-3),
            v(I-1,J), w(I-1,J+1), l(J+1,I). 

w(I,range2-2) :- bits2(I), I>0, I<=(range2-2),
                 v(I-1,range2-2), not l(I,range2-1), not l(range2-1,I). 
w(I,range2-2) :- bits2(I),  I>0, I<=(range2-2),
                 not v(I-1,range2-2), l(I,range2-1), not l(range2-1,I). 
w(I,range2-2) :- bits2(I), I>0, I<=(range2-2), 
                 not v(I-1,range2-2), not l(I,range2-1), l(range2-1,I). 
w(I,range2-2) :- bits2(I), I>0, I<=(range2-2),
                 v(I-1,range2-2), l(I,range2-1), l(range2-1,I). 

w(range2-1,0) :- v(range2-2,0), not w(range2-2,1). 
w(range2-1,0) :- not v(range2-2,0), w(range2-2,1).

w(range2-1,J) :- bits2(J),  J>0, J!=(range2-2),
                 v(range2-2,J), not w(range2-2,J+1), not v(range2-1,J-1). 
w(range2-1,J) :- bits2(J),  J>0, J!=(range2-2), 
                 not v(range2-2,J), w(range2-2,J+1), not v(range2-1,J-1). 
w(range2-1,J) :- bits2(J),   J>0, J!=(range2-2),
                 not v(range2-2,J), not w(range2-2,J+1), v(range2-1,J-1). 
w(range2-1,J) :- bits2(J),   J>0, J!=(range2-2),
                 v(range2-2,J), w(range2-2,J+1), v(range2-1,J-1). 
 
w(range2-1,range2-2) :- v(range2-2,range2-2), not l(range2-1,range2-1), not v(range2-1,range2-3). 
w(range2-1,range2-2) :- not v(range2-2,range2-2), l(range2-1,range2-1), not v(range2-1,range2-3).
w(range2-1,range2-2) :- not v(range2-2,range2-2), not l(range2-1,range2-1), v(range2-1,range2-3). 
w(range2-1,range2-2) :- v(range2-2,range2-2), l(range2-1,range2-1), v(range2-1,range2-3). 

v(0,J) :- bits2(J),  J<=(range2-2), 
             l(0,J+1), l(J+1,0).
 
v(I+1,J) :- bits2(I), bits2(J), I<range2-2, J<range2-2,
                 l(J+1,I+1), v(I,J). 
v(I+1,J) :- bits2(I), bits2(J), I<range2-2,J<range2-2,
                 l(J+1,I+1), w(I,J+1).
v(I+1,J) :- bits2(I), bits2(J), I<range2-2,J<range2-2,
                 v(I,J), w(I,J+1). 

v(I,range2-2) :- bits2(I), I>0, I<=(range2-2),
            v(I-1,range2-2), l(I,range2-1).
v(I,range2-2) :- bits2(I), I>0, I<=(range2-2),
            v(I-1,range2-2), l(range2-1,I). 
v(I,range2-2) :- bits2(I), I>0, I<=(range2-2),
            l(I,range2-1), l(range2-1,I). 

v(range2-1,0) :- v(range2-2,0), w(range2-2,1).

v(range2-1,J) :- bits2(J),  J>0, J!=(range2-2),
            v(range2-2,J), w(range2-2,J+1).
v(range2-1,J) :- bits2(J),  J>0, J!=(range2-2),
            v(range2-2,J), v(range2-1,J-1).
v(range2-1,J) :- bits2(J),  J>0, J!=(range2-2),
            w(range2-2,J+1), v(range2-1,J-1).

v(range2-1,range2-2) :- v(range2-2,range2-2), l(range2-1,range2-1). 
v(range2-1,range2-2) :- v(range2-2,range2-2), v(range2-1,range2-3).
v(range2-1,range2-2) :- l(range2-1,range2-1), v(range2-1,range2-3). 

k(I) :- bits3(I), 
          r(I+(2*b)). 
 
%% MUL3 : k(I)*e(I) = c(I) , 0<=I<b+1 .

c(0) :- i(0,0). 
c(I) :-bits3(I), I>0, 
          z(I-1,0).
c(I+range3) :-bits3(I), I<=(range3-2), z(range3-1,I). 
c(2*range3-1) :- a(range3-1,range3-2).

i(I,J) :-bits3(I),bits3(J),
                   k(I), e(J).

z(0,J) :- bits3(J),  J<(range3-1), 
             i(0,J+1), not i(J+1,0). 
z(0,J) :- bits3(J), J<(range3-1), 
             i(J+1,0), not i(0,J+1). 
 
z(I,J) :- bits3(I), bits3(J), I>0, I<=(range3-2),J<=(range3-3),
            a(I-1,J), not z(I-1,J+1), not i(J+1,I). 
z(I,J) :- bits3(I), bits3(J), I>0,  I<=(range3-2),J<=(range3-3),
            not a(I-1,J), z(I-1,J+1), not i(J+1,I). 
z(I,J) :- bits3(I), bits3(J), I>0, I<=(range3-2),J<=(range3-3),
            not a(I-1,J), not z(I-1,J+1), i(J+1,I). 
z(I,J) :- bits3(I), bits3(J), I>0,  I<=(range3-2),J<=(range3-3),
            a(I-1,J), z(I-1,J+1), i(J+1,I). 

z(I,range3-2) :- bits3(I), I>0, I<=(range3-2),
                 a(I-1,range3-2), not i(I,range3-1), not i(range3-1,I). 
z(I,range3-2) :- bits3(I),  I>0, I<=(range3-2),
                 not a(I-1,range3-2), i(I,range3-1), not i(range3-1,I). 
z(I,range3-2) :- bits3(I), I>0, I<=(range3-2), 
                 not a(I-1,range3-2), not i(I,range3-1), i(range3-1,I). 
z(I,range3-2) :- bits3(I), I>0, I<=(range3-2),
                 a(I-1,range3-2), i(I,range3-1), i(range3-1,I). 

z(range3-1,0) :- a(range3-2,0), not z(range3-2,1). 
z(range3-1,0) :- not a(range3-2,0), z(range3-2,1).

z(range3-1,J) :- bits3(J),  J>0, J!=(range3-2),
                 a(range3-2,J), not z(range3-2,J+1), not a(range3-1,J-1). 
z(range3-1,J) :- bits3(J),  J>0, J!=(range3-2), 
                 not a(range3-2,J), z(range3-2,J+1), not a(range3-1,J-1). 
z(range3-1,J) :- bits3(J),   J>0, J!=(range3-2),
                 not a(range3-2,J), not z(range3-2,J+1), a(range3-1,J-1). 
z(range3-1,J) :- bits3(J),   J>0, J!=(range3-2),
                 a(range3-2,J), z(range3-2,J+1), a(range3-1,J-1). 
 
z(range3-1,range3-2) :- a(range3-2,range3-2), not i(range3-1,range3-1), not a(range3-1,range3-3). 
z(range3-1,range3-2) :- not a(range3-2,range3-2), i(range3-1,range3-1), not a(range3-1,range3-3).
z(range3-1,range3-2) :- not a(range3-2,range3-2), not i(range3-1,range3-1), a(range3-1,range3-3). 
z(range3-1,range3-2) :- a(range3-2,range3-2), i(range3-1,range3-1), a(range3-1,range3-3). 

a(0,J) :- bits3(J),  J<=(range3-2), 
             i(0,J+1), i(J+1,0).
 
a(I+1,J) :- bits3(I), bits3(J), I<range3-2, J<range3-2,
                 i(J+1,I+1), a(I,J). 
a(I+1,J) :- bits3(I), bits3(J), I<range3-2,J<range3-2,
                 i(J+1,I+1), z(I,J+1).
a(I+1,J) :- bits3(I), bits3(J), I<range3-2,J<range3-2,
                 a(I,J), z(I,J+1). 

a(I,range3-2) :- bits3(I), I>0, I<=(range3-2),
            a(I-1,range3-2), i(I,range3-1).
a(I,range3-2) :- bits3(I), I>0, I<=(range3-2),
            a(I-1,range3-2), i(range3-1,I). 
a(I,range3-2) :- bits3(I), I>0, I<=(range3-2),
            i(I,range3-1), i(range3-1,I). 

a(range3-1,0) :- a(range3-2,0), z(range3-2,1).

a(range3-1,J) :- bits3(J),  J>0, J!=(range3-2),
            a(range3-2,J), z(range3-2,J+1).
a(range3-1,J) :- bits3(J),  J>0, J!=(range3-2),
            a(range3-2,J), a(range3-1,J-1).
a(range3-1,J) :- bits3(J),  J>0, J!=(range3-2),
            z(range3-2,J+1), a(range3-1,J-1).

a(range3-1,range3-2) :- a(range3-2,range3-2), i(range3-1,range3-1). 
a(range3-1,range3-2) :- a(range3-2,range3-2), a(range3-1,range3-3).
a(range3-1,range3-2) :- i(range3-1,range3-1), a(range3-1,range3-3). 

compute 1{not false}.
