Exemple #1
0
def glue_logops():

    m = argv.get("m", 4)
    n = argv.get("n", m + m + 1)
    dist = argv.get("dist", 3)
    N = argv.get("N", 2)
    M = argv.get("M", N)
    p = argv.get("p", 0.03)
    weight = argv.weight

    codes = []
    code = None
    for i in range(N):
        Hx, Hz = make_quantum(n, m, dist, weight)
        #Hx, Hz = make_surface()
        print("Hx, Hz:")
        print(shortstrx(Hx, Hz))
        c = CSSCode(Hx=Hx, Hz=Hz)
        codes.append(c)
        code = c if code is None else code + c

    A, B = codes
    code = A + B

    print(code)
    print("Lx, Lz:")
    print(shortstrx(code.Lx, code.Lz))
    print("Hx, Hz:")
    print(shortstrx(code.Hx, code.Hz))
    print()

    #Hx = cat((code.Lx, code.Hx))
    Hx = code.Hx
    Hz = cat((code.Lz, code.Hz))

    idxs = list(range(2 * n))
    idxs.sort(key=lambda i: (-code.Lz[:, i].sum(), ))
    Hx = Hx[:, idxs]
    Hz = Hz[:, idxs]

    print(shortstrx(Hx, Hz))

    i0 = argv.get("i0")
    i1 = argv.get("i1")
    if i0 is None:
        return


#    code = code.glue(0, n)
#    print(code)
#    print(shortstrx(code.Hx, code.Hz))

    Hx, Hz = glue1_quantum(Hx, Hz, i0, i1)
    print("Hx, Hz:")
    print(shortstrx(Hx, Hz))
Exemple #2
0
def find_logops():

    Hz = parse("""
    11111.........................
    1....1111.....................
    .1.......1111.................
    ..1..1.......111..............
    ...1..1..1......11............
    ....1.....1..1....11..........
    ...........1....1...111.......
    ............1.....1.1..11.....
    ..............1....1...1.11...
    .......1.......1.........1.11.
    ........1........1...1.....1.1
    ......................1.1.1.11
    """)

    Hx = parse("""
    11......1..1.........1........
    .....11..11..1................
    ...11...........1.1.1.........
    .........1..1....1......1....1
    ....................11.1.1.1..
    ..........11.......1..1...1...
    .............1.1..1.....1...1.
    ..11...........1.1.........1..
    .....1..1.....1...........1..1
    .11.........1.1........1......
    1...1..1...........1.....1....
    ......11........1.....1.....1.
    """)
    Hz = remove_dependent(Hz)
    Hx = remove_dependent(Hx)

    mx, n = Hx.shape
    mz, n = Hz.shape

    print(n, mx, mz)

    Hz = parse("1.111... .111.1.. 1...1.11")
    Hx = parse("111...1. 11.1...1 ..1.111.")

    from qupy.ldpc.css import CSSCode
    code = CSSCode(Hx=Hx, Hz=Hz)
    print("Lx:")
    print(shortstr(code.Lx))
    print("Lz:")
    print(shortstr(code.Lz))
Exemple #3
0
def find_homology_2(g, f, *dims):

    print("find_homology")
    print(dims[2], "--f-->", dims[1], "--g-->", dims[0])

    F = numpy.zeros((dims[1], dims[2]))
    for row, col in list(f.keys()):
        v = f[row, col]
        F[row, col] = v % 2
    #print shortstr(F.transpose())
    #print

    G = numpy.zeros((dims[0], dims[1]))
    for row, col in list(g.keys()):
        v = g[row, col]
        G[row, col] = v % 2
    #print shortstr(G)

    if argv.ldpc:
        from qupy.ldpc.css import CSSCode
        code = CSSCode(Hx=F.transpose(), Hz=G)
        code.build()
        code = code.prune_deadbits()
        print(code)
        name = argv.get("name")
        if name.endswith(".ldpc"):
            print("saving", name)
            code.save(name)

    if argv.logops:
        L = find_logops(G, F.transpose())
        w = min([v.sum() for v in L])
        print("logops weight:", w)
        L = find_logops(F, G.transpose())
        w = min([v.sum() for v in L])
        print("logops weight:", w)

    GF = numpy.dot(G, F) % 2
    #print shortstr(GF)
    assert numpy.abs(GF).sum() == 0

    F = F.astype(numpy.int32)
    G = G.astype(numpy.int32)

    print("rank(f)=%d, rank(g)=%d" % (rank(F), rank(G)))
    if g:
        kerg = find_kernel(G)
        print("ker(g):", len(kerg))
Exemple #4
0
def test_flow():

    seed(3)

    m, n = argv.get("m", 3), argv.get("n", 3)
    cx = Complex()

    if argv.disc:
        cx.build_surface((0, 0), (m, n))
        k = 0
    elif argv.surface:
        cx.build_surface((0, 0), (m, n), open_top=True, open_bot=True)
        k = 0
    elif argv.torus:
        cx.build_torus(m, n)
        k = 2
    else:
        cx.build_torus(m, n)
        k = 2

    #print(cx)

    for trial in range(10):

        flow = Flow(cx)
        flow.build()

        if argv.render:
            flow.render(name="output")
            break

        chain = flow.morse_homology(1)
        A, B = chain
        BA = B * A
        for key, v in BA.elements.items():
            assert v % 2 == 0
        #print(BA.todense())

        Hzt = A.todense() % 2
        Hz = Hzt.transpose()
        Hx = B.todense() % 2

        assert dot2(Hx, Hzt).sum() == 0
        code = CSSCode(Hx=Hx, Hz=Hz)
        #print("k =", code.k)
        assert code.k == k, (code.k, k)
Exemple #5
0
 def __call__(self, other):
     assert isinstance(other, CSSCode)
     assert other.n * 2 == self.n
     Lx, Lz, Hx, Tz, Hz, Tx, Gx, Gz = (other.Lx, other.Lz, other.Hx,
                                       other.Tz, other.Hz, other.Tx,
                                       other.Gx, other.Gz)
     assert Gx is None
     assert Gz is None
     A = self.A.transpose()
     LxLz = dot2(cat((Lx, Lz), axis=1), A)
     HxTz = dot2(cat((Hx, Tz), axis=1), A)
     TxHz = dot2(cat((Tx, Hz), axis=1), A)
     n = self.n // 2
     Lx, Lz = LxLz[:, :n], LxLz[:, n:]
     Hx, Tz = HxTz[:, :n], HxTz[:, n:]
     Tx, Hz = TxHz[:, :n], TxHz[:, n:]
     code = CSSCode(Lx=Lx, Lz=Lz, Hx=Hx, Tz=Tz, Hz=Hz, Tx=Tx)
     return code
Exemple #6
0
 def get_code(self):
     self.check()
     keys = self.keys
     keymap = self.keymap
     x_ops, z_ops = self.get_stabs()
     n = len(keys)
     mx = len(x_ops)
     mz = len(z_ops)
     Hx = zeros2(mx, n)
     Hz = zeros2(mz, n)
     for idx, stab in enumerate(x_ops):
         for key in stab:
             Hx[idx, keymap[key]] = 1
     for idx, stab in enumerate(z_ops):
         for key in stab:
             Hz[idx, keymap[key]] = 1
     code = CSSCode(Hx=Hx, Hz=Hz)
     return code
Exemple #7
0
 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
