             %%%%%%%%%%%%%%%%%%%%%%%%%%%% 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_1(I)+c_1(I) = d_1(I) , 0<=I<b+1 .

d_1(I) :- bits3(I),   
         p_1(I), not c_1(I), not q_1(I). 
d_1(I) :- bits3(I),   
         not p_1(I), c_1(I), not q_1(I). 
d_1(I) :- bits3(I),   
         not p_1(I), not c_1(I), q_1(I). 
d_1(I) :- bits3(I),   
         p_1(I), c_1(I), q_1(I). 
 
false :- q_1(0). 
 
q_1(I+1) :- bits3(I),   
             p_1(I), c_1(I). 
q_1(I+1) :- bits3(I),   
             p_1(I), not c_1(I), q_1(I). 
q_1(I+1) :- bits3(I),   
             not p_1(I), c_1(I), q_1(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_1(I)+e(I) = x_1(I) ,  0<=I<b+1 .
%% Il vettore "e" rappresenta il complemento a due di "n".

x_1(I) :- bits3(I),   
         d_1(I), not e(I), not u_1(I). 
x_1(I) :- bits3(I),   
         not d_1(I), e(I), not u_1(I). 
x_1(I) :- bits3(I),   
         not d_1(I), not e(I), u_1(I). 
x_1(I) :- bits3(I),   
         d_1(I), e(I), u_1(I). 
 
false :- u_1(0). 
 
u_1(I+1) :- bits3(I),   
             d_1(I), e(I). 
u_1(I+1) :- bits3(I),   
             d_1(I), not e(I), u_1(I). 
u_1(I+1) :- bits3(I),   
             not d_1(I), e(I), u_1(I). 



%% Il vettore m rappresenta il risultato di "f*f mod n".  
%% x_1(b)=sign bit=1 -> zero_1=0 ->  m_1(I)=d_1(I) ,  0<=I<b .
%% x_1(b)=sign bit=0 -> zero_1=1 ->  m_1(I)=x_1(I)=d_1(I)+e(I)=d_1(I)-n(I) ,  0<=I<b .

m_1(I) :- bits1(I),  
         x_1(I), zero_1. 
m_1(I) :- bits1(I),   
         d_1(I), not zero_1. 

zero_1:- not x_1(b).



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

p_1(0) :- g_1(0,0). 
p_1(I) :- bits1(I),I>0, 
          s_1(I-1,0). 
p_1(I+range1) :- bits1(I),   I<=(range1-2), 
               s_1(range1-1,I). 
p_1(2*range1-1) :- h_1(range1-1,range1-2). 

g_1(I,J) :- bits1(I), bits1(J), 
                   m(I), f(J). 
 
s_1(0,J) :- bits1(J),  J<(range1-1), 
             g_1(0,J+1), not g_1(J+1,0). 
s_1(0,J) :- bits1(J), J<(range1-1), 
             g_1(J+1,0), not g_1(0,J+1). 
 
s_1(I,J) :- bits1(I), bits1(J), I>0, I<=(range1-2),J<=(range1-3),
            h_1(I-1,J), not s_1(I-1,J+1), not g_1(J+1,I). 
s_1(I,J) :- bits1(I), bits1(J), I>0,  I<=(range1-2),J<=(range1-3),
            not h_1(I-1,J), s_1(I-1,J+1), not g_1(J+1,I). 
s_1(I,J) :- bits1(I), bits1(J), I>0, I<=(range1-2),J<=(range1-3),
            not h_1(I-1,J), not s_1(I-1,J+1), g_1(J+1,I). 
s_1(I,J) :- bits1(I), bits1(J), I>0,  I<=(range1-2),J<=(range1-3),
            h_1(I-1,J), s_1(I-1,J+1), g_1(J+1,I). 

s_1(I,range1-2) :- bits1(I), I>0, I<=(range1-2),
                 h_1(I-1,range1-2), not g_1(I,range1-1), not g_1(range1-1,I). 
s_1(I,range1-2) :- bits1(I),  I>0, I<=(range1-2),
                 not h_1(I-1,range1-2), g_1(I,range1-1), not g_1(range1-1,I). 
s_1(I,range1-2) :- bits1(I), I>0, I<=(range1-2), 
                 not h_1(I-1,range1-2), not g_1(I,range1-1), g_1(range1-1,I). 
s_1(I,range1-2) :- bits1(I), I>0, I<=(range1-2),
                 h_1(I-1,range1-2), g_1(I,range1-1), g_1(range1-1,I). 

s_1(range1-1,0) :- h_1(range1-2,0), not s_1(range1-2,1). 
s_1(range1-1,0) :- not h_1(range1-2,0), s_1(range1-2,1).

s_1(range1-1,J) :- bits1(J),  J>0, J!=(range1-2),
                 h_1(range1-2,J), not s_1(range1-2,J+1), not h_1(range1-1,J-1). 
s_1(range1-1,J) :- bits1(J),  J>0, J!=(range1-2), 
                 not h_1(range1-2,J), s_1(range1-2,J+1), not h_1(range1-1,J-1). 
s_1(range1-1,J) :- bits1(J),   J>0, J!=(range1-2),
                 not h_1(range1-2,J), not s_1(range1-2,J+1), h_1(range1-1,J-1). 
s_1(range1-1,J) :- bits1(J),   J>0, J!=(range1-2),
                 h_1(range1-2,J), s_1(range1-2,J+1), h_1(range1-1,J-1). 
 
s_1(range1-1,range1-2) :- h_1(range1-2,range1-2), not g_1(range1-1,range1-1), not h_1(range1-1,range1-3). 
s_1(range1-1,range1-2) :- not h_1(range1-2,range1-2), g_1(range1-1,range1-1), not h_1(range1-1,range1-3).
s_1(range1-1,range1-2) :- not h_1(range1-2,range1-2), not g_1(range1-1,range1-1), h_1(range1-1,range1-3). 
s_1(range1-1,range1-2) :- h_1(range1-2,range1-2), g_1(range1-1,range1-1), h_1(range1-1,range1-3). 

h_1(0,J) :- bits1(J),  J<=(range1-2), 
             g_1(0,J+1), g_1(J+1,0).
 
h_1(I+1,J) :- bits1(I), bits1(J), I<range1-2, J<range1-2,
                 g_1(J+1,I+1), h_1(I,J). 
h_1(I+1,J) :- bits1(I), bits1(J), I<range1-2,J<range1-2,
                 g_1(J+1,I+1), s_1(I,J+1).
h_1(I+1,J) :- bits1(I), bits1(J), I<range1-2,J<range1-2,
                 h_1(I,J), s_1(I,J+1). 

h_1(I,range1-2) :- bits1(I), I>0, I<=(range1-2),
            h_1(I-1,range1-2), g_1(I,range1-1).
h_1(I,range1-2) :- bits1(I), I>0, I<=(range1-2),
            h_1(I-1,range1-2), g_1(range1-1,I). 
h_1(I,range1-2) :- bits1(I), I>0, I<=(range1-2),
            g_1(I,range1-1), g_1(range1-1,I). 

h_1(range1-1,0) :- h_1(range1-2,0), s_1(range1-2,1).

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

h_1(range1-1,range1-2) :- h_1(range1-2,range1-2), g_1(range1-1,range1-1). 
h_1(range1-1,range1-2) :- h_1(range1-2,range1-2), h_1(range1-1,range1-3).
h_1(range1-1,range1-2) :- g_1(range1-1,range1-1), h_1(range1-1,range1-3). 


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

l_1(I,J) :- bits2(I),bits2(J), 
                   p_1(I), t(J).
 
r_1(0) :- l_1(0,0).
r_1(I) :- bits2(I), I>0, 
          w_1(I-1,0).
r_1(I+range2) :- bits2(I), I<=b,
               w_1(range2-1,I). 

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

w_1(0,J) :- bits2(J), J<(range2-1),  
             l_1(0,J+1), not l_1(J+1,0). 
w_1(0,J) :- bits2(J), J<(range2-1),  
             l_1(J+1,0), not l_1(0,J+1). 
 
w_1(I,J) :- bits2(I), bits2(J), I>0, I<=(range2-2), J<=(range2-3),
             v_1(I-1,J), not w_1(I-1,J+1), not l_1(J+1,I). 
w_1(I,J) :- bits2(I),bits2(J), I>0, I<=(range2-2), J<=(range2-3),
            not v_1(I-1,J), w_1(I-1,J+1), not l_1(J+1,I). 
w_1(I,J) :- bits2(I),bits2(J), I>0, I<=(range2-2), J<=(range2-3), 
            not v_1(I-1,J), not w_1(I-1,J+1), l_1(J+1,I). 
w_1(I,J) :- bits2(I),bits2(J), I>0, I<=(range2-2), J<=(range2-3),
            v_1(I-1,J), w_1(I-1,J+1), l_1(J+1,I). 

w_1(I,range2-2) :- bits2(I), I>0, I<=(range2-2),
                 v_1(I-1,range2-2), not l_1(I,range2-1), not l_1(range2-1,I). 
w_1(I,range2-2) :- bits2(I),  I>0, I<=(range2-2),
                 not v_1(I-1,range2-2), l_1(I,range2-1), not l_1(range2-1,I). 
w_1(I,range2-2) :- bits2(I), I>0, I<=(range2-2), 
                 not v_1(I-1,range2-2), not l_1(I,range2-1), l_1(range2-1,I). 
w_1(I,range2-2) :- bits2(I), I>0, I<=(range2-2),
                 v_1(I-1,range2-2), l_1(I,range2-1), l_1(range2-1,I). 

w_1(range2-1,0) :- v_1(range2-2,0), not w_1(range2-2,1). 
w_1(range2-1,0) :- not v_1(range2-2,0), w_1(range2-2,1).

w_1(range2-1,J) :- bits2(J),  J>0, J!=(range2-2),
                 v_1(range2-2,J), not w_1(range2-2,J+1), not v_1(range2-1,J-1). 
w_1(range2-1,J) :- bits2(J),  J>0, J!=(range2-2), 
                 not v_1(range2-2,J), w_1(range2-2,J+1), not v_1(range2-1,J-1). 
w_1(range2-1,J) :- bits2(J),   J>0, J!=(range2-2),
                 not v_1(range2-2,J), not w_1(range2-2,J+1), v_1(range2-1,J-1). 
w_1(range2-1,J) :- bits2(J),   J>0, J!=(range2-2),
                 v_1(range2-2,J), w_1(range2-2,J+1), v_1(range2-1,J-1). 
 
w_1(range2-1,range2-2) :- v_1(range2-2,range2-2), not l_1(range2-1,range2-1), not v_1(range2-1,range2-3). 
w_1(range2-1,range2-2) :- not v_1(range2-2,range2-2), l_1(range2-1,range2-1), not v_1(range2-1,range2-3).
w_1(range2-1,range2-2) :- not v_1(range2-2,range2-2), not l_1(range2-1,range2-1), v_1(range2-1,range2-3). 
w_1(range2-1,range2-2) :- v_1(range2-2,range2-2), l_1(range2-1,range2-1), v_1(range2-1,range2-3). 

v_1(0,J) :- bits2(J),  J<=(range2-2), 
             l_1(0,J+1), l_1(J+1,0).
 
v_1(I+1,J) :- bits2(I), bits2(J), I<range2-2, J<range2-2,
                 l_1(J+1,I+1), v_1(I,J). 
v_1(I+1,J) :- bits2(I), bits2(J), I<range2-2,J<range2-2,
                 l_1(J+1,I+1), w_1(I,J+1).
v_1(I+1,J) :- bits2(I), bits2(J), I<range2-2,J<range2-2,
                 v_1(I,J), w_1(I,J+1). 

v_1(I,range2-2) :- bits2(I), I>0, I<=(range2-2),
            v_1(I-1,range2-2), l_1(I,range2-1).
v_1(I,range2-2) :- bits2(I), I>0, I<=(range2-2),
            v_1(I-1,range2-2), l_1(range2-1,I). 
v_1(I,range2-2) :- bits2(I), I>0, I<=(range2-2),
            l_1(I,range2-1), l_1(range2-1,I). 

v_1(range2-1,0) :- v_1(range2-2,0), w_1(range2-2,1).

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

v_1(range2-1,range2-2) :- v_1(range2-2,range2-2), l_1(range2-1,range2-1). 
v_1(range2-1,range2-2) :- v_1(range2-2,range2-2), v_1(range2-1,range2-3).
v_1(range2-1,range2-2) :- l_1(range2-1,range2-1), v_1(range2-1,range2-3). 



k_1(I) :- bits3(I), 
          r_1(I+(2*b)). 
 


%% MUL3 : k_1(I)*e(I) = c_1(I) , 0<=I<b+1 .

c_1(0) :- i_1(0,0). 
c_1(I) :-bits3(I), I>0, 
          z_1(I-1,0).
c_1(I+range3) :-bits3(I), I<=(range3-2), z_1(range3-1,I). 
c_1(2*range3-1) :- a_1(range3-1,range3-2).

i_1(I,J) :-bits3(I),bits3(J),
                   k_1(I), e(J).

z_1(0,J) :- bits3(J),  J<(range3-1), 
             i_1(0,J+1), not i_1(J+1,0). 
z_1(0,J) :- bits3(J), J<(range3-1), 
             i_1(J+1,0), not i_1(0,J+1). 
 
z_1(I,J) :- bits3(I), bits3(J), I>0, I<=(range3-2),J<=(range3-3),
            a_1(I-1,J), not z_1(I-1,J+1), not i_1(J+1,I). 
z_1(I,J) :- bits3(I), bits3(J), I>0,  I<=(range3-2),J<=(range3-3),
            not a_1(I-1,J), z_1(I-1,J+1), not i_1(J+1,I). 
z_1(I,J) :- bits3(I), bits3(J), I>0, I<=(range3-2),J<=(range3-3),
            not a_1(I-1,J), not z_1(I-1,J+1), i_1(J+1,I). 
z_1(I,J) :- bits3(I), bits3(J), I>0,  I<=(range3-2),J<=(range3-3),
            a_1(I-1,J), z_1(I-1,J+1), i_1(J+1,I). 

z_1(I,range3-2) :- bits3(I), I>0, I<=(range3-2),
                 a_1(I-1,range3-2), not i_1(I,range3-1), not i_1(range3-1,I). 
z_1(I,range3-2) :- bits3(I),  I>0, I<=(range3-2),
                 not a_1(I-1,range3-2), i_1(I,range3-1), not i_1(range3-1,I). 
z_1(I,range3-2) :- bits3(I), I>0, I<=(range3-2), 
                 not a_1(I-1,range3-2), not i_1(I,range3-1), i_1(range3-1,I). 
z_1(I,range3-2) :- bits3(I), I>0, I<=(range3-2),
                 a_1(I-1,range3-2), i_1(I,range3-1), i_1(range3-1,I). 

z_1(range3-1,0) :- a_1(range3-2,0), not z_1(range3-2,1). 
z_1(range3-1,0) :- not a_1(range3-2,0), z_1(range3-2,1).

z_1(range3-1,J) :- bits3(J),  J>0, J!=(range3-2),
                 a_1(range3-2,J), not z_1(range3-2,J+1), not a_1(range3-1,J-1). 
z_1(range3-1,J) :- bits3(J),  J>0, J!=(range3-2), 
                 not a_1(range3-2,J), z_1(range3-2,J+1), not a_1(range3-1,J-1). 
z_1(range3-1,J) :- bits3(J),   J>0, J!=(range3-2),
                 not a_1(range3-2,J), not z_1(range3-2,J+1), a_1(range3-1,J-1). 
z_1(range3-1,J) :- bits3(J),   J>0, J!=(range3-2),
                 a_1(range3-2,J), z_1(range3-2,J+1), a_1(range3-1,J-1). 
 
z_1(range3-1,range3-2) :- a_1(range3-2,range3-2), not i_1(range3-1,range3-1), not a_1(range3-1,range3-3). 
z_1(range3-1,range3-2) :- not a_1(range3-2,range3-2), i_1(range3-1,range3-1), not a_1(range3-1,range3-3).
z_1(range3-1,range3-2) :- not a_1(range3-2,range3-2), not i_1(range3-1,range3-1), a_1(range3-1,range3-3). 
z_1(range3-1,range3-2) :- a_1(range3-2,range3-2), i_1(range3-1,range3-1), a_1(range3-1,range3-3). 

a_1(0,J) :- bits3(J),  J<=(range3-2), 
             i_1(0,J+1), i_1(J+1,0).
 
a_1(I+1,J) :- bits3(I), bits3(J), I<range3-2, J<range3-2,
                 i_1(J+1,I+1), a_1(I,J). 
a_1(I+1,J) :- bits3(I), bits3(J), I<range3-2,J<range3-2,
                 i_1(J+1,I+1), z_1(I,J+1).
a_1(I+1,J) :- bits3(I), bits3(J), I<range3-2,J<range3-2,
                 a_1(I,J), z_1(I,J+1). 

a_1(I,range3-2) :- bits3(I), I>0, I<=(range3-2),
            a_1(I-1,range3-2), i_1(I,range3-1).
a_1(I,range3-2) :- bits3(I), I>0, I<=(range3-2),
            a_1(I-1,range3-2), i_1(range3-1,I). 
a_1(I,range3-2) :- bits3(I), I>0, I<=(range3-2),
            i_1(I,range3-1), i_1(range3-1,I). 

a_1(range3-1,0) :- a_1(range3-2,0), z_1(range3-2,1).

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

a_1(range3-1,range3-2) :- a_1(range3-2,range3-2), i_1(range3-1,range3-1). 
a_1(range3-1,range3-2) :- a_1(range3-2,range3-2), a_1(range3-1,range3-3).
a_1(range3-1,range3-2) :- i_1(range3-1,range3-1), a_1(range3-1,range3-3). 






compute 1 {not false}.
