braid.sa
Generated by gen_html_sa_files from ICSI. Contact gomes@icsi.berkeley.edu for details
-- This code is "GPL"ed.
--
-- 1998.07.02 K.Kodama convert to Sather from Modula2 module BRAID.msi
class BRAID_TABLE
class BRAID_TABLE is
-- 2004-02-19 K.Kodama
attr crossTbl:ARRAY{ARRAY{INT}};
attr index:CARD;
create(word:BRAID):SAME is
-- #OUT+"BRAID_TABLE create:"+word.str+"\n";
res::=new;
res.index:=word.index;
res.crossTbl:=#(word.size+1);
loop i::=res.crossTbl.ind!;
res.crossTbl[i]:=#(res.index+1);
loop j::=res.crossTbl[i].ind!;
res.crossTbl[i][j]:=0.int;
end;
if i<word.size then res.crossTbl[i][word[i].abs]:=word[i].sgn; end;
end;
return res;
end;
braid:BRAID is
word:BRAID:=#(index);
loop t::=crossTbl.elt!;
loop u::=t.elt!; j::=t.ind!;
if u.is_pos then word.append(j.int);
elsif u.is_neg then word.append(j.int.negate);
end;
end;
end;
return word;
end;
inspect is
#OUT+" index="+index.str+"\n";
loop t::=crossTbl.elt!;
loop u::=t.elt!;
if u.is_pos then #OUT+"p" ;
elsif u.is_neg then #OUT+"n" ;
else #OUT+".";
end;
end;
#OUT+"\n";
end;
end;
length:CARD is
-- size of crossTbl s.t. [i][*].is_non_zero
loop i::=(crossTbl.size-1).downto!(0);
loop
if crossTbl[i].elt!.is_non_zero then return i+1; end;
end;
end;
return 0;
end;
pack is
i::=0; j::=1;
loop
if i>=crossTbl.size then break!; end;
if (i>0)and crossTbl[i][j].is_non_zero then -- crossing
if crossTbl[i-1][j].is_zero and
crossTbl[i-1][j-1].is_zero and crossTbl[i-1][j+1].is_zero
then -- move crossing
crossTbl[i-1][j]:=crossTbl[i][j]; crossTbl[i][j]:=0.int; i:=i-1;
else -- check next slot
j:=j+1; if j=index then j:=1; i:=i+1; end;
end;
else -- not crossing. check next slot
j:=j+1; if j>=index then j:=1; i:=i+1; end;
end;
end;
end;
end;
class BRAID
class BRAID is
include WORD create->word_create, clone->word_clone, str->word_str,
printD->word_printD, check->word_check,
reverse->word_reverse, inverse->word_inverse,
append->word_append,insert->word_insert;
attr index:CARD;
create:SAME is
res::=new; res.index:=0; res.w:=#; return res;
end;
create(ind:CARD):SAME is
res::=new; res.index:=ind; res.w:=#; return res;
end;
create(s:STR):SAME is
-- convert STR to BRAID.
-- format: "4 : 2 -1 3 -2 -3 2 1 endcode"
-- index^ ^^^^^^^^^^^^^^^^braid word
res:SAME:=#;
sc:STR_CURSOR:=#(s);
res.index:=sc.card;
if res.index<0 then res:=#; return res; end;
str:STR:=STRINGSK::splitStr(inout sc);
if str/=":" then res:=#; return res; end;
s:=sc.get_remainder;--get_rest_str;
i::=s.search("endcode");
if s.has_ind(i).not then res:=#; return res; end;
s:=s.head(i);
res.w:=word_create(s).w;
loop
if res.w.elt!.abs>=res.index.int then res:=#; return res; end;
end;
return res;
end;
str:STR is
-- convert BRAID to STR
-- format: "4 : 2 -1 3 -2 -3 2 1 endcode"
-- index^ ^^^^^^^^^^^^^^^^braid word
s:STR:=index.str+" : "+word_str+" endcode";
return s;
end;
clone:SAME is
res:SAME:=word_clone; res.index:=index; return res;
end;
printD is
-- print for debug/check
#OUT+"braid "+str+"\n";
end;
check:BOOL is
return word_check and (maxGen<index);
end;
perm:PERM is
-- get permutation [1..index]
p:PERM:=#(index);
loop j::=w.elt!.abs.card; p.swap(j,j+1); end;
return p.inv;
end;
create(p:PERM):SAME post result.perm=initial(p) is
-- For permutation p, create standard braid w, s.t. w.perm=p.
w:SAME:=#(p.jn);
loop i::=(w.index).downto!(1); i1::=p[i];
if i/=i1 then
w1:SAME:=#(w.index);
loop j::=(i-1).downto!(i1); w1.append(-j.int); end;
w:=w1*w; p:=p/(w1.perm);
end;
end;
return w;
end;
reach(s:CARD):CARD is
-- where s-th string reach.
return perm[s];
end;
trackString(s:CARD):ARRAY{CARD} is
-- [i]: where s-th string arrives before w[i].
-- i.e. [i+1]: where s-th string arrives after w[i].
pos:CARD:=s; -- current position
tbl:ARRAY{CARD}:=#(size+1); tbl.to_val(0); tbl[0]:=pos;
loop i::=w.ind!; j::=w[i].abs.card;
if j=pos then pos:=pos+1; elsif (j+1)=pos then pos:=pos-1; end;
tbl[i+1]:=pos;
end;
return tbl;
end;
is_PureBraid:BOOL is
return perm.is_one;
end;
writheTbl:ARRAY{INT} is
-- [g] is total_power for g-th generator.
-- [0], [index] as guards.
tbl:ARRAY{INT}:=#(index+1); tbl.to_val(0.int);
loop e::=w.elt!; g::=e.abs; tbl[g]:=tbl[g]+e.sgn; end;
return tbl;
end;
crossingNumTbl:ARRAY{INT} is
-- [g] is total_appearance for g-th generator.
-- [0], [index] as guards.
tbl:ARRAY{INT}:=#(index+1); tbl.to_val(0.int);
loop e::=w.elt!; g::=e.abs; tbl[g]:=tbl[g]+INT::one; end;
return tbl;
end;
lastPositionTbl:ARRAY{INT} is
-- [g] is where g-th generator is appear at last.
-- [0], [index] as guards.
tbl:ARRAY{INT}:=#(index+1); tbl.to_val(0.int);
loop pos::=w.ind!; g::=w[pos].abs; tbl[g]:=pos.int; end;
return tbl;
end;
reverse:SAME is
-- reverse order of elements
b:SAME:=word_reverse; b.index:=index; return b;
end;
inverse:SAME is
-- inverse as group
res:SAME:=word_inverse; res.index:=index; return res;
end;
append(b:SAME) is
index:=index.max(b.index); w:=w.append(b.w);
end;
append(b:SAME):SAME is
res:SAME:=clone; res.append(b); return res;
end;
append(s:INT) is
index:=index.max(s.abs.card+1);
--w:=w.resize(w.size+1); w[w.size-1]:=s;
w:=w.append(|s|);
end;
append(s:INT):SAME is
res:SAME:=clone; res.append(s); return res;
end;
insert(pos:CARD,b:SAME):SAME is
res:SAME:=word_insert(pos,b); res.index:=index.max(b.index);
return res;
end;
insert(pos:CARD, s:INT):SAME is
res:SAME:=word_insert(pos,s); res.index:=index.max((s.abs+1).card);
return res;
end;
insert(pos:CARD, s:INT) is
res::=insert(pos,s); index:=res.index; w:=res.w;
end;
end; -- class BRAID
class BRAID_REDUCTION
class BRAID_REDUCTION is
-----------------word reduction------------------------------
reduction1(inout word:BRAID):BOOL is
-- true if R1-move as a closed braid
rFlg:BOOL:=false;
stTbl:ARRAY{INT}:=word.crossingNumTbl;
posTbl:ARRAY{INT}:=word.lastPositionTbl; -- position of the crossing
si:CARD:=1;
loop while!(si<word.index);
if (stTbl[si].is_one)and( stTbl[si-1].is_zero or stTbl[si+1].is_zero ) then
rFlg:=true; -- r1 move
loop wi::=word.w.ind!;
if word.w[wi].abs.card>si then
if word.w[wi].is_pos then word.w[wi]:=word.w[wi]-1;
else word.w[wi]:=word.w[wi]+1.int;
end;
end;
end;
word.index:=word.index-1;
word.delete(posTbl[si].card);
stTbl:=word.crossingNumTbl;
posTbl:=word.lastPositionTbl;
if si>1 then si:=si-1; end;
else si:=si+1;
end;
end;
return rFlg;
end;
reduction2(inout word:BRAID, closed:BOOL):BOOL is
-- true if R2-move
rFlg:BOOL:=false;
wi:INT:=0.int;
loop while!(wi<word.size.int);
wi1::=wi-1;
loop
if wi1.is_neg then
if closed then wi1:=word.size.int-1; else wi1:=wi; break!; end;
end;
if (word.w[wi1.card].abs-word.w[wi.card].abs).abs<=1.int then break!; end;
wi1:=wi1-1;
end;
if (word.w[wi1.card]+word.w[wi.card]).is_zero then rFlg:=true; -- r2 move
w1, w2:INT;
if wi<wi1 then w1:=wi; w2:=wi1; else w1:=wi1; w2:=wi; end;
word.delete(w2.card); word.delete(w1.card); -- Note that w1<w2.
if wi1<wi then wi:=wi-1; end;
if word.size.int<=wi then wi:=0.int; end;
else
wi:=wi+1;
end;
end;
-- #OUT+"r2\n"; word.checkD;
return rFlg;
end;
wordReduction(word:BRAID, closed:BOOL):BRAID is
reply:BOOL:=true; -- true if no-error.
word:=word.cancel;
loop
rFlg:BOOL:=false;
if closed then rFlg:=reduction1(inout word) ; word:=word.cancel; end;
rFlg:=reduction2(inout word,closed) or rFlg; word:=word.cancel;
if rFlg.not then break!; end;
end;
return word;
end;
end; -- class BRAID_REDUCTION
class ARTIN_FORM
class ARTIN_FORM is
--Artin's normal form for braid word.
--c.f. Artin,E.
-- "Braid groups, generators and relations,solution of word problem"
-- Theorie der Zopfe, Abh.Math.Sem.Univ.Hamburg 4(1926),47-72
--c.f. Artin,E.
-- Theory of braids, Ann. of Math.(2)48(1947),101-126.
--
-- This code is "GPL"ed.
-- 2006.02.14 K.Kodama bug fix in ARTIN_FORM
-- 1998.7.2 K.Kodama
--
private checkD(D:BRAID, j:INT):BOOL is
-- check j(=position of i-th string) in the word D.
pd:CARD;
gd:INT;
loop pd:=D.w.ind!;
gd:=D[pd];
if j=gd.abs then j:=j+1;
elsif j=gd.abs+1 then j:=j-1;
else
return false;
end;
end;
return true;
end;
private twistP(inout Di:BRAID,k0:INT, inout j:INT) is
-- positive twist "k0" and "k0+1"th string
gd:INT;
Dw:BRAID:=#(Di.index);
-- #OUT+"k0,j,Di: "+k0.str+" "+j.str+" "+Di.str+"\n";
loop pd::=Di.w.ind!;
gd:=Di.w[pd];
if (gd=k0-1)and(j=k0-1) then Dw.append(-(k0-1));
elsif (gd=-(k0-1))and(j=k0-1) then
Dw.append(-(k0-1)); Dw.append(-k0); Dw.append(-k0);
elsif (gd=k0-1)and(j=k0) then
Dw.append(k0); Dw.append(k0); Dw.append(k0-1);
elsif (gd=-(k0-1))and(j=k0) then Dw.append(k0-1);
elsif (gd=k0)and(j=k0) then
Dw.append(k0-1); Dw.append(k0-1); Dw.append(k0);
elsif (gd=-(k0))and(j=k0) then Dw.append(k0);
elsif (gd=k0)and(j=k0+1) then Dw.append(-k0);
elsif (gd=-k0)and(j=k0+1) then
Dw.append(-k0); Dw.append(-(k0-1)); Dw.append(-(k0-1));
else Dw.append(gd);
end;
if j=gd.abs then j:=j+1; elsif j=gd.abs+1 then j:=j-1; else
raise "ARTIN_FORM::twistP. Bad crossing code "+pd.str+"\n";
end;
end;
Di:=Dw.cancel;
end;
private twistN(inout Di:BRAID,k0:INT, inout j:INT) is
-- negative twist "k0" and "k0+1"th string
gd:INT;
Dw:BRAID:=#(Di.index);
loop pd::=Di.w.ind!;
gd:=Di[pd];
if (gd=k0-1)and(j=k0-1) then
Dw.append(k0-1);Dw.append(k0); Dw.append(k0)
elsif (gd=-(k0-1))and(j=k0-1) then Dw.append(k0-1);
elsif (gd=k0-1)and(j=k0) then Dw.append(-(k0-1));
elsif (gd=-(k0-1))and(j=k0) then
Dw.append(-k0); Dw.append(-k0); Dw.append(-(k0-1));
elsif (gd=k0)and(j=k0) then Dw.append(-k0);
elsif (gd=-(k0))and(j=k0) then
Dw.append(-(k0-1)); Dw.append(-(k0-1)); Dw.append(-k0);
elsif (gd=k0)and(j=k0+1) then
Dw.append(k0); Dw.append(k0-1); Dw.append(k0-1);
elsif (gd=-k0)and(j=k0+1) then Dw.append(k0);
else Dw.append(gd);
end;
if j=gd.abs then j:=j+1; elsif j=gd.abs+1 then j:=j-1;
else
raise "ARTIN_FORM::twistN. Bad crossing code "+pd.str+"\n";
end;
end;
Di:=Dw.cancel;
end;
private CnvReducedNormalForm(i:INT, inout Ai:BRAID, inout Di:BRAID) is
-- Assume that Ai is pure braid.
if Ai.is_PureBraid.not then
raise "ARTIN_FORM::CnvReducedNormalForm. Not a pure braid.\n";
end;
Ai:=Ai.cancel;
--#OUT+"CnvReducedNormalForm.1 Ai: "+Ai.str+"\n";
g,k0,j:INT;
spos:ARRAY{CARD}:=Ai.trackString(i.card); -- set spos[]. spos[*] track the i-th string.
-- #OUT+"i,Ai,spos:"+i.str+", "+Ai.str+", "+spos.str+"\n";
Aw:BRAID:=#(Ai.index); Di:=#(Ai.index);
if Ai.size>0 then
loop pa::=(Ai.size-1).downto!(0);
-- #OUT+"2-loop";
-- Ai[pa+1]:=0; WrWord(Ai); WrWord(Di); WrWord(Aw);
j:=spos[pa].int; g:=Ai[pa];
if g.abs=j then Di:=Di.insert(0,g);
elsif g.abs+1=j then Di:=Di.insert(0,g);
else
if j>g.abs then k0:=g.abs+1; else k0:=g.abs; end;
if g.is_pos then Aw:=Aw.insert(0,k0);
else Aw:=Aw.insert(0,-k0);
end;
if g.is_pos then twistP(inout Di,k0,inout j); else twistN(inout Di,k0, inout j); end;
end;
end;
end;
Ai:=Aw.cancel; Di:=Di.cancel;
--#OUT+"CnvReducedNormalForm.2 Ai/D1: "+Ai.str+"/ "+Di.str+"\n";
if ~ checkD(Di,i) then
raise "ARTIN_FORM::CnvReducedNormalForm. twist. bad crossing code.\n";
end;
end;
private cnvRA2A(i:INT, inout di:BRAID) is
-- Convert from "Reduced Normal" form to "Normal" form.
di:=di.cancel; if di.w.size.is_zero then return; end;
--#OUT+"cnvRA2A.1 i/ di: "+i.str+"/ "+di.str+"\n"; OUT::flush;
w:BRAID:=#(di.index);
track::=di.trackString(i.card);
j:INT:=i; dir:INT:=1;
p:CARD:=0;
x::=di.w[p];
loop
if dir=1.int then
if track[p]=j.card then
if x=j then
w:=w.append(x); p:=p+1; while!(di.w.has_ind(p)); x:=di.w[p];
j:=j+1;
elsif -x=j then
w:=w.append(x); p:=p+1; while!(di.w.has_ind(p)); x:=di.w[p];
j:=j+1; dir:=-1;
elsif x+1=j then
w:=w.append(x); p:=p+1; while!(di.w.has_ind(p)); x:=di.w[p];
j:=j-1; dir:=-1;
elsif -x+1=j then
w:=w.append(x); p:=p+1; while!(di.w.has_ind(p)); x:=di.w[p];
j:=j-1; dir:=-1;
else
raise "cnvRA2A: error in conversion. d,j,x="+dir.str+","+j.str+","+x.str;
end;
else
w:=w.append(j);
j:=j+1;
end;
elsif dir=-1 then
if track[p]=j.card then
if x=j then
j:=j-1;
w:=w.append(-j);
elsif -x=j then
j:=j-1;
w:=w.append(-j);
elsif x+1=j then
j:=j-1;
w:=w.append(-j);
elsif -x+1=j then
w:=w.append(x); p:=p+1; while!(di.w.has_ind(p)); x:=di.w[p];
j:=j-1;
else
raise "cnvRA2A: error in conversion. d,j,x="+dir.str+","+j.str+","+x.str;
end;
else
j:=j-1;
w:=w.append(-j);
end;
end;
if j=i then dir:=1; end;
end;
di:=w;
--#OUT+"cnvRA2A.1 i/ di: "+i.str+"/ "+di.str+"\n"; OUT::flush;
end;
PureArtinNormalForm(word:BRAID, reduce:BOOL):BRAID pre word.is_PureBraid is
D:BRAID:=#(word.index);
Di:BRAID:=#(word.index);
Ai:BRAID:=word.clone;
loop i::=(1.upto!(word.index-1)).int ;
--#OUT+"PureArtinNormalForm.1 i/Ai/Di: "+i.str+"/ "+Ai.str+"/ "+Di.str+"\n";
CnvReducedNormalForm(i,inout Ai,inout Di);
--#OUT+"PureArtinNormalForm.2 i/Ai/Di: "+i.str+"/ "+Ai.str+"/ "+Di.str+"\n";
if ~reduce then cnvRA2A(i,inout Di); end;
--#OUT+"PureArtinNormalForm.3 i/Ai/Di: "+i.str+"/ "+Ai.str+"/ "+Di.str+"\n";
D:=D*Di;
--#OUT+"PureArtinNormalForm.4 i/D: "+i.str+"/ "+D.str+"\n";
end;
return D;
end;
private GArtinNormalForm_work(word:BRAID, reduce:BOOL):BRAID is
-- Generalized Artin Normal form.
-- For braid w, w/E is pure braid,
-- A be Normal form of w/E, A E is Gen. A. form.
E:BRAID:=#(word.perm);
--#OUT+"GArtinNormalForm word, E: "+word.str+", "+E.str+"\n";
w1::=word/E;
--#OUT+"GArtinNormalForm word/E: "+w1.str+"\n";
return PureArtinNormalForm(w1,reduce)*E;
end;
GArtinNormalForm(word:BRAID, reduce:BOOL):BRAID post GArtinNormalForm_work(result/word,true).is_trivial is
word1::=GArtinNormalForm_work(word, reduce);
return word1;
end;
end; -- class ARTIN_FORM
class TEST_BRAID
class TEST_BRAID is
include TEST;
test_braid is
class_name("BRAID");
s:STR:="4 : 2 -1 3 -2 -3 2 1 endcode";
b:BRAID:=#(s);
test("create",b.str, s);
--
test("rev", (b*b.inverse).cancel.is_trivial.str, "true");
--
b1:BRAID:=#(s);
p1::=b1.perm;
test("braid to perm", p1.str, "4 1 2 3");
E:BRAID:=#(p1);
test("perm to braid", E.str, "4 : -1 -2 -3 endcode");
finish;
end;
test_artin is
class_name("ARTIN_FORM");
s:STR:="4 : 2 -1 3 -2 -3 2 1 endcode";
b:BRAID:=#(s);
b1::=ARTIN_FORM::GArtinNormalForm(b,true);
b1:=ARTIN_FORM::GArtinNormalForm(b1/b,true);
test("artin.reduced", b1.is_trivial.str,"true");
b1:=ARTIN_FORM::GArtinNormalForm(b,false);
b1:=ARTIN_FORM::GArtinNormalForm(b1/b,true);
test("artin.normal", b1.is_trivial.str,"true");
--
s:="5 : -1 -2 -2 -3 -3 -2 3 1 2 3 3 -4 3 -2 3 4 endcode";
b:=#(s);
b1:=ARTIN_FORM::GArtinNormalForm(b,true);
#OUT+b1.str+"\n";
b1:=ARTIN_FORM::GArtinNormalForm(b1/b,true);
test("artin.reduced", b1.is_trivial.str,"true");
b1:=ARTIN_FORM::GArtinNormalForm(b,false);
#OUT+b1.str+"\n";
b1:=ARTIN_FORM::GArtinNormalForm(b1/b,true);
test("artin.normal", b1.is_trivial.str,"true");
finish;
end;
main is
test_braid;
test_artin;
end;
end;