Exemple #8
0
def is_422_cat_selfdual(Hz, Hx, perm):
    "concatenate with the [[4,2,2]] code and see if we get a self-dual code"
    from numpy import alltrue, zeros, dot
    import qupy.ldpc.solve
    import bruhat.solve
    qupy.ldpc.solve.int_scalar = bruhat.solve.int_scalar
    from bruhat.solve import shortstrx, zeros2, dot2, array2, solve
    from qupy.ldpc.css import CSSCode
    Cout = CSSCode(Hz=Hz, Hx=Hx)
    #print(Cout)
    #Cin = CSSCode(Hz=array2([[1,1,1,1]]), Hx=array2([[1,1,1,1]]))
    #print(Cin)

    pairs = []
    singles = []
    for i in range(Cout.n):
        j = perm[i]
        if j < i:
            continue
        if i == j:
            singles.append(i)
        else:
            pairs.append((i, j))
    #print(singles, pairs)
    M = len(singles) + 4 * len(pairs)

    # encoding matrices
    enc_z = zeros2(M, Cout.n)
    enc_x = zeros2(M, Cout.n)

    row = 0
    for col in singles:
        enc_z[row, col] = 1
        enc_x[row, col] = 1
        row += 1
    H = []
    for (i, j) in pairs:
        enc_z[row, i] = 1  # 1010
        enc_z[row + 2, i] = 1
        enc_z[row, j] = 1  # 1100
        enc_z[row + 1, j] = 1

        enc_x[row, i] = 1  # 1100
        enc_x[row + 1, i] = 1
        enc_x[row, j] = 1  # 1010
        enc_x[row + 2, j] = 1
        h = array2([0] * M)
        h[row:row + 4] = 1
        H.append(h)

        row += 4
    assert row == M

    #print(shortstrx(enc_z, enc_x))

    Hz = dot2(enc_z, Cout.Hz.transpose()).transpose()
    Hx = dot2(enc_x, Cout.Hx.transpose()).transpose()
    assert alltrue(dot2(Hz, Hx.transpose()) == 0)

    Hz = numpy.concatenate((Hz, H))
    Hx = numpy.concatenate((Hx, H))
    assert alltrue(dot2(Hz, Hx.transpose()) == 0)

    C = CSSCode(Hz=Hz, Hx=Hx)
    assert C.k == Cout.k
    #print(C)

    lhs = (solve(Hz.transpose(), Hx.transpose()) is not None)
    rhs = (solve(Hx.transpose(), Hz.transpose()) is not None)
    return lhs and rhs
Exemple #9
0
def even_code():

    p = argv.get("p", 7)

    #assert (p%8) in [1, 7]
    # equivalent to "2 (binary!) is a quadratic _residue mod p"
    # eg. 7 17 23 31 41 47 71 73 79 89 97

    def neginv(i):
        if i == 0:
            return p
        if i == p:
            return 0
        for j in range(1, p):
            if (i * j) % p == 1:
                break
        else:
            assert 0
        return (-j) % p

    nonresidues = set(range(1, p))
    residues = set()
    for i in range(1, p):
        j = (i * i) % p
        if j not in residues:
            residues.add(j)
            nonresidues.remove(j)
    print("residues:", residues)
    print("non-residues:", nonresidues)

    # extended binary quadratic _residue code
    N = p + 1
    G = zeros2(N, N)

    G[p, :] = 1
    for u in range(p):
        G[u, p] = 0 if (p - 1) % 8 == 0 else 1
        for v in range(p):
            if u == v:
                i = 0
            elif (v - u) % p in residues:
                i = 1
            else:
                i = 0
            G[u, v] = i

    G = linear_independent(G)
    print("G =")
    print(shortstr(G))

    from qupy.ldpc.css import CSSCode
    from qupy.ldpc.gallagher import classical_distance
    G = G.astype(numpy.int32)
    code = CSSCode(Hx=G, Hz=G)
    print(code)

    from bruhat.codes import strong_morthogonal
    for genus in range(1, 4):
        print("genus:", genus, "strong_morthogonal:",
              strong_morthogonal(G, genus))

    def double(G):
        M, N = G.shape
        DG = zeros2(M + 1, 2 * N)
        DG[1:, 0:N] = G
        DG[1:, N:2 * N] = G
        DG[0, 0:N] = 1
        DG = DG.astype(numpy.int32)
        return DG

    DG = G
    DG = DG.astype(numpy.int32)
    print("distance:", classical_distance(DG))
    for _ in range(2):

        DG = double(DG)
        DG = linear_independent(DG)
        print(shortstr(DG))

        for genus in range(1, 5):
            print("genus:", genus, "strong_morthogonal:",
                  strong_morthogonal(DG, genus))

        code = CSSCode(Hx=DG, Hz=DG)
        print(code)
