def __init__(self, U, q=2): m, n = U.shape #scalars = list(range(1, q)) #print(scalars, U) #vecs = list(((r*v)) for v in span(U) for r in scalars) #print(vecs) #vecs = list(((r*v)%q) for v in span(U) for r in scalars) #print(vecs) #print() #vecs = set(((r*v)%q).tostring() for v in span(U) for r in scalars) vecs = set() vals = list(range(q)) for u in cross((vals, ) * m): vec = numpy.dot(u, U) % q vecs.add(vec.tostring()) vecs = list(vecs) vecs.sort() vecs = tuple(vecs) #assert len(vecs) == len(set(vecs)) self.n = n self.U = U self._key = vecs N = len(vecs) m = int(round(log2(N) / log2(q))) assert q**m == N self.m = m # rank of U
def find_alpha(g): # alpha is determined by its values on the basis elements # (no it's not linear!) but here we search through all functions # (dict's) space -> 2Z/4Z . There are always N solutions . n = g.n space = vecspace(2 * n) lhs = {} pairs = [(v, w) for v in space for w in space] for (v, w) in pairs: lhs[v, w] = (beta(g(v), g(w)) - beta(v, w)) % 4 N = 2**(2 * n) for value in cross([(0, 1)] * N): alpha = {} for idx, v in enumerate(space): alpha[v] = 2 * value[idx] #print(alpha) for (v, w) in pairs: #if alpha[v] + alpha[w] != alpha[v+w]: # break #lhs = (beta(g(v), g(w)) - beta(v, w)) % 4 rhs = (alpha[v + w] - alpha[v] - alpha[w]) % 4 if lhs[v, w] != rhs: break else: yield alpha
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 zeros2(0, row) return if row == 0: yield identity2(col) return # recursive steps: m, n = col, col + row for left in get_cell(row, col - 1, p): A = zeros2(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 = zeros2(m, n) A[:, :n - 1] = right A[:, n - 1] = v yield A
def all_codes_3(pauli, n): I = pauli.I X = pauli.X Y = pauli.Y Z = pauli.Z In = reduce(matmul, [I] * n) all_ops = [reduce(matmul, op) for op in cross([[I, X, Y, Z]] * n)] assert all_ops[0] == In all_ops.pop(0) N = len(all_ops) print("all_ops:", N) for i in range(N): opi = all_ops[i] for j in range(i + 1, N): opj = all_ops[j] if opi * opj != opj * opi: continue for k in range(j + 1, N): opk = all_ops[k] if opi * opk != opk * opi: continue if opj * opk != opk * opj: continue yield [opi, opj, opk]
def get_basis(self): count = 0 for decl in cross(["IXZY"] * self.n): decl = ''.join(decl) op = parse(decl) yield decl, op count += 1 assert count == 4**self.n
def search(): CX = X.control(0, 1) # target, source assert CZ == Z.control(0, 1) assert CZ == Z.control(1, 0) #print(CZ.flat().v) #print(X.control(0, 1).flat().v) #print(X.control(1, 0).flat().v) #chi = (I @ CX @ I) * (bell @ bell) # looking to teleport a CX gate #B = (H @ H) * CZ chi = (I @ CZ @ I) * (bell @ bell) # looking to teleport a CZ gate B = CZ start = (B @ I @ I @ B) * (I @ chi @ I) for idxs in cross([(0, 1, 2)] * 6): ops = [(I, X, Z)[i] for i in idxs] # IXX XIX lhs = ops[0].control(2, 4, rank=6) * start lhs = ops[1].control(3, 4, rank=6) * lhs lhs = ops[2].control(2, 5, rank=6) * lhs lhs = ops[3].control(2, 0, rank=6) * lhs lhs = ops[4].control(3, 0, rank=6) * lhs lhs = ops[5].control(3, 1, rank=6) * lhs lhs0 = lhs x = plus #x = one lhs = (~x @ ~x @ I @ I @ ~x @ ~x) * lhs #print(lhs.valence) #print(lhs.valence, lhs.shortstr(), lhs[0,0,0,0]) r = lhs[0, 0, 0, 0] if abs(r) < EPSILON: continue lhs /= r if lhs == CZ: print("FOUND " * 10) print(lhs.shortstr()) print(['IXZ'[i] for i in idxs]) #break if 0: print(lhs0.shortstr()) op = (Z.control(0, 5) * (I @ plus @ plus @ plus @ plus @ I)) print(op.shortstr())
def vecspace(n): if n in _vec_cache: return _vec_cache[n] items = [(0, 1)] * n space = [] for v in cross(items): space.append(Vector(v)) _vec_cache[n] = space return space
def generate(self, q): A = self.A stars = self.stars q = range(q) for vals in cross((q, ) * len(stars)): B = A.copy() for i, val in enumerate(vals): B[stars[i]] = val yield B
def borel_gl(n, q): "Borel subgroup of GL(n, q)" A = numpy.zeros((n, n), dtype=int) stars = [(i, j) for i in range(0, n - 1) for j in range(i + 1, n)] nz = list(range(1, q)) diags = [diag for diag in cross((nz, ) * n)] #print(len(diags), len(stars)) N = len(stars) for vals in cross((range(q), ) * N): for diag in diags: X = A.copy() for i, val in enumerate(vals): X[stars[i]] = val for i in range(n): X[i, i] = diag[i] yield X
def get_reflects(G, I): reflects = [] count = 0 for ops in cross((G, ) * degree): op = reduce(matmul, ops) if op * op == I: count += 1 reflects.append(op) reflects.remove(I) reflects.remove(nI) return reflects
def borel_sp(n, q): "Borel subgroup of Sp(n, q)" assert n % 2 == 0 n2 = n // 2 J = mk_form(n, q) mul = list(range(1, q)) inv = {} for i in mul: for j in mul: if (i * j) % q == 1: inv[i] = j break else: assert 0 diags = [] for diag0 in cross((mul, ) * n2): diag1 = tuple(inv[i] for i in diag0) diags.append(diag0 + diag1) #print(diag0 + diag1) stars = [(i, j) for i in range(0, n2) for j in range(n2, n)] J = mk_form(n, q) N = len(stars) X = numpy.zeros((n, n), dtype=int) for vals in cross((range(q), ) * N): for i, star in enumerate(stars): X[star] = vals[i] for diag in diags: for i in range(n): X[i, i] = diag[i] XtJX = numpy.dot(X.transpose(), numpy.dot(J, X)) % q if XtJX.tostring() == J.tostring(): yield X.copy()
def make_relators(I, gen, names=None, depth=5): # make some gap code for generators and relators n = len(gen) rels = set() def addword(word): i = min(word) idx = word.index(i) n = len(word) word = tuple(word[(i + idx) % n] for i in range(n)) rels.add(word) for width in range(2, depth): itemss = [tuple(range(n))] * width for word in cross(itemss): gword = [gen[i] for i in word] g = reduce(mul, gword) if g == I: for h in rels: if contains(h, word + word): break else: addword(word) print("rels:", len(rels)) if names is None: names = string.ascii_letters[:n] if len(names) < n: names = [ "%s%s" % (a, b) for a in string.ascii_letters for b in string.ascii_letters ] assert len(names) == len(set(names)) == n, repr(names) print() print("F := FreeGroup(%s);;" % (",".join('"%s"' % l for l in names))) for idx, name in enumerate(names): print("%s := F.%s;;" % (name, idx + 1)) items = [] rels = list(rels) rels.sort() for rel in rels: rel = [names[idx] for idx in rel] rel = "*".join(rel) items.append(rel) print("G := F / [%s];;" % (','.join(items))) print("Order(G);")
def find_triorth(m, k): # 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) if 0: A = list(span(G)) print(strong_morthogonal(A, 1)) print(strong_morthogonal(A, 2)) print(strong_morthogonal(A, 3)) G = [row for row in G if row.sum() % 2 == 0] return array2(G) #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 bruhat(): n = argv.get("n", 4) assert n % 2 == 0, repr(n) m = argv.get("m", 2) q = argv.get("q", 2) # symplectic form A = mk_form(n, q) # all non-zero vectors vals = list(range(q)) vecs = list(cross((vals, ) * n)) assert sum(vecs[0]) == 0 vecs.pop(0) # find unique spaces spaces = set() for U in cross_upper(vecs, m): U = numpy.array(U) U.shape = m, n B = numpy.dot(U, numpy.dot(A, U.transpose())) % q if B.max(): continue space = Space(U, q) if space.m != m: continue spaces.add(space) if 0: #space = [str(v) for v in span(U)] # SLOW space = [v.tostring() for v in span(U)] # q==2 only if len(space) != q**m: continue space.sort() #space = ''.join(space) #print(space) space = tuple(space) spaces.add(space) N = len(spaces) print("points:", N) if argv.verbose: for X in spaces: print(X) B = list(borel_sp(n, q)) print("borel:", len(B)) assert len(B) spaces = list(spaces) lookup = dict((space, i) for (i, space) in enumerate(spaces)) orbits = list(set([space]) for space in spaces) perms = [] for g in B: perm = [] for i, space in enumerate(spaces): U = numpy.dot(space.U, g) % q t = Space(U, q) #if t not in lookup: # print(space) # print(t) perm.append(lookup[t]) perms.append(perm) print(".", end=" ", flush=True) print() remain = set(range(N)) orbits = [] while remain: i = iter(remain).__next__() remain.remove(i) orbit = [i] for perm in perms: j = perm[i] if j in remain: remain.remove(j) orbit.append(j) orbits.append(orbit) orbits.sort(key=len) print("%d orbits:" % len(orbits)) for orbit in orbits: print("size =", len(orbit)) for idx in orbit: space = spaces[idx] U = space.U if q == 2: U = row_reduce(U)
def main(): #pauli = build_algebra("IXZY", "X*X=I Z*Z=I Y*Y=-I X*Z=Y Z*X=-Y X*Y=Z Y*X=-Z Z*Y=-X Y*Z=X") pauli = build_algebra( "IXZY", "X*X=I Z*Z=I Y*Y=I X*Z=-iY Z*X=iY X*Y=iZ Y*X=-iZ Z*Y=-iX Y*Z=iX") I = pauli.I X = pauli.X Y = pauli.Y Z = pauli.Z n = argv.get("n", 4) #all_ops = [reduce(matmul, op) for op in cross([[I, X, Y, Z]]*n)] if 0: code = StabilizerCode(pauli, "XXXI ZZIZ IYYY") #code = StabilizerCode(pauli, "XYZI IXYZ ZIXY") #code = StabilizerCode(pauli, "XZZXI IXZZX XIXZZ ZXIXZ") n = code.n P = code.get_projector() print(P) I = Gate.I X = Gate.X Z = Gate.Z Y = Gate.Y S = Gate.S Sd = S.dag() ns = {"I": I, "X": X, "Z": Z, "Y": Y, "S": S} Xt = reduce(matmul, [X] * n) Zt = reduce(matmul, [Z] * n) Yt = reduce(matmul, [Y] * n) St = reduce(matmul, [S] * n) if 0: for g in all_ops: desc = str(g) g = get_dense(g) if g * St != St * g: continue print(desc) return #code = StabilizerCode(pauli, "XZZXI IXZZX XIXZZ ZXIXZ") # S is not transversal count = 0 for P in uniq_codes(pauli, n): desc = str(P) P = get_dense(P) if P * Xt != Xt * P: continue if P * Zt != Zt * P: continue if P * St != St * P: continue if P * Xt == P or P * Xt == -P: continue if P * Zt == P or P * Zt == -P: continue if P * Yt == P or P * Yt == -P: continue print(desc) count += 1 print("count:", count) if 0: for ops in cross([["I", "S", "X", "Z", "Y"]] * n): s = "".join(ops) ops = [ns[op] for op in ops] op = reduce(matmul, ops) if P * op == op * P: print(s)