Positive Garside-factor tokenizer / garside_track.py

Mechanism confirmed, baseline not beaten

Raw ⬇ ZIP
 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}