Exemple #10
0
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))
Exemple #11
0
def main():

    m = argv.get('m', 6)  # constraints (rows)
    n = argv.get('n', 16)  # bits (cols)
    j = argv.get('j', 3)  # column weight (left degree)
    k = argv.get('k', 8)  # row weight (constraint weight; right degree)

    #assert 2*m<=n, "um?"

    max_iter = argv.get('max_iter', 200)
    verbose = argv.verbose
    check = argv.get('check', False)

    strop = shortstr

    Lx = None
    Lz = None
    Hx = None
    Tz = None
    Hz = None
    Tx = None
    build = argv.get('build', False)
    logops_only = argv.get("logops_only", True)

    code = None

    if argv.code == 'ldpc':

        H = ldpc(m, n, j, k)
        code = CSSCode(Hz=H, Hx=zeros2(0, n))

    elif argv.code == 'cycle':

        #n = argv.get('n', 20)
        #m = argv.get('m', 18)

        row = str(argv.get('H', '1101'))

        H = []

        for i in range(n):
            h = [0] * n
            for j, c in enumerate(row):
                h[(i + j) % n] = int(c)
            H.append(h)

        delta = n - m
        for i in range(delta):
            H.pop(i * n // delta - i)

#        while len(H) > m:
#            idx = randint(0, len(H)-1)
#            H.pop(idx)

        Hz = array2(H)

        print(shortstr(Hz))

        #print shortstr(solve.row_reduce(Hz))

#        code = CSSCode(Hz=Hz)
#        print
#        print code
#        print code.weightstr()
#
#        decoder = StarDynamicDistance(code)
#        L = decoder.find(verbose=verbose)
#        print shortstr(L)
#        print "distance:", L.sum()
#        return

    elif argv.code == "opticycle":

        code = opticycle(m, n)

        H = Hz = code.Hz

        #return

    elif argv.code == 'tree':

        k = argv.get('k', 5)
        n = 2**k + 1

        code = build_tree(45)
        print(code)

#        graph = Graph()
#        for i in range(H.shape[0]):
#            edge = list(numpy.where(H[i])[0])
#            #print edge,
#            for i0 in edge:
#              for i1 in edge:
#                if i0!=i1:
#                    graph.add_edge(i0, i1)
#
#        leaves = [idx for idx in range(n) if H[:, idx].sum()<=1]
#        print leaves
#
#
#        k = len(leaves)//2
#        print graph.metric(leaves[1], leaves[k])
#        return
#        for i in range(k-1):
#            #i0 = poprand(leaves)
#            #i1 = poprand(leaves)
#            u = zeros2(1, n)
#            u[0, leaves[i]] = 1
#            u[0, leaves[i+k]] = 1
#            # what about picking three leaves?
#            print (leaves[i], leaves[i+k]),
#            H = append2(H, u)
#        print
#
#        # if we take all the leaves we get degenerate...
#        leaves = [idx for idx in range(n) if H[:, idx].sum()<=1]
#        print "leaves:", leaves
#
#        #print shortstr(H)
#        #print
#        #print shortstr(solve.row_reduce(H))

#        code = CSSCode(Hz=H)
#        print code
#        print code.weightstr()

#        print numpy.where(code.Lx[3])
#
#        return

    elif argv.code == 'bicycle':

        from qupy.ldpc.bicycle import Bicycle_LDPC
        print("Bicycle_LDPC(%s, %s, %s, %s)" % (m, n, j, k))
        b = Bicycle_LDPC(m, n, j, k)
        Hx = Hz = b.H

    elif argv.code == 'toric':

        from qupy.ldpc.toric import Toric2D

        l = argv.get('l', 8)
        li = argv.get('li', l)
        lj = argv.get('lj', l)
        si = argv.get('si', 0)
        sj = argv.get('sj', 0)

        toric = Toric2D(li, lj, si, sj)
        Hx, Hz = toric.Hx, toric.Hz
        strop = toric.strop
        #print("Hx:")
        #print(shortstr(Hx))
        #print("Lx:")
        #print(shortstr(toric.Lx))
        code = CSSCode(Hx=Hx, Hz=Hz, Lx=toric.Lx, Lz=toric.Lz)

    elif argv.code == 'cylinder':

        from qupy.ldpc.toric import Cylinder

        l = argv.get('l', 8)
        li = argv.get('li', l)
        lj = argv.get('lj', l)
        si = argv.get('si', 0)
        sj = argv.get('sj', 0)
        assert si == 0

        surface = Cylinder(li, lj, sj)
        Hx, Hz = surface.Hx, surface.Hz
        strop = surface.strop
        #print("Hx:")
        #print(shortstr(Hx))
        #print("Lx:")
        #print(shortstr(surface.Lx))
        code = CSSCode(Hx=Hx, Hz=Hz)

    elif argv.code == 'torichie':

        from qupy.ldpc.toric import Toric2DHie
        l = argv.get('l', 8)

        toric = Toric2DHie(l)
        Hx, Hz = toric.Hx, toric.Hz

    elif argv.code == 'surface':

        from qupy.ldpc.toric import Surface
        l = argv.get('l', 8)
        si = argv.get('si', 0)  # todo
        sj = argv.get('sj', 0)

        surface = Surface(l)
        #Hx, Hz = surface.Hx, surface.Hz
        #strop = surface.strop
        #print shortstr(Hx)
        code = surface.get_code()

    elif argv.code == 'toric3':

        from qupy.ldpc.toric import Toric3D
        l = argv.get('l', 8)

        toric = Toric3D(l)
        Hx, Hz = toric.Hx, toric.Hz
        strop = toric.strop
        #print shortstr(Hx)

    elif argv.code == 'gcolor':

        from qupy.ldpc.gcolor import Lattice
        l = argv.get('l', 1)
        lattice = Lattice(l)
        #code = lattice.build_code()
        G = lattice.Hx
        print(shortstr(G))
        m, n = G.shape
        G1 = zeros2(m + 1, n + 1)
        G1[1:, 1:] = G
        G1[0, :] = 1
        print()
        print(shortstr(G1))
        for genus in range(1, 5):
            print(genus, strong_morthogonal(G1, genus))
        code = CSSCode(Hx=G1, Hz=G1)

    elif argv.code == 'self_ldpc':

        from qupy.ldpc.search import SelfContainingLDPC_Code
        ldpc_code = SelfContainingLDPC_Code(m, n, j, k)
        ldpc_code.search(max_step=argv.get('max_step', None), verbose=verbose)
        #print ldpc_code

        H = ldpc_code.H
        print("H:")
        print(shortstr(H))
        H = solve.linear_independent(H)
        Hx = Hz = H

        code = CSSCode(Hx=Hx, Hz=Hz)

    elif argv.code == 'cssldpc':

        from qupy.ldpc.search import CSS_LDPC_Code
        ldpc_code = CSS_LDPC_Code(m, n, j, k)
        ldpc_code.search(max_step=argv.get('max_step', None), verbose=verbose)
        #print ldpc_code

        Hx, Hz = ldpc_code.Hx, ldpc_code.Hz
        #print "Hx:"
        #print shortstr(Hx)
        Hx = solve.linear_independent(Hx)
        Hz = solve.linear_independent(Hz)
        #Hx = Hz = H

        code = CSSCode(Hx=Hx, Hz=Hz)

    elif argv.code == "hpack":

        code = hpack(n, j=j, k=k, check=check, verbose=verbose)

    elif argv.code == 'randldpc':

        mz = argv.get('mz', n // 3)
        rw = argv.get('rw', 12)  # row weight
        code = randldpc(n, mz, rw, check=check, verbose=verbose)

    elif argv.code == 'randcss':

        mx = argv.get('mx', n // 3)
        mz = argv.get('mz', n // 3)
        distance = argv.get("code_distance")
        code = randcss(n,
                       mx,
                       mz,
                       distance=distance,
                       check=check,
                       verbose=verbose)

    elif argv.code == 'sparsecss':

        mx = argv.get('mx', n // 3)
        mz = argv.get('mz', n // 3)
        weight = argv.get('weight', 4)
        code = sparsecss(n, mx, mz, weight, check=check, verbose=verbose)

    elif argv.code == 'ensemble':

        mx = argv.get('mx', n // 3)
        mz = argv.get('mz', mx)
        rw = argv.get('rw', 12)  # row weight
        maxw = argv.get('maxw', 4 * rw)
        C = argv.get("C", 100)
        code = ensemble.build(n,
                              mx,
                              mz,
                              rw,
                              maxw,
                              C,
                              check=check,
                              verbose=verbose)

    elif argv.code == "rm" or argv.code == "reed_muller":
        from qupy.ldpc import reed_muller
        r = argv.get("r", 1)
        m = argv.get("m", 4)
        puncture = argv.puncture
        cl_code = reed_muller.build(r, m, puncture)
        G = cl_code.G
        G = array2([row for row in G if row.sum() % 2 == 0])
        code = CSSCode(Hx=G, Hz=G)

    elif argv.code == "qrm":
        from qupy.ldpc.gallagher import get_code, hypergraph_product
        from qupy.ldpc import reed_muller
        r = argv.get("r", 1)
        m = argv.get("m", 4)
        puncture = argv.puncture
        cl_code = reed_muller.build(r, m, puncture)
        H = cl_code.G
        H = array2([row for row in H if row.sum() % 2 == 0])
        print(shortstr(H))
        m, n = 4, 4
        J = zeros2(m, n)
        for i in range(m):
            J[i, i] = 1
            J[i, (i + 1) % n] = 1
        print()
        print(shortstr(J))
        Hx, Hz, Lx, Lz = hypergraph_product(J, H)
        code = CSSCode(Hx=Hx, Hz=Hz, Lx=Lx, Lz=Lz)
        #print(code.weightstr())
        #print("Hz:")
        #print(shortstr(code.Hz))
        #print("Hx:")
        #print(shortstr(code.Hx))

    elif argv.code == "qgall":
        from qupy.ldpc.gallagher import make_gallagher, hypergraph_product
        l = argv.get("l", 3)  # column weight
        m = argv.get("m", 4)  # row weight
        n = argv.get("n", 8)  # cols
        r = argv.get("r", n * l // m)  # rows
        dist = argv.get("dist", 4)  # distance
        H = make_gallagher(r, n, l, m, dist)
        #print(H)
        rm = argv.get("rm", dist)
        J = zeros2(rm, rm)
        for i in range(rm):
            J[i, i] = 1
            J[i, (i + 1) % rm] = 1
        #print(J)
        Hx, Hz, Lx, Lz = hypergraph_product(J, H)
        code = CSSCode(Hx=Hx, Hz=Hz, Lx=Lx, Lz=Lz)
        #print(code.weightstr())
        #print("Hz:")
        #print(shortstr(code.Hz))
        #print("Hx:")
        #print(shortstr(code.Hx))

    elif argv.code == "qr7":
        H = parse("""
        ...1111
        .11..11
        1.1.1.1
        """)
        code = CSSCode(Hx=H, Hz=H)

    elif argv.code == "golay" or argv.code == "qr23":
        H = parse("""
        1.1..1..11111..........
        1111.11.1....1.........
        .1111.11.1....1........
        ..1111.11.1....1.......
        ...1111.11.1....1......
        1.1.1.111..1.....1.....
        1111...1..11......1....
        11.111...11........1...
        .11.111...11........1..
        1..1..11111..........1.
        .1..1..11111..........1
        """)
        code = CSSCode(Hx=H, Hz=H)

    elif argv.code == "dgolay":  # double golay code (tri-orthogonal)
        H = parse("""
        111111111111111111111111........................
        .1111.1.11..11..1.1....1.1111.1.11..11..1.1....1
        ..1111.1.11..11..1.1...1..1111.1.11..11..1.1...1
        ...1111.1.11..11..1.1..1...1111.1.11..11..1.1..1
        ....1111.1.11..11..1.1.1....1111.1.11..11..1.1.1
        .....1111.1.11..11..1.11.....1111.1.11..11..1.11
        1.....1111.1.11..11..1.11.....1111.1.11..11..1.1
        .1.....1111.1.11..11..11.1.....1111.1.11..11..11
        1.1.....1111.1.11..11..11.1.....1111.1.11..11..1
        .1.1.....1111.1.11..11.1.1.1.....1111.1.11..11.1
        ..1.1.....1111.1.11..111..1.1.....1111.1.11..111
        1..1.1.....1111.1.11..111..1.1.....1111.1.11..11
        11..1.1.....1111.1.11..111..1.1.....1111.1.11..1
        """)
        code = CSSCode(Hx=H, Hz=H)

    elif argv.code == "dham":  # double hamming code (tri-orthogonal)
        H = parse("""
        11111111........
        .11.1..1.11.1..1
        ..11.1.1..11.1.1
        ...11.11...11.11
        1...11.11...11.1
        """)
        code = CSSCode(Hx=H, Hz=H)

    elif argv.code == "ddham":  # double double hamming code
        H = parse("""
        1111111111111111................
        11111111........11111111........
        .11.1..1.11.1..1.11.1..1.11.1..1
        ..11.1.1..11.1.1..11.1.1..11.1.1
        ...11.11...11.11...11.11...11.11
        1...11.11...11.11...11.11...11.1
        """)
        code = CSSCode(Hx=H, Hz=H)

    elif argv.code == "qr31":
        H = parse("""
        1..1..1.1...11.11..............
        11.11.1111..1.11.1.............
        11111111.11.1.....1............
        .11111111.11.1.....1...........
        ..11111111.11.1.....1..........
        ...11111111.11.1.....1.........
        1..111.1.1111.11......1........
        11.111....11...........1.......
        .11.111....11...........1......
        ..11.111....11...........1.....
        ...11.111....11...........1....
        ....11.111....11...........1...
        1..1.1...11.11..............1..
        .1..1.1...11.11..............1.
        ..1..1.1...11.11..............1
        """)
        code = CSSCode(Hx=H, Hz=H)

    elif argv.code == "qr17":
        # not self-dual
        Hz = parse("""
        .11.1...11...1.11
        1.11.1...11...1.1
        11.11.1...11...1.
        .11.11.1...11...1
        1.11.11.1...11...
        .1.11.11.1...11..
        ..1.11.11.1...11.
        ...1.11.11.1...11
        1...1.11.11.1...1
        11...1.11.11.1...
        .11...1.11.11.1..
        ..11...1.11.11.1.
        ...11...1.11.11.1
        1...11...1.11.11.
        .1...11...1.11.11
        1.1...11...1.11.1
        11.1...11...1.11.
        """)
        Hx = parse("""
        ...1.111..111.1..
        11.1.....1.111..1
        111..111.1.....1.
        ....1.111..111.1.
        111.1.....1.111..
        .111..111.1.....1
        .....1.111..111.1
        .111.1.....1.111.
        1.111..111.1.....
        1.....1.111..111.
        ..111.1.....1.111
        .1.111..111.1....
        .1.....1.111..111
        1..111.1.....1.11
        ..1.111..111.1...
        1.1.....1.111..11
        11..111.1.....1.1
        """)
        Hz = solve.linear_independent(Hz)
        Hx = solve.linear_independent(Hx)
        code = CSSCode(Hx=Hx, Hz=Hz)

    elif argv.code == "qr41":
        # not self-dual
        Hz = parse("""
        .11.11..111.....1.1.11.1.1.....111..11.11
        1.11.11..111.....1.1.11.1.1.....111..11.1
        11.11.11..111.....1.1.11.1.1.....111..11.
        .11.11.11..111.....1.1.11.1.1.....111..11
        1.11.11.11..111.....1.1.11.1.1.....111..1
        11.11.11.11..111.....1.1.11.1.1.....111..
        .11.11.11.11..111.....1.1.11.1.1.....111.
        ..11.11.11.11..111.....1.1.11.1.1.....111
        1..11.11.11.11..111.....1.1.11.1.1.....11
        11..11.11.11.11..111.....1.1.11.1.1.....1
        111..11.11.11.11..111.....1.1.11.1.1.....
        .111..11.11.11.11..111.....1.1.11.1.1....
        ..111..11.11.11.11..111.....1.1.11.1.1...
        ...111..11.11.11.11..111.....1.1.11.1.1..
        ....111..11.11.11.11..111.....1.1.11.1.1.
        .....111..11.11.11.11..111.....1.1.11.1.1
        1.....111..11.11.11.11..111.....1.1.11.1.
        .1.....111..11.11.11.11..111.....1.1.11.1
        1.1.....111..11.11.11.11..111.....1.1.11.
        .1.1.....111..11.11.11.11..111.....1.1.11
        """)
        Hx = parse("""
        ...1..11...11111.1.1..1.1.11111...11..1..
        1111...11..1.....1..11...11111.1.1..1.1.1
        111.1.1..1.1.11111...11..1.....1..11...11
        ....1..11...11111.1.1..1.1.11111...11..1.
        11111...11..1.....1..11...11111.1.1..1.1.
        1111.1.1..1.1.11111...11..1.....1..11...1
        .....1..11...11111.1.1..1.1.11111...11..1
        .11111...11..1.....1..11...11111.1.1..1.1
        11111.1.1..1.1.11111...11..1.....1..11...
        1.....1..11...11111.1.1..1.1.11111...11..
        1.11111...11..1.....1..11...11111.1.1..1.
        .11111.1.1..1.1.11111...11..1.....1..11..
        .1.....1..11...11111.1.1..1.1.11111...11.
        .1.11111...11..1.....1..11...11111.1.1..1
        ..11111.1.1..1.1.11111...11..1.....1..11.
        ..1.....1..11...11111.1.1..1.1.11111...11
        1.1.11111...11..1.....1..11...11111.1.1..
        ...11111.1.1..1.1.11111...11..1.....1..11
        1..1.....1..11...11111.1.1..1.1.11111...1
        .1.1.11111...11..1.....1..11...11111.1.1.
        """)
        code = CSSCode(Hz=Hz, Hx=Hx)

    elif argv.code == "qr47":
        H = parse("""
        1...11..11.11..1..1.1..11......................
        11..1.1.1.11.1.11.1111.1.1.....................
        111.1..11.....111111.111..1....................
        11111......11...11.1..1....1...................
        .11111......11...11.1..1....1..................
        1.11..1.11.11111...111.1.....1.................
        11.1.1.11.11.11.1.1..111......1................
        111..11.......1..1111.1........1...............
        .111..11.......1..1111.1........1..............
        1.11.1.1.1.11..11.11.111.........1.............
        11.1.11..111.1.11111..1...........1............
        .11.1.11..111.1.11111..1...........1...........
        1.111..1.1...1...1.1.1.1............1..........
        11.1.....1111.11......11.............1.........
        111..1..111..1..1.1.1.................1........
        .111..1..111..1..1.1.1.................1.......
        ..111..1..111..1..1.1.1.................1......
        ...111..1..111..1..1.1.1.................1.....
        1.....1.1..1.111.11...11..................1....
        11..11.11..1..1.1..11......................1...
        .11..11.11..1..1.1..11......................1..
        ..11..11.11..1..1.1..11......................1.
        ...11..11.11..1..1.1..11......................1
        """)
        code = CSSCode(Hx=H, Hz=H)

    elif argv.code == "qr71":
        H = parse("""
        1.1.1.11.1...11..11.....1....1...1111..................................
        1111111.111..1.1.1.1....11...11..1...1.................................
        .1111111.111..1.1.1.1....11...11..1...1................................
        ..1111111.111..1.1.1.1....11...11..1...1...............................
        1.11.1..1..11.1.11..1.1.1..111..1.11....1..............................
        1111...1....1.11.....1.111..1.1...1......1.............................
        .1111...1....1.11.....1.111..1.1...1......1............................
        1..1.111.....1..1.1....11111.11.1111.......1...........................
        111.....11...1....11.....1111111............1..........................
        .111.....11...1....11.....1111111............1.........................
        ..111.....11...1....11.....1111111............1........................
        ...111.....11...1....11.....1111111............1.......................
        ....111.....11...1....11.....1111111............1......................
        1.1.11...1.......1.....1.....1111................1.....................
        .1.1.11...1.......1.....1.....1111................1....................
        ..1.1.11...1.......1.....1.....1111................1...................
        ...1.1.11...1.......1.....1.....1111................1..................
        1.1....11.....1..11..1..1..1.1.......................1.................
        .1.1....11.....1..11..1..1..1.1.......................1................
        ..1.1....11.....1..11..1..1..1.1.......................1...............
        ...1.1....11.....1..11..1..1..1.1.......................1..............
        ....1.1....11.....1..11..1..1..1.1.......................1.............
        .....1.1....11.....1..11..1..1..1.1.......................1............
        ......1.1....11.....1..11..1..1..1.1.......................1...........
        1.1.1.1......1.1.11..1...1..11.1.1.1........................1..........
        1111111..1...1..11.1..1.1.1...1.11.1.........................1.........
        11.1.1...11..1......1..111.1.1.1...1..........................1........
        11.....1.111.1...11..1...11.111.1111...........................1.......
        11..1.11111111...1.1..1.1.11..11................................1......
        .11..1.11111111...1.1..1.1.11..11................................1.....
        ..11..1.11111111...1.1..1.1.11..11................................1....
        ...11..1.11111111...1.1..1.1.11..11................................1...
        ....11..1.11111111...1.1..1.1.11..11................................1..
        1.1.11.1...11..11.....1....1...1111..................................1.
        .1.1.11.1...11..11.....1....1...1111..................................1
        """)
        code = CSSCode(Hx=H, Hz=H)

    elif argv.code == "rm_2_5_p":
        H = parse("""
        ...11111111....................
        .11..1111..11..................
        1.1.1.11.1.1.1.................
        11.1..1.11.1..1................
        ...1111........1111............
        .11..11........11..11..........
        1.1.1.1........1.1.1.1.........
        11.1..1.........11.1..1........
        .11111111......11......11......
        1.111111.1.....1.1.....1.1.....
        11.1111.11......11.....1..1....
        111.1111...1...1...1...1...1...
        1111.11.1..1....1..1...1....1..
        11111.1..1.1.....1.1...1.....1.
        111111.111.1...111.1...1......1
        """)
        code = CSSCode(Hx=H, Hz=H)

    elif argv.code == "to_16_6":  # triorthogonal
        H = parse("""
        ........11111111
        ....1111....1111
        11111111........
        ..11..11..11..11
        .1.1.1.1.1.1.1.1
        1..1.11..11.1..1
        """)  # distance = 4
        code = CSSCode(Hx=H, Hz=H)

    elif argv.code == "B11":  # Pless 1971, punctured B12
        H = parse("""
        .1111......
        ...1111....
        .....1111..
        .......1111
        1.1.1.1.1.1
        """)
        from qupy.ldpc.gallagher import classical_distance
        print(classical_distance(H))
        code = CSSCode(Hx=H, Hz=H)

    elif argv.code == "glue_classical_self":
        from qupy.ldpc.glue import glue_classical, glue_classical_self
        H = glue_classical_self()
        H = H.copy()
        code = CSSCode(Hx=H, Hz=H)
        #if argv.classical_distance:
        #    from qupy.ldpc.gallagher import classical_distance
        #    print("distance:", classical_distance(H))

    elif argv.code == "randselfdual":
        m = argv.get("m", 4)
        n = argv.get("n", 8)
        rw = argv.get("rw", 4)
        code = randselfdual(m, n, rw)

    else:
        from qupy.ldpc.gallagher import get_code
        code = get_code(argv.code)

    if argv.truncate:
        idx = argv.truncate
        Hx = Hx[:idx]
        Hz = Hz[:idx]

    for arg in argv:
        if arg.endswith('.ldpc'):
            code = CSSCode.load(arg,
                                build=build,
                                check=check,
                                rebuild=argv.rebuild)

            if argv.rebuild:
                code.save(arg)

            break

    if code is None:
        code = CSSCode(Lx,
                       Lz,
                       Hx,
                       Tz,
                       Hz,
                       Tx,
                       build=build,
                       check=check,
                       verbose=verbose,
                       logops_only=logops_only)

    if argv.dual:
        print("dual code...")
        code = code.dual(build=build)

    # take several copies of the code..
    mul = argv.get("mul", 1)
    code = mul * code

    if argv.classical_product:
        H1 = code.Hx
        H2 = H1.transpose()
        Hx, Hz = hypergraph_product(H1, H2)
        code = CSSCode(Hx=Hx, Hz=Hz)

    if argv.product:

        codes = code.product(code.dual())

        for _code in codes:
            print(_code)
            if _code.k:
                _code.save(stem="prod")

    if argv.verbose != 0:
        print(code)
        #print code.longstr()
        #print code.weightstr()
        print(code.weightsummary())

    if argv.shorten:
        code.shorten()
        print(code)
        print(code.weightsummary())

    if argv.prune:
        print("pruning:", argv.prune)
        code.prune_xlogops(argv.prune)
        print(code)
        print(code.weightsummary())

    if argv.split:

        for i in range(4):
            code = x_split(code, build=False)
            print(code)
            print(code.weightsummary())
            code = code.dual()
            code = x_split(code, build=False)
            code = code.dual()
            print(code)
            print(code.weightsummary())
            code.save(stem="split")

    if argv.save:
        code.save(argv.save)

    if argv.symplectic:
        i = randint(0, code.mz - 1)
        j = randint(0, code.k - 1)
        code.Lz[j] += code.Hz[i]
        code.Lz[j] %= 2
        code.Tx[i] -= code.Lx[j]
        code.Tx[i] %= 2
        code.do_check()

        return

    if argv.showcode:
        print(code.longstr())

    if argv.todot:
        todot(code.Hz)
        return

    if argv.tanner:
        Hx = code.Hx
        graph = Tanner(Hx)
        #graph.add_dependent()

        depth = 3

        graphs = [graph]
        for i in range(depth):
            _graphs = []
            for g in graphs:
                left, right = g.split()
                _graphs.append(left)
                _graphs.append(right)
            graphs = _graphs
        print("split", graphs)

        k = code.Lx.shape[0]
        op = code.Lx[1]
        #op = (op + code.Tx[20])%2
        print(strop(op), op.sum())
        print()
        for i in range(Hx.shape[0]):
            if random() <= 0.5:
                op = (op + Hx[i]) % 2
        #print shortstr(op), op.sum()

        print(strop(op), op.sum())
        print()

        #for graph in [left, right]:
        for graph in graphs * 2:

            #op = graph.minimize(op, verbose=True)
            op = graph.localmin(op, verbose=True)
            print(strop(op), op.sum())
            print()

        #op = graph.localmin(op)
        #print strop(op), op.sum()
        #print
        #print shortstr(op), op.sum()

        return

    if argv.distance == 'star':
        decoder = StarDynamicDistance(code)
        L = decoder.find(verbose=verbose)
        print(shortstr(L))
        print("distance <=", L.sum())
    elif argv.distance == 'stab':
        d = random_distance_stab(code)
        print("distance <=", d)
    elif argv.distance == 'pair':
        d = pair_distance(code)
        print("distance <=", d)
    elif argv.distance == 'free':
        d = free_distance(code)
        print("distance <=", d)
    elif argv.distance == 'lookup':
        d = lookup_distance(code)
        if d <= 4:
            print("distance =", d)
        else:
            print("distance <=", d)

    if type(argv.distance) == str:
        return

    if argv.get('exec'):

        exec(argv.get('exec'))

    N = argv.get('N', 0)
    p = argv.get('p', 0.01)
    weight = argv.weight

    #assert code.Tx is not None, "use code.build ?"

    decoder = get_decoder(argv, argv.decode, code)
    if decoder is None:
        return

    if argv.whack:
        whack(code, decoder, p, N, argv.get("C0", 10),
              argv.get("error_rate", 0.05), argv.get("mC", 1.2), verbose, argv)
        return

    if argv.noerr:
        print("redirecting stderr to stderr.out")
        fd = os.open("stderr.out", os.O_CREAT | os.O_WRONLY)
        os.dup2(fd, 2)

    decoder.strop = strop
    print("decoder:", decoder.__class__.__name__)

    n_ranks = numpy.zeros((code.n, ), dtype=numpy.float64)
    n_record = []
    k_ranks = numpy.zeros((code.k, ), dtype=numpy.float64)
    k_record = []

    failures = open(argv.savefail, 'w') if argv.savefail else None

    if argv.loadfail:
        loadfail = open(argv.loadfail)
        errs = loadfail.readlines()
        N = len(errs)

    newHx = []
    newHz = []

    distance = code.n
    count = 0
    failcount = 0
    nonuniq = 0

    if argv.weight1:
        # run through all weight=1 errors
        N = code.n

    if argv.weight2:
        # run through all weight=1 errors
        N = code.n**2

    for i in range(N):

        # We use Hz to look at X type errors (bitflip errors)

        if argv.loadfail:
            err_op = parse(errs[i])
            err_op.shape = (code.n, )
        elif argv.weight1:
            err_op = zeros2(code.n)
            err_op[i % code.n] = 1
        elif argv.weight2:
            err_op = zeros2(code.n)
            ai = i % code.n
            bi = (i // code.n)
            err_op[ai] = 1
            err_op[bi] = 1

        elif weight is not None:
            err_op = zeros2(code.n)
            r = 0
            while r < weight:
                idx = randint(0, code.n - 1)
                if err_op[idx] == 0:
                    err_op[idx] = 1
                    r += 1
            #print err_op
        else:
            err_op = ra.binomial(1, p, (code.n, ))
            err_op = err_op.astype(numpy.int32)

#        err_op = parse("..............................")
#        err_op.shape = (err_op.shape[1],)
        write(str(err_op.sum()))
        #print err_op.shape

        s = dot2(code.Hz, err_op)
        write(":s%d:" % s.sum())

        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)
            if dot2(code.Hz, op).sum() != 0:
                print(dot2(code.Hz, op))
                print("\n!!!!!  BUGBUG  !!!!!", sparsestr(err_op))
                continue
            write("%d:" % op.sum())

            #print "is_stab:"
            #print strop(op)
            # Are we in the image of Hx ? If so, then success.
            #success = code.is_stab(op)
            success = dot2(code.Lz, op).sum() == 0

            if success and op.sum():
                nonuniq += 1
            #    print "\n", shortstr(err_op)
            #    return

            c = '.' if success else 'x'

            if argv.k_rank:

                # XX this does not work very well...

                a = dot2(code.Lz, op)
                assert (a.sum() == 0) == success

                if not success:
                    #r = -1. // (a.sum()**0.5) # sqrt ??
                    r = -1. / a.sum()
                    k_ranks += r * a
                else:
                    #r = 1. / (code.k**0.5)
                    r = 1. / code.k
                    k_ranks += r * a

                k_record.append((a, success))

            if op.sum() and not success:
                distance = min(distance, op.sum())
                #if op.sum() == 2:
                #    print()
                #    print("main:")
                #    print(shortstr(op))
                #    print()
                #    print(strop(op))

                if argv.minop and argv.minop >= op.sum():
                    a = dot2(code.Lz, op)
                    print()
                    print(sparsestr(a))

            if not success and argv.addstabs and op.sum() <= argv.addstabs:
                #write("%d"%op.sum())
                print((sparsestr(op)))
                newHx.append(op)

                A = numpy.concatenate((code.Lx, code.Hx))
                c = solve.solve(A.transpose(), op.transpose()).transpose()
                cL = c[:code.k]
                zstab = dot2(cL, code.Lz)
                print(shortstr(zstab))
                graph = Tanner(code.Hz)
                zstab = graph.minimize(zstab, target=8, verbose=True)
                print(shortstr(zstab))
                newHz.append(zstab)
                break


#                Hz, Hx = code.Hz, append2(code.Hx, op)
#                #if len(Hz) < len(Hx):
#                #    Hx, Hz = Hz, Hx
#                print Hx.shape, Hz.shape
#                code = CSSCode(Hx=Hx, Hz=Hz)
#                if len(Hz) < len(Hx):
#                    code = code.dual()
#                    decoder = get_decoder(argv, argv.decode, code)
#                print
#                print code
#                print code.weightsummary()
#                code.save("addstabs_%d_%d_%d.ldpc"%(code.n, code.k, code.distance))

            if not success and argv.showfail:
                print()
                print("FAIL:")
                print(shortstr(err_op))

        else:
            failcount += 1

            if failures:
                print(shortstr(err_op), file=failures)
                failures.flush()

        if argv.n_rank:
            r = 2. * int(success) - 1
            #print "r =", r
            if err_op.sum():
                r /= err_op.sum()
                #print r
                #print r*err_op
                n_ranks += r * err_op
                n_record.append((err_op, success))

        write(c + ' ')
        count += success

    if hasattr(decoder, 'fini'):
        decoder.fini()

    if N:
        print()
        print(datestr)
        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)

    if argv.n_rank:
        #n_ranks //= N
        n_ranks = list(enumerate(n_ranks))
        n_ranks.sort(key=lambda item: -item[1])
        #print [r[0] for r in n_ranks]
        print(' '.join('%d:%.2f' % r for r in n_ranks))
        #print min(r[1] for r in n_ranks)
        #print max(r[1] for r in n_ranks)
        A = numpy.array([rec[0] for rec in n_record])
        b = numpy.array([rec[1] for rec in n_record])
        print(A.shape, b.shape)
        sol = lstsq(A, b)
        x, res, rk, s = sol
        #print x
        for i, val in enumerate(x):
            if val < 0:
                print(i, end=' ')
        print()

    if argv.k_rank:
        #k_ranks //= N
        k_ranks = list(enumerate(k_ranks))
        k_ranks.sort(key=lambda item: -item[1])
        #print [r[0] for r in k_ranks]
        print(' '.join('%d:%.2f' % r for r in k_ranks))
        #print ' '.join(str(r) for r in k_ranks)
        #print min(r[1] for r in k_ranks)
        #print max(r[1] for r in k_ranks)
        A = numpy.array([rec[0] for rec in k_record])
        b = numpy.array([rec[1] for rec in k_record])
        #print A.shape, b.shape
        sol = lstsq(A, b)
        x, res, rk, s = sol
        #print x
        xs = list(enumerate(x))
        xs.sort(key=lambda item: item[1])
        print(' '.join('%d:%.2f' % item for item in xs))

    if argv.addstabs and newHz:
        Hz = append2(code.Hz, newHz[0])
        code = CSSCode(Hx=code.Hx, Hz=Hz)
        code.save(stem="addstabs")
        print(code)
        print(code.weightsummary())

    elif argv.addstabs and newHx:  # and newHx.shape[0]>code.Hx.shape[0]:
        newHx = array2(newHx)
        newHx = numpy.concatenate((code.Hx, newHx))
        #print shortstr(newHx)
        #print
        Hx = solve.linear_independent(newHx)
        #print shortstr(Hx)
        #print
        code = CSSCode(Hx=Hx, Hz=code.Hz)
        code.save(stem="addstabs")
        print(code)
        print(code.weightsummary())
Exemple #12
0
def test_symplectic():

    n = 3
    I = Matrix.identity(n)
    for idx in range(n):
        for jdx in range(n):
            if idx == jdx:
                continue
            CN_01 = Matrix.cnot(n, idx, jdx)
            CN_10 = Matrix.cnot(n, jdx, idx)
            assert CN_01 * CN_01 == I
            assert CN_10 * CN_10 == I
            lhs = CN_10 * CN_01 * CN_10
            rhs = Matrix.swap(n, idx, jdx)
            assert lhs == rhs
            lhs = CN_01 * CN_10 * CN_01
            assert lhs == rhs

    #print(Matrix.cnot(3, 0, 2))

    #if 0:
    cnot = Matrix.cnot
    hadamard = Matrix.hadamard
    n = 2
    gen = [cnot(n, 0, 1), cnot(n, 1, 0), hadamard(n, 0), hadamard(n, 1)]
    for A in gen:
        assert A.is_symplectic()
    Cliff2 = mulclose_fast(gen)
    assert len(Cliff2) == 72  # index 10 in Sp(2, 4)

    CZ = array2([[1, 0, 0, 0], [0, 1, 0, 0], [0, 1, 1, 0], [1, 0, 0, 1]])
    CZ = Matrix(CZ)
    assert CZ.is_symplectic()
    assert CZ in Cliff2

    n = 3
    gen = [
        cnot(n, 0, 1),
        cnot(n, 1, 0),
        cnot(n, 0, 2),
        cnot(n, 2, 0),
        cnot(n, 1, 2),
        cnot(n, 2, 1),
        hadamard(n, 0),
        hadamard(n, 1),
        hadamard(n, 2),
    ]
    for A in gen:
        assert A.is_symplectic()
    assert len(mulclose_fast(gen)) == 40320  # index 36 in Sp(2,4)

    if 0:
        # cnot's generate GL(2, n)
        n = 4
        gen = []
        for i in range(n):
            for j in range(n):
                if i != j:
                    gen.append(cnot(n, i, j))
        assert len(mulclose_fast(gen)) == 20160

    if 0:
        n = 2
        count = 0
        for A in enum2(4 * n * n):
            A.shape = (2 * n, 2 * n)
            A = Matrix(A)
            try:
                assert A.is_symplectic()
                count += 1
            except:
                pass
        print(count)  # 720 = |Sp(2, 4)|
        return

    for n in [1, 2]:
        gen = []
        for x in enum2(2 * n):
            A = Matrix.transvect(x)
            assert A.is_symplectic()
            gen.append(A)
        G = mulclose_fast(gen)
        assert len(G) == [6, 720][n - 1]

    n = 2
    Sp = G
    #print(len(Sp))
    found = set()
    for g in Sp:
        A = g.A.copy()
        A[:n, n:] = 0
        A[n:, :n] = 0
        found.add(str(A))
    #print(len(A))

    #return

    n = 4
    I = Matrix.identity(n)
    H = Matrix.hadamard(n, 0)
    assert H * H == I

    CN_01 = Matrix.cnot(n, 0, 1)
    assert CN_01 * CN_01 == I

    n = 3
    trivial = CSSCode(Lx=parse("1.."),
                      Lz=parse("1.."),
                      Hx=zeros2(0, n),
                      Hz=parse(".1. ..1"))

    assert trivial.row_equal(CSSCode.get_trivial(3, 0))

    repitition = CSSCode(Lx=parse("111"),
                         Lz=parse("1.."),
                         Hx=zeros2(0, n),
                         Hz=parse("11. .11"))

    assert not trivial.row_equal(repitition)

    CN_01 = Matrix.cnot(n, 0, 1)
    CN_12 = Matrix.cnot(n, 1, 2)
    CN_21 = Matrix.cnot(n, 2, 1)
    CN_10 = Matrix.cnot(n, 1, 0)
    encode = CN_12 * CN_01

    code = CN_01(trivial)
    assert not code.row_equal(repitition)
    code = CN_12(code)
    assert code.row_equal(repitition)

    A = get_encoder(trivial, repitition)

    gen, names = get_gen(3)
    word = mulclose_find(gen, names, A)

    if 1:
        assert type(word) is tuple
        #print("word:")
        #print(repr(word))

        items = [gen[names.index(op)] for op in word]
        op = reduce(mul, items)

        #print(op)
        #assert op*(src) == (tgt)

        #print(op(trivial).longstr())
        assert op(trivial).row_equal(repitition)
Exemple #13
0
def make_surface_54_oriented(G0):
    " find integer chain complex "
    from bruhat.solve import shortstr, zeros2, dot2
    from numpy import alltrue, zeros, dot

    print()
    print("|G0| =", len(G0))

    a, ai, b, bi, c, ci, d, di = G0.gens

    # 5,5 coxeter subgroup
    G_55 = Group.generate([a, b, c])
    assert G0.is_subgroup(G_55)

    # orientation subgroup
    L = Group.generate([a * b, a * d])
    #assert len(L) == 60, len(L)
    print("L:", len(L))
    orients = G0.left_cosets(L)
    assert len(orients) == 2
    orients = list(orients)

    H = Group.generate([a, b])
    faces = G_55.left_cosets(H)
    fold_faces = G0.left_cosets(H)
    print("faces:", len(faces))
    print("fold_faces:", len(fold_faces))
    #hom = G.left_action(faces)
    o_faces = [face.intersect(orients[0]) for face in faces]  # oriented faces
    r_faces = [face.intersect(orients[1])
               for face in faces]  # reverse oriented faces

    K = Group.generate([b, c])
    vertices = G_55.left_cosets(K)
    #assert len(vertices) == 12 # unoriented vertices
    o_vertices = [vertex.intersect(orients[0])
                  for vertex in vertices]  # oriented vertices
    print("o_vertices:", len(o_vertices))

    J0 = Group.generate([a, d])
    assert len(J0) == 8

    assert G0.is_subgroup(J0)
    act_edges = G0.action_subgroup(J0)
    act_fold_faces = G0.action_subgroup(H)
    #print("stab:", len(act_edges.get_stabilizer()))
    print("|G0| =", len(G0))
    print("edges:", len(G0) // len(J0))
    edges = G0.left_cosets(J0)
    #for e in edges:
    #    k = choice(e.perms)
    #    e1 = e.left_mul(~k)
    #    assert set(e1.perms) == set(J0.perms)
    fold_perms = []
    for i, g in enumerate(G0):
        assert g in G0
        #h_edge = act_edges.tgt[act_edges.send_perms[i]]
        #h_fold_faces = act_fold_faces.tgt[act_fold_faces.send_perms[i]]
        h_edge = act_edges[g]
        h_fold_faces = act_fold_faces[g]
        n_edge = len(h_edge.fixed())
        n_fold_faces = len(h_fold_faces.fixed())
        count = 0
        #perms = [] # extract action on the fixed edges
        #for e0 in edges:
        #    #e1 = e0.left_mul(g)
        #    e1 = g*e0
        #    if e0 != e1:
        #        continue
        #    perm = e0.left_mul_perm(g)
        #    #print(perm, end=" ")
        #    perms.append(perm)
        #    count += 1
        #assert count == n_edge
        if g.order() == 2 and g not in G_55 and g not in L:
            fold_perms.append(g)
        else:
            continue
        #print([p.order() for p in perms] or '', end="")
        print(
            "[|g|=%s,%s.%s.%s.%s]" % (
                g.order(),
                n_edge or ' ',  # num fixed edges
                n_fold_faces or ' ',  # num fixed faces+vertexes
                ["    ", "pres"
                 ][int(g in G_55)],  # preserves face/vertex distinction
                ["refl", "rot "][int(g in L)],  # oriented or un-oriented
            ),
            end=" ",
            flush=True)
        print()
    print()

    J = Group.generate([a, c])
    u_edges = G_55.left_cosets(J)
    print("u_edges:", len(u_edges))

    J = Group.generate([c])
    edges = G_55.left_cosets(J)
    print("edges:", len(edges))

    # Here we choose an orientation on each edge:
    pairs = {}
    for e in u_edges:
        pairs[e] = []
        for e1 in edges:
            if e.intersect(e1):
                pairs[e].append(e1)
        assert len(pairs[e]) == 2, len(pairs[e])

    def shortstr(A):
        s = str(A)
        s = s.replace("0", '.')
        return s

    Hz = zeros((len(o_faces), len(u_edges)), dtype=int)
    for i, l in enumerate(o_faces):
        for j, e in enumerate(u_edges):
            le = l.intersect(e)
            if not le:
                continue
            e1, e2 = pairs[e]
            if e1.intersect(le):
                Hz[i, j] = 1
            elif e2.intersect(le):
                Hz[i, j] = -1
            else:
                assert 0

    Hxt = zeros((len(u_edges), len(o_vertices)), dtype=int)
    for i, e in enumerate(u_edges):
        for j, v in enumerate(o_vertices):
            ev = e.intersect(v)
            if not ev:
                continue
            e1, e2 = pairs[e]
            if e1.intersect(ev):
                Hxt[i, j] = 1
            elif e2.intersect(ev):
                Hxt[i, j] = -1
            else:
                assert 0

    #print(shortstr(Hz))
    #print()
    #print(shortstr(Hxt))
    #print()

    assert alltrue(dot(Hz, Hxt) == 0)

    for perm in fold_perms:
        pass

    import qupy.ldpc.solve
    import bruhat.solve
    qupy.ldpc.solve.int_scalar = bruhat.solve.int_scalar
    from qupy.ldpc.css import CSSCode
    Hz = Hz % 2
    Hx = Hxt.transpose() % 2
    code = CSSCode(Hz=Hz, Hx=Hx)
    print(code)
Exemple #14
0
 def get_code(self, grade=1):
     Hz, Hx = self.get_parity_checks(grade)
     code = CSSCode(Hx=Hx, Hz=Hz)
     return code
Exemple #15
0
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:]))
Exemple #16
0
def main():

    l = argv.get('l', 8)
    li = argv.get('li', l)
    lj = argv.get('lj', l)
    si = argv.get('si', 0)
    sj = argv.get('sj', 0)

    toric = Toric2D(li, lj, si, sj)
    Hx, Hz = toric.Hx, toric.Hz
    strop = toric.strop
    #print("Hx:")
    #print(shortstr(Hx))
    #print("Lx:")
    #print(shortstr(toric.Lx))
    code = CSSCode(Hx=Hx, Hz=Hz, Lx=toric.Lx, Lz=toric.Lz)

    print(code)
    print(code.Lx)

    decoder = ClusterCSSDecoder(2, code.Hx, code.Hz)

    N = argv.get("N", 0)
    p = argv.get("p", 0.05)
    verbose = argv.verbose

    distance = code.n
    count = 0
    failcount = 0
    nonuniq = 0

    total = numpy.array([0.] * code.k)

    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()))
        #print err_op.shape

        s = dot2(code.Hz, err_op)
        write(":s%d:" % s.sum())

        op = decoder.decode(p, err_op, verbose=verbose, argv=argv)

        c = 'F'
        success = False
        result = numpy.array([1] * code.k)
        if op is not None:
            op = (op + err_op) % 2
            # Should be a codeword of Hz (kernel of Hz)
            if dot2(code.Hz, op).sum() != 0:
                print(dot2(code.Hz, op))
                print("\n!!!!!  BUGBUG  !!!!!", sparsestr(err_op))
                continue
            write("%d:" % op.sum())

            # Are we in the image of Hx ? If so, then success.
            result = dot2(code.Lz, op)
            success = result.sum() == 0

            #print(result, end=" ")

            if success and op.sum():
                nonuniq += 1
            #    print "\n", shortstr(err_op)
            #    return

            c = '.' if success else 'x'

            if op.sum() and not success:
                distance = min(distance, op.sum())

        else:
            failcount += 1

            if failures:
                print(shortstr(err_op), file=failures)
                failures.flush()

        total += result

        write(c + ' ')
        count += success

    if N:
        print()
        print(datestr)
        print(argv)
        print("error rate = %.8f" % (1. - 1. * count / (trial + 1)))
        print("fail rate = %.8f" % (1. * failcount / (trial + 1)))
        print("nonuniq = %d" % nonuniq)
        print("distance <= %d" % distance)
        total = total / (trial + 1)
        print("logop errors = [%s]" % ', '.join(str(x) for x in total))
Exemple #17
0
def main():

    n = 5
    Tx = parse("""
    1....
    1.1..
    1.1.1
    """)

    Tz = parse("""
    .1...
    ...1.
    """)


    code = CSSCode(Hx=Tx, Hz=Tz)

    #print(code)
    #print(code.longstr())

    S = parse("""
    1.1..1
    11.1..
    .11.1.
    ...111
    """)

    I = parse("""
    1...
    .1..
    ..1.
    ...1
    """)

    A = parse("""
    1...
    11..
    ..1.
    ...1
    """)

    B = parse("""
    1...
    .1..
    .11.
    ...1
    """)

    C = parse("""
    1...
    .1..
    ..1.
    ..11
    """)

    #print(I)
    #print(dot2(A))
    #print(dot2(B, A))
    L = dot2(C, B, A)
    #print(dot2(L, S)) # row reduced S

    L = L[:3, :3]

    S = S[:3, :]
    print("S =")
    print(S)

    print("LS =")
    print(dot2(L, S))

    J = parse("""
    1..
    11.
    ...
    ...
    111
    ...
    """)

    U = parse("""
    1..
    .11
    ..1
    """)

    print(dot2(U, L, S))
Exemple #18
0
 def get_code(self, **kw):
     from qupy.ldpc.css import CSSCode
     code = CSSCode(Hx=self.Hx, Hz=self.Hz, **kw)
     code.__dict__.update(self.__dict__)
     return code
Exemple #19
0
def check_dualities(Hz, Hxt, dualities):
    from bruhat.solve import shortstr, zeros2, dot2, array2, solve, span
    from numpy import alltrue, zeros, dot

    import qupy.ldpc.solve
    import bruhat.solve
    qupy.ldpc.solve.int_scalar = bruhat.solve.int_scalar
    from qupy.ldpc.css import CSSCode
    Hz = Hz % 2
    Hx = Hxt.transpose() % 2
    code = CSSCode(Hz=Hz, Hx=Hx)
    print(code)
    n = code.n

    Lx, Lz = code.Lx, code.Lz

    # check we really do have weak dualities here:
    for perm in dualities:
        Hz1 = Hz[:, perm]
        Hxt1 = Hxt[perm, :]
        assert solve(Hxt, Hz1.transpose()) is not None
        assert solve(Hz1.transpose(), Hxt) is not None

        Lz1 = Lz[:, perm]
        Lx1 = Lx[:, perm]
        find_xz = solve(concatenate((Lx, Hx)).transpose(),
                        Lz1.transpose()) is not None
        find_zx = solve(concatenate((Lz1, Hz1)).transpose(),
                        Lx.transpose()) is not None
        #print(find_xz, find_zx)
        assert find_xz
        assert find_zx

        # the fixed points live simultaneously in the homology & the cohomology
        fixed = [i for i in range(n) if perm[i] == i]
        if len(fixed) == 0:
            continue
        v = array2([0] * n)
        v[fixed] = 1
        v.shape = (n, 1)
        find_xz = solve(concatenate((Lx, Hx)).transpose(), v) is not None
        find_zx = solve(concatenate((Lz, Hz)).transpose(), v) is not None
        #print(find_xz, find_zx)
        assert find_xz
        assert find_zx

    from qupy.ldpc.asymplectic import Stim as Clifford
    s_gates = []
    h_gates = []
    s_names = []
    for idx, swap in enumerate(dualities):

        fixed = [i for i in range(n) if swap[i] == i]
        print(idx, fixed)
        for signs in cross([(-1, 1)] *
                           len(fixed)):  # <------- does not scale !!! XXX
            v = [0] * n
            for i, sign in enumerate(signs):
                v[fixed[i]] = sign
            ux = numpy.dot(Hx, v)
            uz = numpy.dot(Hz, v)
            if numpy.alltrue(ux == 0) and numpy.alltrue(uz == 0):
                #print("*", end=" ")
                break
        #else:
        #    assert 0
        #print(v)
        #print()

        # transversal S/CZ
        g = Clifford.identity(n)
        name = []
        for i in range(n):
            j = swap[i]
            if j < i:
                continue
            if j == i:
                assert v[i] in [1, -1]
                if v[i] == 1:
                    op = Clifford.s_gate(n, i)
                    name.append("S_%d" % (i, ))
                else:
                    op = Clifford.s_gate(n, i).inverse()
                    name.append("Si_%d" % (i, ))
            else:
                op = Clifford.cz_gate(n, i, j)
                name.append("CZ_%d_%d" % (i, j))
            g = op * g
        name = "*".join(reversed(name))
        s_names.append(name)
        #print(g)
        #print()
        #assert g.is_transversal(code)

        s_gates.append(g)

        h = Clifford.identity(n)
        for i in range(n):
            h = h * Clifford.h_gate(n, i)

        for i in range(n):
            j = swap[i]
            if j <= i:
                continue
            h = h * Clifford.swap_gate(n, i, j)
        #print(g)
        #print()
        #assert h.is_transversal(code)
        h_gates.append(h)

    if 0:
        print()
        print("CZ:")
        CZ = Clifford.cz_gate(2, 0, 1)
        op = (1., [0, 0], [1, 1])
        for i in range(4):
            print(op)
            op = CZ(*op)
        return

    for idx, sop in enumerate(s_gates):
        print("idx =", idx)
        #for hx in Hx:
        perm = dualities[idx]
        #for hx in span(Hx):
        for hx in Hx:
            #print("hx =", hx)
            #print(s_names[idx])
            phase, zop, xop = sop(1., None, hx)
            assert numpy.alltrue(xop == hx)  # fixes x component
            print(phase, zop, xop, dot2(zop, xop))
            for (i, j) in enumerate(perm):
                if xop[i] and xop[j] and i < j:
                    print("pair", (i, j))
            if toric is None:
                continue
            print("xop =")
            print(toric.strop(xop))
            print("zop =")
            print(toric.strop(zop))
            print()