Positive Garside-factor tokenizer / garside_track.py
Mechanism confirmed, baseline not beaten
1import itertools, numpy as np
2META={'name':'braid_garside_classification','domain':'algebraic braid presentations','description':'B4 positive braid words with removable left Delta powers; classify parity of sigma1 usage.'}
3N=4
4SIMPLES=list(itertools.permutations(range(N)))
5IDENT=tuple(range(N)); DELTA=tuple(reversed(range(N)))
6
7def compose(p,q): return tuple(p[q[i]] for i in range(N))
8def inverse(p):
9 z=[0]*N
10 for i,v in enumerate(p): z[v]=i
11 return tuple(z)
12def swap(g):
13 p=list(range(N)); p[g-1],p[g]=p[g],p[g-1]; return tuple(p)
14def invcount(p): return sum(p[i]>p[j] for i in range(N) for j in range(i+1,N))
15def divides(a,b): return invcount(a)+invcount(compose(inverse(a),b))==invcount(b)
16def factors(word):
17 fs=[]
18 for g in word:
19 fs.append(swap(g)); i=len(fs)-2
20 while i>=0:
21 x,y=fs[i],fs[i+1]; comp=compose(inverse(x),DELTA)
22 cs=[c for c in SIMPLES if divides(c,comp) and divides(c,y)]
23 a=max(cs,key=invcount)
24 if a==IDENT: break
25 fs[i]=compose(x,a); fs[i+1]=compose(inverse(a),y)
26 if fs[i+1]==IDENT: fs.pop(i+1)
27 i-=1
28 return fs
29def factor_id(p): return sum(v*(N+1)**i for i,v in enumerate(p))
30def samples(seed,n):
31 rng=np.random.RandomState(seed); out=[]
32 for _ in range(n):
33 base=rng.randint(1,N,size=rng.randint(10,25)).tolist(); k=int(rng.randint(0,4))
34 word=DELTA_WORD*k+base; y=sum(g==1 for g in base)%2
35 out.append((word,base,y,k))
36 return out
37DELTA_WORD=[3,2,1,3,2,3]
38def get_dataset(seed,n_train=400,n_test=400):
39 tr=samples(seed,n_train); te=samples(seed+5000,n_test)
40 def raw(es):
41 a=np.zeros((len(es),N-1),np.float32)
42 for i,(w,b,y,k) in enumerate(es):
43 for g in w:a[i,g-1]+=1
44 a[i]/=len(w)
45 return a
46 return {'xtr':raw(tr),'ytr':np.array([e[2] for e in tr]),'xte':raw(te),'yte':np.array([e[2] for e in te]),'task':'classification','metric':'err','out_dim':2}