def glue_pairs(H1, H2, pairs): m1, n1 = H1.shape m2, n2 = H2.shape k = len(pairs) A1 = Chain([H1]) A2 = Chain([H2]) C = Chain([identity2(k)]) C1n = zeros2(n1, k) for idx, pair in enumerate(pairs): i, j = pair C1n[i, idx] = 1 C1m = dot2(H1, C1n) C1 = Morphism(C, A1, [C1m, C1n]) C2n = zeros2(n2, k) for idx, pair in enumerate(pairs): i, j = pair C2n[j, idx] = 1 C2m = dot2(H2, C2n) C2 = Morphism(C, A2, [C2m, C2n]) AD, BD, D, _ = chain.pushout(C1, C2) H = D[0] #print(H.shape) #print(H) return H
def glue_self(Hx, Hz, pairs): mx, n = Hx.shape mz, _ = Hz.shape k = len(pairs) A = Chain([Hz, Hx.transpose()]) C = Chain([identity2(k), zeros2(k, 0)]) fn = zeros2(n, k) for idx, pair in enumerate(pairs): i1, i2 = pair fn[i1, idx] = 1 fm = dot2(Hz, fn) f = Morphism(C, A, [fm, fn, zeros2(mx, 0)]) gn = zeros2(n, k) for idx, pair in enumerate(pairs): i1, i2 = pair gn[i2, idx] = 1 gm = dot2(Hz, gn) g = Morphism(C, A, [gm, gn, zeros2(mx, 0)]) _, _, D = chain.equalizer(f, g) Hz, Hxt = D[0], D[1] return Hxt.transpose(), Hz
def glue_quantum(Hx1, Hz1, Hx2, Hz2, pairs): mx1, n1 = Hx1.shape mx2, n2 = Hx2.shape mz1, _ = Hz1.shape mz2, _ = Hz2.shape k = len(pairs) A1 = Chain([Hz1, Hx1.transpose()]) A2 = Chain([Hz2, Hx2.transpose()]) C = Chain([identity2(k), zeros2(k, 0)]) C1n = zeros2(n1, k) for idx, pair in enumerate(pairs): i, j = pair C1n[i, idx] = 1 C1m = dot2(Hz1, C1n) C1 = Morphism(C, A1, [C1m, C1n, zeros2(mx1, 0)]) C2n = zeros2(n2, k) for idx, pair in enumerate(pairs): i, j = pair C2n[j, idx] = 1 C2m = dot2(Hz2, C2n) C2 = Morphism(C, A2, [C2m, C2n, zeros2(mx2, 0)]) AD, BD, D, _ = chain.pushout(C1, C2) Hz, Hxt = D[0], D[1] #print(H.shape) #print(H) return Hz, Hxt.transpose()
def glue_self_classical(Hz, pairs): mz, n = Hz.shape k = len(pairs) A = Chain([Hz]) C = Chain([identity2(k)]) fn = zeros2(n, k) for idx, pair in enumerate(pairs): i1, i2 = pair fn[i1, idx] = 1 fm = dot2(Hz, fn) f = Morphism(C, A, [fm, fn]) gn = zeros2(n, k) for idx, pair in enumerate(pairs): i1, i2 = pair gn[i2, idx] = 1 gm = dot2(Hz, gn) g = Morphism(C, A, [gm, gn]) _, _, D = chain.equalizer(f, g) Hz = D[0] return Hz
def test_glue(): m = argv.get("m", 9) n = argv.get("n", 10) d = argv.get("d", 0) p = argv.get("p", 0.5) weight = argv.weight H1 = rand2(m, n, p, weight) G1 = find_kernel(H1) G1t = G1.transpose() H1t = H1.transpose() A1 = Chain([G1, H1t]) k1 = len(G1) print("H1") print(fstr(H1)) print() print(fstr(G1)) w = wenum(H1) print("wenum:", [len(wi) for wi in w]) H2 = rand2(m, n, p, weight) H2t = H2.transpose() G2 = find_kernel(H2) G2t = G2.transpose() A2 = Chain([G2, H2t]) k2 = len(G2) print("H2") print(fstr(H2)) print() print(fstr(G2)) w = wenum(H2) print("wenum:", [len(wi) for wi in w]) if k1 != k2: return k = k1 I = identity2(k) B = Chain([I, zeros2(k, 0)]) a = zeros2(n, k) for i in range(k): a[i, i] = 1 f1 = Morphism(B, A1, [dot2(G1, a), a, zeros2(m, 0)]) f2 = Morphism(B, A2, [dot2(G2, a), a, zeros2(m, 0)]) a, b, C, _ = chain.pushout(f1, f2) H = C[1].transpose() print("H:") print(fstr(H)) w = wenum(H) print("wenum:", [len(wi) for wi in w])
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 glue(self, i1, i2): assert i1!=i2 Hx = self.Hx Hz = self.Hz mx, n = Hx.shape mz, _ = Hz.shape k = 1 A = Chain([Hz, Hx.transpose()]) C = Chain([identity2(k), zeros2(k, 0)]) fn = zeros2(n, 1) fn[i1, 0] = 1 fm = dot2(Hz, fn) f = Morphism(C, A, [fm, fn, zeros2(mx, 0)]) gn = zeros2(n, 1) gn[i2, 0] = 1 gm = dot2(Hz, gn) g = Morphism(C, A, [gm, gn, zeros2(mx, 0)]) _, _, D = equalizer(f, g) Hz, Hxt = D[0], D[1] Hx = Hxt.transpose() code = CSSCode(Hx=Hx, Hz=Hz) return code
def symplectic_form(cls, n): A = zeros2(2 * n, 2 * n) I = identity2(n) A[:n, n:] = I A[n:, :n] = I A = Matrix(A) return A
def get_logops(idxs_C, idxs_Ct, idxs_D, idxs_Dt): # Lx -------------------------------------------------------------- Ic1 = identity2(c1)[idxs_C, :] Lx_h = kron(Ic1, CokerD), zeros2(len(idxs_C) * CokerD.shape[0], c0 * d1) Lx_h = numpy.concatenate(Lx_h, axis=1) assert dot2(Lx_h, Hz.transpose()).sum() == 0 Id1 = identity2(d1)[idxs_D, :] Lx_v = zeros2(CokerC.shape[0] * len(idxs_D), c1 * d0), kron(CokerC, Id1) Lx_v = numpy.concatenate(Lx_v, axis=1) Lxi = numpy.concatenate((Lx_h, Lx_v), axis=0) # Lz -------------------------------------------------------------- KerCt = KerC.transpose() Id0 = identity2(d0)[:, idxs_Dt] Lzt_h = kron(KerCt, Id0), zeros2(c0 * d1, KerCt.shape[1] * len(idxs_Dt)) Lzt_h = numpy.concatenate(Lzt_h, axis=0) assert dot2(Hx, Lzt_h).sum() == 0 KerDt = KerD.transpose() assert KerDt.shape[0] == d1 Ic0 = identity2(c0)[:, idxs_Ct] Lzt_v = zeros2(c1 * d0, len(idxs_Ct) * KerDt.shape[1]), kron(Ic0, KerDt) Lzt_v = numpy.concatenate(Lzt_v, axis=0) assert dot2(Hx, Lzt_v).sum() == 0 Lzti = numpy.concatenate((Lzt_h, Lzt_v), axis=1) Lzi = Lzti.transpose() # checking --------------------------------------------------------- assert dot2(Hx, Lzti).sum() == 0 assert rank(Lxi) == len(Lxi) # full rank assert rank(Lzi) == len(Lzi) # full rank assert eq_span(numpy.concatenate((Lxi, Hx)), LxiHx) assert eq_span(numpy.concatenate((Lzi, Hz)), LziHz) return Lxi, Lzi
def main(): n = argv.get("n", 8) k = argv.get("k", 4) kt = argv.get("kt", 4) d = argv.get("d", 1) # distance na = argv.get("na", n) nb = argv.get("nb", n) ka = argv.get("ka", k) kat = argv.get("kat", kt) kb = argv.get("kb", k) kbt = argv.get("kbt", kt) A = random_code(na, ka, kat, d) B = random_code(nb, kb, kbt, d) #assert A.shape == (na-ka, na), (A.shape,) #assert B.shape == (nb-kb, nb), (B.shape,) print("A, B:") print(shortstrx(A, B)) if 1: # A tensor B kw = hypergraph_product(A, B) test_puncture(**kw) else: # -------------------------------------- #B, Bt = Bt, B KerA = find_kernel(A).transpose() ma = na-ka mb = nb-kb print("KerA:") print(shortstrx(KerA)) print() # print(shortstrx(kron(KerA, identity2(mb)))) print(shortstrx( kron(identity2(mb), KerA), kron(B, identity2(na))))
def rand_codes(m, n, trials=10000): assert 0<=m<=n k = n-m I = identity2(m) count = 0 while count < trials: H = zeros2(m, n) A = rand2(m, k) H[:, :k] = A H[:, k:] = I yield H count += 1
def in_support(H, keep_idxs): # find span of H contained within idxs support n = H.shape[1] remove_idxs = [i for i in range(n) if i not in keep_idxs] A = identity2(n) A = A[remove_idxs] #print("in_support", remove_idxs) P = get_reductor(A) PH = dot2(H, P.transpose()) PH = row_reduce(PH) #print(shortstr(PH)) return PH
def in_support(H, keep_idxs, check=False): # copied from classical.py # find span of H contained within idxs support n = H.shape[1] remove_idxs = [i for i in range(n) if i not in keep_idxs] A = identity2(n) A = A[keep_idxs] H1 = intersect(A, H) if check: lhs = set(str(x) for x in span(A)) rhs = set(str(x) for x in span(H)) meet = lhs.intersection(rhs) assert meet == set(str(x) for x in span(H1)) return H1
def get_puncture(M, k): "k-puncture the rowspace of M" m, n = M.shape assert 0<=k<=n mask = [1]*k + [0]*(n-k) I = identity2(n) while 1: shuffle(mask) A = I[list(idx for idx in range(n) if mask[idx])] assert A.shape == (k, n) AM = intersect(A, M) if len(AM) == 0: break #print("get_puncture:", mask) #print(M, k) idxs = [i for i in range(n) if mask[i]] return idxs
def make_gallagher(r, n, l, m, distance=0, verbose=False): assert r % l == 0 assert n % m == 0 assert r * m == n * l if verbose: print("make_gallagher", r, n, l, m, distance) H = zeros2(r, n) H1 = zeros2(r // l, n) H11 = identity2(r // l) #print(H1) #print(H11) for i in range(m): H1[:, (n // m) * i:(n // m) * (i + 1)] = H11 #print(shortstrx(H1)) while 1: H2 = H1.copy() idxs = list(range(n)) for i in range(l): H[(r // l) * i:(r // l) * (i + 1), :] = H2 shuffle(idxs) H2 = H2[:, idxs] #print(H.shape) Hli = linear_independent(H) k = Hli.shape[0] - Hli.shape[1] assert k <= 24, "ummm, too big? k = %d" % k if distance is None: break if verbose: write("/") dist = classical_distance(Hli, distance) if dist >= distance: break if verbose: write(".") if verbose: write("\n") return Hli
def glue1_quantum(Hx, Hz, i1, i2): assert i1 != i2 mx, n = Hx.shape mz, _ = Hz.shape k = 1 A = Chain([Hz, Hx.transpose()]) C = Chain([identity2(k), zeros2(k, 0)]) fn = zeros2(n, 1) fn[i1, 0] = 1 fm = dot2(Hz, fn) f = Morphism(C, A, [fm, fn, zeros2(mx, 0)]) gn = zeros2(n, 1) gn[i2, 0] = 1 gm = dot2(Hz, gn) g = Morphism(C, A, [gm, gn, zeros2(mx, 0)]) _, _, D = chain.equalizer(f, g) Hz, Hxt = D[0], D[1] return Hxt.transpose(), Hz
def is_correctable(idxs, n, LxiHx, LziHz, Hx, Hz, Lx, Lz, **kw): #print("len(idxs) =", len(idxs)) #Ax = in_support(LxiHx, idxs) #print(Ax.shape) A = identity2(n)[idxs] Ax = intersect(LxiHx, A) Az = intersect(LziHz, A) assert dot2(Ax, Hz.transpose()).sum() == 0 assert dot2(Az, Hx.transpose()).sum() == 0 if dot2(Ax, Lz.transpose()).sum() == 0 and dot2(Az, Lx.transpose()).sum() == 0: return True if 0: #draw.mark_zop(Az[0]) print("Ax:") print(shortstr(Ax)) print("Az:") print(shortstr(Az)) return False
def main(): import models assert not argv.orbiham, "it's called orbigraph now" if argv.find_ideals: find_ideals() return Gx, Gz, Hx, Hz = models.build() if argv.chainmap: do_chainmap(Gx, Gz) if argv.symmetry: do_symmetry(Gx, Gz, Hx, Hz) return #print shortstrx(Gx, Gz) if argv.report: print("Hz:") for i, h in enumerate(Hz): print(i, shortstr(h), h.sum()) #print shortstr(find_stabilizers(Gx, Gz)) Lz = find_logops(Gx, Hz) Lx = find_logops(Gz, Hx) #print "Lz:", shortstr(Lz) if Lz.shape[0]*Lz.shape[1]: print(Lz.shape, Gx.shape) check_commute(Lz, Gx) check_commute(Lz, Hx) Px = get_reductor(Hx) # projector onto complement of rowspan of Hx Pz = get_reductor(Hz) Rz = [dot2(Pz, g) for g in Gz] Rz = array2(Rz) Rz = row_reduce(Rz, truncate=True) rz = len(Rz) n = Gx.shape[1] print("n =", n) if len(Lx): print("Lx Lz:") print(shortstrx(Lx, Lz)) print("Hx:", len(Hx), "Hz:", len(Hz)) print("Gx:", len(Gx), "Gz:", len(Gz)) Rx = [dot2(Px, g) for g in Gx] Rx = array2(Rx) Rx = row_reduce(Rx, truncate=True) rx = len(Rx) print("Rx:", rx, "Rz:", rz) if argv.show: print(shortstrx(Rx, Rz)) Qx = u_inverse(Rx) Pxt = Px.transpose() assert eq2(dot2(Rx, Qx), identity2(rx)) assert eq2(dot2(Rx, Pxt), Rx) #print shortstr(dot2(Pxt, Qx)) PxtQx = dot2(Pxt, Qx) lines = [shortstr(dot2(g, PxtQx)) for g in Gx] lines.sort() #print "PxtQx:" #for s in lines: # print s #print "RzRxt" #print shortstr(dot2(Rz, Rx.transpose())) offset = argv.offset if len(Hz): Tx = find_errors(Hz, Lz, Rz) else: Tx = zeros2(0, n) if argv.dense: dense(**locals()) return if argv.dense_full: dense_full(**locals()) return if argv.show_delta: show_delta(**locals()) return if argv.slepc: slepc(**locals()) return # if argv.orbigraph: # from linear import orbigraph # orbigraph(**locals()) # return v0 = None # excite = argv.excite # if excite is not None: # v0 = zeros2(n) # v0[excite] = 1 verts = [] lookup = {} for i, v in enumerate(span(Rx)): # XXX does not scale well if v0 is not None: v = (v+v0)%2 v = dot2(Px, v) lookup[v.tobytes()] = i verts.append(v) print("span:", len(verts)) assert len(lookup) == len(verts) mz = len(Gz) n = len(verts) if argv.lie: U = [] for i, v in enumerate(verts): count = dot2(Gz, v).sum() Pxv = dot2(Px, v) assert count == dot2(Gz, Pxv).sum() U.append(mz - 2*count) uniq = list(set(U)) uniq.sort(reverse=True) s = ', '.join("%d(%d)"%(val, U.count(val)) for val in uniq) print(s) print("sum:", sum(U)) return if n <= 1024 and argv.solve: H = numpy.zeros((n, n)) syndromes = [] for i, v in enumerate(verts): syndromes.append(dot2(Gz, v)) count = dot2(Gz, v).sum() Pxv = dot2(Px, v) assert count == dot2(Gz, Pxv).sum() H[i, i] = mz - 2*count for g in Gx: v1 = (g+v)%2 v1 = dot2(Px, v1) j = lookup[v1.tobytes()] H[i, j] += 1 if argv.showham: s = lstr2(H, 0).replace(', ', ' ') s = s.replace(' 0', ' .') s = s.replace(', -', '-') print(s) vals, vecs = numpy.linalg.eigh(H) show_eigs(vals) if argv.show_partition: beta = argv.get("beta", 1.0) show_partition(vals, beta) if argv.orbigraph: if argv.symplectic: H1 = build_orbigraph(H, syndromes) else: H1 = build_orbigraph(H) print("orbigraph:") print(H1) vals, vecs = numpy.linalg.eig(H1) show_eigs(vals) elif argv.sparse: print("building H", end=' ') A = {} # adjacency U = [] # potential if offset is None: offset = mz + 1 # make H positive definite for i, v in enumerate(verts): if i%1000==0: write('.') count = dot2(Gz, v).sum() #H[i, i] = mz - 2*count U.append(offset + mz - 2*count) for g in Gx: v1 = (g+v)%2 v1 = dot2(Px, v1) j = lookup[v1.tobytes()] A[i, j] = A.get((i, j), 0) + 1 print("\nnnz:", len(A)) if argv.lanczos: vals, vecs = do_lanczos(A, U) elif argv.orbigraph: vals, vecs = do_orbigraph(A, U) else: return vals -= offset # offset doesn't change vecs show_eigs(vals) elif argv.orbigraph: assert n<=1024 H = numpy.zeros((n, n)) syndromes = [] for i, v in enumerate(verts): syndromes.append(dot2(Gz, v)) count = dot2(Gz, v).sum() Pxv = dot2(Px, v) assert count == dot2(Gz, Pxv).sum() H[i, i] = mz - 2*count for g in Gx: v1 = (g+v)%2 v1 = dot2(Px, v1) j = lookup[v1.tobytes()] H[i, j] += 1 if argv.showham: s = lstr2(H, 0).replace(', ', ' ') s = s.replace(' 0', ' .') s = s.replace(', -', '-') print(s) if argv.symplectic: H1 = build_orbigraph(H, syndromes) else: H1 = build_orbigraph(H)
def hpack(n, j=4, k=1, check=True, verbose=False): write("hpack...") U = identity2(n) # upper triangular L = identity2(n) # lower triangular I = identity2(n) for count in range(j*n): i = randint(0, n-1) j = randint(0, n-1) if i==j: continue U[i] = (U[i] + U[j])%2 L[j] = (L[j] - L[i])%2 assert solve.rank(U) == n assert solve.rank(L) == n assert eq2(dot2(U, L.transpose()), I) if verbose: print() print(shortstrx(U, L)) print() ws = [n] * n ws = stabweights(U, L) for i in range(n): w = min(U[i].sum(), L[i].sum()) ws[i] = min(ws[i], w) ws = list(enumerate(ws)) ws.sort(key = lambda item : -item[1]) idxs = [ws[i][0] for i in range(k)] idxs.sort() Lx, Lz = zeros2(0, n), zeros2(0, n) for idx in reversed(idxs): Lz = append2(Lz, U[idx:idx+1]) Lx = append2(Lx, L[idx:idx+1]) U = pop2(U, idx) L = pop2(L, idx) m = (n-k)//2 Hz, Tz = U[:m], U[m:] Tx, Hx = L[:m], L[m:] if verbose: print() print(shortstrx(Hx, Hz)) write("done.\n") code = CSSCode(Lx, Lz, Hx, Tz, Hz, Tx, check=check, verbose=verbose) return code
def build_from_gauge(self, check=True, verbose=False): write("build_from_gauge:") Gx, Gz = self.Gx, self.Gz Hx, Hz = self.Hx, self.Hz Lx, Lz = self.Lx, self.Lz #print "build_stab" #print shortstr(Gx) #vs = solve.find_kernel(Gx) #vs = list(vs) #print "kernel Gx:", len(vs) n = Gx.shape[1] if Hz is None: A = dot2(Gx, Gz.transpose()) vs = solve.find_kernel(A) vs = list(vs) #print "kernel GxGz^T:", len(vs) Hz = zeros2(len(vs), n) for i, v in enumerate(vs): Hz[i] = dot2(v.transpose(), Gz) Hz = solve.linear_independent(Hz) if Hx is None: A = dot2(Gz, Gx.transpose()) vs = solve.find_kernel(A) vs = list(vs) Hx = zeros2(len(vs), n) for i, v in enumerate(vs): Hx[i] = dot2(v.transpose(), Gx) Hx = solve.linear_independent(Hx) if check: check_commute(Hz, Hx) check_commute(Hz, Gx) check_commute(Hx, Gz) #Gxr = numpy.concatenate((Hx, Gx)) #Gxr = solve.linear_independent(Gxr) #print(Hx.shape) #assert rank(Hx) == len(Hx) #assert eq2(Gxr[:len(Hx)], Hx) #Gxr = Gxr[len(Hx):] Px = solve.get_reductor(Hx).transpose() Gxr = dot2(Gx, Px) Gxr = solve.linear_independent(Gxr) #Gzr = numpy.concatenate((Hz, Gz)) #Gzr = solve.linear_independent(Gzr) #assert eq2(Gzr[:len(Hz)], Hz) #Gzr = Gzr[len(Hz):] Pz = solve.get_reductor(Hz).transpose() Gzr = dot2(Gz, Pz) Gzr = solve.linear_independent(Gzr) if Lx is None: Lx = solve.find_logops(Gz, Hx) if Lz is None: Lz = solve.find_logops(Gx, Hz) write('\n') print("Gxr", Gxr.shape) print("Gzr", Gzr.shape) assert len(Gxr)==len(Gzr) kr = len(Gxr) V = dot2(Gxr, Gzr.transpose()) U = solve.solve(V, identity2(kr)) assert U is not None Gzr = dot2(U.transpose(), Gzr) if check: check_conjugate(Gxr, Gzr) check_commute(Hz, Gxr) check_commute(Hx, Gzr) check_commute(Lz, Gxr) check_commute(Lx, Gzr) assert len(Lx)+len(Hx)+len(Hz)+len(Gxr)==n self.Lx, self.Lz = Lx, Lz self.Hx, self.Hz = Hx, Hz self.Gxr, self.Gzr = Gxr, Gzr
def test(): n = 3 F = symplectic_form(n) I = identity2(2 * n) assert numpy.alltrue(I == dot2(F, F)) # -------------------------------------------- # Clifford group order is 24 n = 1 I = Clifford.identity(n) X = Clifford.x(n, 0) Z = Clifford.z(n, 0) S = Clifford.s(n, 0) Si = S.inverse() H = Clifford.hadamard(n, 0) Y = X * Z print("X =") print(X) print("Z =") print(Z) print("S =") print(S) print("Si =") print(Si) print() assert X != I assert Z != I assert X * X == I assert Z * Z == I assert Z * X == X * Z # looses the phase assert Si * S == S * Si == I assert Si * Si == Z assert S * Z == Z * S assert S * X == Y * S assert S * Y * Si == X assert S * S == Z assert S * X != X * S assert S * S * S * S == I assert S * S * S == Si assert H * H == I assert H * X * H == Z assert H * Z * H == X assert S * H * S * H * S * H == I G = mulclose_fast([S, H]) assert len(G) == 24 # # -------------------------------------------- # # Look for group central extension # # G = list(G) # G.sort() # P = [g for g in G if g.is_translation()] # Pauli group # N = len(G) # lookup = dict((g, idx) for (idx, g) in enumerate(G)) # coord = lambda g, h : lookup[h] + N*lookup[g] # #phi = numpy.zeros((N, N), dtype=int) # # phi = {} # for g in P: # for h in P: # phi[g, h] = 0 # # pairs = [(g, h) for g in G for h in G] # triples = [(g, h, k) for g in G for h in G for k in G] # done = False # while not done: # done = True # print(len([phi.get(k) for k in pairs if phi.get(k) is None])) # for (g, h, k) in triples: # vals = [ # phi.get((g, h)), # phi.get((h, k)), # phi.get((g, h*k)), # phi.get((g*h, k))] # if vals.count(None) == 1: # phi[g, h] = 0 # phi[h, k] = 0 # phi[g, h*k] = 0 # phi[g*h, k] = 0 # done = False # print(len([phi.get(k) for k in pairs if phi.get(k) is None])) # print(len(phi)) # print(len(pairs)) # # return # -------------------------------------------- # Clifford group order is 11520 n = 2 II = Clifford.identity(n) XI = Clifford.x(n, 0) IX = Clifford.x(n, 1) ZI = Clifford.z(n, 0) IZ = Clifford.z(n, 1) SI = Clifford.s(n, 0) IS = Clifford.s(n, 1) SS = SI * IS HI = Clifford.hadamard(n, 0) IH = Clifford.hadamard(n, 1) XX = XI * IX ZZ = ZI * IZ XZ = XI * IZ ZX = IX * ZI YI = XI * ZI IY = IX * IZ YY = YI * IY XY = XI * IY YX = IX * YI ZY = ZI * IY YZ = IZ * YI CX = Clifford.cnot(n, 0, 1) CX1 = Clifford.cnot(n, 1, 0) CZ = Clifford.cz(n, 0, 1) CZ1 = Clifford.cz(n, 1, 0) print("CZ =") print(CZ) print("CX =") print(CX) assert SI * SI == ZI assert SI * ZI == ZI * SI assert SI * XI != XI * SI assert SI * SI * SI * SI == II assert CX * CX == II assert CZ * CZ == II assert CZ1 == CZ assert CX * IX == IX * CX assert CX * XI * CX == XX assert CX * ZI == ZI * CX assert CX * IZ * CX == ZZ SWAP = Clifford.swap(n, 0, 1) assert SWAP * ZI == IZ * SWAP assert SWAP * XI == IX * SWAP assert CX * CX1 * CX == SWAP assert CZ == IH * CX * IH assert CZ * ZI == ZI * CZ assert CZ * IZ == IZ * CZ assert CZ * XI * CZ == XI * IZ assert CZ * IX * CZ == IX * ZI assert CX * IZ * CX == ZZ assert CX * ZZ * CX == IZ assert CX * XI * CX == XX assert CZ * XX * CZ == YY assert CX * XZ * CX == YY assert CX * CZ == CZ * CX print("CX * CZ =") print(CX * CZ) #print(CX*CX1) #print() #print(SWAP) G = mulclose_fast([SI, IS, CX, HI, IH]) assert len(G) == 11520 for g in G: assert g.check() h = g.inverse() assert h.check() assert g * h == II # -------------------------------------------- n = 5 I = Clifford.identity(n) CZ = Clifford.cz(n, 0, 1) SWAP = Clifford.swap(n, 0, 1) assert CZ * CZ == I assert SWAP * CZ == CZ * SWAP
def hypergraph_product(C, D, check=False): print("hypergraph_product: C=%s, D=%s" % (C.shape, D.shape)) c0, c1 = C.shape d0, d1 = D.shape Ic0 = identity2(c0) Id0 = identity2(d0) Ic1 = identity2(c1) Id1 = identity2(d1) Hz0 = kron(Ic1, D.transpose()), kron(C.transpose(), Id1) Hz = numpy.concatenate(Hz0, axis=1) # horizontal concatenate Hx0 = kron(C, Id0), kron(Ic0, D) #print("Hx0:", Hx0[0].shape, Hx0[1].shape) Hx = numpy.concatenate(Hx0, axis=1) # horizontal concatenate assert dot2(Hx, Hz.transpose()).sum() == 0 n = Hz.shape[1] assert Hx.shape[1] == n # --------------------------------------------------- # Build Lz KerC = find_kernel(C) #KerC = min_span(KerC) # does not seem to matter... ?? KerC = rand_span(KerC) # ?? KerC = row_reduce(KerC) assert KerC.shape[1] == c1 K = KerC.transpose() #K = min_span(K) #K = rand_span(K) #E = identity2(d0) #print("c0,c1,d0,d1=", c0, c1, d0, d1) Lzt0 = kron(K, Id0), zeros2(c0 * d1, K.shape[1] * d0) Lzt0 = numpy.concatenate(Lzt0, axis=0) assert dot2(Hx, Lzt0).sum() == 0 KerD = find_kernel(D) K = KerD.transpose() assert K.shape[0] == d1 Lzt1 = zeros2(c1 * d0, K.shape[1] * c0), kron(Ic0, K) Lzt1 = numpy.concatenate(Lzt1, axis=0) assert dot2(Hx, Lzt1).sum() == 0 Lzt = numpy.concatenate((Lzt0, Lzt1), axis=1) # horizontal concatenate Lz = Lzt.transpose() assert dot2(Hx, Lzt).sum() == 0 # These are linearly independent among themselves, but # once we add stabilixers it will be reduced: assert rank(Lz) == len(Lz) # --------------------------------------------------- # Build Lx counit = lambda n: unit2(n).transpose() CokerD = find_cokernel(D) # matrix of row vectors #CokerD = min_span(CokerD) CokerD = rand_span(CokerD) Lx0 = kron(Ic1, CokerD), zeros2(CokerD.shape[0] * c1, c0 * d1) Lx0 = numpy.concatenate(Lx0, axis=1) # horizontal concatenate assert dot2(Lx0, Hz.transpose()).sum() == 0 CokerC = find_cokernel(C) Lx1 = zeros2(CokerC.shape[0] * d1, c1 * d0), kron(CokerC, Id1) Lx1 = numpy.concatenate(Lx1, axis=1) # horizontal concatenate Lx = numpy.concatenate((Lx0, Lx1), axis=0) assert dot2(Lx, Hz.transpose()).sum() == 0 # --------------------------------------------------- # overlap = 0 for lz in Lz: for lx in Lx: w = (lz * lx).sum() overlap = max(overlap, w) assert overlap <= 1, overlap #print("max overlap:", overlap) if 0: # here we assume that Hz/Hx are full rank Hzi = Hz Hxi = Hx assert rank(Hz) == len(Hz) assert rank(Hx) == len(Hx) mz = len(Hz) mx = len(Hx) else: Hzi = remove_dependent(Hz) Hxi = remove_dependent(Hx) mz = rank(Hz) mx = rank(Hx) assert len(Hzi) == mz assert len(Hxi) == mx # --------------------------------------------------- # Lz0, Lz1 = Lzt0.transpose(), Lzt1.transpose() Lzi = independent_logops(Lz, Hzi) Lxi = independent_logops(Lx, Hxi) print("Lzi:", len(Lzi)) print("Lxi:", len(Lxi)) k = len(Lzi) assert len(Lxi) == k assert mz + mx + k == n LziHz = numpy.concatenate((Lzi, Hzi)) assert rank(LziHz) == k + mz LxiHx = numpy.concatenate((Lxi, Hxi)) assert rank(LxiHx) == k + mx return locals()
def is_translation(self): n = self.n A = self.A A = A[:n - 1, :n - 1] return numpy.alltrue(A == identity2(n - 1))
def hypergraph_product(A, B, check=False): #print("hypergraph_product: A=%s, B=%s"%(A.shape, B.shape)) ma, na = A.shape mb, nb = B.shape Ima = identity2(ma) Imb = identity2(mb) Ina = identity2(na) Inb = identity2(nb) Hz0 = kron(Ina, B.transpose()), kron(A.transpose(), Inb) Hz = numpy.concatenate(Hz0, axis=1) # horizontal concatenate Hx0 = kron(A, Imb), kron(Ima, B) #print("Hx0:", Hx0[0].shape, Hx0[1].shape) Hx = numpy.concatenate(Hx0, axis=1) # horizontal concatenate assert dot2(Hx, Hz.transpose()).sum() == 0 n = Hz.shape[1] assert Hx.shape[1] == n # --------------------------------------------------- # Build Lz KerA = find_kernel(A) #KerA = rand_rowspan(KerA) # ?? KerA = row_reduce(KerA) ka = len(KerA) assert KerA.shape[1] == na K = KerA.transpose() #K = rand_rowspan(K) #E = identity2(mb) #print("ma,na,mb,nb=", ma, na, mb, nb) Lzt0 = kron(K, Imb), zeros2(ma*nb, K.shape[1]*mb) Lzt0 = numpy.concatenate(Lzt0, axis=0) assert dot2(Hx, Lzt0).sum() == 0 KerB = find_kernel(B) KerB = row_reduce(KerB) kb = len(KerB) K = KerB.transpose() assert K.shape[0] == nb Lzt1 = zeros2(na*mb, K.shape[1]*ma), kron(Ima, K) Lzt1 = numpy.concatenate(Lzt1, axis=0) assert dot2(Hx, Lzt1).sum() == 0 Lzt = numpy.concatenate((Lzt0, Lzt1), axis=1) # horizontal concatenate Lz = Lzt.transpose() assert dot2(Hx, Lzt).sum() == 0 # These are linearly independent among themselves, but # once we add stabilizers it will be reduced: assert rank(Lz) == len(Lz) # --------------------------------------------------- # Build Lx counit = lambda n : unit2(n).transpose() CokerB = find_cokernel(B) # matrix of row vectors #CokerB = rand_rowspan(CokerB) assert rank(CokerB)==len(CokerB) kbt = len(CokerB) Lx0 = kron(Ina, CokerB), zeros2(CokerB.shape[0]*na, ma*nb) Lx0 = numpy.concatenate(Lx0, axis=1) # horizontal concatenate assert dot2(Lx0, Hz.transpose()).sum() == 0 CokerA = find_cokernel(A) assert rank(CokerA)==len(CokerA) kat = len(CokerA) Lx1 = zeros2(CokerA.shape[0]*nb, na*mb), kron(CokerA, Inb) Lx1 = numpy.concatenate(Lx1, axis=1) # horizontal concatenate Lx = numpy.concatenate((Lx0, Lx1), axis=0) assert dot2(Lx, Hz.transpose()).sum() == 0 #print(ka, kat, kb, kbt) # --------------------------------------------------- # overlap = 0 for lz in Lz: for lx in Lx: w = (lz*lx).sum() overlap = max(overlap, w) assert overlap <= 1, overlap #print("max overlap:", overlap) if 0: # here we assume that Hz/Hx are full rank Hzi = Hz Hxi = Hx assert rank(Hz) == len(Hz) assert rank(Hx) == len(Hx) mz = len(Hz) mx = len(Hx) else: Hzi = remove_dependent(Hz) Hxi = remove_dependent(Hx) mz = rank(Hz) mx = rank(Hx) assert len(Hzi) == mz assert len(Hxi) == mx # --------------------------------------------------- # Lz0, Lz1 = Lzt0.transpose(), Lzt1.transpose() Lzi = independent_logops(Lz, Hzi) Lxi = independent_logops(Lx, Hxi) #print("Lzi:", len(Lzi)) #print("Lxi:", len(Lxi)) k = len(Lzi) assert len(Lxi) == k assert mz + mx + k == n LziHz = numpy.concatenate((Lzi, Hzi)) assert rank(LziHz) == k+mz LxiHx = numpy.concatenate((Lxi, Hxi)) assert rank(LxiHx) == k+mx return locals()
def build(self, logops_only=False, check=True, verbose=False): Hx, Hz = self.Hx, self.Hz Lx, Lz = self.Lx, self.Lz Tx, Tz = self.Tx, self.Tz if verbose: _write = write else: _write = lambda *args : None _write('li:') self.Hx = Hx = solve.linear_independent(Hx) self.Hz = Hz = solve.linear_independent(Hz) mz, n = Hz.shape mx, nx = Hx.shape assert n==nx assert mz+mx<=n, (mz, mx, n) _write('build:') if check: # check kernel of Hx contains image of Hz^t check_commute(Hx, Hz) if Lz is None: _write('find_logops(Lz):') Lz = solve.find_logops(Hx, Hz, verbose=verbose) #print shortstr(Lz) #_write(len(Lz)) k = len(Lz) assert n-mz-mx==k, "_should be %d logops, found %d. Is Hx/z degenerate?"%( n-mx-mz, k) _write("n=%d, mx=%d, mz=%d, k=%d\n" % (n, mx, mz, k)) # Find Lx -------------------------- if Lx is None: _write('find_logops(Lx):') Lx = solve.find_logops(Hz, Hx, verbose=verbose) assert len(Lx)==k if check: check_commute(Lx, Hz) check_commute(Lz, Hx) U = dot2(Lz, Lx.transpose()) I = identity2(k) A = solve.solve(U, I) assert A is not None, "problem with logops: %s"%(U,) #assert eq2(dot2(U, A), I) #assert eq2(dot2(Lz, Lx.transpose(), A), I) Lx = dot2(A.transpose(), Lx) if check: check_conjugate(Lz, Lx) if not logops_only: # Find Tz -------------------------- _write('Find(Tz):') U = zeros2(mx+k, n) U[:mx] = Hx U[mx:] = Lx B = zeros2(mx+k, mx) B[:mx] = identity2(mx) Tz_t = solve.solve(U, B) Tz = Tz_t.transpose() assert len(Tz) == mx check_conjugate(Hx, Tz) check_commute(Lx, Tz) # Find Tx -------------------------- _write('Find(Tx):') U = zeros2(n, n) U[:mz] = Hz U[mz:mz+k] = Lz U[mz+k:] = Tz B = zeros2(n, mz) B[:mz] = identity2(mz) Tx_t = solve.solve(U, B) Tx = Tx_t.transpose() _write('\n') if check: check_conjugate(Hz, Tx) check_commute(Lz, Tx) check_commute(Tz, Tx) self.k = k self.Lx = Lx self.Lz = Lz self.Tz = Tz self.Tx = Tx
def hypergraph_product(C, D, check=False): print("hypergraph_product:", C.shape, D.shape) print("distance:", classical_distance(C)) c0, c1 = C.shape d0, d1 = D.shape E1 = identity2(c0) E2 = identity2(d0) M1 = identity2(c1) M2 = identity2(d1) Hx0 = kron(M1, D.transpose()), kron(C.transpose(), M2) Hx = numpy.concatenate(Hx0, axis=1) # horizontal concatenate Hz0 = kron(C, E2), kron(E1, D) #print("Hz0:", Hz0[0].shape, Hz0[1].shape) Hz = numpy.concatenate(Hz0, axis=1) # horizontal concatenate assert dot2(Hz, Hx.transpose()).sum() == 0 n = Hx.shape[1] assert Hz.shape[1] == n # --------------------------------------------------- # Build Lx KerC = find_kernel(C) #KerC = min_span(KerC) # does not seem to matter... ?? assert KerC.shape[1] == c1 K = KerC.transpose() E = identity2(d0) print(shortstr(KerC)) print() Lxt0 = kron(K, E), zeros2(c0 * d1, K.shape[1] * d0) Lxt0 = numpy.concatenate(Lxt0, axis=0) assert dot2(Hz, Lxt0).sum() == 0 K = find_kernel(D).transpose() assert K.shape[0] == d1 E = identity2(c0) Lxt1 = zeros2(c1 * d0, K.shape[1] * c0), kron(E, K) Lxt1 = numpy.concatenate(Lxt1, axis=0) assert dot2(Hz, Lxt1).sum() == 0 Lxt = numpy.concatenate((Lxt0, Lxt1), axis=1) # horizontal concatenate Lx = Lxt.transpose() assert dot2(Hz, Lxt).sum() == 0 # These are linearly dependent, but # once we add stabilizers it will be reduced: assert rank(Lx) == len(Lx) if 0: # --------------------------------------------------- print(shortstr(Lx)) k = get_k(Lx, Hx) print("k =", k) left, right = [], [] draw = Draw(c0, c1, d0, d1) cols = [] for j in range(d0): # col col = [] for i in range(len(KerC)): # logical op = Lx[i * d0 + j] col.append(op) if j == i: draw.mark_xop(op) if j < d0 / 2: left.append(op) else: right.append(op) cols.append(col) draw.save("output.2") left = array2(left) right = array2(right) print(get_k(left, Hx)) print(get_k(right, Hx)) return # --------------------------------------------------- # Build Lz counit = lambda n: unit2(n).transpose() K = find_cokernel(D) # matrix of row vectors #E = counit(c1) E = identity2(c1) Lz0 = kron(E, K), zeros2(K.shape[0] * c1, c0 * d1) Lz0 = numpy.concatenate(Lz0, axis=1) # horizontal concatenate assert dot2(Lz0, Hx.transpose()).sum() == 0 K = find_cokernel(C) #E = counit(d1) E = identity2(d1) Lz1 = zeros2(K.shape[0] * d1, c1 * d0), kron(K, E) Lz1 = numpy.concatenate(Lz1, axis=1) # horizontal concatenate Lz = numpy.concatenate((Lz0, Lz1), axis=0) assert dot2(Lz, Hx.transpose()).sum() == 0 overlap = 0 for lx in Lx: for lz in Lz: w = (lx * lz).sum() overlap = max(overlap, w) assert overlap <= 1, overlap #print("max overlap:", overlap) assert rank(Hx) == len(Hx) assert rank(Hz) == len(Hz) mx = len(Hx) mz = len(Hz) # --------------------------------------------------- Lxs = [] for op in Lx: op = (op + Hx) % 2 Lxs.append(op) LxHx = numpy.concatenate(Lxs) LxHx = row_reduce(LxHx) print("LxHx:", len(LxHx)) assert LxHx.shape[1] == n print(len(intersect(LxHx, Hx)), mx) assert len(intersect(LxHx, Hx)) == mx Lzs = [] for op in Lz: op = (op + Hz) % 2 Lzs.append(op) LzHz = numpy.concatenate(Lzs) LzHz = row_reduce(LzHz) print("LzHz:", len(LzHz)) assert LzHz.shape[1] == n # --------------------------------------------------- # Remove excess logops. # print("remove_dependent") # # # -------- Lx # # Lx, Lx1 = mk_disjoint_logops(Lx, Hx) # # # -------- Lz # # Lz, Lz1 = mk_disjoint_logops(Lz, Hz) # -------------------------------- # independent_logops for Lx k = get_k(Lx, Hx) idxs0, idxs1 = [], [] for j in range(d0): # col for i in range(c1): idx = j + i * d0 if j < d0 // 2: idxs0.append(idx) else: idxs1.append(idx) Lx0 = in_support(LxHx, idxs0) Lx0 = independent_logops(Lx0, Hx) k0 = (len(Lx0)) Lx1 = in_support(LxHx, idxs1) Lx1 = independent_logops(Lx1, Hx) k1 = (len(Lx1)) assert k0 == k1 == k, (k0, k1, k) # -------------------------------- # independent_logops for Lz idxs0, idxs1 = [], [] for j in range(d0): # col for i in range(c1): idx = j + i * d0 if i < c1 // 2: idxs0.append(idx) else: idxs1.append(idx) Lz0 = in_support(LzHz, idxs0) Lz0 = independent_logops(Lz0, Hz) k0 = (len(Lz0)) Lz1 = in_support(LzHz, idxs1) Lz1 = independent_logops(Lz1, Hz) k1 = (len(Lz1)) assert k0 == k1 == k, (k0, k1, k) # --------------------------------------------------- # #assert eq2(dot2(Lz, Lxt), identity2(k)) assert mx + mz + k == n print("mx = %d, mz = %d, k = %d : n = %d" % (mx, mz, k, n)) # --------------------------------------------------- # # if Lx1 is None: # return # # if Lz1 is None: # return # --------------------------------------------------- # op = zeros2(n) for lx in Lx0: for lz in Lz0: lxz = lx * lz #print(lxz) #print(op.shape, lxz.shape) op += lxz for lx in Lx1: for lz in Lz1: lxz = lx * lz #print(lxz) #print(op.shape, lxz.shape) op += lxz idxs = numpy.where(op)[0] print("correctable region size = %d" % len(idxs)) #print(op) #print(idxs) Lx, Lz = Lx0, Lz0 Lxs = [] for op in Lx: op = (op + Hx) % 2 Lxs.append(op) LxHx = numpy.concatenate(Lxs) LxHx = row_reduce(LxHx) assert LxHx.shape[1] == n Lzs = [] for op in Lz: op = (op + Hz) % 2 Lzs.append(op) LzHz = numpy.concatenate(Lzs) LzHz = row_reduce(LzHz) assert LzHz.shape[1] == n if argv.draw: do_draw(**locals()) good = is_correctable(n, idxs, LxHx, LzHz) assert good print("good") # --------------------------------------------------- # if argv.code: print("code = CSSCode()") code = CSSCode(Hx=Hx, Hz=Hz, Lx=Lx, Lz=Lz, check=True, verbose=False, build=True) print(code) #print(code.weightstr()) if check: U = solve(Lx.transpose(), code.Lx.transpose()) assert U is not None #print(U.shape) assert eq2(dot2(U.transpose(), Lx), code.Lx) #print(shortstr(U)) if 0: Lx, Lz = code.Lx, code.Lz print("Lx:", Lx.shape) print(shortstr(Lx)) print("Lz:", Lz.shape) print(shortstr(Lz))
def test(A, B, ma, na, mb, nb, Ina, Ima, Inb, Imb, ka, kb, kat, kbt, k, KerA, KerB, CokerA, CokerB, Lzi, Lxi, Hzi, Hxi, **kw): #print("ka=%s, kat=%s, kb=%s, kbt=%s"%(ka, kat, kb, kbt)) assert k == ka*kbt + kat*kb == len(Lzi) == len(Lxi) KerA = KerA.transpose() # use convention in paper KerB = KerB.transpose() # use convention in paper CokerA = CokerA.transpose() # use convention in paper CokerB = CokerB.transpose() # use convention in paper blocks = [ [kron(KerA, Imb), zeros2(na*mb, ma*kb), kron(Ina, B)], [zeros2(ma*nb, ka*mb), kron(Ima, KerB), kron(A,Inb)], ] print("blocks:", [[X.shape for X in row] for row in blocks]) #print(shortstrx(*blocks[0])) #print() #print(shortstrx(*blocks[1])) Hzt = cat((blocks[0][2], blocks[1][2]), axis=0) K = find_kernel(Hzt) assert len(K) == ka*kb # see proof of Lemma 3 Lzv = cat((blocks[0][0], blocks[1][0])).transpose() Lzh = cat((blocks[0][1], blocks[1][1])).transpose() assert dot2(Hxi, Lzv.transpose()).sum() == 0 # Hz = Hzt.transpose() # Hzi = linear_independent(Hz) # Lzhi = independent_logops(Lzh, Hzi, verbose=True) # print("Lzhi:", Lzhi.shape) # -------------------------------------------------------- # basis for all logops, including stabilizers lz = find_kernel(Hxi) # returns transpose of kernel #lz = rand_rowspan(lz) #print("lz:", lz.shape) assert len(lz) == k+len(Hzi) # vertical qubits Iv = cat((identity2(na*mb), zeros2(ma*nb, na*mb)), axis=0).transpose() # horizontal qubits Ih = cat((zeros2(na*mb, ma*nb), identity2(ma*nb)), axis=0).transpose() assert len(intersect(Iv, Ih))==0 # sanity check # now restrict these logops to vertical qubits #print("Iv:", Iv.shape) lzv = intersect(Iv, lz) #print("lzv:", lzv.shape) J = intersect(lzv, Lzv) assert len(J) == len(lzv) # -------------------------------------------------------- # now we manually build _lz supported on vertical qubits x = rand2(ka*mb, ka*nb) y = kron(KerA, Inb) assert eq2(dot2(blocks[0][2], y), kron(KerA, B)) v = (dot2(blocks[0][0], x) + dot2(blocks[0][2], y)) % 2 h = zeros2(ma*nb, v.shape[1]) _lzt = cat((v, h)) assert dot2(Hxi, _lzt).sum() == 0 #print(shortstr(_lzt)) _lz = _lzt.transpose() _lz = linear_independent(_lz) #print("*"*(na*mb)) #print(shortstr(_lz)) assert len(intersect(_lz, Ih)) == 0 assert len(intersect(_lz, Iv)) == len(_lz) J = intersect(_lz, lz) assert len(J) == len(_lz) J = intersect(_lz, Lzv) #print(J.shape, _lz.shape, Lzv.shape) assert len(J) == len(_lz) if 0: V = cat(blocks[0][:2], axis=1) H = cat(blocks[1][:2], axis=1) X = cat((V, H), axis=0) K = find_kernel(X) print(K.shape) V = cat(blocks[0], axis=1) H = cat(blocks[1], axis=1) X = cat((V, H), axis=0) K = find_kernel(X) print(K.shape) #print("-"*(ka*mb+ma*kb)) I = cat((identity2(ka*mb+ma*kb), zeros2(ka*mb+ma*kb, na*nb)), axis=1) J = intersect(K, I) print("J:", J.shape)