def is_transversal(A, code): Lz = [Clifford.make_op(l, Clifford.z) for l in code.Lz] Lx = [Clifford.make_op(l, Clifford.x) for l in code.Lx] Hz = [Clifford.make_op(l, Clifford.z) for l in code.Hz] Hx = [Clifford.make_op(l, Clifford.x) for l in code.Hx] hz = [op.get_translation() for op in Hz] hx = [op.get_translation() for op in Hx] h = array2(hz + hx) ht = h.transpose() Ai = A.inverse() tgt = [] for u in Hz + Hx: v = A * u * Ai assert v.is_translation() v = v.get_translation() tgt.append(v) #print(u.get_translation()) #print("-->") #print(v) #print() tgt = array2(tgt) src = array2([u.get_translation() for u in Hz + Hx]) tgt, src = tgt.transpose(), src.transpose() if solve(tgt, src) is None: return False if solve(src, tgt) is None: return False return True
def solve(self, H, minimize=True, verbose=True): m, n = H.shape # rows, cols u1 = self.u1 assert u1.shape == (m, ) rows = [i for i in range(m) if u1[i]] #print rows H = H[rows, :] u0 = self.u0[rows] v = self.v cols = [i for i in range(n) if v[i]] #print cols H = H[:, cols] assert cols, self.u0 #print shortstr(H) #print "u0:", shortstr(u0) if verbose: print("Cluster.solve:", H.shape) v = solve.solve(H, u0) if v is None: return if minimize: kern = solve.find_kernel(H) if kern: kern = array2(kern) write("[w=%d, kern=%d, " % (v.sum(), len(list(kern)))) graph = dynamic.Tanner(kern) #v = graph.minimize(v, target=30, verbose=True) v = graph.localmin(v, verbose=True) write("w=%d]" % v.sum()) #u = dot(H, v) #assert numpy.abs(u-u0).sum() == 0 v0 = numpy.zeros((n, ), dtype=numpy.int32) v0[cols] = v #print "v0:", shortstr(v0) #write("[%d]"%v0.sum()) return v0
def is_stab_cluster(self, v, str=shortstr, verbose=False): if v.max() == 0: if verbose: print("is_stab: zero") return True if verbose: print("is_stab: v") print(str(v)) v0 = v v = v.copy() Hx_t = self.Hx.transpose() c = Cluster(v) c = c.grow(Hx_t, 2) # hmmm... doesn't work when the code has an empty colum u = c.solve(Hx_t, verbose=False) if u is None: write('S') u = solve.solve(Hx_t, v, debug=False) if u is None: if verbose: print("is_stab: no solution found") write('N') return None v1 = dot(Hx_t, u) % 2 if verbose: print("is_stab: solved") assert ((v0 + v) % 2).max() == 0 # v0==v assert ((v1 + v) % 2).max() == 0 # !!! return ((v1 + v) % 2).max() == 0 # v1==v ie. solution found
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 is_stab_0(self, v): write('/') Hx_t = self.Hx.transpose() u = solve.solve(Hx_t, v) if u is not None: #print "[%s]"%u.sum(), v1 = dot2(Hx_t, u) assert ((v+v1)%2).max() == 0 write('\\') return u is not None
def is_stab_full(self, v, str=shortstr, verbose=False): Hx_t = self.Hx.transpose() #Hx_t = Hx_t.copy() #u = solve.search(Hx_t, v) #print "is_stab:", Hx_t.shape, v.shape,;sys.stdout.flush() u = solve.solve(Hx_t, v) #print u is not None if u is not None: #print "[%s]"%u.sum(), v1 = dot(Hx_t, u) % 2 assert ((v + v1) % 2).max() == 0 return u is not None
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 minsolve(self, H, verbose): m, n = H.shape # rows, cols u1 = self.u1 assert u1.shape == (m, ) rows = [i for i in range(m) if u1[i]] #print rows H = H[rows, :] u0 = self.u0[rows] v = self.v cols = [i for i in range(n) if v[i]] #print cols H = H[:, cols] assert cols, self.u0 #print shortstr(H) #print "u0:", shortstr(u0) if verbose: print("Cluster.solve:", H.shape) v = solve.solve(H, u0)
def eq_span(A, B): u = solve(A.transpose(), B.transpose()) if u is None: return False u = solve(B.transpose(), A.transpose()) return u is not None
def test_code(Hxi, Hzi, Hx, Lx, Lz, Lx0, Lx1, LxiHx, **kw): code = CSSCode(Hx=Hxi, Hz=Hzi) print(code) assert rank(intersect(Lx, code.Lx)) == code.k assert rank(intersect(Lz, code.Lz)) == code.k verbose = argv.verbose decoder = get_decoder(argv, argv.decode, code) if decoder is None: return p = argv.get("p", 0.01) N = argv.get("N", 0) distance = code.n count = 0 failcount = 0 nonuniq = 0 logops = [] for i in range(N): err_op = ra.binomial(1, p, (code.n, )) err_op = err_op.astype(numpy.int32) op = decoder.decode(p, err_op, verbose=verbose, argv=argv) c = 'F' success = False if op is not None: op = (op + err_op) % 2 # Should be a codeword of Hz (kernel of Hz) assert dot2(code.Hz, op).sum() == 0 write("%d:" % op.sum()) # Are we in the image of Hx ? If so, then success. success = dot2(code.Lz, op).sum() == 0 if success and op.sum(): nonuniq += 1 c = '.' if success else 'x' if op.sum() and not success: distance = min(distance, op.sum()) write("L") logops.append(op.copy()) else: failcount += 1 write(c + ' ') count += success if N: print() print(argv) print("error rate = %.8f" % (1. - 1. * count / (i + 1))) print("fail rate = %.8f" % (1. * failcount / (i + 1))) print("nonuniq = %d" % nonuniq) print("distance <= %d" % distance) mx0, mx1 = len(Lx0), len(Lx1) LxHx = numpy.concatenate((Lx0, Lx1, Hx)) for op in logops: print(op.sum()) #print(shortstr(op)) #print(op.shape) #print(op) K = solve(LxHx.transpose(), op) K.shape = (1, len(K)) print(shortstrx(K[:, :mx0], K[:, mx0:mx0 + mx1], K[:, mx0 + mx1:]))
def rowspan_le(A, B): u = solve(B.transpose(), A.transpose()) if u is None: return False return True
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 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_target(): i = 1j fold = Diag([ 1, 1, i, -i, i, -i, 1, 1, 1, 1, i, -i, i, -i, 1, 1, 1, 1, -i, i, i, -i, -1, -1, 1, 1, -i, i, i, -i, -1, -1, i, i, -1, 1, -1, 1, i, i, i, i, -1, 1, -1, 1, i, i, -i, -i, -1, 1, 1, -1, i, i, -i, -i, -1, 1, 1, -1, i, i, 1, -1, i, i, i, i, 1, -1, -1, 1, -i, -i, -i, -i, -1, 1, 1, -1, -i, -i, i, i, -1, 1, -1, 1, i, i, -i, -i, 1, -1, i, -i, -1, -1, -1, -1, i, -i, -i, i, 1, 1, 1, 1, -i, i, -i, i, -1, -1, 1, 1, i, -i, i, -i, 1, 1, -1, -1, -i, i, -i, -i, 1, -1, -1, 1, i, i, i, i, -1, 1, 1, -1, -i, -i, i, i, 1, -1, 1, -1, i, i, -i, -i, -1, 1, -1, 1, -i, -i, 1, 1, i, -i, -i, i, -1, -1, -1, -1, -i, i, i, -i, 1, 1, 1, 1, -i, i, -i, i, 1, 1, -1, -1, i, -i, i, -i, -1, -1, -i, i, 1, 1, -1, -1, i, -i, -i, i, 1, 1, -1, -1, i, -i, i, -i, 1, 1, 1, 1, i, -i, i, -i, 1, 1, 1, 1, i, -i, 1, -1, i, i, -i, -i, -1, 1, 1, -1, i, i, -i, -i, -1, 1, 1, -1, -i, -i, -i, -i, 1, -1, 1, -1, -i, -i, -i, -i, 1, -1, ]) k = 8 N = 2**k assert len(fold) == N # print(fold) # I = Diag([1.]*len(fold)) # op = fold # count = 1 # while op != I: # op = fold * op # count += 1 # print(count) # return # --------------- Diag ->>> Cliff --------------------- fold = fold.get_cliff() IN = Cliff([0] * N) I = Cliff([0, 0]) phase = Cliff([1]) Z = Cliff([0, 2]) S = Cliff([0, 1]) Si = Cliff([0, 3]) CZ = Cliff([0, 0, 0, 2]) II = Cliff([0, 0, 0, 0]) s_gate = reduce(tensor, [S, I, S, I, I, S, S, I]) s_gate_i = reduce(tensor, [Si, I, Si, I, I, Si, Si, I]) target = s_gate * fold print(target) gens = [] phase_gate = Cliff([1] * N) names = [] # # single qubit S gates # for i in range(k): # for s_gate in [S, Si]: # ops = [I]*k # ops[i] = s_gate # op = reduce(tensor, ops) # #gens.append(op) for i in range(k): diag = [0] * N for idx in range(N): if idx & (2**i): diag[idx] = 2 Z = Cliff(diag) assert (Z * Z) == Cliff([0] * N) gens.append(Z) names.append("Z_{%d}" % i) for i in range(k): for j in range(i + 1, k): diag = [0] * N for idx in range(N): if idx & (2**i) and idx & (2**j): diag[idx] = 2 cz = Cliff(diag) assert (cz * cz) == Cliff([0] * N) gens.append(cz) names.append("CZ_{%d,%d}" % (i, j)) print("gens:", len(gens)) #for a in gens: # for b in gens: # print("%4s" % a.inner(b), end=" ") # print() A = numpy.zeros((len(gens), N), dtype=int_scalar) for i, gen in enumerate(gens): A[i] = gen.diag A //= 2 #A = row_reduce(A) #print(shortstr(A)) print("rank:", rank(A)) rhs = target.diag rhs = rhs.astype(int_scalar) rhs //= 2 u = solve(A.transpose(), rhs) print(u) opnames = [] op = s_gate_i for i, name in enumerate(names): if u[i]: opnames.append(names[i]) op = gens[i] * op print("op =", "*".join(opnames)) print(op) print(fold) assert op == fold
def __init__(self, l): stars = [] for i in range(l): for j in range(l): for k in range(l): stars.append((2 * i, 2 * j, 2 * k)) self.l = l self.keys = keys = [] self.keymap = keymap = {} for i, j, k in stars: self.add_site(i + 1, j, k) self.add_site(i, j + 1, k) self.add_site(i, j, k + 1) #print keymap #print keys n = len(keys) #print "n =", n assert n == 3 * (l**3) assert keys[keymap[2 * l - 1, 0, 0]] == (2 * l - 1, 0, 0) assert keys[keymap[-1, 0, 0]] == (2 * l - 1, 0, 0) m = len(stars) Hz = zeros2(m - 1, n) for row, (i, j, k) in enumerate(stars): if row == len(stars) - 1: break #if row==4: #print shortstr(Hz[row]), (i, j, k) #for d in (-1, 1): #print keys[keymap[i+d, j, k]], #print keys[keymap[i, j+d, k]], #print keys[keymap[i, j, k+d]], #print for d in (-1, 1): Hz[row, keymap[i + d, j, k]] = 1 Hz[row, keymap[i, j + d, k]] = 1 Hz[row, keymap[i, j, k + d]] = 1 #print shortstr(Hz) Hx = zeros2(3 * m, n) row = 0 square = [(1, 0), (0, 1), (1, 2), (2, 1)] for i, j, k in stars: #print i, j, k if i + 2 < 2 * l or j + 2 < 2 * l: for d1, d2 in square: #print (i+d1, j+d2, k), #print keys[keymap[i+d1, j+d2, k]], Hx[row, keymap[i + d1, j + d2, k]] = 1 #print #print shortstr(Hx[row]) #for q in range(m-1): #if dot2(Hx[row], Hz[q].transpose()).sum(): #print shortstr(Hz[q]), "XXX" assert dot2(Hx[row], Hz.transpose()).sum() == 0 assert dot2(Hx, Hz.transpose()).sum() == 0 if not row or solve(Hx[:row].transpose(), Hx[row]) is None: row += 1 else: Hx[row] = 0 if i + 2 < 2 * l or k + 2 < 2 * l: for d1, d2 in square: Hx[row, keymap[i + d1, j, k + d2]] = 1 assert dot2(Hx, Hz.transpose()).sum() == 0 if solve(Hx[:row].transpose(), Hx[row]) is None: row += 1 else: Hx[row] = 0 if i == 0 and (j + 2 < 2 * l or k + 2 < 2 * l): for (d1, d2) in square: Hx[row, keymap[i, j + d1, k + d2]] = 1 assert dot2(Hx, Hz.transpose()).sum() == 0 if solve(Hx[:row].transpose(), Hx[row]) is None: row += 1 else: Hx[row] = 0 Hx = Hx[:row].copy() self.Hx = Hx self.Hz = Hz
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 do_draw(c0, c1, d0, d1, Lx, Lz, Hx, Hz, idxs, LxHx, LzHz, **kw): draw = Draw(c0, c1, d0, d1) mark_xop = draw.mark_xop mark_zop = draw.mark_zop mark_idx = draw.mark_idx m, n = LxHx.shape assert rank(LxHx) == len(LxHx) assert rank(Hx) == len(Hx) assert rank(Lx) == len(Lx) #print(rank(LxHx)) #print(rank(Hx)) #print(rank(Lx)) assert rank(Lx) + rank(Hx) == len(LxHx) + 1 if 0: w = n best = None for i in range(10000): v = rand2(1, m) lop = dot2(v, LxHx)[0] #print(lop) if lop.sum() < w: best = lop w = lop.sum() print(w) mark_xop(best) all_idxs = list(range(c1 * d0 + c0 * d1)) h_idxs, v_idxs = all_idxs[:c1 * d0], all_idxs[c1 * d0:] if 0: # find Hx stabilizers with horizontal support #for idx in h_idxs: # mark_idx(idx) PHx = in_support(Hx, h_idxs) op = rand_span(PHx) mark_xop(op) # plenty... if 0: left = [draw.get_hidx(row, 0) for row in range(d0)] right = [draw.get_hidx(row, 5) for row in range(d0)] for idx in left + right: mark_idx(idx) PLx = in_support(LxHx, left + right) lop = rand_span(PLx) mark_xop(lop) PLx_left = in_support(LxHx, left) PLx_right = in_support(LxHx, right) PLx = numpy.concatenate((PLx_left, PLx_right)) assert rank(PLx) == rank(PLx_left) + rank(PLx_right) U = solve(PLx.transpose(), lop) assert U is not None #print(U) draw.save("output.logop") return for op in Lx: #cl = color.rgb(0.2*random(), 0.2*random(), random(), 0.5) draw.mark_op(op, st_qubit=[blue] + st_thick, r=0.06, stroke=True) for op in Lz: #cl = color.rgb(0.2*random(), random(), 0.2*random(), 0.5) draw.mark_op(op, st_qubit=[green] + st_thick, r=0.12, stroke=True) for idx in idxs: draw.mark(idx, st_qubit=[red] + st_thick, r=0.16, stroke=True) correctable = draw.cvs #draw.save("output") rows = [[], []] margin = 0.2 mkbox = lambda cvs: MarginBox(cvs, margin, 2 * margin) for op in Lx: draw = Draw(c0, c1, d0, d1) draw.mark_op(op, st_qubit=[blue] + st_thick, r=0.06, stroke=True) rows[0].append(mkbox(draw.cvs)) for op in Lz: draw = Draw(c0, c1, d0, d1) draw.mark_op(op, st_qubit=[green] + st_thick, r=0.12, stroke=True) rows[1].append(mkbox(draw.cvs)) row = [None] * len(Lx) row[0] = correctable rows.append(row) box = TableBox(rows) cvs = box.render() cvs.writePDFfile("output.pdf")