def pushout(a, b, _amorph=None, _bmorph=None, _chain=None, check=True): """ Construct pushout of Morphism's a, b. If supplied with another cocone over a, b then also construct unique Morphism to that cocone. """ assert isinstance(a, Morphism) assert isinstance(b, Morphism) assert a.src == b.src src = a.src n = len(src) amorph = [] bmorph = [] chain = [] aprev = None bprev = None for i in range(n + 1): a1, b1, c1 = solve.pushout(a[i], b[i], aprev, bprev) amorph.append(a1) bmorph.append(b1) chain.append(c1) aprev = compose2(a.tgt[i], a1) bprev = compose2(b.tgt[i], b1) #_a1, _b1, _ = solve.pushout(a[i], b[i]) #assert eq2(a1, _a1) #assert eq2(b1, _b1) chain = Chain(chain[1:]) amorph = Morphism(a.tgt, chain, amorph) bmorph = Morphism(b.tgt, chain, bmorph) if check: assert amorph * a == bmorph * b assert (_amorph is None) == (_bmorph is None) == (_chain is None) morph = None if _amorph is not None: assert amorph.tgt == bmorph.tgt assert _amorph * a == _bmorph * b, "not a cocone!" Ds = [] for i in range(n + 1): a1, b1, d = solve.pushout(a[i], b[i], _amorph[i], _bmorph[i]) Ds.append(d) assert eq2(dot2(d, a1), _amorph[i]) assert eq2(dot2(d, b1), _bmorph[i]) assert eq2(a1, amorph[i]) assert eq2(b1, bmorph[i]) morph = Morphism(chain, _chain, Ds) if check: #lhs = morph * amorph #rhs = _amorph #print(lhs.shape) #print(rhs.shape) assert morph * amorph == _amorph assert morph * bmorph == _bmorph return amorph, bmorph, chain, morph
def test_colimit(): n = 4 m = n - 1 H = zeros2(m, n) for i in range(m): H[i, i] = 1 H[i, i + 1] = 1 A = Chain([H]) B = Chain([zeros2(0, 0)]) C = Chain([array2([[1]])]) CAm = zeros2(m, 1) CAm[0, 0] = 1 CAm[m - 1, 0] = 1 CAn = zeros2(n, 1) CAn[0, 0] = 1 CAn[n - 1, 0] = 1 CA = Morphism(C, A, [CAm, CAn]) CBm = zeros2(0, 1) CBn = zeros2(0, 1) CB = Morphism(C, B, [CBm, CBn]) AD, BD, D, _ = chain.pushout(CA, CB) assert eq2(D[0], array2([[1, 1, 1], [0, 1, 1]])) # glue two checks at a bit # -------------------------- A = Chain([H.transpose()]) B = Chain([zeros2(0, 0)]) C = Chain([zeros2(1, 0)]) CAn = zeros2(n, 1) CAn[0, 0] = 1 CAn[n - 1, 0] = 1 CAm = zeros2(m, 0) CA = Morphism(C, A, [CAn, CAm]) CBn = zeros2(0, 1) CBm = zeros2(0, 0) CB = Morphism(C, B, [CBn, CBm]) AD, BD, D, _ = chain.pushout(CA, CB) D = D[0] #print(D) assert eq2(D, array2([[1, 0, 1], [1, 1, 0], [0, 1, 1]])) # glue two bits
def is_stab(self, v): write('/') Hx_t = self.Hx.transpose() # # Hx_t u = v # # u = Hx_t^-1 v # if self.Hx_t_inv is None: # Hx_t_inv = solve.pseudo_inverse(Hx_t) # self.Hx_t_inv = Hx_t_inv # Hx_t_inv = self.Hx_t_inv # u = dot2(Hx_t_inv, v) u = dot2(self.Tz, v) #u = solve.solve(Hx_t, v) #if u is not None: if eq2(dot2(Hx_t, u), v): #print "[%s]"%u.sum(), v1 = dot2(Hx_t, u) assert ((v+v1)%2).max() == 0 # assert self.is_stab_0(v) # double check else: # assert not self.is_stab_0(v) # double check u = None write('\\') return u is not None
def show_stabx(self, sx): gxs = [] for gx in self.Gx: if eq2(gx * sx, gx): gxs.append(gx) Gx = array2(gxs) #print "Gx:", Gx.shape #print shortstr(Gx) print("sx.sum() =", sx.sum(), end=' ') Gxt = Gx.transpose() K = find_kernel(Gxt) #print "kernel:", K K = array2(K) #print "kernel:", len(K) #print shortstr(K) #print best = None ubest = None u = solve(Gxt, sx) for w in enum2(len(K)): u2 = (u + dot2(w, K)) % 2 if best is None or u2.sum() < best: best = u2.sum() ubest = u2 print("u.sum() =", u2.sum(), end=' ') print()
def test_equalizer(): n = 4 m = n - 1 H = zeros2(m, n) for i in range(m): H[i, i] = 1 H[i, i + 1] = 1 A = Chain([H]) C = Chain([array2([[1]])]) fm = zeros2(m, 1) fm[m - 1, 0] = 1 fn = zeros2(n, 1) fn[n - 1, 0] = 1 f = Morphism(C, A, [fm, fn]) gm = zeros2(m, 1) gm[0, 0] = 1 gn = zeros2(n, 1) gn[0, 0] = 1 g = Morphism(C, A, [gm, gn]) AD, BD, D = chain.equalizer(f, g) assert eq2(D[0], array2([[1, 1, 1], [0, 1, 1]])) # glue two checks at a bit # -------------------------- A = Chain([H.transpose()]) C = Chain([zeros2(1, 0)]) fn = zeros2(n, 1) fn[0, 0] = 1 fm = zeros2(m, 0) f = Morphism(C, A, [fn, fm]) gn = zeros2(n, 1) gn[n - 1, 0] = 1 gm = zeros2(m, 0) g = Morphism(C, A, [gn, gm]) AD, BD, D = chain.equalizer(f, g) D = D[0] #print(D) assert eq2(D, array2([[1, 0, 1], [1, 1, 0], [0, 1, 1]])) # glue two bits
def __eq__(self, other): assert len(self) == len(other) if len(self) != len(other): return False n = len(self) for i in range(n): if not eq2(self.Hs[i], other.Hs[i]): return False return True
def __eq__(self, other): assert isinstance(other, Morphism) assert self.shape == other.shape if self.shape != other.shape: return False n = len(self) for i in range(n): if not eq2(self[i], other[i]): return False return True
def independent_logops(L, H): m = len(H) LH = numpy.concatenate((L, H), axis=0) keep, remove = dependent_rows(LH) LH = LH[keep] assert rank(LH) == len(LH) assert len(LH) >= m assert eq2(LH[-len(H):], H) L = LH[:-m] return L
def check(self): src, tgt = self.src, self.tgt Ds = self.Ds for i in range(len(src)): D0, D1 = Ds[i], Ds[i + 1] if D0 is None or D1 is None: continue lhs, rhs = compose2(src[i], D0), compose2(D1, tgt[i]) if not eq2(lhs, rhs): print("!!!!! Not a chain map !!!!!") print("lhs =", lhs) print("rhs =", rhs) raise Exception
def independent_logops(L, H, verbose=False): m = len(H) LH = numpy.concatenate((L, H), axis=0) keep, remove = dependent_rows(LH) if verbose: print(keep, remove) LH = LH[keep] assert rank(LH) == len(LH) assert len(LH) >= m assert eq2(LH[-len(H):], H), "H not linearly independent ?" L = LH[:-m] return L
def mk_disjoint_logops(L, H): m = len(H) #print("L:", len(L)) L0 = L # save this LH = numpy.concatenate((L, H), axis=0) #LH = remove_dependent(LH) keep, remove = dependent_rows(LH) #print("dependent_rows:", len(keep), len(remove)) LH = LH[keep] assert rank(LH) == len(LH) assert len(LH) >= m assert eq2(LH[-len(H):], H) L = LH[:-m] #print("L:", len(L)) # find disjoint set of L ops keep = set([idx for idx in keep if idx < len(L0)]) assert len(keep) == len(L) idxs = list(range(len(L0))) idxs.sort(key=lambda idx: -int(idx in keep)) assert idxs[0] in keep L1 = L0[idxs] assert L1.shape == L0.shape LH = numpy.concatenate((L1, H), axis=0) LH = remove_dependent(LH) L1 = LH[:-m] assert len(L) == len(L1), (L.shape, L1.shape) #print(shortstr(L)) #print("--") #print(shortstr(L1)) #print("--") A = numpy.dot(L, L1.transpose()) #assert A.sum() == 0, "found overlap" if A.sum(): print("*" * 79) print("WARNING: A.sum() =", A.sum()) print("failed to find disjoint logops") print("*" * 79) return L, None return L, L1
def find_encoding(A, code): Lx = [Clifford.make_op(l, Clifford.x) for l in code.Lx] Lz = [Clifford.make_op(l, Clifford.z) for l in code.Lz] Hx = [Clifford.make_op(l, Clifford.x) for l in code.Hx] Hz = [Clifford.make_op(l, Clifford.z) for l in code.Hz] assert len(Lx) == len(Lz) Ai = A.inverse() rows = [] for l in Lz + Lx: B = A * l * Ai assert B.is_translation() v = B.get_translation() rows.append(v) B = numpy.array(rows) #B = B[:8, :] #print(B.shape) #print(shortstr(B)) U = numpy.array([l.get_translation() for l in Lz + Lx + Hz + Hx]) #print(U.shape) #print(shortstr(U)) Ut = U.transpose() V = solve(Ut, B.transpose()) if V is None: return None V = V[:2 * code.k] #print(V.shape) #print(shortstr(V)) # check that V is symplectic n = len(V) // 2 F = symplectic_form(n) lhs = dot2(V.transpose(), dot2(F, V)) assert eq2(lhs, F) #print(A.get_translation()) u = solve(Ut, A.get_translation()) u = u[:2 * code.k] #print(shortstr(u)) return Clifford.from_symplectic_and_translation(V, u)
def decode(self, p, err_op, verbose=False, **kw): code = self.code xs, ys = self.xs, self.ys x = dot2(code.Hz, err_op) x.shape = (1, code.mz) a = (self.xs + x) % 2 #print shortstr(a) a = a.sum(1) a = list(enumerate(a)) a.sort(key=lambda item: item[1]) # print a # print shortstr(y) # print shortstr(x) for idxs in self.search: #print idxs y1 = ys[a[idxs[0]][0]] for idx in idxs[1:]: y1 = y1 + ys[a[idx][0]] # print shortstr(y1) x1 = dot2(code.Hz, y1) #print shortstr(x1) if eq2(x1, x): # print "OK", idxs break else: return None return y1
def check_conjugate(A, B): if A is None or B is None: return assert A.shape == B.shape I = numpy.identity(A.shape[0], dtype=numpy.int32) assert eq2(dot2(A, B.transpose()), I)
def build_model(Gx=None, Gz=None, Hx=None, Hz=None): if Gx is None: Gx, Gz, Hx, Hz = build() n = Gx.shape[1] if Hx is None: Hx = find_stabilizers(Gz, Gx) if Hz is None: Hz = find_stabilizers(Gx, Gz) check_commute(Hx, Hz) check_commute(Gx, Hz) check_commute(Hx, Gz) #Px = get_reductor(concatenate((Lx, Hx))) #Pz = get_reductor(concatenate((Lz, Hz))) Px = get_reductor(Hx) Pz = get_reductor(Hz) # Lz = find_logops( Hx , Hz ) # find_logops( ............. , ............. ) # ( commutes with , orthogonal to ) # ( ............. , ............. ) Lz = find_logops(Gx, Hz) assert Lz.shape[1] == n if 0: PGz = get_reductor(Gz) Lz = dot2(Lz, PGz.transpose()) Lz = row_reduce(Lz) print(shortstrx(Lz, Gz, Hz)) if len(Lz): #print Lz.shape, Hz.shape assert len(row_reduce(concatenate((Lz, Hz)))) == len(Lz) + len(Hz) assert len(row_reduce(concatenate( (Lz, Gz)))) == len(Lz) + len(row_reduce(Gz)) # Tz = find_errors( Hx , Lx ) # find_errors( ............. , ............. ) # ( conjugate to , commutes with ) # ( ............. , ............. ) Lx = find_errors(Lz, Gz) # invert Lz, commuting with Gz check_commute(Lx, Gz) check_commute(Lx, Hz) check_conjugate(Lx, Lz) check_commute(Lz, Gx) check_commute(Lz, Hx) # Lx | Lz # Hx | ? # ? | Hz # ? | ? #Rz = find_logops(concatenate((Lx, Hx)), Hz) Rz = dot2(Gz, Pz.transpose()) Rz = row_reduce(Rz) check_commute(Rz, Lx) check_commute(Rz, Hx) Rx = dot2(Gx, Px.transpose()) Rx = row_reduce(Rx) check_commute(Rx, Lz) check_commute(Rx, Hz) # Lx | Lz # Hx | ? # ? | Hz # Rx'| Rz' Tz = find_errors(Hx, concatenate((Lx, Rx))) Tx = find_errors(Hz, concatenate((Lz, Rz, Tz))) assert len((concatenate((Lx, Hx, Tx, Rx)))) == n assert len((concatenate((Lz, Hz, Tz, Rz)))) == n assert len(row_reduce(concatenate((Lx, Hx, Tx, Rx)))) == n assert len(row_reduce(concatenate((Lz, Hz, Tz, Rz)))) == n check_commute(Rz, Tx) Rx = find_errors(Rz, concatenate((Lz, Hz, Tz))) check_conjugate(Rx, Rz) check_commute(Rx, Hz) check_commute(Rx, Tz) check_commute(Rx, Lz) Rxt = Rx.transpose() Rzt = Rz.transpose() Pxt = Px.transpose() Pzt = Pz.transpose() check_sy(Lx, Hx, Tx, Rx, Lz, Hz, Tz, Rz) assert eq2(dot2(Gz, Rxt), dot2(Gz, Pzt, Rxt)) assert eq2(dot2(Gx, Rzt), dot2(Gx, Pxt, Rzt)) # print shortstrx(dot2(Rx, Pz), Rx) assert eq2(dot2(Rx, Pz), Rx) assert eq2(dot2(Rz, Px), Rz) assert len(find_kernel(dot2(Gz, Rx.transpose()))) == 0 model = Model(locals()) if argv.dual: model = model.get_dual() argv.dual = False # HACK !! return model
def __eq__(self, other): if self.w != other.w: return False # that was easy return eq2(self.T, other.T)
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 __eq__(self, other): return eq2(self.Hx, other.Hx) and eq2(self.Hz, other.Hz)
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)
def process(G, H): m, n = G.shape row = 0 while row < m: col = 0 while G[row, col] == 0: col += 1 assert col >= row swap_col(G, row, col) swap_col(H, row, col) echelon(G, row, row) row += 1 col = row row = 0 m, n = H.shape while row < m: j = col while H[row, j] == 0: j += 1 swap_col(G, col, j) swap_col(H, col, j) echelon(H, row, col) row += 1 col += 1 k = n-m print("G =") print(shortstr(G)) print("H =") print(shortstr(H)) print() A = G[:, k:] B = H[:, :k] assert eq2(A.transpose(), B) if 0: for size in range(2, k): result = search(G, H, size=size, verbose=True) print("search(size=%d): %s"%(size, result)) wd = weight_dist(H) print("H:", wd, sum(wd)) wd = weight_dist(G) print("G:", wd, sum(wd)) r = rank(A) print("rank deficit:", k-r) if r == k: idxs = list(range(k)) jdxs = list(range(k, 2*k)) C = cokernel(B)[0] C = row_reduce(C) rows, cols = C.shape assert rows == n-2*k assert cols == n-k jdxs = list(range(m)) pivots = [] for i in range(rows): for j in range(i, cols): if C[i, j] != 0: pivots.append(j) jdxs.remove(j) break print("C:", pivots) print(shortstr(C)) assert len(jdxs) == k jdxs = [k+i for i in jdxs] assert len( in_support(G, idxs) ) == 0 assert len( in_support(G, jdxs) ) == 0 assert len( in_support(H, idxs) ) == 0 for row in in_support(H, jdxs): print("in_support:", row) assert len( in_support(H, jdxs) ) == 0 print("OK")
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 find_ideals(): import networkx as nx from models import build_model model = build_model() if argv.verbose: print(model) print() #print(shortstrx(Hx, Hz)) Gx, Gz = model.Gx, model.Gz Hx, Hz = model.Hx, model.Hz #print shortstrx(Gx, Gz) Rx, Rz = model.Rx, model.Rz Rxt = Rx.transpose() Rzt = Rz.transpose() Px, Pz = model.Px, model.Pz Pxt = Px.transpose() Pzt = Pz.transpose() r, n = Rx.shape assert eq2(dot2(Rx, Pxt), Rx) # print shortstrx(Gx, Gz) # print PGx = dot2(Gx, Pxt) PGz = dot2(Gz, Pzt) # print shortstrx(PGx, PGz) # print if 0: ng = len(PGx) graph = nx.Graph() for i in range(ng): graph.add_node(i) for i, gi in enumerate(PGx): for j, gj in enumerate(PGz): if (gi*gj).sum()%2: graph.add_edge(i, j) mx = len(Gx) mz = len(Gz) graph = nx.Graph() for i in range(mx+mz): graph.add_node(i) for ix in range(mx): for iz in range(mz): if (Gx[ix]*Gz[iz]).sum()%2: graph.add_edge(ix, mx+iz) # excite = argv.excite # if type(excite) is int: # _excite = [0]*len(model.Tx) # _excite[excite] = 1 # excite = tuple(_excite) # #elif excite is None: # print("excite:", excite) equs = nx.connected_components(graph) equs = list(equs) print(model) print(("find_ideals:", len(equs))) models = [] for equ in equs: equ = list(equ) equ.sort() #print(equ) gxs = [] gzs = [] for i in equ: if i<mx: gxs.append(Gx[i]) else: gzs.append(Gz[i-mx]) _model = build_model(array2(gxs), array2(gzs)) print(_model) #print(shortstrx(_model.Gx)) basis = find_kernel(_model.Gx.transpose()) print(("kernel:", len(basis), [v.sum() for v in basis])) models.append(_model) idx = argv.dumpc if idx is not None: model = models[idx] #model = model.get_sector(compress=True) print(model) #print(shortstrx(model.Gx)) basis = find_kernel(model.Gx.transpose()) print(("kernel:", len(basis), [v.sum() for v in basis])) models.append(_model) model.dumpc() return if not argv.solve: return if argv.excite or argv.exciteall or argv.minweightall: if argv.minweightall: excites = minweightall(Hz) #print("excite", excite) elif argv.exciteall: excites = list(enum2(len(Hz)))[1:] else: assert len(Hz), Hz excites = [] for i in range(len(Hz)): excite = array2([0]*len(Hz)) excite[i] = 1 excites.append(excite) print(("excites", len(excites))) else: excites = [None] if eq2(model.Hx, model.Hz): print("self dual stabilizers") _excite = None top = None for excite in excites: #if excite is not None: # print "excite:", (excite) # g = dot2(model.Hx.transpose(), excite) # model.show_stabx(g) if excite is not None: tx = dot2(excite, model.Tx) total = 0. gaps = [] for _model in models: #print(_model) if excite is not None: _tx = dot2(tx, _model.Hz.transpose(), _model.Tx) _excite = dot2(_tx, _model.Hz.transpose()) #print(shortstrx(_excite)) #print _excite r = len(_model.Rx) if r <= 12 and not argv.slepc and not argv.sparse: H = _model.build_ham(_excite) #weights=weights1) if argv.orbigraph: H1 = build_orbigraph(H) vals, vecs = numpy.linalg.eigh(H) elif argv.sparse and r <= 19: vals = _model.sparse_ham_eigs(_excite) #weights=weights1) elif r <= 27: #for i in range(len(_excite)): # _excite[i] = 1 #print("excite:", tuple(_excite)) #vals = slepc(excite=tuple(_excite), **_model.__dict__) if _excite is not None: _excite = tuple(_excite) #vals = slepc(excite=_excite, **_model.__dict__) vals = _model.do_slepc(excite=_excite) #vals = [0, 0] else: assert 0, "r=%d too big"%r vals = list(vals) vals.sort(reverse=True) print(("total +=", vals[0])) total += vals[0] gaps.append(vals[0]-vals[1]) if top is None or total > top: top = total print(("eval_1:", total)) print(("eval_2:", total-min(gaps))) print(("top:", top))
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 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)