def genus_enum1(code=None, verbose=False): if code is None: code = get_code() G = code.G print(shortstr(G)) m, n = G.shape poly = lambda cs : Poly(cs, 2, "x_0 x_1".split()) #x_1 = poly({(0, 1) : 1}) #x_0 = poly({(1, 0) : 1}) #xs = [x0, x1] cs = {} for v0 in span(G): exp = [0, 0] #vv = numpy.array([2*v0, v1]) for i in range(n): exp[v0[i]] += 1 exp = tuple(exp) cs[exp] = cs.get(exp, 0) + 1 p = poly(cs) if argv.show: if argv.latex: print(p) else: print(p.flatstr()) Z = numpy.array([[1, 0], [0, 1]]) q = p.transform(Z) print("invariant under Z", q==p) S2 = numpy.array([[0, 1], [-1, 0]]) q = p.transform(S2) print("invariant under CS2", q==p)
def test_triorth(): code = reed_muller(1, 5) code = code.puncture(0) code.dump() print(code.is_triorthogonal()) A = array2(list(span(code.G))) print(is_morthogonal(A, 2)) #print(shortstr(A)) k = len(A) for i in range(k): for j in range(i+1, k): u = A[i] v = A[j] x = (u*v).sum() % 2 if x == 0: continue #print(shortstr(u)) #print(shortstr(v)) #print() for a in range(k): for b in range(a+1, k): for c in range(b+1, k): u = A[a] v = A[b] w = A[c] x = (u*v*w).sum() % 2
def tensor_enum(self, A, B): G = self.G the_op = None for v in span(G): op = A if v[0]==0 else B for vi in v[1:]: op = op @ (A if vi==0 else B) the_op = op if the_op is None else the_op + op return the_op
def get_distance(self): G = self.G d = None for v in span(G): w = v.sum() if w==0: continue if d is None or w<d: d = w if self.d is None: self.d = d return d
def genus_enum1(G, verbose=False): m, n = G.shape cs = {} for v0 in span(G): exp = [0, 0] for i in range(n): exp[v0[i]] += 1 exp = tuple(exp) cs[exp] = cs.get(exp, 0) + 1 p = xpoly1(cs) return p
def gen(): r = argv.get("r", None) # degree m = argv.get("m", None) if r is not None and m is not None: code = reed_muller(r, m) #print(code) #print("d =", code.get_distance()) #code.dump() #code = code.puncture(3) #print(code) code = code.puncture(0) print(code) for g in code.G: print(shortstr(g), g.sum()) print() #code.dump() #print("d =", code.get_distance()) return for m in range(2, 8): for r in range(0, m+1): code = reed_muller(r, m) print(code, end=" ") if code.is_selfdual(): print("is_selfdual", end=" ") if code.is_morthogonal(2): print("is_biorthogonal", end=" ") if code.is_morthogonal(3): print("is_triorthogonal", end=" ") if dot2(code.H, code.H.transpose()).sum()==0: print("***", end=" ") p = code.puncture(0) if p.is_morthogonal(3): print("puncture.is_triorthogonal", end=" ") if p.is_selfdual(): print("puncture.is_selfdual", end=" ") if dot2(p.H, p.H.transpose()).sum()==0: print("***", end=" ") print() if p.is_triorthogonal() and p.k < 20: G = p.G #print(shortstr(G)) A = list(span(G)) A = array2(A) print(is_morthogonal(A, 3))
def test_rm(): params = [(r, m) for m in range(2, 8) for r in range(1, m)] r = argv.get("r", None) # degree m = argv.get("m", None) if r is not None and m is not None: params = [(r, m)] for (r, m) in params: #code = reed_muller(r, m) # for code in [ reed_muller(r, m), reed_muller(r, m).puncture(0) ]: for code in [reed_muller(r, m)]: if argv.puncture: print(code, end=" ", flush=True) code = code.puncture(0) code = code.get_even() if argv.puncture==2: code = code.puncture(0) code = code.get_even() G = code.G k, n = G.shape #code = Code(G) #d = code.get_distance() d = "." print("puncture [%d, %d, %s]" % (n, k, d), end=" ", flush=True) else: G = code.G print(code, end=" ", flush=True) i = 1 while i<8: if (is_morthogonal(G, i)): print("(%d)"%i, end="", flush=True) i += 1 else: break if i > code.k: print("*", end="") break print() if argv.show: print(G.shape) print(shortstr(G)) print(dot2(G, G.transpose()).sum()) if len(G) >= 14: continue A = array2(list(span(G))) for i in [1, 2, 3]: assert strong_morthogonal(G, i) == strong_morthogonal(A, i)
def genus_enum2(G, verbose=False): m, n = G.shape cs = {} items = list(span(G)) for v0 in items: #print(".",end='',flush=True) for v1 in items: exp = [0, 0, 0, 0] #vv = numpy.array([2*v0, v1]) for i in range(n): exp[2*v0[i] + v1[i]] += 1 exp = tuple(exp) cs[exp] = cs.get(exp, 0) + 1 #break #print() p = xpoly2(cs) return p
def genus_enum4(G, verbose=False): #print(shortstr(G)) m, n = G.shape cs = {} exp = numpy.array([0]*16, dtype=int) items = list(span(G)) for v0 in items: #print(".",end='',flush=True) for v1 in items: for v2 in items: for v3 in items: exp[:] = 0 for i in range(n): exp[8*v0[i] + 4*v1[i] + 2*v2[i] + v3[i]] += 1 key = tuple(exp) cs[key] = cs.get(key, 0) + 1 p = xpoly4(cs) return p
def test(): for idx, H in enumerate(items): H = array2(H) #print(H.shape) print(names[idx]) print(shortstr(H)) assert (dot2(H, H.transpose()).sum()) == 0 # orthogonal code G = H for genus in range(1, 4): print(strong_morthogonal(G, genus), end=" ") print() keys = [0, 4, 8, 12, 16, 20, 24] counts = {0: 0, 4: 0, 8: 0, 12: 0, 16: 0, 20: 0, 24: 0} for v in span(G): counts[v.sum()] += 1 print([counts[k] for k in keys]) print()
def search_extend(): # Extend the checks of a random code to make it triorthogonal. # Based on the search function above. verbose = argv.get("verbose") m = argv.get("m", 6) n = argv.get("n", m+2) k = argv.get("k") # odd _numbered rows ( logical operators) code = argv.get("code", "rand") if code == "rand": while 1: G0 = rand2(m, n) counts = G0.sum(0) if min(counts)==2 and rank(G0) == m: cols = set() for i in range(n): cols.add(tuple(G0[:, i])) if len(cols) == n: # no repeated cols break elif code == "toric": G0 = parse(""" 11.11... .111..1. 1...11.1 """) # l=2 toric code X logops + X stabs l = argv.get("l", 3) G0 = build_toric(l) m, n = G0.shape else: return code = Code(G0, check=False) print(shortstr(G0)) print("is_triorthogonal:", code.is_triorthogonal()) # these are the variables N_x xs = list(cross([(0, 1)]*m)) N = len(xs) lookup = {} for i, x in enumerate(xs): lookup[x] = i lhs = [] rhs = [] taken = set() for i in range(n): x = G0[:, i] idx = lookup[tuple(x)] assert idx not in taken taken.add(idx) if verbose: for idx in range(N): print(idx, xs[idx], "*" if idx in taken else "") for idx in taken: v = zeros2(N) v[idx] = 1 lhs.append(v) rhs.append(1) # bi-orthogonality for a in range(m): for b in range(a+1, m): v = zeros2(N) for i, x in enumerate(xs): if x[a] == x[b] == 1: v[i] += 1 assert v.sum() lhs.append(v) rhs.append(0) # tri-orthogonality for a in range(m): for b in range(a+1, m): for c in range(b+1, m): v = zeros2(N) for i, x in enumerate(xs): if x[a] == x[b] == x[c] == 1: v[i] += 1 assert v.sum() lhs.append(v) rhs.append(0) # dissallow columns with weight <= 1 for i, x in enumerate(xs): if sum(x)<=1: v = zeros2(N) v[i] = 1 lhs.append(v) rhs.append(0) if k is not None: # constrain to k _number of odd-weight rows assert 0<=k<m for a in range(m): v = zeros2(N) for i, x in enumerate(xs): if x[a] == 1: v[i] = 1 lhs.append(v) if a<k: rhs.append(1) else: rhs.append(0) A = array2(lhs) rhs = array2(rhs) if verbose: print("lhs:") print(shortstr(A)) print("rhs:") print(shortstr(rhs)) B = pseudo_inverse(A) soln = dot2(B, rhs) if not eq2(dot2(A, soln), rhs): print("no solution") return if verbose: print("soln:") print(shortstr(soln)) soln.shape = (N, 1) rhs.shape = A.shape[0], 1 K = array2(list(find_kernel(A))) best = None density = 1.0 size = 9999*n trials = argv.get("trials", 1024) count = 0 for trial in range(trials): u = rand2(len(K), 1) v = dot2(K.transpose(), u) #print(v) assert dot2(A, v).sum()==0 #if v.sum() != n: # continue assert v[0]==0 v = (v+soln)%2 assert eq2(dot2(A, v), rhs) Gt = list(G0.transpose()) for i, x in enumerate(xs): if v[i] and not i in taken: Gt.append(x) if not Gt: continue Gt = array2(Gt) G = Gt.transpose() if verbose: print("G0") print(shortstr(G0)) print("solution:") print(shortstr(G)) assert is_morthogonal(G, 3) if G.shape[1]<m: continue if 0 in G.sum(1): continue #print(shortstr(G)) # for g in G: # print(shortstr(g), g.sum()) # print() _density = float(G.sum()) / (G.shape[0]*G.shape[1]) #if best is None or _density < density: if best is None or G.shape[1] < size: best = G density = _density size = G.shape[1] if 0: #sols.append(G) Gx = even_rows(G) assert is_morthogonal(Gx, 3) if len(Gx)==0: continue GGx = array2(list(span(Gx))) assert is_morthogonal(GGx, 3) count += 1 print("found %d solutions" % count) G = best #print(shortstr(G)) for g in G: print(shortstr(g), g.sum()) print() print("density:", density)
def projective(n, dim=2): # Take n-dim F_2-vector space # points are subspaces of dimension 1 # lines are subspaces of dimension 2 # etc. def get_key(L): vs = [str(v) for v in span(L) if v.sum()] vs.sort() key = ''.join(vs) return key assert n > 1 points = [] for P in enum2(n): P = array2(P) if P.sum() == 0: continue points.append(P) #print "points:", len(points) lines = [] lookup = {} for L in enum2(2 * n): L = array2(L) L.shape = (2, n) L = row_reduce(L) if len(L) != 2: continue key = get_key(L) if key in lookup: continue lines.append(L) lookup[key] = L #print "lines:", len(lines) spaces = [] if n > 3 and dim > 2: m = 3 lookup = {} for A in enum2(m * n): A.shape = (m, n) A = row_reduce(A) if len(A) != m: continue key = get_key(A) if key in lookup: continue spaces.append(A) lookup[key] = A #print "spaces:", len(spaces) incidence = [] tpmap = {} for point in points: point = str(point) tpmap[point] = 0 #print point for L in lines: line = str(tuple(tuple(row) for row in L)) tpmap[line] = 1 for P in span(L): if P.sum(): incidence.append((str(P), line)) for A in spaces: space = freeze(A) tpmap[space] = 2 for P in span(A): if P.sum() == 0: continue incidence.append((str(P), space)) for L in lines: B = solve(A.transpose(), L.transpose()) if B is not None: line = str(tuple(tuple(row) for row in L)) incidence.append((space, line)) g = Geometry(incidence, tpmap) if dim == 2: assert g.get_diagram() == [(0, 1)] elif dim == 3: assert n > 3 assert g.get_diagram() == [(0, 1), (1, 2)] return g
def triortho(): code = get_code() code.dump() print(code) Gx = [] for u in code.G: print(shortstr(u), u.sum()%2) parity = u.sum()%2 if parity==0: Gx.append(u) Gx = array2(Gx) print("is_triorthogonal:", code.is_triorthogonal()) A = array2(list(span(Gx))) print("span(Gx) is_morthogonal(2):", is_morthogonal(A, 2)) print("span(Gx) is_morthogonal(3):", is_morthogonal(A, 3)) return G = code.G # A = array2(list(span(G))) # poly = {} # for v in A: # w = v.sum() # poly[w] = poly.get(w, 0) + 1 # print(poly) k, n = G.shape if 0: from comm import Poly a = Poly({(1,0):1}) b = Poly({(0,1):1}) poly = Poly.zero(2) for v in span(G): w = v.sum() term = Poly({(n-w,0) : 1}) * Poly({(0,w) : 1}) poly = poly + term print(poly) # print higher genus weight enumerator genus = argv.get("genus", 1) assert 1<=genus<=4 N = 2**genus idxs = list(cross([(0,1)]*genus)) cs = {} # _coefficients : map exponent to coeff for vs in cross([list(span(G)) for _ in range(genus)]): key = [0]*N for i in range(n): ii = tuple(v[i] for v in vs) idx = idxs.index(ii) key[idx] += 1 key = tuple(key) cs[key] = cs.get(key, 0) + 1 #print(cs) keys = list(cs.keys()) keys.sort() print(idxs) for key in keys: print(key, cs[key])
def search_selfdual(): verbose = argv.get("verbose") m = argv.get("m", 6) # _number of rows k = argv.get("k", None) # _number of odd-weight rows maxweight = argv.get("maxweight", m) minweight = argv.get("minweight", 1) # these are the variables N_x print("building xs...") if 0: xs = cross([(0, 1)]*m) xs = [x for x in xs if minweight <= sum(x) <= maxweight] prune = argv.get("prune", 0.5) xs = [x for x in xs if random() < prune] xs = [] N = argv.get("N", m*100) colweight = argv.get("colweight", maxweight) assert colweight <= m for i in range(N): x = [0]*m total = 0 while total < colweight: idx = randint(0, m-1) if x[idx] == 0: x[idx] = 1 total += 1 xs.append(x) N = len(xs) lhs = [] rhs = [] # bi-orthogonality for a in range(m): for b in range(a+1, m): v = zeros2(N) for i, x in enumerate(xs): if x[a] == x[b] == 1: v[i] = 1 if v.sum(): lhs.append(v) rhs.append(0) k = 0 # all rows must have even weight # constrain to k _number of odd-weight rows assert 0<=k<m for a in range(m): v = zeros2(N) for i, x in enumerate(xs): if x[a] == 1: v[i] = 1 lhs.append(v) if a<k: rhs.append(1) else: rhs.append(0) logops = argv.logops A = array2(lhs) rhs = array2(rhs) #print(shortstr(A)) print("solve...") B = pseudo_inverse(A) soln = dot2(B, rhs) if not eq2(dot2(A, soln), rhs): print("no solution") return if verbose: print("soln:") print(shortstr(soln)) soln.shape = (N, 1) rhs.shape = A.shape[0], 1 K = array2(list(find_kernel(A))) print("kernel:", K.shape) if len(K)==0: return #print(K) #print( dot2(A, K.transpose())) #sols = [] #for v in span(K): best = None density = 1.0 size = 99*N trials = argv.get("trials", 1024) count = 0 print("trials...") for trial in range(trials): u = rand2(len(K), 1) v = dot2(K.transpose(), u) #print(v) v = (v+soln)%2 assert eq2(dot2(A, v), rhs) if v.sum() >= size: continue if v.sum() < m: continue if v.sum(): print(v.sum(), end=" ", flush=True) size = v.sum() if logops is not None and size != 2*m+logops: continue Gt = [] for i, x in enumerate(xs): if v[i]: Gt.append(x) Gt = array2(Gt) G = Gt.transpose() if dot2(G, Gt).sum() != 0: # not self-dual print(shortstr(dot2(G, Gt))) assert 0 return #if G.shape[1]<m: # continue if 0 in G.sum(1): print(".", end="", flush=True) continue #print(shortstr(G)) # for g in G: # print(shortstr(g), g.sum()) # print() _density = float(G.sum()) / (G.shape[0]*G.shape[1]) #if best is None or _density < density: if best is None or G.shape[1] <= size: best = G size = G.shape[1] density = _density if 0: #sols.append(G) Gx = even_rows(G) assert is_morthogonal(Gx, 3) if len(Gx)==0: continue GGx = array2(list(span(Gx))) assert is_morthogonal(GGx, 3) count += 1 print("found %d solutions" % count) if best is None: return G = best #print(shortstr(G)) f = open("selfdual.ldpc", "w") for spec in ["Hx =", "Hz ="]: print(spec, file=f) for g in G: print(shortstr(g), file=f) f.close() print() print("density:", density) print("shape:", G.shape) if 0: B = pseudo_inverse(A) v = dot2(B, rhs) print("B:") print(shortstr(B)) print("v:") print(shortstr(v)) assert eq2(dot2(B, v), rhs)
def get_codespace(G): space = list(span(G)) return space
def search(): # Bravyi, Haah, 1209.2426v1 sec IX. # https://arxiv.org/pdf/1209.2426.pdf verbose = argv.get("verbose") m = argv.get("m", 6) # _number of rows k = argv.get("k", None) # _number of odd-weight rows # these are the variables N_x xs = list(cross([(0, 1)]*m)) maxweight = argv.maxweight minweight = argv.get("minweight", 1) xs = [x for x in xs if minweight <= sum(x)] if maxweight: xs = [x for x in xs if sum(x) <= maxweight] N = len(xs) lhs = [] rhs = [] # bi-orthogonality for a in range(m): for b in range(a+1, m): v = zeros2(N) for i, x in enumerate(xs): if x[a] == x[b] == 1: v[i] = 1 if v.sum(): lhs.append(v) rhs.append(0) # tri-orthogonality for a in range(m): for b in range(a+1, m): for c in range(b+1, m): v = zeros2(N) for i, x in enumerate(xs): if x[a] == x[b] == x[c] == 1: v[i] = 1 if v.sum(): lhs.append(v) rhs.append(0) # # dissallow columns with weight <= 1 # for i, x in enumerate(xs): # if sum(x)<=1: # v = zeros2(N) # v[i] = 1 # lhs.append(v) # rhs.append(0) if k is not None: # constrain to k _number of odd-weight rows assert 0<=k<m for a in range(m): v = zeros2(N) for i, x in enumerate(xs): if x[a] == 1: v[i] = 1 lhs.append(v) if a<k: rhs.append(1) else: rhs.append(0) A = array2(lhs) rhs = array2(rhs) #print(shortstr(A)) B = pseudo_inverse(A) soln = dot2(B, rhs) if not eq2(dot2(A, soln), rhs): print("no solution") return if verbose: print("soln:") print(shortstr(soln)) soln.shape = (N, 1) rhs.shape = A.shape[0], 1 K = array2(list(find_kernel(A))) #print(K) #print( dot2(A, K.transpose())) #sols = [] #for v in span(K): best = None density = 1.0 size = 99*N trials = argv.get("trials", 1024) count = 0 for trial in range(trials): u = rand2(len(K), 1) v = dot2(K.transpose(), u) #print(v) v = (v+soln)%2 assert eq2(dot2(A, v), rhs) if v.sum() > size: continue size = v.sum() Gt = [] for i, x in enumerate(xs): if v[i]: Gt.append(x) if not Gt: continue Gt = array2(Gt) G = Gt.transpose() assert is_morthogonal(G, 3) if G.shape[1]<m: continue if 0 in G.sum(1): continue if argv.strong_morthogonal and not strong_morthogonal(G, 3): continue #print(shortstr(G)) # for g in G: # print(shortstr(g), g.sum()) # print() _density = float(G.sum()) / (G.shape[0]*G.shape[1]) #if best is None or _density < density: if best is None or G.shape[1] <= size: best = G size = G.shape[1] density = _density if 0: #sols.append(G) Gx = even_rows(G) assert is_morthogonal(Gx, 3) if len(Gx)==0: continue GGx = array2(list(span(Gx))) assert is_morthogonal(GGx, 3) count += 1 print("found %d solutions" % count) if best is None: return G = best #print(shortstr(G)) for g in G: print(shortstr(g), g.sum()) print() print("density:", density) print("shape:", G.shape) G = linear_independent(G) A = list(span(G)) print(strong_morthogonal(A, 1)) print(strong_morthogonal(A, 2)) print(strong_morthogonal(A, 3)) #print(shortstr(dot2(G, G.transpose()))) if 0: B = pseudo_inverse(A) v = dot2(B, rhs) print("B:") print(shortstr(B)) print("v:") print(shortstr(v)) assert eq2(dot2(B, v), rhs)
def genus_enum2(code=None, verbose=False): if code is None: code = get_code() G = code.G print(shortstr(G)) m, n = G.shape poly = lambda cs : Poly(cs, 4, "x_{00} x_{01} x_{10} x_{11}".split()) cs = {} for v0 in span(G): print(".",end='',flush=True) for v1 in span(G): exp = [0, 0, 0, 0] #vv = numpy.array([2*v0, v1]) for i in range(n): exp[2*v0[i] + v1[i]] += 1 exp = tuple(exp) cs[exp] = cs.get(exp, 0) + 1 #break print() p = poly(cs) if argv.latex: print(p) else: print(p.flatstr()) CZ = numpy.array([ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, -1]]) q = p.transform(CZ) print("invariant under CZ", q==p) CS2 = numpy.array([ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, -1, 0]]) q = p.transform(CS2) print("invariant under CS2", q==p) CX = numpy.array([ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]) q = p.transform(CX) print("invariant under CX", q==p) T2 = numpy.array([ [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1], [-1, 0, 0, 0]]) q = p.transform(T2) print("invariant under T2", q==p) A = numpy.array([ [0, 0, 1, 0], [0, 0, 0, 1], [0, 1, 0, 0], [-1, 0, 0, 0]]) q = p.transform(A) print("invariant under A", q==p)
def genus_enum3(code=None, verbose=False): if code is None: code = get_code() G = code.G print(shortstr(G)) m, n = G.shape rank = 8 poly = lambda cs : Poly(cs, rank, "x_{000} x_{001} x_{010} x_{011} x_{100} x_{101} x_{110} x_{111}".split()) cs = {} assert len(G) < 14 items = list(span(G)) for v0 in items: print(".",end='',flush=True) for v1 in items: for v2 in items: exp = [0, 0, 0, 0, 0, 0, 0, 0] #vv = numpy.array([2*v0, v1]) for i in range(n): exp[4*v0[i] + 2*v1[i] + v2[i]] += 1 exp = tuple(exp) cs[exp] = cs.get(exp, 0) + 1 #break print() p = poly(cs) if argv.latex: print(p) else: print(p.flatstr()) print() CCZ = numpy.array([ [1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, -1]]) q = p.transform(CCZ) print("invariant under CCZ", q==p) CS2 = numpy.array([ [1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, -1, 0]]) q = p.transform(CS2) print("invariant under CS2", q==p) CCX = numpy.array([ [1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 1, 0]]) q = p.transform(CCX) print("invariant under CCX", q==p) T3 = numpy.array([ [1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, -1, 0, 0, 0]]) q = p.transform(T3) print("invariant under T3", q==p) A = numpy.array([ [1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, -1, 0, 0, 0]]) q = p.transform(A) print("invariant under A", q==p)
def get_key(L): vs = [str(v) for v in span(L) if v.sum()] vs.sort() key = ''.join(vs) return key