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 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 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_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, 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 lookup_distance(code): n = code.n Hz, Tx = code.Hz, code.Tx d = n u = zeros2(n) for i0 in range(n): u[i0] = 1 if dot2(Hz, u).sum() == 0: #print("*", shortstr(u)) d = min(d, 1) for i1 in range(i0+1, n): u[i1] = 1 if dot2(Hz, u).sum() == 0: #print("*", shortstr(u)) if d>2: print("d=", d) d = min(d, 2) for i2 in range(i1+1, n): u[i2] = 1 if dot2(Hz, u).sum() == 0: #print("*", shortstr(u)) if d>3: print("d=", d) d = min(d, 3) for i3 in range(i2+1, n): u[i3] = 1 if dot2(Hz, u).sum() == 0: #print("*", shortstr(u)) d = min(d, 4) u[i3] = 0 u[i2] = 0 u[i1] = 0 u[i0] = 0 return d
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 make_q(n, m, weight=None): k = n - 2 * m assert k >= 0 assert m > 0 Hx = [rand2(1, n, weight=weight)[0]] Hz = [] while 1: _Hx = array2(Hx) while 1: v = rand2(1, n, weight=weight) if dot2(Hx, v.transpose()).sum() == 0: break Hz.append(v[0]) if len(Hz) == m: break while 1: v = rand2(1, n, weight=weight) if dot2(Hz, v.transpose()).sum() == 0: break Hx.append(v[0]) Hx = array2(Hx) Hz = array2(Hz) assert dot2(Hx, Hz.transpose()).sum() == 0 return Hx, Hz
def score(code, p=0.05, N=10000): # each bit gets a score: higher is worse decoder = RadfordBPDecoder(2, code.Hz) n = code.n counts = numpy.zeros(n, dtype=int) err = 0 for trial in range(N): err_op = ra.binomial(1, p, (code.n, )) err_op = err_op.astype(numpy.int32) #write(str(err_op.sum())) s = dot2(code.Hz, err_op) # syndrome #write(":s%d:"%s.sum()) op = decoder.decode(p, err_op, verbose=False) 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()) if dot2(code.Lz, op).sum(): # counts += op counts += err_op else: success = True if not success: err += 1 return counts, (err / N)
def glue2(H1, H2, i1, i2): m1, n1 = H1.shape m2, n2 = H2.shape A1 = Chain([H1]) A2 = Chain([H2]) C = Chain([array2([[1]])]) C1n = zeros2(n1, 1) C1n[i1, 0] = 1 C1m = dot2(H1, C1n) C1 = Morphism(C, A1, [C1m, C1n]) C2n = zeros2(n2, 1) C2n[i2, 0] = 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_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 eq(self, other): "Two codes are equal if their generating matrices have the same span." G1, G2 = self.G, other.G if len(G1) != len(G2): return False A = dot2(self.H, other.G.transpose()) B = dot2(other.H, self.G.transpose()) assert (A.sum() == 0) == (B.sum() == 0) return A.sum() == 0
def check(self): # check symplectic condition A = self.A nn = self.n n = (nn - 1) // 2 B = A[:2 * n, :2 * n] F = symplectic_form(n) lhs = dot2(dot2(B.transpose(), F), B) return numpy.alltrue(lhs == F)
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 build(items): items = items.strip().split() #print(items) rows = [] n = None for item in items: assert n is None or len(items)==n n = len(items) row = [] for i in item: if i=="X": row += [1, 0] elif i=="Z": row += [0, 1] elif i=="Y": row += [1, 1] elif i=="I": row += [0, 0] else: assert 0 rows.append(row) H = solve.array2(rows) #print(H) J = sy_form(n) HJ = solve.dot2(H, J) #print(HJ) T = solve.pseudo_inverse(HJ.transpose()) #print(T) TJ = solve.dot2(T, J) #print(TJ) #print(solve.dot2(TJ, H.transpose())) # identity ops = [] for row in T: op = [] for i in range(n): opi = list(row[2*i : 2*(i+1)]) if opi == [0, 0]: op.append(I) #write("I") elif opi == [1, 0]: op.append(X) #write("X") elif opi == [0, 1]: op.append(Z) #write("Z") elif opi == [1, 1]: op.append(Y) #write("Y") else: assert 0, opi op = reduce(matmul, op) ops.append(op) #write("\n") return ops
def sparsecss(n, mx, mz, weight=8, **kw): print("sparsecss", n, mx, mz) k = n-mx-mz assert k>=0 vec = lambda n=n, weight=weight : rand2(1, n, weight=weight) Hz = zeros2(0, n) Hx = zeros2(0, n) Hx = append2(Hx, vec()) while len(Hz)<mz or len(Hx)<mx: # append2 Hz rows = shortstr(Hz).split() #print rows while Hz.shape[0]<mz: v = vec() u = dot2(Hx, v.transpose()) if u.sum() == 0 and shortstr(v) not in rows: Hz = append2(Hz, v) break # append2 Hx rows = shortstr(Hx).split() #print rows while Hx.shape[0]<mx: v = vec() u = dot2(Hz, v.transpose()) if u.sum() == 0 and shortstr(v) not in rows: Hx = append2(Hx, v) break print(shortstrx(Hz, Hx)) print() bits = [] for i in range(n): if Hx[:, i].sum() == 0: bits.append(i) elif Hz[:, i].sum() == 0: bits.append(i) for i in reversed(bits): Hx = numpy.concatenate( (Hx[:, :i], Hx[:, i+1:]), axis=1) Hz = numpy.concatenate( (Hz[:, :i], Hz[:, i+1:]), axis=1) #print shortstrx(Hx, Hz) C = CSSCode(Hx=Hx, Hz=Hz, **kw) return C
def glue_gcolor(): from qupy.ldpc.gcolor import Lattice l = argv.get('l', 1) lattice = Lattice(l) #code = lattice.build_code() H = lattice.Hx print("H:", H.shape) print(shortstr(H)) m, n = H.shape H1 = zeros2(m + 1, n + 1) H1[1:, 1:] = H H1[0, :] = 1 # print() # print(shortstr(H1)) # for genus in range(1, 5): # print(genus, strong_morthogonal(H1, genus)) H = H1 genus = argv.get("genus", 3) H = H.astype(numpy.int32) n = H.shape[1] if argv.scramble: R = rand2(m, m) H = dot2(R, H) print("H:", H.shape) print(shortstrx(H)) assert dot2(H, H.transpose()).sum() == 0 i0 = argv.get("i0", 0) i1 = argv.get("i1", i0) i2 = argv.get("i2", n) i3 = argv.get("i3", i2 + 1) # glue i0<-->i2 and i1<-->i3 H2 = direct_sum(H, H) print(H2.shape) print(shortstrx(H2)) assert strong_morthogonal(H2, genus) print() H3 = glue_self_classical(H2, [(i0, i2), (i1, i3)]) print(H3.shape) print(shortstrx(H3)) assert strong_morthogonal(H3, genus) print() print(shortstr((H2[:m, 1:n] + H3[:m, 1:n]) % 2)) #print(eq2(H2[m+2:, i1+2:], H3[m:, i1:])) #print(classical_distance(H3)) return H3
def x_split(C0, build=True, **kw): "split the x-stabilizers of C0" #print "x_split" mz, n, mx = C0.mz, C0.n+C0.mx, 2*C0.mx #print C0.longstr() Hz = zeros2(mz, n) Hz[:, :C0.n] = C0.Hz Hx = zeros2(mx, n) #print "Hz:" #print shortstrx(Hz) for i in range(C0.mx): op = C0.Hx[i] #Hx[:C0.mx-1, :C0.n] = pop2(C0.Hx, i) #print "Hx:" #print shortstrx(Hx) idxs = [j for j in range(C0.n) if op[j]] idxs0 = idxs[:len(idxs)//2] idxs1 = idxs[len(idxs)//2:] #print idxs, idxs0, idxs1 i0, i1 = 2*i, 2*i+1 for j in idxs0: Hx[i0, j] = 1 for j in idxs1: Hx[i1, j] = 1 Hx[i0, C0.n+i] = 1 Hx[i1, C0.n+i] = 1 #print "Hx:" #print shortstrx(Hx) for j in range(mz): if dot2(Hz[j], Hx[i0]): assert dot2(Hz[j], Hx[i1]) # brilliant! Hz[j, C0.n+i] = 1 C1 = CSSCode(Hx=Hx, Hz=Hz, build=build, **kw) #print C1.weightsummary() return C1
def inverse(self): A = self.A nn = self.n n = (nn - 1) // 2 B = A[:2 * n, :2 * n] # symplectic v = A[:2 * n, 2 * n] # translation, shape (2*n,) F = symplectic_form(n) Fi = F # an involution Bi = dot2(Fi, dot2(B.transpose()), F) A1 = A.copy() A1[:2 * n, :2 * n] = Bi A1[:2 * n, 2 * n] = dot2(-Bi, v) return Clifford(A1)
def __mul__(self, other): "composition: apply other then self" assert isinstance(other, Morphism) assert other.tgt == self.src n = len(self) Ds = [dot2(self[i], other[i]) for i in range(n)] return Morphism(other.src, self.tgt, Ds)
def get_syndrome(self, op): syndrome = [] for i in range(len(self.Gz)): r = dot2(op, self.Gz[i].transpose()) if r: syndrome.append(i) return syndrome
def test_isotropic(): n = 3 gen, _ = get_gen(n) assert len(mulclose_fast(gen)) == 1451520 return n = argv.get("n", 3) F = Matrix.symplectic_form(n).A found = [] for A in all_codes(n, 2 * n): B = dot2(dot2(A, F), A.transpose()) if B.sum() == 0: A = Matrix(A) found.append(A) #print(A) found = set(found) print(len(found)) gen, _ = get_gen(n) #gen = get_transvect(n) orbit = set() A = iter(found).__next__() bdy = [A] orbit = set(bdy) while bdy: _bdy = [] for A in bdy: print(A) for g in gen: B = A * g print(B) print() B = B.normal_form() print(B) print() assert B in found if B not in orbit: _bdy.append(B) orbit.add(B) bdy = _bdy print(len(orbit))