def build_gates(ring, i4, root2, i8): qubit = Space(2, ring) hom = Hom(qubit, qubit) I = Map.from_array([[1, 0], [0, 1]], hom) X = Map.from_array([[0, 1], [1, 0]], hom) Z = Map.from_array([[1, 0], [0, -1]], hom) H = (1/root2)*(X+Z) assert H*H == I S = Map.from_array([[1, 0], [0, i4]], hom) assert S*S == Z T = Map.from_array([[1, 0], [0, i8]], hom) assert S*S == Z #gen = [X, Z, S] # generates 32 elements gen = [X, Z, S, H] # generates 192 elements #gen = [X, Z, S, H, T] if argv.gap: print("G := Group(") ms = [] for g in gen: m = gapstr(g) ms.append(m) print(",\n".join(ms)+");;") if ring.p <= 41: G = mulclose(gen) print("|G| =", len(G))
def tensor_rep(G, space): "build rep of permutation action of G on tensor power of space" gen = G.items n = len(gen) d = len(space) ring = space.ring # tensor power of the space tensor = lambda x, y: x @ y tspace = reduce(tensor, [space] * n) # build action on the tensor power thom = Hom(tspace, tspace) send_perms = {} for g in G: #print(g) items = [] for idxs in tspace.gen: jdxs = tuple(idxs[g[i]] for i in range(len(idxs))) items.append(((idxs, jdxs), ring.one)) #print(idxs, "->", jdxs) #print() swap = Map(items, thom) send_perms[g] = swap tp = Cat(G, ring) rep = Rep(send_perms, tspace, tp) return rep
def main(): #U = numpy.array([[0, 1], [-1, -1]]) V = Space(2, Z) hom = Hom(V, V) U = Map.from_array([[0, 1], [-1, -1]], hom) A = Map.from_array([[1, 0], [0, 1]], hom) A0 = A for i in range(2): print(A) A = U * A * U.transpose() A0 = A0 + A print(A) print("sum:") print(A0)
def find_span(vs): rows = [] for v in vs: v = v.transpose() row = v.to_array() assert row.shape[0] == 1 rows.append(row[0]) ring = v.ring src = v.src hom = Hom(src, Space(len(vs), ring)) A = Map.from_array(rows, hom) A = A.transpose() A = A.image() return A
def perm_rep(cls, tp): G = tp.G ring = tp.ring one = ring.one basis = G.items V = Space(basis, ring) send_perms = {} hom = Hom(V, V) for g in G: rg = Map([((g[i], i), one) for i in basis], hom) send_perms[g] = rg rep = cls(send_perms, V, tp) return rep
def specht(n, space): assert n >= 2 d = len(space) ring = space.ring items = list(range(n)) gen1 = [] for i in range(n - 1): perm = dict((item, item) for item in items) perm[items[i]] = items[i + 1] perm[items[i + 1]] = items[i] perm = Perm(perm, items) gen1.append(perm) perms = mulclose(gen1) G = Group(perms, items) #I = space.ident # tensor power of the space tensor = lambda x, y: x @ y tspace = reduce(tensor, [space] * n) # build action of symmetric group on the tensor power thom = Hom(tspace, tspace) gen2 = [] for g in gen1: items = [] for idxs in tspace.gen: jdxs = tuple(idxs[g[i]] for i in range(len(idxs))) items.append(((idxs, jdxs), ring.one)) #print(idxs, "->", jdxs) #print() swap = Map(items, thom) gen2.append(swap) action = mulclose_hom(gen1, gen2) for g in G: for h in G: assert action[g * h] == action[g] * action[h] # check it's a group hom tp = Cat(G, ring) rep = Rep(action, tspace, tp) return rep
def mk_rep(cls, act, tp): G = tp.G ring = tp.ring one = ring.one gen = act.items V = Space(gen, ring) send_perms = {} hom = Hom(V, V) for g in G: ag = act[g] rg = Map([((ag[i], i), one) for i in gen], hom) #print(g, "--->") #print(rg) send_perms[g] = rg rep = cls(send_perms, V, tp) rep.check() return rep
def test(): ring = element.Q n = argv.get("n", 3) d = argv.get("d", 2) G = Group.symmetric(n) algebra = GroupAlgebra(G, ring) v = algebra.zero for g in G: v = v + g assert 2 * v == v + v assert v - v == algebra.zero for g in algebra.basis: assert g * v == v assert v * g == v center = algebra.get_center() for v in center: for g in algebra.basis: assert g * v == v * g # --------------------------------------- # build standard representation of symmetric group act = G.left_action(list(range(n))) #print(act) tp = Cat(G, ring) rep = Rep.mk_rep(act, tp) #rep.dump() module = algebra.extend(rep) #print(module.action(v)) # --------------------------------------- # build representation of symmetric group on tensor product space = Space(d, ring) rep = tensor_rep(G, space) #rep.check() module = algebra.extend(rep) #print(module.action(v)) # --------------------------------------- # Build the young symmetrizers projs = [] part = argv.get("part") parts = [part] if part else partitions(n) for part in parts: items = G.items A = algebra.zero for g in G: labels = [g[item] for item in items] tableau = Young(G, part, labels) P = algebra.get_symmetrizer(tableau) A = A + P #tableau = Young(G, part) #A = algebra.get_symmetrizer(tableau) print("partition:", part) #print("H:") #print(module.action(H)) #print("V:") #print(module.action(V)) print([g * A == A * g for g in algebra.basis]) specht = [] for v in algebra.basis: u = v * A specht.append(u.to_array()) hom = Space(len(G), ring).endo_hom() specht = Map.from_array(specht, hom) specht = specht.image() #print(specht) dim = specht.shape[1] print("S(n)-algebra dim:", dim) if len(part) > d: continue print("A:", A) P = module.action(A) #P = P.transpose() P = P.image() print(P.longstr()) print(P.shape) return print("multiplicity:", P.shape[1]) src = P.src for v in src.get_basis(): u = P * v #print(u.longstr()) items = [] for g in algebra.basis: g = module.action(g) w = g * u #print(w.longstr()) items.append(w) A = find_span(items) print("dimension:", A.shape[1])
def burnside(tp): # make it a method ring = tp.ring G = tp.G Hs = conjugacy_subgroups(G) names = {} letters = list(string.ascii_uppercase + string.ascii_lowercase) letters.remove("O") letters.remove("o") letters = letters + [l + "'" for l in letters] + [l + "''" for l in letters] assert len(letters) >= len(Hs) letters = letters[:len(Hs)] for i, H in enumerate(Hs): names[H] = "%s_0" % letters[i] # identity coset acts = {} for i, H in enumerate(Hs): cosets = G.left_cosets(H) assert len(G) == len(cosets) * len(H) items = [names[H]] letter = letters[i] assert H in cosets idx = 1 for gH in cosets: if gH == H: continue name = "%s_%d" % (letter, idx) names[gH] = name items.append(name) idx += 1 act = G.left_action(cosets) assert act.src is G act = act.rename(names, items) act.name = letter H.name = act.name acts[letter] = act assert len(act.components()) == 1 # transitive #print act.tgt.perms print( "%s subgroup order = %d, number of cosets = %d, conjugates = %d" % (act.name, len(H), len(cosets), len(H.conjugates))) #print(list(names.values())) reps = {} for act in acts.values(): rep = Rep.mk_rep(act, tp) reps[act.name] = rep arg = argv.next() or "B*C" assert "*" in arg left, right = arg.split("*") act0 = acts[left] act1 = acts[right] rep0 = reps[left] rep1 = reps[right] act2 = act0.pushout(act1) rep = Rep.mk_rep(act2, tp) U0 = Space(act0.items, ring) U1 = Space(act1.items, ring) UU = U0 @ U1 print(UU) one = ring.one hom = Hom(U0, U1) for act in act2.components(): items = [((y, x), one) for (x, y) in act.items] f = Map(items, hom) print(f) assert tp.is_hom(rep0, rep1, f) print("kernel:") g = f.kernel() print(g) print() print("cokernel:") g = f.cokernel() print(g) print()
def __init__(self, n, space): assert n >= 2 d = len(space) ring = space.ring items = list(range(n)) gen1 = [] for i in range(n - 1): perm = dict((item, item) for item in items) perm[items[i]] = items[i + 1] perm[items[i + 1]] = items[i] perm = Perm(perm, items) gen1.append(perm) perms = mulclose(gen1) G = Group(perms, items) #I = space.ident # tensor power of the space tensor = lambda x, y: x @ y tspace = reduce(tensor, [space] * n) # build action of symmetric group on the tensor power thom = Hom(tspace, tspace) gen2 = [] for g in gen1: items = [] for idxs in tspace.gen: jdxs = tuple(idxs[g[i]] for i in range(len(idxs))) items.append(((idxs, jdxs), ring.one)) #print(idxs, "->", jdxs) #print() swap = Map(items, thom) gen2.append(swap) action = mulclose_hom(gen1, gen2) for g in G: for h in G: assert action[ g * h] == action[g] * action[h] # check it's a group hom # Build the young symmetrizers projs = [] parts = [] for part in partitions(n): if len(part) > d: continue parts.append(part) t = Young(G, part) rowG = t.get_rowperms() colG = t.get_colperms() horiz = None for g in rowG: P = action[g] horiz = P if horiz is None else (horiz + P) vert = None for g in colG: P = action[g] s = g.sign() P = s * P vert = P if vert is None else (vert + P) A = vert * horiz + horiz * vert #A = horiz * vert assert vert * vert == len(colG) * vert assert horiz * horiz == len(rowG) * horiz #A = A.transpose() projs.append(A) #print(part) #print(t) #print(A) self.projs = projs self.parts = parts
def main(): d = argv.get("d", 3) assert d>=2 double = argv.double if d==2: ring = CyclotomicRing(4) #ring = element.Z gamma = ring.x w = gamma**2 assert w == -1 double = True else: ring = CyclotomicRing(d**2) gamma = ring.x w = gamma**d I = numpy.zeros((d, d), dtype=object) wI = numpy.zeros((d, d), dtype=object) X = numpy.zeros((d, d), dtype=object) Z = numpy.zeros((d, d), dtype=object) Zdag = numpy.zeros((d, d), dtype=object) S = numpy.zeros((d, d), dtype=object) Sdag = numpy.zeros((d, d), dtype=object) T = numpy.zeros((d, d), dtype=object) Tdag = numpy.zeros((d, d), dtype=object) for j in range(d): I[j, j] = 1 wI[j, j] = w X[j, (j+1)%d] = 1 Z[j, j] = w**j Zdag[j, j] = w**(d-j) if d==2: val = gamma**(j**2) ival = gamma**(d**2 - (j**2)%(d**2)) else: val = w**(j**2) ival = w**(d - (j**2)%d) assert val*ival == 1 S[j, j] = val Sdag[j, j] = ival if d in [2, 3, 6]: val = gamma**(j**3) ival = gamma**(d**2 - (j**3)%(d**2)) else: val = w**(j**3) ival = w**(d - (j**3)%d) assert val*ival == 1 T[j, j] = val Tdag[j, j] = ival qu = Space(d, ring) hom = Hom(qu, qu) I = Map.from_array(I, hom) wI = Map.from_array(wI, hom) Xdag = Map.from_array(X.transpose(), hom) X = Xs = Map.from_array(X, hom) Z = Map.from_array(Z, hom) Zdag = Map.from_array(Zdag, hom) S = Map.from_array(S, hom) Sdag = Map.from_array(Sdag, hom) T = Map.from_array(T, hom) Tdag = Map.from_array(Tdag, hom) if d==2: Y = gamma*X*Z # ? else: Y = w*X*Z # ? assert S*Sdag == I assert Z*Zdag == I assert X*Xdag == I if d>2: for j in range(1, d+1): assert (j==d) == (X**j==I) assert (j==d) == (Z**j==I) else: assert X != I assert Z != I assert X*X == I assert Z*Z == I assert Z*X == (w**(d-1))*X*Z if double: pauli = mulclose([X, Z, gamma*I]) names = mulclose_names([X, Z, gamma*I], "X Z i".split()) else: pauli = mulclose([X, Z]) names = mulclose_names([X, Z, Xdag, Zdag, -I], "X Z Xi Zi -I".split()) pauli = set(pauli) print("pauli:", len(pauli)) assert Zdag in pauli assert Xdag in pauli if d<6: # slow.. lhs = atpow(X, d) rhs = atpow(Z, d) assert lhs * rhs == rhs * lhs lhs = X@X rhs = Z@Zdag assert lhs * rhs == rhs * lhs lhs = X@(X**(d-1)) rhs = Z@Z assert lhs * rhs == rhs * lhs if 0: n = 5 ops = [X, Xdag] lhs = [] for op in cross([ops]*n): op = reduce(matmul, op) lhs.append(op) ops = [Z, Zdag] rhs = [] for op in cross([ops]*n): op = reduce(matmul, op) rhs.append(op) for l in lhs: for r in rhs: if l*r == r*l: print("/", end=" ", flush=True) else: print(".", end=" ", flush=True) print() print("S =") print(S) print("XSX =") print(X*S*X) print("XSXS =") print(X*S*X*S) #print("Y =") #print(Y) #print("S*X*Sdag =") #print(S*X*Sdag) assert Y == S*X*Sdag def get_orbit(g, gi, v): orbit = [v] while 1: u = g*orbit[-1]*gi if u == orbit[0]: break orbit.append(u) return orbit print("S orbit:") for A in [X, Z]: print('\t', [''.join(names[op]) for op in get_orbit(S, Sdag, A)]) U = X*S Ui = Sdag * Xdag assert U*Ui == I print("XS orbit:") for A in [X, Z]: print('\t', [''.join(names[op]) for op in get_orbit(U, Ui, A)]) U = X*X*S Ui = Sdag * Xdag * Xdag assert U*Ui == I print("XXS orbit:") for A in [X, Z]: print('\t', [''.join(names[op]) for op in get_orbit(U, Ui, A)]) return inverse = {} for g in pauli: for h in pauli: if g*h == I: inverse[g] = h inverse[h] = g def is_cliff(A, Ai): assert A*Ai == I for g in pauli: h = A*g*Ai if h not in pauli: return False return True print("S =") print(S) print("S**2 =") print(S**2) print("Sdag =") print(Sdag) assert is_cliff(S, Sdag) #print("is_cliff:", (S in pauli), is_cliff(S, Sdag)) def is_third_level(A, Ai): assert A*Ai == I for g in pauli: gi = inverse[g] h = A*g*Ai*gi hi = g*A*gi*Ai if not is_cliff(h, hi): return False return True print("is_pauli(S)", S in pauli) print("is_cliff(S)", is_cliff(S, Sdag)) #print("is_third_level(S)", is_third_level(S, Tdag)) print("is_pauli(T)", T in pauli) print("is_cliff(T)", is_cliff(T, Tdag)) print("is_third_level(T)", is_third_level(T, Tdag)) print("OK")
def getdag(A): items = [((j, i), dag[v]) for ((i, j), v) in A.items] return Map(items, hom)
def clifford(): p = argv.get("p", 17) field = FiniteField(p) #ring = PolynomialRing(field) #x = ring.x for fgen in range(1, p): items = set() j = fgen while j not in items: items.add(j) j = (j*fgen)%p if len(items) == p-1: break else: assert 0 finv = {} for i in range(1, p): for j in range(1, p): if (i*j)%p == 1: finv[i] = j finv[j] = i assert len(finv) == p-1 #print("fgen:", fgen) items = [field.promote(i) for i in range(p)] has_imag = [i for i in items if i*i == -1] #print(p, has_imag) if not has_imag: assert 0 i4 = has_imag[0] assert -i4 == has_imag[1] has_root2 = [i for i in items if i*i == 2] if not has_root2: assert 0 r2 = has_root2[0] assert -r2 == has_root2[1] has_i8 = [i for i in items if i*i == i4] if not has_i8: assert 0 i8 = has_i8[0] assert -i8 == has_i8[1] print("p =", p) #print(i4, r2, i8) #print(has_imag, has_root2, has_i8) for i in items: if i*i8 == 1: i8_dag = i #print(i8_dag) # try to take a daggar... doesn't really work tho. assert p==17 dag = { 0:0, 1:1, 2:9, 3:3, 4:13, 5:12, 6:6, 7:7, 8:15, 9:2, 10:10, 11:11, 12:5, 13:4, 14:14, 15:8, 16:16, } for (k, v) in list(dag.items()): dag[k] = field.promote(v) dag[field.promote(k)] = field.promote(v) assert dag[i4] == -i4 qubit = Space(2, field) hom = Hom(qubit, qubit) def getdag(A): items = [((j, i), dag[v]) for ((i, j), v) in A.items] return Map(items, hom) I = Map.from_array([[1, 0], [0, 1]], hom) X = Map.from_array([[0, 1], [1, 0]], hom) Z = Map.from_array([[1, 0], [0, -1]], hom) H = (1/r2)*(X+Z) assert H*H == I S = Map.from_array([[1, 0], [0, i4]], hom) Sdag = Map.from_array([[1, 0], [0, dag[i4]]], hom) assert S*S == Z assert S*Sdag == I assert getdag(S) == Sdag T = Map.from_array([[1, 0], [0, i8]], hom) assert S*S == Z C1 = mulclose([X, Z]) assert len(C1) == 8 # C1 is Pauli group + phases #P = fgen*I # phase P = i4*I C1 = mulclose([X, Z, P]) # add phases # assert len(C1) == 64, len(C1) assert len(C1) == 32, len(C1) C1_lookup = set(C1) #gen = [X, Z, S, H] #C2 = mulclose(gen) #assert len(C2) == 192 G = [] for a in range(p): for b in range(p): for c in range(p): for d in range(p): if (a*d - b*c)%p: G.append(Map.from_array([[a, b], [c, d]], hom)) G_lookup = set(G) print("|GL(%d, 2)|=%d" % (p, len(G))) U = [] for g in G: if g*getdag(g) == I: U.append(g) print("|U|=", len(U)) gen = [X, Z, S, H, P] # Clifford group + phases C2 = mulclose(gen) # assert len(C2) == 384, len(C2) assert len(C2) == 192, len(C2) C2_lookup = set(C2) print("|C2| =", len(C2)) print(C2_lookup == set(U)) for g in C2: assert g in G_lookup #assert g*getdag(g) == I, str(g) # FAIL # inv = {I:I} # for a in G: # if a in inv: # continue # for b in G: # ab = a*b # ci = inv.get(ab) # if ci is None: # continue # inv[a] = b*ci # inv[b] = ci*a # print(len(inv), end=" ", flush=True) # print() inv = {I:I} remain = set(G) remain.remove(I) while remain: a = iter(remain).__next__() assert a not in inv for b in G: ab = a*b ci = inv.get(ab) if ci is None: continue if a not in inv: inv[a] = b*ci remain.remove(a) if b not in inv: inv[b] = ci*a remain.remove(b) print(len(inv), end=" ", flush=True) print() assert len(inv) == len(G) if 0: for g2 in C2: for g in C1: assert g2 * g * inv[g2] in C1 C2 = [] for g2 in G: for g in C1: if g2*g*inv[g2] not in C1_lookup: break else: C2.append(g2) assert len(C2) == 384 # same as above C2_lookup = set(C2) C3 = [] for g3 in G: for g in C1: if g3*g*inv[g3] not in C2_lookup: break else: C3.append(g3) print("|C3| =", len(C3)) C3_lookup = set(C3) shuffle(C3) # count = 0 # for a in C3: # for b in C3: # if a*b in C3_lookup: # count += 1 # print(count) def src(a): return set([b for b in C3 if a*b in C3_lookup]) def tgt(a): return set([b for b in C3 if b*a in C3_lookup]) if 0: items = iter(C3) a = items.__next__() src_a = src(a) print("|src_a| =", len(src_a)) srcs = [] for b in C3: src_b = src(b) if src_b not in srcs: print("|src_b| = ", len(src_b)) srcs.append(src_b) if len(srcs)==4: # there is only 4 of these to be found break obs = list(srcs) tgts = [] for b in C3: tgt_b = tgt(b) if tgt_b not in obs: obs.append(tgt_b) if tgt_b not in tgts: print("|tgt_b| = ", len(tgt_b)) tgts.append(tgt_b) if len(tgts)==4: # there is only 4 of these to be found break done = False while not done: done = True #print("obs:", len(obs)) obs.sort(key = len, reverse=True) obs1 = list(obs) for s in obs: for t in obs: st = s.intersection(t) a = ' ' if st not in obs1: a = '*' obs1.append(st) done = False #print("%4d"%(len(st)), end=a) #print() obs = obs1 obs.sort(key = len, reverse=True) print("obs:", len(obs), [len(ob) for ob in obs]) for ob in obs: #print(len(ob), end=" ") iob = [inv[a] for a in ob if inv[a] in ob] print((len(ob), len(iob)), end=" ") print()
def main(): Z = element.Z ring = element.CyclotomicRing(8) x = ring.x r2 = x + x**7 assert r2**2 == 2 qubit = Space(2, ring) q2 = qubit @ qubit hom = Hom(qubit, qubit) I = Map.from_array([[1, 0], [0, 1]], hom) X = Map.from_array([[0, 1], [1, 0]], hom) Z = Map.from_array([[1, 0], [0, -1]], hom) Y = Map.from_array([[0, x**6], [x**2, 0]], hom) assert Y * Y == I assert Y == (x**2) * X * Z II = I @ I XI = X @ I IX = I @ X XX = X @ X ZI = Z @ I IZ = I @ Z assert XI * IX == XX T = Map.from_array([[1, 0], [0, x]], hom) Td = Map.from_array([[1, 0], [0, x**7]], hom) S = T * T Sd = Td * Td assert Z == S * S assert T * Td == I assert S * Sd == I assert S * Z == Z * S assert T * Z == Z * T assert (Z * X * Z) == -X assert ((Z @ Z) * (X @ X) * (Z @ Z)) == X @ X assert ((S @ S) * (X @ X) * (Sd @ Sd)) == atpow((S * X * Sd), 2) SXSd = S * X * Sd TXTd = T * X * Td lhs = r2 * TXTd i = x**2 assert (lhs == X + i * X * Z) if 0: names = mulclose_names([X, Z, x * I], "X Z xI".split()) #print("SXSd:", "*".join(names[SXSd])) names = mulclose_names([XI, IX, ZI, IZ], "XI IX ZI IZ".split()) g = atpow(SXSd, 2) #print("*".join(names[g])) gen = [ X @ I @ I @ I, I @ X @ I @ I, I @ I @ X @ I, I @ I @ I @ X, Z @ I @ I @ I, I @ Z @ I @ I, I @ I @ Z @ I, I @ I @ I @ Z, x * (I @ I @ I @ I) ] names = "XIII IXII IIXI IIIX ZIII IZII IIZI IIIZ wIIII".split() names = mulclose_names(gen, names) g = atpow(SXSd, 4) #print("*".join(names[g])) g = atpow(TXTd, 4) assert g not in names I8, X8, Z8 = atpow(I, 8), atpow(X, 8), atpow(Z, 8) T8 = atpow(T, 8) #print(T8.str(hide_zero=True, sep="")) Td8 = atpow(Td, 8) G = mulclose([X8, Z8]) P = I8 + X8 + Z8 + X8 * Z8 assert P * P == 4 * P lhs = P rhs = T8 * P * Td8 assert (rhs * rhs == 4 * rhs) #T1 = reduce(matmul, [T, Td]*4) #T2 = reduce(matmul, [Td, T]*4) #print(T1*P*T2) #return Q = P @ P RM14 = """ 1111111111111111 .1.1.1.1.1.1.1.1 ..11..11..11..11 ....1111....1111 ........11111111 """.strip().split() RM14.pop(0) def interp(row, op): ops = [op if s == "1" else I for s in row] A = reduce(matmul, ops) return A RM14 = [row[1:] for row in RM14] # puncture n = len(RM14[0]) Sx = [interp(row, X) for row in RM14] Sz = [interp(row, Z) for row in RM14] if 0: print("mulclose...") G = mulclose(Sx + Sz, maxsize=2**len(Sx + Sz)) # too slow :-( print(len(G)) P = reduce(add, G) assert P * P == len(G) * P Tn = atpow(T, n) Tdn = atpow(Td, n) print(P == Tn * P * Tdn) #print(lhs.str(hide_zero=True, sep="")) #print() #print() #print() #print(rhs.str(hide_zero=True, sep="")) gen = [ X @ I @ I @ I @ I @ I @ I @ I, I @ X @ I @ I @ I @ I @ I @ I, I @ I @ X @ I @ I @ I @ I @ I, I @ I @ I @ X @ I @ I @ I @ I, I @ I @ I @ I @ X @ I @ I @ I, I @ I @ I @ I @ I @ X @ I @ I, I @ I @ I @ I @ I @ I @ X @ I, I @ I @ I @ I @ I @ I @ I @ X, Z @ I @ I @ I @ I @ I @ I @ I, I @ Z @ I @ I @ I @ I @ I @ I, I @ I @ Z @ I @ I @ I @ I @ I, I @ I @ I @ Z @ I @ I @ I @ I, I @ I @ I @ I @ Z @ I @ I @ I, I @ I @ I @ I @ I @ Z @ I @ I, I @ I @ I @ I @ I @ I @ Z @ I, I @ I @ I @ I @ I @ I @ I @ Z, x * (I @ I @ I @ I @ I @ I @ I @ I) ] names = """ XIIIIIII IXIIIIII IIXIIIII IIIXIIII IIIIXIII IIIIIXII IIIIIIXI IIIIIIIX ZIIIIIII IZIIIIII IIZIIIII IIIZIIII IIIIZIII IIIIIZII IIIIIIZI IIIIIIIZ wIIIIIIII """.strip().split() gen.pop(-1) names.pop(-1) if 0: g = atpow(TXTd, 8) for i in range(8): print(g == (x**i) * atpow(X * Z, 8)) return if 0: names = mulclose_names(gen, names) g = atpow(TXTd, 8) for i in range(8): print(names.get((x**i) * g, "?")) #for i in [1, 2, 4]: # print(atpow(TXTd, i)) if 0: #print(Td*X*T) X4 = X @ X @ X @ X T4 = T @ T @ T @ T Td4 = Td @ Td @ Td @ Td print(Td4 * X4 * T4) H = X + Z E = Map.from_array([[0, 1], [0, 0]], hom) # raising F = Map.from_array([[0, 0], [1, 0]], hom) # lowering CNOT = Map.from_array( [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]], hom @ hom) SWAP = Map.from_array( [[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]], hom @ hom) assert SWAP * SWAP == II assert CNOT * CNOT == II G = mulclose([XI, IX, CNOT]) # order 8 G = mulclose([XI, IX, CNOT, SWAP]) # order 24.. must be S_4 G = mulclose([CNOT, SWAP]) # print(len(G)) # for g in G: # print(g) A = SWAP @ I B = I @ SWAP S_3 = list(mulclose([A, B])) assert len(S_3) == 6 # for g in G: # print(g) # print(g.hom) hom = A.hom space = hom.src N = 2**3 basis = space.get_basis() orbits = set() for v in basis: v1 = space.zero_vector() for g in S_3: u = g * v v1 = v1 + u orbits.add(v1) orbits = list(orbits) # for v in orbits: # print(v) HHH = H @ H @ H v = basis[7] #print(v) #print(HHH * v) print("OK")
def make_dicyclic(n, debug=False): # Binary dihedral group # https://people.maths.bris.ac.uk/~matyd/GroupNames/dicyclic.html p = cyclotomic(PolynomialRing(Z), 4 * n) ring = PolynomialRing(Z) / p rzeta = ring.x zeta = rzeta**2 izeta = zeta**(2 * n - 1) # inverse for k in range(1, 6 * n): if zeta**k == 1: break assert k == 2 * n if n == 3: assert zeta - 1 == zeta**2 i = rzeta**n assert i != 1 assert i**2 == -1 assert i**3 == -i assert i**4 == 1 assert zeta**(2 * n) == 1 assert izeta != 1 assert zeta * izeta == 1 def is_real(v): # this is a total hack assert ring.promote(v) is v x = exp(2.j * pi / (4 * n)) s = str(v) v = eval(s, locals()) return abs(v.imag) < EPSILON for k in range(1, 6 * n): assert is_real(rzeta**k) == (k % (2 * n) == 0) assert is_real(zeta + izeta) # we use the natural 2-dim representation GL = Linear(2, ring) e = GL.get([[1, 0], [0, 1]]) r = GL.get([[zeta, 0], [0, izeta]]) s = GL.get([[0, -1], [1, 0]]) Di = mulclose([r, s]) Di = list(Di) assert len(Di) == 4 * n eidx = Di.index(e) ridx = Di.index(r) sidx = Di.index(s) G = cayley(Di) e = G[eidx] r = G[ridx] s = G[sidx] assert r**(2 * n) == e assert s**2 == r**n assert r * s * r == s # complex characters ---------------------------------------------------- # build the transpose of the character table. cols = [] elems = [] # group elements with order the cols cgy = [] # element of each cgy class kidxs = range(2, n) desc = [] # class: e, size 1 elems.append(e) cgy.append(e) desc.append("e") cols.append([1, 1, 1, 1, 2] + [2 for k in kidxs]) # class: s^2, size 1 cols.append([1, 1, (-1)**n, (-1)**n, -2] + [((-1)**k) * 2 for k in kidxs]) elems.append(s * s) cgy.append(s * s) desc.append("s^2") for idx in range(1, n): # class: r**idx, size 2 col = [1, 1, (-1)**idx, (-1)**idx, zeta**idx + izeta**idx ] + [zeta**(idx * k) + izeta**(idx * k) for k in kidxs] cols.append(col) cols.append(col) elems.append(r**idx) cgy.append(r**idx) desc.append("r^%d" % idx) elems.append(r**(2 * n - idx)) for idx in range(n): # class: s, size n cols.append([1, -1, i**n, -i**n, 0] + [0 for k in kidxs]) elems.append(s * (r**(2 * idx))) cgy.append(s) desc.append("s") for idx in range(n): # class: s*r, size n cols.append([1, -1, -i**n, i**n, 0] + [0 for k in kidxs]) elems.append(s * (r**(2 * idx + 1))) cgy.append(s * r) desc.append("sr") #print(i, -i, i**n, -i**n) assert len(set(elems)) == len(elems) == len(G) assert set(elems) == set(G) for col in cols: assert len(col) == n + 3, len(col) if debug: print() for s in desc: s = "%10s" % s print(s, end=" ") print() c_chars = [] for k in range(n + 3): chi = dict((elems[i], cols[i][k]) for i in range(4 * n)) f = CFunc(G, chi) for g in cgy: s = "%10s" % (f[g]) print(s, end=" ") print() c_chars.append(f) print() for f in c_chars: for g in c_chars: val = f.dot(g, normalize=False) #assert (f == g) == (val == 1) print(val, end=" ") print() else: c_chars = [] for k in range(n + 3): chi = dict((elems[i], cols[i][k]) for i in range(4 * n)) f = CFunc(G, chi) c_chars.append(f) for f in c_chars: for g in c_chars: val = f.dot(g) assert (f == g) == (val == 1) G.c_chars = c_chars # complex reps ---------------------------------------------------- c_reps = [] e = G[eidx] r = G[ridx] s = G[sidx] tp = Cat(G, ring) def mk_rep(gen, reps): assert reps f = reps[0] V = f.hom.src send_perms = mulclose_hom(gen, reps) rep = Rep(send_perms, V, tp) return rep # 1-dim irreps V = Space(1, ring) hom = Hom(V, V) f_1 = Map.from_array([[1]], hom) f_n1 = Map.from_array([[-1]], hom) c_reps.append(mk_rep([r, s], [f_1, f_1])) # Triv c_reps.append(mk_rep([r, s], [f_1, f_n1])) # 1A f_r = Map.from_array([[-1]], hom) f_s = Map.from_array([[i**n]], hom) c_reps.append(mk_rep([r, s], [f_r, f_s])) # 1B f_s = Map.from_array([[-i**n]], hom) c_reps.append(mk_rep([r, s], [f_r, f_s])) # 1C # 2-dim irreps V = Space(2, ring) hom = Hom(V, V) for k in range(1, n): rho_r = Map.from_array([[zeta**k, 0], [0, izeta**k]], hom) rho_s = Map.from_array([[0, 1], [(-1)**k, 0]], hom) c_reps.append(mk_rep([r, s], [rho_r, rho_s])) # rho_k for idx, rep in enumerate(c_reps): rep.check() char = c_chars[idx] tr = rep.trace() tr = CFunc(G, tr) # print(tr, end=" ") # val = tr.frobenius_schur() # if val == -1: # print("quaternionic") # elif val == 0: # print("complex") # elif val == 1: # print("real") # else: # assert 0, val for g in G: lhs, rhs = tr[g], char[g] assert lhs == rhs, "%d: %s != %s" % (idx, lhs, rhs) assert len(c_reps) == n + 3 G.c_reps = c_reps # real characters ---------------------------------------------------- r_chars = [] r_chars.append(c_chars[0]) # Triv r_chars.append(c_chars[1]) # 1A if n % 2 == 0: assert c_chars[2].frobenius_schur() == 1 # real assert c_chars[3].frobenius_schur() == 1 # real r_chars.append(c_chars[2]) # 1B r_chars.append(c_chars[3]) # 1C else: assert c_chars[2].frobenius_schur() == 0 # complex assert c_chars[3].frobenius_schur() == 0 # complex r_chars.append(c_chars[2] + c_chars[3]) # 1B+1C for idx, rep in enumerate(c_reps): if idx < 4: continue char = c_chars[idx] val = char.frobenius_schur() if val == 1: r_chars.append(char) elif val == -1: r_chars.append(2 * char) else: assert 0 G.r_chars = r_chars return G
def main(): d = 2 ring = CyclotomicRing(8) #ring = element.Z e = ring.x gamma = e**2 w = gamma**2 assert w == -1 I = numpy.zeros((d, d), dtype=object) wI = numpy.zeros((d, d), dtype=object) X = numpy.zeros((d, d), dtype=object) Z = numpy.zeros((d, d), dtype=object) Zdag = numpy.zeros((d, d), dtype=object) S = numpy.zeros((d, d), dtype=object) Sdag = numpy.zeros((d, d), dtype=object) T = numpy.zeros((d, d), dtype=object) Tdag = numpy.zeros((d, d), dtype=object) for j in range(d): I[j, j] = 1 wI[j, j] = w X[j, (j + 1) % d] = 1 Z[j, j] = w**j Zdag[j, j] = w**(d - j) val = [1, gamma][j] ival = [1, -gamma][j] assert val * ival == 1 S[j, j] = val Sdag[j, j] = ival val = [1, e][j] ival = [1, e**7][j] assert val * ival == 1 T[j, j] = val Tdag[j, j] = ival qu = Space(d, ring) hom = Hom(qu, qu) I = Map.from_array(I, hom) wI = Map.from_array(wI, hom) Xdag = Map.from_array(X.transpose(), hom) X = Xs = Map.from_array(X, hom) Z = Map.from_array(Z, hom) Zdag = Map.from_array(Zdag, hom) S = Map.from_array(S, hom) Sdag = Map.from_array(Sdag, hom) T = Map.from_array(T, hom) Tdag = Map.from_array(Tdag, hom) Y = w * X * Z # ? assert S * Sdag == I assert S * S == Z assert T * T == S assert Z * Zdag == I assert X * Xdag == I if d > 2: for j in range(1, d + 1): assert (j == d) == (X**j == I) assert (j == d) == (Z**j == I) else: assert X != I assert Z != I assert X * X == I assert Z * Z == I assert Z * X == (w**(d - 1)) * X * Z pauli = mulclose([X, Z, gamma * I]) pauli = set(pauli) print("pauli:", len(pauli)) assert Zdag in pauli assert Xdag in pauli if d < 6: # slow.. lhs = atpow(X, d) rhs = atpow(Z, d) assert lhs * rhs == rhs * lhs lhs = X @ X rhs = Z @ Zdag assert lhs * rhs == rhs * lhs lhs = X @ (X**(d - 1)) rhs = Z @ Z assert lhs * rhs == rhs * lhs if 0: n = 5 ops = [X, Xdag] lhs = [] for op in cross([ops] * n): op = reduce(matmul, op) lhs.append(op) ops = [Z, Zdag] rhs = [] for op in cross([ops] * n): op = reduce(matmul, op) rhs.append(op) for l in lhs: for r in rhs: if l * r == r * l: print("/", end=" ", flush=True) else: print(".", end=" ", flush=True) print() #print(Z@Z@Z) #print(Y) #print(S*X*Sdag) #print(Y == S*X*Sdag) if d == 3: assert (Y == S * X * Sdag) inverse = {} for g in pauli: for h in pauli: if g * h == I: inverse[g] = h inverse[h] = g def is_cliff(A, Ai): assert A * Ai == I for g in pauli: h = A * g * Ai if h not in pauli: return False return True print(S) print(Sdag) assert is_cliff(S, Sdag) #print("is_cliff:", (S in pauli), is_cliff(S, Sdag)) def is_third_level(A, Ai): assert A * Ai == I for g in pauli: gi = inverse[g] h = A * g * Ai * gi hi = g * A * gi * Ai if not is_cliff(h, hi): return False return True print("is_pauli(S)", S in pauli) print("is_cliff(S)", is_cliff(S, Sdag)) #print("is_third_level(S)", is_third_level(S, Tdag)) print("is_pauli(T)", T in pauli) print("is_cliff(T)", is_cliff(T, Tdag)) print("is_third_level(T)", is_third_level(T, Tdag)) #C2 = mulclose([X, T, H]) print("OK")
def main(): #ring = element.Z ring = element.Q qubit = Space(2, ring) q2 = qubit @ qubit hom = Hom(qubit, qubit) I = Map.from_array([[1, 0], [0, 1]], hom) X = Map.from_array([[0, 1], [1, 0]], hom) Z = Map.from_array([[1, 0], [0, -1]], hom) H = X + Z E = Map.from_array([[0, 1], [0, 0]], hom) # raising F = Map.from_array([[0, 0], [1, 0]], hom) # lowering II = I @ I XI = X @ I IX = I @ X XX = X @ X assert XI * IX == XX CNOT = Map.from_array( [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]], hom @ hom) SWAP = Map.from_array( [[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]], hom @ hom) assert SWAP * SWAP == II assert CNOT * CNOT == II G = mulclose([XI, IX, CNOT]) # order 8 G = mulclose([XI, IX, CNOT, SWAP]) # order 24.. must be S_4 G = mulclose([CNOT, SWAP]) # print(len(G)) # for g in G: # print(g) A = SWAP @ I B = I @ SWAP S_3 = list(mulclose([A, B])) assert len(S_3) == 6 # for g in G: # print(g) # print(g.hom) hom = A.hom space = hom.src N = 2**3 basis = space.get_basis() orbits = set() for v in basis: v1 = space.zero_vector() for g in S_3: u = g * v v1 = v1 + u orbits.add(v1) orbits = list(orbits) # for v in orbits: # print(v) HHH = H @ H @ H v = basis[7] #print(v) #print(HHH * v) # ---------------------------------------------------------- specht = Specht(4, qubit) for i, A in enumerate(specht.projs): print("part:", specht.parts[i]) print("proj:") im = A.image() #im = A src, tgt = im.hom for i in src: for j in tgt: v = im[j, i] if v != ring.zero: print("%s*%s" % (v, j), end=" ") print() return # ---------------------------------------------------------- items = [0, 1, 2, 3] g1 = Perm({0: 1, 1: 0, 2: 2, 3: 3}, items) g2 = Perm({0: 0, 1: 2, 2: 1, 3: 3}, items) g3 = Perm({0: 0, 1: 1, 2: 3, 3: 2}, items) gen1 = [g1, g2, g3] s1 = SWAP @ I @ I s2 = I @ SWAP @ I s3 = I @ I @ SWAP gen2 = [s1, s2, s3] G = mulclose(gen1) hom = mulclose_hom(gen1, gen2) for g in G: for h in G: assert hom[g * h] == hom[g] * hom[h] # check it's a group hom projs = [] for part in [(4, ), (3, 1), (2, 2)]: t = Young(part) rowG = t.get_rowperms() colG = t.get_colperms() horiz = None for g in rowG: P = hom[g] horiz = P if horiz is None else (horiz + P) vert = None for g in colG: P = hom[g] s = g.sign() P = s * P vert = P if vert is None else (vert + P) A = vert * horiz #A = horiz * vert assert vert * vert == len(colG) * vert assert horiz * horiz == len(rowG) * horiz #print(t) #print(A) projs.append(A) for A in projs: for B in projs: assert A * B == B * A # print() # for A in projs: # for g in G: # P = hom[g] # if P*A != A*P: # print(P*A) # print(A*P) # return for A in projs: print("proj:") im = A.image() #im = A src, tgt = im.hom for i in src: for j in tgt: v = im[j, i] if v != ring.zero: print("%s*%s" % (v, j), end=" ") print()