def build_random(n): weight = argv.get("weight", 3) coweight = argv.get("coweight") p = argv.get("p", 0.3) m = argv.get("m", n) mx = argv.get("mx", m) mz = argv.get("mz", m) if coweight is not None: Gx = rand2(n, mx, weight=coweight).transpose() Gz = rand2(n, mz, weight=coweight).transpose() else: Gx = rand2(mx, n, p=p, weight=weight) Gz = rand2(mz, n, p=p, weight=weight) Hx = Hz = None Gx = Gx[[i for i in range(m) if Gx[i].sum()], :] Gz = Gz[[i for i in range(m) if Gz[i].sum()], :] li = argv.get("li", True) if li: Gx = linear_independent(Gx) Gz = linear_independent(Gz) return Gx, Gz, Hx, Hz
def build_random_selfdual(n): weight = argv.get("weight", 3) m = argv.get("m", n) h = argv.get("h", 0) while 1: Gx = rand2(m, n, weight=weight) Gz = Gx.copy() Hx = Hz = None Gx = Gx[[i for i in range(m) if Gx[i].sum()], :] Gx = linear_independent(Gx) if len(Gx) < m: write("m") continue Gz = Gx.copy() Hx = find_stabilizers(Gz, Gx) Hz = find_stabilizers(Gx, Gz) if len(Hx) == h and len(Hz) == h: break write("H(%d,%d)" % (len(Hx), len(Hz))) print() return Gx, Gz, Hx, Hz
def puncture(self, i): assert 0 <= i < self.n G = self.G A = G[:, :i] B = G[:, i + 1:] G = numpy.concatenate((A, B), axis=1) G = linear_independent(G, check=True) return Code(G)
def get_code(self, idx=0, build=True, check=True): #print "get_code" Hs = self.Hs Hx = Hs[idx] write("li:") Hx = solve.linear_independent(Hx) Hz = Hs[idx + 1].transpose() write("li:") Hz = solve.linear_independent(Hz) #print(Hx.shape, Hz.shape) if self.Ls: Lz = self.Ls[idx] #print "get_code:", Lz.shape else: Lz = None #print shortstr(dot(Hx, Hz.transpose())) #print "Hz:" #print shortstr(Hz) #print "Hx:" #print shortstr(Hx) from qupy.ldpc.css import CSSCode code = CSSCode(Hx=Hx, Hz=Hz, Lz=Lz, build=build, check=check) return code
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 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 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 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 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