sl2p.sa
Generated by gen_html_sa_files from ICSI. Contact gomes@icsi.berkeley.edu for details
class SL2P < $IS_LT{SL2P},$STR,$HASH
class SL2P < $IS_LT{SL2P},$STR,$HASH is
-- MAT2P with determinant=1.
include COMPARABLE;
include MAT2{FINITE_FIELD};
include MAT2_F2{FINITE_FIELD} inverse->inverse_mat;
include MAT2_PSL{FINITE_FIELD};
include MAT2P_ALG{FINITE_FIELD};
include MAT2_DIA_ORDER{FINITE_FIELD};
get_list:ARRAY{SAME} is
a:ARRAY{SAME}:=#; loop a:=a.append(|#SAME(0.int,1.int,-1,0.int).up_sl!|); end; return a;
end;
end;
class MAT2P < $IS_LT{MAT2P},$STR,$HASH
class MAT2P < $IS_LT{MAT2P},$STR,$HASH is
include COMPARABLE;
include MAT2{FINITE_FIELD};
include MAT2_F2{FINITE_FIELD};
include MAT2P_ALG{FINITE_FIELD};
end;
partial class MAT2P_ALG{ET}
partial class MAT2P_ALG{ET} is
-- assume thet ET is finite field F(p).
shared base:INT; -- prime
set_base(p:INT) is base:=#(p); ET::set_base(base); end;
create(a,b,c,d:INT):SAME is
res:SAME:=#; res.m[0][0]:=#(a); res.m[0][1]:=#(b); res.m[1][0]:=#(c); res.m[1][1]:=#(d);
return res;
end;
one:SAME is return #(1.int,0.int,0.int,1.int); end;
zero:SAME is return #(0.int,0.int,0.int,0.int); end;
hash:CARD is p::=m[0][0].p; return (((m[0][0].n*p+m[0][1].n)*p+m[1][0].n)*p+m[1][1].n).hash; end;
is_one:BOOL is
return m[0][0].is_one and m[0][1].is_zero and m[1][0].is_zero and m[1][1].is_one;
end;
times(i:INT):SAME is return self*(#ET(i)); end;
div(i:INT):SAME is return div(#ET(i)); end;
next_mat:SAME is
-- consist with is_lt
p00::=m[0][0]; p01::=m[0][1];
p10::=m[1][0]; p11::=m[1][1]+1.int;
if p11.is_zero then p10:=p10+1.int;
if p10.is_zero then p01:=p01+1.int;
if p01.is_zero then p00:=p00+1.int;
if p00.is_zero then return zero; end;
end;
end;
end;
return #(p00,p01,p10,p11);
end;
up_mat!:SAME is
res::=self;
loop yield res; res:=res.next_mat;
if res.is_zero then break!; end;
end;
end;
next_sl:SAME pre det.is_one is
-- ireturn (0,0:0,0) when end.
p00::=m[0][0]; p01::=m[0][1];
p10::=m[1][0]; p11::=m[1][1];
if p00.is_zero then
p11:=p11+1.int;
if p11.is_zero then p01:=p01+1.int;
if p01.is_zero then return #(1.int,0.int,0.int,1.int);
else return #(p00,p01,-p01.inverse,p11);
end;
else return #(p00,p01,p10,p11);
end;
else
p10:=p10+1;
if p10.is_zero then p01:=p01+1.int;
if p01.is_zero then p00:=p00+1.int;
if p00.is_zero then return zero; end;
end;
end;
return #(p00,p01,p10,(p01*p10+1.int)/p00);
end;
end;
up_sl!:SAME
pre det.is_one
post result.det.is_one
is
res::=self;
loop yield res; res:=res.next_sl;
if res.is_zero then break!; end;
end;
end;
end;
class SL2P_CNJ_CLS
class SL2P_CNJ_CLS is
-- list conjugate classes of SL2(p) in MAP2P.
attr cls:ARRAY{ARRAY{SL2P}}; -- conjugate class --> list of matrix
attr map:MAP{SL2P,CARD}; -- matrix --> conjugate class
private is_lt_mat(s1,s2:SL2P):BOOL is return s1.is_lt_dia(s2); end; --return s1.is_lt(s2);
private is_lt_cls(a1,a2:ARRAY{SL2P}):BOOL is return is_lt_mat(a1[0],a2[0]); end;
create:SAME is res:SAME:=new; res.set_cnj_cls; return res; end;
private set_cnj_cls is
list::=SL2P::get_list;
map:=#; loop map[list.elt!]:=0; end;
cls:=#; map_work::=map.copy;
loop k::=map.ind!;
if k.det.is_one.not then
#OUT+"set_cnj_cls: k="+k.str+"\n";
end;
if map_work.has_ind(k) then
cls:=cls.append(#ARRAY{SL2P}); ci::=cls.size-1;
loop
kl::=list.elt!;
c::=k.conjugate(kl);
if c.det.is_one.not then
#OUT+"set_cnj_cls: c="+c.str+"="+kl.str+"*"+k.str+"*"+kl.inverse.str+"\n";
end;
if map_work.has_ind(c) then
cls[ci]:=cls[ci].append(|c|); map_work.delete(c);
end;
end;
end;
end;
loop c::=cls.ind!; cls[c].insertion_sort_by(bind(is_lt_mat(_,_))); end;
cls.insertion_sort_by(bind(is_lt_cls(_,_)));
map:=#;
loop c::=cls.ind!; loop map[cls[c].elt!]:=c; end; end;
end;
str:STR is
s::="";
loop c::=cls.ind!;
s:=s+"class# "+c.str+" : ";
loop s:=s+" "+cls[c].elt!.str; end;
s:=s+"\n";
end;
return s;
end;
str(lib : LIBCHARS) : STR is return str; end;
end;
partial class MAT2_PSL{ET}
partial class MAT2_PSL{ET} is
-- assume that det=1.(Positive Special Linear)
inverse:SAME
--pre det.is_one
post times(result).is_one
is
return cofactor_matrix;
end;
end;
partial class MAT2_F2{ET}
partial class MAT2_F2{ET} is
-- ET is field
div(i:ET):SAME is return #(m[0][0]/i,m[0][1]/i,m[1][0]/i,m[1][1]/i); end;
inverse:SAME is return cofactor_matrix/det; end;
div(o:SAME):SAME is return self*(o.inverse); end;
conjugate(o:SAME):SAME is
-- o * self * o~
return o*self/o;
end;
conjugateR(o:SAME):SAME is
-- o~ * self * o
res::=o.inverse*self*o;
return o.inverse*self*o;
end;
end;
partial class MAT2_DIA_ORDER{ET}
partial class MAT2_DIA_ORDER{ET} is
-- alternate ordering with diagonal part preference.
-- Diagonal or Jordan form is less than others in the same conjugacy class.
is_lt_dia(o:SAME):BOOL is return compare_dia(o)=-1; end;
ET_compare_dia(e1,e2:ET):INT is
-- e1<e2 means near with zero.
e1a::=e1.abs; e2a::=e2.abs;
if e1a<e2a then return -1; elsif e1a>e2a then return 1.int;
elsif e1<e2 then return -1; elsif e1>e2 then return 1.int;
else return 0.int;
end;
end;
compare_dia(o:SAME):INT is
-- lexicographical order of [1][0], [0][1], [0][0], [1][1]
c::=ET_compare_dia(m[1][0],o.m[1][0]); if c.is_non_zero then return c; end;
c:=ET_compare_dia(m[0][1],o.m[0][1]); if c.is_non_zero then return c; end;
c:=ET_compare_dia(m[0][0],o.m[0][0]); if c.is_non_zero then return c; end;
c:=ET_compare_dia(m[1][1],o.m[1][1]);
return c;
end;
end;
partial class MAT2{ET}
partial class MAT2{ET} is
attr m:ARRAY{ARRAY{ET}};
aset(i1,i2:CARD,val:ET) is m[i1][i2]:=val; end;
aget(i1,i2:CARD):ET is return m[i1][i2]; end;
create:SAME is res:SAME:=new; res.m:=#(2); res.m[0]:=#(2); res.m[1]:=#(2); return res; end;
create(a,b,c,d:ET):SAME is
res:SAME:=#; res.m[0][0]:=a; res.m[0][1]:=b; res.m[1][0]:=c; res.m[1][1]:=d; return res;
end;
copy:SAME is return #(m[0][0].copy,m[0][1].copy,m[1][0].copy,m[1][1].copy); end;
is_eq(o:SAME):BOOL is
return (m[0][0]=o.m[0][0])and(m[0][1]=o.m[0][1])and(m[1][0]=o.m[1][0])and(m[1][1]=o.m[1][1]);
end;
is_zero:BOOL is
return m[0][0].is_zero and m[0][1].is_zero and m[1][0].is_zero and m[1][1].is_zero;
end;
is_lt(o:SAME):BOOL is
-- lexicographical order of [0][0], [0][1], [1][0], [1][1]
if m[0][0]<o.m[0][0] then return true; elsif m[0][0]>o.m[0][0] then return false;
elsif m[0][1]<o.m[0][1] then return true; elsif m[0][1]>o.m[0][1] then return false;
elsif m[1][0]<o.m[1][0] then return true; elsif m[1][0]>o.m[1][0] then return false;
elsif m[1][1]<o.m[1][1] then return true; elsif m[1][1]>o.m[1][1] then return false;
else return false;
end;
end;
str:STR is s::="("+m[0][0].str+", "+m[0][1].str+" : "+m[1][0].str+", "+m[1][1].str+")"; return s; end;
str(lib : LIBCHARS) : STR is return str; end;
det:ET is return m[0][0]*m[1][1]-m[1][0]*m[0][1]; end;
negate:SAME is return #(-m[0][0],-m[0][1],-m[1][0],-m[1][1]); end;
plus(o:SAME):SAME is
return #(m[0][0]+o.m[0][0],m[0][1]+o.m[0][1],m[1][0]+o.m[1][0],m[1][1]+o.m[1][1]);
end;
minus(o:SAME):SAME is
return #(m[0][0]-o.m[0][0],m[0][1]-o.m[0][1],m[1][0]-o.m[1][0],m[1][1]-o.m[1][1]);
end;
times(o:SAME):SAME is
return #(m[0][0]*o.m[0][0]+m[0][1]*o.m[1][0],m[0][0]*o.m[0][1]+m[0][1]*o.m[1][1],
m[1][0]*o.m[0][0]+m[1][1]*o.m[1][0],m[1][0]*o.m[0][1]+m[1][1]*o.m[1][1]);
end;
times(i:ET):SAME is return #(m[0][0]*i,m[0][1]*i,m[1][0]*i,m[1][1]*i); end;
cofactor_matrix:SAME is return #(m[1][1],-m[0][1],-m[1][0],m[0][0]); end;
end;
class TEST_MAT2P
class TEST_MAT2P is
include TEST;
test_mat2p is
class_name("MAT2P");
p:INT:=11.int;
MAT2P::set_base(p);
m,m1,m2:MAT2P;
m:=#(1.int,2.int,3.int,4.int);
test("create",m.str,"(1, 2 : 3, 4)");
test("negate",(-m).str,"(10, 9 : 8, 7)");
test("copy",(m.copy=m).str,"true");
test("det",m.det.str,"9");
m1:=#(2.int,3.int,4.int,5.int);
test("is_zero",(m1.is_zero).str,"false");
test("is_eq",(m1=m).str,"false");
test("is_eq",(m=m).str,"true");
test("is_lt",(m>m1).str,"false");
test("is_lt",(m<m1).str,"true");
test("plus",(m+m1).str,"(3, 5 : 7, 9)");
test("minus",(m1-m).str,"(1, 1 : 1, 1)");
test("times",(m*m1).str,"(10, 2 : 0, 7)");
test("times",(m*2.int).str,"(2, 4 : 6, 8)");
test("cofactor",m.cofactor_matrix.str,"(4, 9 : 8, 1)");
test("det.inverse",m.det.inverse.str,"5");
test("inverse",m.inverse.str,"(9, 1 : 7, 5)");
test("times inverse",(m*(m.inverse)).str,MAT2P::one.str);
test("div by int",(m/2.int).str,"(6, 1 : 7, 2)");
test("div times",((m/m1)*m1).str,m.str);
test("div times",(m/m1).str,"(7, 5 : 6, 6)");
finish;
end;
test_sl2p is
class_name("SL2P");
p:INT:=3.int;
m,m1,m2:SL2P;
SL2P::set_base(p);
m:=#(1.int,2.int,2.int,5.int);
#OUT+m.str+".up_mat!: det="+m.det.str+"\n"; #OUT.flush;
loop m1:=m.up_mat!;
#OUT+m1.str+"\n"; #OUT.flush;
end;
#OUT+m.str+".up_sl: det="+m.det.str+"\n"; #OUT.flush;
loop m1:=m.up_sl!; #OUT+m1.str+"\n"; #OUT.flush; end;
m:=#(0.int,1.int,-1,0.int);
#OUT+m.str+".up_sl!\n"; #OUT.flush;
loop m1:=m.up_sl!; #OUT+m1.str+"\n"; #OUT.flush; end;
-- print conjugate class
SL2P::set_base(5.int);
#OUT+#SL2P_CNJ_CLS.str;
end;
main is
test_mat2p;
test_sl2p;
end;
end;