def all_parts2(self): "all the ways to break self into two subsets" items = self.items n = len(items) # if n==0: # yield items, items # return # # if n==1: # yield [], items # yield items, [] # return # # if n==2: # yield [], items # yield [items[0]], [items[1]] # yield [items[1]], [items[0]] # yield items, [] # return bits = [(0, 1)] * n for idxs in cross(bits): left = Set([items[i] for i in range(n) if idxs[i] == 0]) right = Set([items[i] for i in range(n) if idxs[i] == 1]) yield left, right
def build_E8(cls, check=False): D8 = cls.build_D(8, check=check) half = Fraction(1, 2) roots = list(D8.roots) for signs in cross([(-1, 1)] * 8): r = reduce(mul, signs) if r != 1: continue root = tuple(sign * half for sign in signs) roots.append(root) assert len(roots) == 240 simple = [] for i in range(6): root = [0] * 8 root[i] = 1 root[i + 1] = -1 simple.append(tuple(root)) root = [0] * 8 root[i] = 1 root[i + 1] = 1 simple.append(tuple(root)) root = [-half] * 8 simple.append(tuple(root)) return Weyl_E8.buildfrom_simple(roots, simple, name="E_8", order=696729600, check=check)
def dist(self): "depth-first _apply dist" if not self: return self op = self[0].dist() i = 1 while i < len(self): op = op * self[i].dist() i += 1 itemss = [] for item in self: if isinstance(item, (Var, Integer, Reciprocal)): itemss.append([item]) elif isinstance(item, Add): itemss.append(item.items) else: assert 0, repr(item) ops = [] for items in cross(itemss): ops.append(reduce(mul, items)) assert len(ops) if len(ops) == 1: op = ops[0] else: op = Add(ops) return op
def all_states(self): N = self.N ceil = self.ceil itemss = [list(range(ceil[idx])) for idx in range(1, N)] for values in cross(itemss): state = self.make_state(values) yield state
def get_cell(row, col, p=2): """ return all matrices in bruhat cell at (row, col) These have shape (col, col+row). """ if col == 0: yield zeros(0, row) return if row == 0: yield identity(col) return # recursive steps: m, n = col, col + row for left in get_cell(row, col - 1, p): A = zeros(m, n) A[:m - 1, :n - 1] = left A[m - 1, n - 1] = 1 yield A els = list(range(p)) vecs = list(cross((els, ) * m)) for right in get_cell(row - 1, col, p): for v in vecs: A = zeros(m, n) A[:, :n - 1] = right A[:, n - 1] = v yield A
def __init__(self, ring, mod): ModuloRing.__init__(self, ring, mod) assert isinstance(ring, PolynomialRing) assert mod[mod.deg] == 1 # monic dim = mod.deg assert dim>1 one = ring.one # unwrapped x = ring.x # unwrapped basis = [one, x] for i in range(dim-2): basis.append(basis[-1]*x) self.basis = basis # unwrapped elements = [] els = list(ring.base.get_elements()) for idx in cross((els,)*dim): a = ring.zero # unwrapped for i, coeff in enumerate(idx): a = a + coeff * basis[i] a = ModuloElement(a, self) # wrap elements.append(a) self.elements = elements assert len(elements) == len(els) ** dim, len(elements) self.mod = mod self.zero = ModuloElement(ring.zero, self) self.one = ModuloElement(one, self) self.x = ModuloElement(x, self)
def all_act(n, m): itemss = [tuple(range(m))] * (n - 1) * m for idxs in cross(itemss): act = table(n, m) for i in range(m): act[0, i] = i # identity is always zero for i in range(n - 1): for j in range(m): act[1 + i, j] = idxs[i + (n - 1) * j] yield act
def build_F4(cls, **kw): roots = [] idxs = range(4) for root in cross([(-1, 0, 1)] * 4): d = sum(root[i]**2 for i in idxs) if d == 1 or d == 2: roots.append(root) half = Fraction(1, 2) for root in cross([(-half, 0, half)] * 4): d = sum(root[i]**2 for i in idxs) if d == 1 or d == 2: roots.append(root) assert len(roots) == 48 simple = [(1, -1, 0, 0), (0, 1, -1, 0), (0, 0, 1, 0), (-half, -half, -half, -half)] return Weyl_F.buildfrom_simple(roots, simple, name="F_4", order=1152, **kw)
def build_G2(cls, **kw): roots = [] for root in cross([(-2, -1, 0, 1, 2)] * 3): if sum(root) != 0: continue d = sum(root[i]**2 for i in range(3)) if d == 2 or d == 6: roots.append(root) assert len(roots) == 12 simple = [(1, -1, 0), (-1, 2, -1)] return Weyl_G.buildfrom_simple(roots, simple, name="G_2", **kw)
def all_mul(n): itemss = [tuple(range(n))] * (n - 1) * (n - 1) for idxs in cross(itemss): mul = table(n, n) for i in range(n): mul[0, i] = i # identity is always zero mul[i, 0] = i # identity is always zero for i in range(n - 1): for j in range(n - 1): mul[1 + i, 1 + j] = idxs[i + (n - 1) * j] yield mul
def all_subsets(els): els = tuple(els) n = len(els) if n == 0: yield () return if n == 1: yield () yield els return bits = [(0, 1)] * n for select in cross(bits): items = tuple(els[i] for i in range(n) if select[i]) yield items
def getitem(self, idx): idxs = list(range(idx+1)) n = self.n child = self.child ring = self.ring value = ring.zero for jdxs in cross([idxs]*(n-1)): total = 0 walue = ring.one for j in jdxs: walue *= child[j] total += j if total <= idx: walue *= child[idx-total] value += walue return value
def __getitem__(self, U): F = self.F G = self.G # print("ComposeSpecies.__getitem__", F, G, U) items = [] for p in U.all_partitions(): # the partition p is a Set of Set's (subsets of U) # print("partition:", p) factors = [] for V in p: # print("V = %s, len(V)=%s, G[V] = %s" % (V, len(V), G[V])) factors.append(tuple(G[V])) for struct in F[p]: # print("F[p]:", struct) #item = Set.mul_many([struct] + factors) for item in cross(factors): yield (struct, item)
def main(): p = argv.get("p", 3) field = FiniteField(p) ring = PolynomialRing(field) x = ring.x found = set() items = [list(field.elements)] * p for cs in cross(items): f = ring.zero for c in cs: f = x * f f = f + c vals = tuple(f(j) for j in field.elements) found.add(vals) print(' '.join([str(v) for v in vals])) print(len(found), p**p)
def all_monomials(vs, deg, ring): n = len(vs) assert n>0 if n==1: v = vs[0] yield v**deg return items = list(range(deg+1)) for idxs in cross((items,)*(n-1)): idxs = list(idxs) remain = deg - sum(idxs) if remain < 0: continue idxs.append(remain) p = Poly({():1}, ring) assert p==1 for idx, v in zip(idxs, vs): p = p * v**idx yield p
def find_irreducible(ring, deg): assert isinstance(ring.base, FiniteField) assert deg > 1 field = ring.base x = ring.x vals = list(range(field.p)) poly = None for coefs in cross([vals]*deg): #f = ring.promote(coefs[0]) f = ring.one for c in coefs: f = x*f + c #print(coefs, f) for i in range(field.p): if f(i)==0: break else: poly = f if poly is not None: break return poly
def all_trees(self): # A tree is a sequence of partitions of self, # each succesively refining the next, including top and bot. # See: https://oeis.org/A000311 items = self.items top = Set((self, )) if len(items) == 0: return if len(items) == 1: yield (top, ) # top == bot return if len(items) == 2: a, b = self bot = Set([Set([a]), Set([b])]) yield (top, bot) return for partition in self.all_partitions(): if len(partition) == 1: continue if len(partition) == len(self): yield (top, partition) # top, bot continue stack = [] # not a stack for part in partition: trees = list(part.all_trees()) stack.append(trees) for section in cross(stack): n = max(len(tree) for tree in section) result = [partition] for i in range(n): items = [tree[min(i, len(tree) - 1)] for tree in section] # brain hurts... items = Set(items) result.append(items) yield tuple(result)
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 main(): d = argv.get("d", 3) assert d>=2 double = argv.double if d==2: ring = CyclotomicRing(4) #ring = element.Z gamma = ring.x w = gamma**2 assert w == -1 double = True else: ring = CyclotomicRing(d**2) gamma = ring.x w = gamma**d I = numpy.zeros((d, d), dtype=object) wI = numpy.zeros((d, d), dtype=object) X = numpy.zeros((d, d), dtype=object) Z = numpy.zeros((d, d), dtype=object) Zdag = numpy.zeros((d, d), dtype=object) S = numpy.zeros((d, d), dtype=object) Sdag = numpy.zeros((d, d), dtype=object) T = numpy.zeros((d, d), dtype=object) Tdag = numpy.zeros((d, d), dtype=object) for j in range(d): I[j, j] = 1 wI[j, j] = w X[j, (j+1)%d] = 1 Z[j, j] = w**j Zdag[j, j] = w**(d-j) if d==2: val = gamma**(j**2) ival = gamma**(d**2 - (j**2)%(d**2)) else: val = w**(j**2) ival = w**(d - (j**2)%d) assert val*ival == 1 S[j, j] = val Sdag[j, j] = ival if d in [2, 3, 6]: val = gamma**(j**3) ival = gamma**(d**2 - (j**3)%(d**2)) else: val = w**(j**3) ival = w**(d - (j**3)%d) assert val*ival == 1 T[j, j] = val Tdag[j, j] = ival qu = Space(d, ring) hom = Hom(qu, qu) I = Map.from_array(I, hom) wI = Map.from_array(wI, hom) Xdag = Map.from_array(X.transpose(), hom) X = Xs = Map.from_array(X, hom) Z = Map.from_array(Z, hom) Zdag = Map.from_array(Zdag, hom) S = Map.from_array(S, hom) Sdag = Map.from_array(Sdag, hom) T = Map.from_array(T, hom) Tdag = Map.from_array(Tdag, hom) if d==2: Y = gamma*X*Z # ? else: Y = w*X*Z # ? assert S*Sdag == I assert Z*Zdag == I assert X*Xdag == I if d>2: for j in range(1, d+1): assert (j==d) == (X**j==I) assert (j==d) == (Z**j==I) else: assert X != I assert Z != I assert X*X == I assert Z*Z == I assert Z*X == (w**(d-1))*X*Z if double: pauli = mulclose([X, Z, gamma*I]) names = mulclose_names([X, Z, gamma*I], "X Z i".split()) else: pauli = mulclose([X, Z]) names = mulclose_names([X, Z, Xdag, Zdag, -I], "X Z Xi Zi -I".split()) pauli = set(pauli) print("pauli:", len(pauli)) assert Zdag in pauli assert Xdag in pauli if d<6: # slow.. lhs = atpow(X, d) rhs = atpow(Z, d) assert lhs * rhs == rhs * lhs lhs = X@X rhs = Z@Zdag assert lhs * rhs == rhs * lhs lhs = X@(X**(d-1)) rhs = Z@Z assert lhs * rhs == rhs * lhs if 0: n = 5 ops = [X, Xdag] lhs = [] for op in cross([ops]*n): op = reduce(matmul, op) lhs.append(op) ops = [Z, Zdag] rhs = [] for op in cross([ops]*n): op = reduce(matmul, op) rhs.append(op) for l in lhs: for r in rhs: if l*r == r*l: print("/", end=" ", flush=True) else: print(".", end=" ", flush=True) print() print("S =") print(S) print("XSX =") print(X*S*X) print("XSXS =") print(X*S*X*S) #print("Y =") #print(Y) #print("S*X*Sdag =") #print(S*X*Sdag) assert Y == S*X*Sdag def get_orbit(g, gi, v): orbit = [v] while 1: u = g*orbit[-1]*gi if u == orbit[0]: break orbit.append(u) return orbit print("S orbit:") for A in [X, Z]: print('\t', [''.join(names[op]) for op in get_orbit(S, Sdag, A)]) U = X*S Ui = Sdag * Xdag assert U*Ui == I print("XS orbit:") for A in [X, Z]: print('\t', [''.join(names[op]) for op in get_orbit(U, Ui, A)]) U = X*X*S Ui = Sdag * Xdag * Xdag assert U*Ui == I print("XXS orbit:") for A in [X, Z]: print('\t', [''.join(names[op]) for op in get_orbit(U, Ui, A)]) return inverse = {} for g in pauli: for h in pauli: if g*h == I: inverse[g] = h inverse[h] = g def is_cliff(A, Ai): assert A*Ai == I for g in pauli: h = A*g*Ai if h not in pauli: return False return True print("S =") print(S) print("S**2 =") print(S**2) print("Sdag =") print(Sdag) assert is_cliff(S, Sdag) #print("is_cliff:", (S in pauli), is_cliff(S, Sdag)) def is_third_level(A, Ai): assert A*Ai == I for g in pauli: gi = inverse[g] h = A*g*Ai*gi hi = g*A*gi*Ai if not is_cliff(h, hi): return False return True print("is_pauli(S)", S in pauli) print("is_cliff(S)", is_cliff(S, Sdag)) #print("is_third_level(S)", is_third_level(S, Tdag)) print("is_pauli(T)", T in pauli) print("is_cliff(T)", is_cliff(T, Tdag)) print("is_third_level(T)", is_third_level(T, Tdag)) print("OK")
Theorem: It is not possible to assign values phi in {-1, 1} to every member of the 2-qubit pauli group such that phi(XI)*phi(IX)*phi(XX) = 1 phi(IZ)*phi(ZI)*phi(ZZ) = 1 phi(XZ)*phi(ZX)*phi(YY) = 1 phi(XI)*phi(IZ)*phi(XZ) = 1 phi(IX)*phi(ZI)*phi(ZX) = 1 phi(XX)*phi(ZZ)*phi(YY) = -1 """ items = "XI IX XX IZ ZI ZZ XZ ZX YY".split() XI, IX, XX, IZ, ZI, ZZ, XZ, ZX, YY = items n = len(items) for vals in cross([(-1, 1)] * n): phi = {} for idx, item in enumerate(items): phi[items[idx]] = vals[idx] if (phi[XI] * phi[IX] * phi[XX] == 1 and phi[IZ] * phi[ZI] * phi[ZZ] == 1 and phi[XZ] * phi[ZX] * phi[YY] == 1 and phi[XI] * phi[IZ] * phi[XZ] == 1 and phi[IX] * phi[ZI] * phi[ZX] == 1 and phi[XX] * phi[ZZ] * phi[YY] == -1): for idx, item in enumerate(items): print("phi(%s)=%s " % (item, phi[item]), end=" ") if (idx + 1) % 3 == 0: print() break
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 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 find_stabilizer_code(H): H = H.strip().split() H = [list(row) for row in H] H = numpy.array(H) m, n = H.shape #print(H) import z3 from z3 import Bool, And, Or, Not, Implies, If, Solver vs = {} clauses = [] solver = Solver() for i in range(m): for j in range(n): c = H[i, j] if c == '.': continue X = Bool("X_%d_%d" % (i, j)) Z = Bool("Z_%d_%d" % (i, j)) vs[i, j] = (X, Z) if c == 'I': # X or Z and not both solver.add(Or(X, Z)) solver.add(Not(And(X, Z))) elif c == 'X': # freeze this as X solver.add(X) solver.add(Not(Z)) elif c == 'Z': # freeze this Z solver.add(Not(X)) solver.add(Z) elif c == 'Y': # freeze this as X and Z solver.add(X) solver.add(Z) else: assert 0, (i, j, c) for i in range(m): for j in range(i + 1, m): bits = [] for k in range(n): if H[i, k] == '.' or H[j, k] == '.': continue bits.append(k) if not bits: continue #print() #print(i, j, bits) for lhs in cross([(0, 1)] * len(bits)): lvars = [vs[i, k][l] for (k, l) in zip(bits, lhs)] #print(lhs, lvars) for rhs in cross([(0, 1)] * len(bits)): rvars = [vs[j, k][r] for (k, r) in zip(bits, rhs)] syndrome = len([ idx for idx in range(len(bits)) if lhs[idx] != rhs[idx] ]) % 2 #print('\t', rhs, rvars, syndrome) if syndrome: clause = Not(And(*lvars, *rvars)) #print('\t', clause) solver.add(clause) result = solver.check() if result != z3.sat: return None H = numpy.empty((m, n), dtype=object) H[:] = '.' model = solver.model() for key, XZ in vs.items(): #for v in XZ: #print(v, model.evaluate(v)) X, Z = XZ X = model.evaluate(X) Z = model.evaluate(Z) assert X or Z assert not (X and Z) if X: H[key] = 'X' if Z: H[key] = 'Z' H = ("\n".join(''.join(row) for row in H)) return H
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 GF(q): ps = factorize(q) assert len(set(ps)) == 1 p = ps[0] r = len(ps) assert q == p**r #print(p, r) field = FiniteField(p) if r == 1: return field ring = PolynomialRing(field) zero = ring.zero one = ring.one x = ring.x itemss = [tuple(range(p)) for i in range(r)] for idxs in cross(itemss): poly = x**r for i, idx in enumerate(idxs): poly += idx * (x**i) #print(poly) for i in range(p): if poly(i) == zero: #print("i=", i) break else: break #print("poly:", poly) #print([str(poly(i)) for i in range(p)]) F = GaloisField(ring, poly) def frobenius(a): return a**p def hermitian(a, b): return a * (b**p) def trace_hermitian(a, b): return (a**p) * b + a * (b**p) F.frobenius = frobenius F.hermitian = hermitian one = F.one zero = F.zero def order(u): count = 1 v = u assert v != zero while v != one: v = u * v count += 1 assert count < 2 * q return count for u in F.elements: if u == zero: continue #print(u, order(u)) if order(u) == q - 1: F.omega = u # generator of multiplicative group break else: assert 0 return F
def ffield(): "look for finite field solutions" p = argv.get("p", 3) dim = argv.get("dim", 3) dim2 = dim**2 I = empty((dim, dim), dtype=int) I[:] = 0 for i in range(dim): I[i, i] = 1 #print(I) SWAP = empty((dim, dim, dim, dim), dtype=int) SWAP[:] = 0 for i in range(dim): for j in range(dim): SWAP[i, j, j, i] = 1 SWAP.shape = dim2, dim2 #print(SWAP) assert alltrue(dot(SWAP, SWAP) == tensor(I, I)) # ----------------------------------------------------------- # Build some Frobenius algebra's ... find the copyable states system = System() F = system.array(dim, dim**2, "F") # mul G = system.array(dim, 1, "G") # unit D = system.array(dim**2, dim, "D") # comul E = system.array(1, dim, "E") # counit #for item in system.items: # print(item) IF = tensor(I, F) FI = tensor(F, I) IG = tensor(I, G) GI = tensor(G, I) ID = tensor(I, D) DI = tensor(D, I) IE = tensor(I, E) EI = tensor(E, I) # unit system.add(compose(IG, F), I) system.add(compose(GI, F), I) # _assoc system.add(compose(FI, F), compose(IF, F)) # commutative commutative = argv.get("commutative", True) if commutative: system.add(F, compose(SWAP, F)) # counit system.add(compose(D, IE), I) system.add(compose(D, EI), I) # _coassoc system.add(compose(D, DI), compose(D, ID)) # cocommutative #system.add(D, compose(D, SWAP)) # Frobenius system.add(compose(DI, IF), compose(F, D)) system.add(compose(ID, FI), compose(F, D)) # special special = argv.get("special", True) if special: system.add(compose(D, F), I) # https://theory.stanford.edu/~nikolaj/programmingz3.html import z3 def all_smt(s, initial_terms): def block_term(s, m, t): s.add(t != m.eval(t, model_completion=True)) def fix_term(s, m, t): s.add(t == m.eval(t, model_completion=True)) def all_smt_rec(terms): if z3.sat == s.check(): m = s.model() yield m for i in range(len(terms)): s.push() block_term(s, m, terms[i]) for j in range(i): fix_term(s, m, terms[j]) yield from all_smt_rec(terms[i:]) s.pop() yield from all_smt_rec(list(initial_terms)) def block_model(s): m = s.model() s.add(z3.Or([f() != m[f] for f in m.decls() if f.arity() == 0])) ns = {} clauses = [] for v in system.vs: v = str(v) iv = z3.Int(v) ns[v] = iv clauses.append(iv < p) clauses.append(0 <= iv) print(ns) for eq in system.eqs: eq = eval(str(eq), ns) % p == 0 clauses.append(eq) solver = z3.Solver() for c in clauses: solver.add(c) # print("solve...") # result = solver.check() # assert result == z3.sat, result # print("done.") #for model in all_smt(solver, []): while solver.check() == z3.sat: model = solver.model() values = {} for d in model: #print(d, model[d]) values[str(d)] = int(str(model[d])) print(values) items = [] for A in system.items: B = numpy.zeros(A.shape, int) for idx in numpy.ndindex(A.shape): B[idx] = values[str(A[idx])] items.append(B) F, G, D, E = items print(F) for vals in cross([tuple(range(dim))] * dim): v = numpy.array(vals) v.shape = (dim, 1) if v.sum() == 0: continue lhs = dot(D, v) rhs = tensor(v, v) if numpy.allclose(lhs, rhs): print(v.transpose()) block_model(solver) print() print("done")
def check_dualities(Hz, Hxt, dualities): from bruhat.solve import shortstr, zeros2, dot2, array2, solve, span from numpy import alltrue, zeros, dot import qupy.ldpc.solve import bruhat.solve qupy.ldpc.solve.int_scalar = bruhat.solve.int_scalar from qupy.ldpc.css import CSSCode Hz = Hz % 2 Hx = Hxt.transpose() % 2 code = CSSCode(Hz=Hz, Hx=Hx) print(code) n = code.n Lx, Lz = code.Lx, code.Lz # check we really do have weak dualities here: for perm in dualities: Hz1 = Hz[:, perm] Hxt1 = Hxt[perm, :] assert solve(Hxt, Hz1.transpose()) is not None assert solve(Hz1.transpose(), Hxt) is not None Lz1 = Lz[:, perm] Lx1 = Lx[:, perm] find_xz = solve(concatenate((Lx, Hx)).transpose(), Lz1.transpose()) is not None find_zx = solve(concatenate((Lz1, Hz1)).transpose(), Lx.transpose()) is not None #print(find_xz, find_zx) assert find_xz assert find_zx # the fixed points live simultaneously in the homology & the cohomology fixed = [i for i in range(n) if perm[i] == i] if len(fixed) == 0: continue v = array2([0] * n) v[fixed] = 1 v.shape = (n, 1) find_xz = solve(concatenate((Lx, Hx)).transpose(), v) is not None find_zx = solve(concatenate((Lz, Hz)).transpose(), v) is not None #print(find_xz, find_zx) assert find_xz assert find_zx from qupy.ldpc.asymplectic import Stim as Clifford s_gates = [] h_gates = [] s_names = [] for idx, swap in enumerate(dualities): fixed = [i for i in range(n) if swap[i] == i] print(idx, fixed) for signs in cross([(-1, 1)] * len(fixed)): # <------- does not scale !!! XXX v = [0] * n for i, sign in enumerate(signs): v[fixed[i]] = sign ux = numpy.dot(Hx, v) uz = numpy.dot(Hz, v) if numpy.alltrue(ux == 0) and numpy.alltrue(uz == 0): #print("*", end=" ") break #else: # assert 0 #print(v) #print() # transversal S/CZ g = Clifford.identity(n) name = [] for i in range(n): j = swap[i] if j < i: continue if j == i: assert v[i] in [1, -1] if v[i] == 1: op = Clifford.s_gate(n, i) name.append("S_%d" % (i, )) else: op = Clifford.s_gate(n, i).inverse() name.append("Si_%d" % (i, )) else: op = Clifford.cz_gate(n, i, j) name.append("CZ_%d_%d" % (i, j)) g = op * g name = "*".join(reversed(name)) s_names.append(name) #print(g) #print() #assert g.is_transversal(code) s_gates.append(g) h = Clifford.identity(n) for i in range(n): h = h * Clifford.h_gate(n, i) for i in range(n): j = swap[i] if j <= i: continue h = h * Clifford.swap_gate(n, i, j) #print(g) #print() #assert h.is_transversal(code) h_gates.append(h) if 0: print() print("CZ:") CZ = Clifford.cz_gate(2, 0, 1) op = (1., [0, 0], [1, 1]) for i in range(4): print(op) op = CZ(*op) return for idx, sop in enumerate(s_gates): print("idx =", idx) #for hx in Hx: perm = dualities[idx] #for hx in span(Hx): for hx in Hx: #print("hx =", hx) #print(s_names[idx]) phase, zop, xop = sop(1., None, hx) assert numpy.alltrue(xop == hx) # fixes x component print(phase, zop, xop, dot2(zop, xop)) for (i, j) in enumerate(perm): if xop[i] and xop[j] and i < j: print("pair", (i, j)) if toric is None: continue print("xop =") print(toric.strop(xop)) print("zop =") print(toric.strop(zop)) print()
def main(): d = 2 ring = CyclotomicRing(8) #ring = element.Z e = ring.x gamma = e**2 w = gamma**2 assert w == -1 I = numpy.zeros((d, d), dtype=object) wI = numpy.zeros((d, d), dtype=object) X = numpy.zeros((d, d), dtype=object) Z = numpy.zeros((d, d), dtype=object) Zdag = numpy.zeros((d, d), dtype=object) S = numpy.zeros((d, d), dtype=object) Sdag = numpy.zeros((d, d), dtype=object) T = numpy.zeros((d, d), dtype=object) Tdag = numpy.zeros((d, d), dtype=object) for j in range(d): I[j, j] = 1 wI[j, j] = w X[j, (j + 1) % d] = 1 Z[j, j] = w**j Zdag[j, j] = w**(d - j) val = [1, gamma][j] ival = [1, -gamma][j] assert val * ival == 1 S[j, j] = val Sdag[j, j] = ival val = [1, e][j] ival = [1, e**7][j] assert val * ival == 1 T[j, j] = val Tdag[j, j] = ival qu = Space(d, ring) hom = Hom(qu, qu) I = Map.from_array(I, hom) wI = Map.from_array(wI, hom) Xdag = Map.from_array(X.transpose(), hom) X = Xs = Map.from_array(X, hom) Z = Map.from_array(Z, hom) Zdag = Map.from_array(Zdag, hom) S = Map.from_array(S, hom) Sdag = Map.from_array(Sdag, hom) T = Map.from_array(T, hom) Tdag = Map.from_array(Tdag, hom) Y = w * X * Z # ? assert S * Sdag == I assert S * S == Z assert T * T == S assert Z * Zdag == I assert X * Xdag == I if d > 2: for j in range(1, d + 1): assert (j == d) == (X**j == I) assert (j == d) == (Z**j == I) else: assert X != I assert Z != I assert X * X == I assert Z * Z == I assert Z * X == (w**(d - 1)) * X * Z pauli = mulclose([X, Z, gamma * I]) pauli = set(pauli) print("pauli:", len(pauli)) assert Zdag in pauli assert Xdag in pauli if d < 6: # slow.. lhs = atpow(X, d) rhs = atpow(Z, d) assert lhs * rhs == rhs * lhs lhs = X @ X rhs = Z @ Zdag assert lhs * rhs == rhs * lhs lhs = X @ (X**(d - 1)) rhs = Z @ Z assert lhs * rhs == rhs * lhs if 0: n = 5 ops = [X, Xdag] lhs = [] for op in cross([ops] * n): op = reduce(matmul, op) lhs.append(op) ops = [Z, Zdag] rhs = [] for op in cross([ops] * n): op = reduce(matmul, op) rhs.append(op) for l in lhs: for r in rhs: if l * r == r * l: print("/", end=" ", flush=True) else: print(".", end=" ", flush=True) print() #print(Z@Z@Z) #print(Y) #print(S*X*Sdag) #print(Y == S*X*Sdag) if d == 3: assert (Y == S * X * Sdag) inverse = {} for g in pauli: for h in pauli: if g * h == I: inverse[g] = h inverse[h] = g def is_cliff(A, Ai): assert A * Ai == I for g in pauli: h = A * g * Ai if h not in pauli: return False return True print(S) print(Sdag) assert is_cliff(S, Sdag) #print("is_cliff:", (S in pauli), is_cliff(S, Sdag)) def is_third_level(A, Ai): assert A * Ai == I for g in pauli: gi = inverse[g] h = A * g * Ai * gi hi = g * A * gi * Ai if not is_cliff(h, hi): return False return True print("is_pauli(S)", S in pauli) print("is_cliff(S)", is_cliff(S, Sdag)) #print("is_third_level(S)", is_third_level(S, Tdag)) print("is_pauli(T)", T in pauli) print("is_cliff(T)", is_cliff(T, Tdag)) print("is_third_level(T)", is_third_level(T, Tdag)) #C2 = mulclose([X, T, H]) print("OK")
def super_young(U, V, part): ring = U.ring n = sum(part) lookup = {} summands = [] for idxs in cross([(0, 1)] * n): spaces = [[U, V][idx] for idx in idxs] space = reduce(matmul, spaces) lookup[idxs] = len(summands) summands.append(space) #print(idxs, end=" ") #print(space.n) src = reduce(add, summands) G = Group.symmetric(n) hom = {} colim = src.identity() for action in G: perm = tuple(action[i] for i in range(n)) #print(perm) sumswap = [None] * len(summands) fs = [] for i, idxs in enumerate(cross([(0, 1)] * n)): jdxs = tuple(idxs[i] for i in perm) #print(idxs, "-->", jdxs) sumswap[lookup[jdxs]] = i space = src.items[i] f = space.get_swap(perm) fs.append(f) #print(sumswap) f = reduce(dsum, fs) #print(f.src.name, "-->", f.tgt.name) g = f.tgt.get_swap(sumswap) #print(g.src.name, "-->", g.tgt.name) assert f.tgt == g.src assert g.tgt == src hom[action] = (g, f) #print() young = Young(G, part) #print("Young:") #print(young) rowperms = young.get_rowperms() colperms = young.get_colperms() #print("rowperms", len(rowperms)) #print("colperms", len(colperms)) horiz = None for action in rowperms: (g, f) = hom[action] gf = g * f horiz = gf if horiz is None else (horiz + gf) assert horiz is not None vert = None for action in colperms: sign = action.sign() * ring.one g, f = hom[action] g = sign * g gf = g * f vert = gf if vert is None else (vert + gf) assert vert is not None P = horiz * vert P = P.row_reduce() #print(P.rank()) #print(P) #for a in src.items: # print(a) even = src.identity() odd = src.identity() i = 0 j = 0 for space in src.items: j += space.n while i < j: if space.grade % 2 == 0: odd[i, i] = ring.zero else: even[i, i] = ring.zero i += 1 return (P * even).rank(), (P * odd).rank()