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;