def test_adjoint(): for A in Gate.I, Gate.X, Gate.Y, Gate.Z, Gate.H: B = A * ~A assert B.is_close(Gate.I) B = ~A * A assert B.is_close(Gate.I) A = Qu.random((2, 3), 'ud') assert (~A).shape == (2, 3) assert (~A).valence == 'du' H = ~A * A assert Gate.promote(H).is_hermitian() B = Qu.random((4, 2), 'ud') E = Qu.random((3, 2, 2), 'udu') u = Qu.random(2, 'u') v = Qu.random(3, 'd') for i in range(100): word = [] for j in range(randint(1, 4)): word.append(choice((A, B, E, u, v))) lhs = ~reduce(matmul, word) rhs = reduce(matmul, [~x for x in word]) assert lhs.space == rhs.space, (lhs.space, rhs.space) assert lhs.is_close(rhs)
def test_flatten(): shape = (2, 3, 4) valence = 'uuu' A = Qu.random(shape, valence) op = A.get_flatop() B = op.do(A) assert B.shape == (2 * 3 * 4, ), B.shape assert B.valence == 'u' shape = (2, 3) valence = 'ud' a = Qu.random(shape, valence) op = a.get_flatop() assert op.do(a).is_close(a) shape = (2, 3, 4, 5) valence = "udud" a = Qu.random(shape, valence) op = a.get_flatop() b = op.do(a) c = op.undo(b) assert c.is_close(a)
def main_1(): I = Qu((2, 2), 'ud', [[1, 0], [0, 1]]) X = Qu((2, 2), 'ud', [[0, 1], [1, 0]]) Z = Qu((2, 2), 'ud', [[1, 0], [0, -1]]) Y = X*Z T = Qu((2, 2), 'ud', [[1, 0], [0, cyclotomic(8)]]) op = get_projector() n = op.grade if argv.show: print(op) P = op.evaluate({"I":I, "X":X, "Z":Z, "Y":Y}) Tn = reduce(matmul, [T]*n) TnP = Tn*P PTn = P*Tn print(numpy.abs(TnP.v - PTn.v).sum()) if Tn*P == P*Tn: print("transversal T") else: print("no transversal T")
def get_encoded(self): self.build() n = self.n v = Qu((self.d, ) * n, 'u' * n) v[(0, ) * n] = 1. v = self.P * v #for op in self.LG: # yield op*v v /= v.norm() return v
def build_pauli(*args): X = Qu((2, 2), 'ud', [[0., 1], [1., 0.]]) Z = Qu((2, 2), 'ud', [[1., 0], [0., -1.]]) gen = [X, Z] G = mulclose(gen) assert len(G) == 8 return gen, G
def test_transpose(): a = Qu.random(2, 'u') r = ~a * a assert is_close(r, a.norm()**2) v = a.v[:] v.shape = v.shape + (1, ) A = Qu(v.shape, 'ud', v) r = ~A * A assert is_close(r[0, 0], a.norm()**2)
def test_shor_code(): x0 = (1./(2*r2)) * (bits('000') + bits('111'))\ @ (bits('000') + bits('111')) \ @ (bits('000') + bits('111')) x1 = (1./(2*r2)) * (bits('000') - bits('111')) \ @ (bits('000') - bits('111')) \ @ (bits('000') - bits('111')) A = Qu((2, ) * 10, 'u' * 9 + 'd') A[(slice(None), ) * 9 + (0, )] = x0 A[(slice(None), ) * 9 + (1, )] = x1 x = Qu.random(2, 'u') x.normalize() y = A * x # encode # now entangle with environment... env = Qu.random(2, 'u') z = y @ env return # this takes a while... rank = z.rank space = Space(2**rank, 'u') H = Qu.random_hermitian(space @ ~space) print("H:", H.space) U = H.evolution_operator(1.) print("U:", U.space, "rank:", U.rank) op = z.get_flatop() z = op.do(z) z1 = U * z if 0: space = z.space @ ~z.space # U = Qu.random_unitary(space) H = Qu.random_hermitian(space) print("H:", H.space) U = H.evolution_operator(1.) print("U:", U.space, "rank:", U.rank) z1 = U * z
def measure(H, v): assert H.is_hermitian() d = FuzzyDict() for val, vec in H.eigs(): assert abs(val.imag) < EPSILON val = val.real space = d.get(val, []) space.append(vec) d[val] = space povm = [] assert abs(1. - v.norm()) < EPSILON x = random() total = 0. result = None value = None ps = [] for val, space in d.items(): op = Qu(H.shape, H.valence) for vec in space: op += vec @ ~vec assert op*op == op u = op*v r = ~u * v #print(fstr(r)) total += r if result is None and x < total: result = u / u.norm() value = val ps.append(r) #print(fstr(sum(ps))) return value, result
def test_1(): assert S*S == Z i = 1.j phase = numpy.exp(i*pi/8) C1 = mulclose([X, Z, phase*I]) # Pauli group C2 = mulclose([H, S, phase*I]) # Clifford group assert len(C1) == 64, len(C1) assert len(C2) == 384, len(C2) r = numpy.exp(-pi*i/8)/sqrt(2) v = r*numpy.array([[1., i], [i, 1.]]) M = Qu((2, 2), 'ud', v) for g in C2: ginv = inv(g) assert g*ginv == I for g2 in C2: g2inv = inv(g2) assert g2*g2inv == I for g in C1: k = g2 * g * g2inv assert find(k, C1) print(M) print(find(M, C2)) for g in C1: k = M * g * inv(M) assert find(k, C1)
def __init__(self, gen, els, ops): n = ops.shape[0] # number of generators assert n == len(gen) degree = ops.shape[1] assert ops.shape[2] == degree ops = [Qu((degree, degree), 'ud', v) for v in ops] assert len(ops) == n self.ops = ops lookup = dict(zip(gen, ops)) #self.group = mulclose(ops) lookup["I"] = Qu.identity(degree) for el in els: op = eval(el, lookup) print("%s =" % el) print(op)
def test_gate_identities(): X, Y, Z, H, I = Gate.X, Gate.Y, Gate.Z, Gate.H, Gate.I zero = Qu((2, 2), 'ud') assert (X * X) == I assert (Y * Y) == I assert (Z * Z) == I assert anticommutator(X, Z) == zero assert anticommutator(Y, Z) == zero assert anticommutator(X, Y) == zero assert (Z * X) == 1.j * Y assert (X * Y) == 1.j * Z assert (Y * Z) == 1.j * X CZ = Z.control() A = (I @ H) * CZ * (I @ H) CX = X.control() assert A == CX assert CZ * CX == (Z * X).control() assert CX * CZ == (X * Z).control() assert (X.control() * (H @ I)) * ((H @ I) * X.control()) == I @ I assert H == ~H assert H * ~H == I assert H * X * ~H == Z
def build_octa(idx=0): " binary _octahedral group " x = cyclotomic(8) r2 = x - x**3 # sqrt(2) i = x**2 gen = [ [[[(-1 + i) / 2, (-1 + i) / 2], [(1 + i) / 2, (-1 - i) / 2]], [[(1 + i) / r2, 0], [0, (1 - i) / r2]]], [ # 2A [[(1. + i) / r2, 0.], [0., (1 - i) / r2]], [[1. / r2, -i / r2], [-i / r2, 1. / r2]], ], [ # 2B [[(-1. - i) / r2, 0.], [0., (-1. + i) / r2]], [[-1. / r2, i / r2], [i / r2, -1. / r2]], ], # [ # 2C # [[1., 0.], [-1., -1.]], # [[0., 1.], [1., 0.]], # ], ][idx] gen = [Qu((2, 2), 'ud', v) for v in gen] octa_gen = gen #a, b = gen #print((a**3*b).trace()) Octa = mulclose(gen) assert len(Octa) == 48, len(Octa) #print("Octa:", Octa.words.values()) return gen, Octa
def inv(A): A = A.v a, b = A[0] c, d = A[1] r = 1. / (a*d - b*c) v = numpy.array([[d, -b], [-c, a]])*r B = Qu((2, 2), 'ud', v) return B
def test_bitflip_code(): x0 = bits('000') x1 = bits('111') A = Qu((2, ) * 4, "uduu") A[:, 0, :, :] = x0 A[:, 1, :, :] = x1 assert (A * off).is_close(x0) assert (A * on).is_close(x1) B = Gate.CN B = B * (Gate.I @ off) B = B @ off C = Gate.CN @ Gate.I assert (C * bits('000')).decode() == '000' assert (C * bits('100')).decode() == '110' assert (C * bits('111')).decode() == '101' C = C.swap((2, 4), (3, 5)) # yuck... assert (C * bits('000')).decode() == '000' assert (C * bits('100')).decode() == '101' assert (C * bits('111')).decode() == '110' B = C * B assert B.is_close(A) x = Qu.random(2, 'u') x.normalize() y = A * x # encode # now entangle with environment... env = Qu.random(2, 'u') z = y @ env space = z.space @ ~z.space U = Qu.random_unitary(space) z1 = U * z
def test_random(): A = Qu.random((2, 2), 'ud') A = Gate.random_hermitian(4) assert A.is_hermitian() A = Gate.random_unitary(4) assert A.is_unitary()
def build_icosa(idx=0): " binary _icosahedral group " i = cyclotomic(4) v = cyclotomic(10) z = v**2 r5 = 2 * z**3 + 2 * z**2 + 1 #sqrt(5) gen = [ [ # Same as Nat ? [[z**3, 0], [0, z**2]], [[(z**4 - z) / r5, (z**2 - z**3) / r5], [(z**2 - z**3) / r5, -(z**4 - z) / r5]] ], [ # Nat [[v, 0], [0, v**9]], [[(5 * (v - v**4) - r5 * (v + v**4)) / 10., (-2 * r5 * (v + v**4)) / 10.], [(-2 * r5 * (v + v**4)) / 10., (5 * (v - v**4) + r5 * (v + v**4)) / 10.]] ], [ [[0, i], [i, (1 - r5) / 2]], [[-i, i], [-(1 - r5) / 2., (1 - r5) / 2 + i]], ] ][idx] gen = [Qu((2, 2), 'ud', v) for v in gen] #a, b = gen #H = mulclose([b], maxsize=100) #print(len(H)) X = Qu((2, 2), 'ud', [[0., 1], [1., 0.]]) Z = Qu((2, 2), 'ud', [[1., 0], [0., -1.]]) G = mulclose(gen, maxsize=256) assert len(G) == 120 if idx in (0, 1): assert X * Z in G assert X not in G assert Z not in G return gen, G
def make_state(self, idxs=None): "computational basis state" n = self.n v = Qu((self.d, ) * n, 'u' * n) if idxs is not None: bits = [0] * n for i in idxs: bits[i] = 1 v[tuple(bits)] = 1. return v
def get_group(n): I = Gate.I X = Gate.X Z = Gate.Z Y = Gate.Y S = Qu((2, 2), 'ud', [[1, 0], [0, cyclotomic(4)]]) for op in [X, Z]: op = reduce(matmul, [op] * n) yield op
def test_pure(): v = Qu.random((2, ), 'u') v /= v.norm() A = v @ ~v A = Gate.promote(A) assert is_close(A.trace(), 1.) assert A.is_pure() A = 0.5 * Gate.dyads[0] + 0.5 * Gate.dyads[1] A = Gate.promote(A) assert is_close(A.trace(), 1.) assert not A.is_pure()
def test_bell_basis(): raise test.Skip A = (Gate.H @ Gate.I) * Gate.CN print() xs = Qu.bell_basis(2) for x in xs: print(x.shortstr()) print() for i, word in enumerate(['00', '01', '10', '11']): x = bits(word) print((A * x).shortstr())
def build_compound(self, rows, col, namespace): tracks = self.tracks rank = self.rank ops = [self[row, col] for row in rows] if '.' in ops: ctrl_bits = [tracks.index(rows[idx]) for idx in range(len(ops)) if ops[idx]=='.'] A = Qu((2,)*(2*rank), 'ud'*rank) for ctrl in genidx((2,)*len(ctrl_bits)): factors = [Gate.I] * rank for idx, bit_idx in enumerate(ctrl_bits): factors[bit_idx] = Gate.dyads[ctrl[idx]] if 0 not in ctrl: # all 1's for row in rows: op = self[row, col] if op != '.': op = 'X' if op == '+' else op G = namespace.get(op) if G is None: raise ParseError(self, row, col, "cannot find gate %r"%op) factors[tracks.index(row)] = G A += reduce(matmul, factors) elif 'x' in ops: if ops != ['x', 'x']: raise ParseError(self, rows, col, 'expected exactly two swaps (x)') row0, row1 = rows factors = [Gate.I]*(self.rank-1) factors[row0] = Gate.SWAP A = reduce(matmul, factors) A.swap2(tracks.index(row0)+1, tracks.index(row1)) else: raise ParseError(self, rows, col, 'no control or swap found') return A
def build_tetra(idx=0): " binary _tetrahedral group " i = cyclotomic(4) r2 = sqrt(2) r3 = sqrt(3) r6 = sqrt(6) gen = [ [ # same as Natural repr ? [[(-1 + i) / 2, (-1 + i) / 2], [(1 + i) / 2, (-1 - i) / 2]], # order 3 [[-1 / 2 - 1 / 2 * i, -1 / 2 - 1 / 2 * i], [1 / 2 - 1 / 2 * i, -1 / 2 + 1 / 2 * i]] # order 3 ], [ # Natural repr [[(1 + i * r3) / 2, 0], [0, (1 - i * r3) / 2]], [[(r3 - i) / (2 * r3), (-i * 2 * r2) / (2 * r3)], [(-i * 2 * r2) / (2 * r3), (r3 + i) / (2 * r3)]], ], [ # 2A [[(-2) / 2., 0], [0, (1 + i * r3) / 2.]], [[(2 * i) / (2 * r3), (r6 + i * r2) / (2 * r3)], [(r6 + i * r2) / (2 * r3), (i - r3) / (2 * r3)]], ], [ # 2B [[(1 - i * r3) / 2., 0], [0, (-2) / 2.]], [[(-r3 - i) / (2 * r3), (-r6 + i * r2) / (2 * r3)], [(-r6 + i * r2) / (2 * r3), (-2 * i) / (2 * r3)]], ], ][idx] gen = [Qu((2, 2), 'ud', v) for v in gen] a, b = gen #print( len(mulclose([b], maxsize=32))) assert len(mulclose([a], maxsize=32)) in (3, 6) assert len(mulclose([b], maxsize=32)) in (3, 6) Tetra = mulclose(gen, maxsize=32) assert len(Tetra) == 24 return gen, Tetra
def test_evolve(): t = 1. H = Gate.random_hermitian(2) U = H.evolution_operator(t) W = H.evolution_operator(t / 2) #print (W*W).shortstr() assert (W * W).is_close(U) v = Qu.random(2, 'u') v.normalize() #print w = U * v #print w.shortstr() x = W * v x = W * x #print x.shortstr() assert w.is_close(x)
def test_pipe_op(): a = Qu(2, 'u', [0, 1]) b = Qu(2, 'd', [1, 2]) c = b * a # dot product! assert type(c) is scalar assert is_close(c, 2) A = Qu((2, 2), 'ud') v = Qu(2, 'u') u = A * v assert u.space == v.space # The pipe operator: valence A = Gate.I @ Gate.X B0 = A * A B1 = A @ A assert B1.valence == "udududud" valence = list(B1.valence) B1 = B1.contract(1, 4) assert B1.valence == "uuddud" B1 = B1.contract(2, 4) assert B1.valence == "uudd" B1.permute([0, 2, 1, 3]) assert B0.is_close(B1) #assert (1.j*A).is_close(1.j*A) # use left multiply for this... B = A.clone() A = A * A assert A.is_close(B * B)
from qupy.argv import argv from qupy.util import mulclose, show_spec I, X, Z, H = Gate.I, Gate.X, Gate.Z, Gate.H S, T = Gate.S, Gate.T # S aka P SWAP = Gate.SWAP CX = Gate.CN v = numpy.array([ [1., 0., 0., 0.], [0., 1., 0., 0.], [0., 0., 1., 0.], [0., 0., 0., -1.]]) v.shape = (2,2,2,2) CZ = Qu((2,2,2,2), 'udud', v) def find(op, ops): for op1 in ops: #if numpy.abs(op-op1).sum() < EPSILON: if op == op1: return True return False def inv(A): A = A.v a, b = A[0] c, d = A[1] r = 1. / (a*d - b*c)
def test_2(): "two qubits" i = 1.j phase = numpy.exp(i*pi/8) II = I@I XI = X@I IX = I@X ZI = Z@I IZ = I@Z gen = [XI, IX, ZI, IZ, phase*II] gen = [op.flat() for op in gen] C1 = mulclose(gen) assert len(C1) == 256, len(C1) # CZ = Z.control() # op = CZ.flat() # print(op) # print(op.valence) r = numpy.exp(-pi*i/8) v = r*numpy.array([ [1., 0., 0., 0.], [0., 1.j, 0., 0.], [0., 0., 1.j, 0.], [0., 0., 0., 1.]]) CZ = Qu((4, 4), 'ud', v) II = II.flat() assert (CZ*~CZ) == II assert not find(CZ, C1) for g in C1: k = CZ * g * ~CZ assert find(k, C1) r = numpy.exp(pi*i/8)/sqrt(2) v = r*numpy.array([[1., i], [i, 1.]]) H = Qu((2, 2), 'ud', v) plus = 1./sqrt(2) * (bitvec(0) + bitvec(1)) #print(plus) #print(H*plus) # proportional to plus state IH = (I@H).flat() HI = (H@I).flat() HH = (H@H).flat() assert IH * CZ * IH == CZ * IH * CZ # Reidemeister III move g = CZ * HH * CZ assert g*g == II assert g != SWAP.flat() A = (CZ @ I).flat() B = (I @ CZ).flat() III = (II@I).flat() assert A*B == B*A ABA = A*B*A BAB = B*A*B r = numpy.exp(pi*i/8) print((ABA/r).shortstr()) print((BAB/r).shortstr()) #assert A*B*A == B*A*B op = III for i in range(1, 100): op = ABA * op if op == III: break else: assert 0 print(i) assert ABA ** 16 == III assert BAB ** 16 == III
def test_setitem(): A = Qu((2, ) * 3, 'uuu') A[:] = bits('010')
def main(): _I = Qu((2, 2), 'ud', [[1, 0], [0, 1]]) _X = Qu((2, 2), 'ud', [[0, 1], [1, 0]]) _Z = Qu((2, 2), 'ud', [[1, 0], [0, -1]]) _Y = _X*_Z _S = Qu((2, 2), 'ud', [[1, 0], [0, cyclotomic(4)]]) _T = Qu((2, 2), 'ud', [[1, 0], [0, cyclotomic(8)]]) _Ti = _T.dag() assert _T * _Ti == _I _H = (1./sqrt(2))*Qu((2, 2), 'ud', [[1, 1], [1, -1]]) pauli = build_algebra("IXZY", "X*X=I Z*Z=I Y*Y=-I X*Z=Y Z*X=-Y X*Y=Z Y*X=-Z Z*Y=-X Y*Z=X") I = pauli.I X = pauli.X Y = pauli.Y Z = pauli.Z S, Si, T, Ti, H = list(promote_pauli(pauli, [_S, _S.dag(), _T, _Ti, _H])) assert S*Si == I assert Si*S == I assert T*Ti == I assert Ti*T == I K = S*H # the "Bravyi-Kitaev T" gate Ki = H*Si assert K*Ki == I print("S conjugation:") for src in [X, Z, Y]: print(src, "-->", S*src*Si) print("T conjugation:") for src in [X, Z, Y]: print(src, "-->", T*src*Ti) return if argv.hamiltonian: P = get_hamiltonian(pauli) else: code = build_code(pauli) P = code.get_projector() m = len(code.ops) # number of independent stab gen print("m =", m) r = 2**(-m) P = r*P assert P*P == P n = P.grade #Xn = reduce(matmul, [X]*n) #print("K transverse:", Kn*P == P*Kn) #print(P*Kn == Kn*P) gate = argv.get("gate", "S") if gate == "X": A = B = reduce(matmul, [X]*n) Q = Xn*P*Xn elif gate == "S": # clifford A = reduce(matmul, [S]*n) B = reduce(matmul, [Si]*n) elif gate == "SSdag": # clifford A = reduce(matmul, ([S, Si]*n)[:n]) B = reduce(matmul, ([Si, S]*n)[:n]) elif gate == "S2": # clifford A = reduce(matmul, [S, Si]*2 + [I]*4) B = reduce(matmul, [Si, S]*2 + [I]*4) elif gate == "K": # clifford A = reduce(matmul, [K]*n) B = reduce(matmul, [Ki]*n) elif gate == "T": # non-clifford A = reduce(matmul, [T]*n) B = reduce(matmul, [Ti]*n) else: assert 0, gate print("go:") Q = A*P*B print("32*Q:") print(32*Q) print("Q==P:", Q == P) QQ = (Q*Q) print("Q*Q==Q:", QQ == Q)
def main(): t = argv.get("t", 0.02) T = build(""" XZZXI IXZZX XIXZZ ZXIXZ XXXXX """) n = 5 stabs = [ X@Z@Z@X@I, I@X@Z@Z@X, X@I@X@Z@Z, Z@X@I@X@Z] Lx = X@X@X@X@X #Lz = Z@Z@Z@Z@Z Lz = T[n-1] ops = stabs + [Lx] for i in range(n): for j in range(n): c = (T[i]*ops[j] == ops[j]*T[i]) assert c == (i!=j) a = (T[i]*ops[j] == -ops[j]*T[i]) assert a == (i==j) G = mulclose(stabs) assert len(G) == 16 N = len(G) P = (1./N) * sumops(G) assert P*P == P for op in stabs: assert Lx*op == op*Lx assert Lz*op == op*Lz trials = argv.get("trials", 100) for trial in range(trials): if 1: # noise on one qubit U = errop(t) U = U@I@I@I@I else: # noise on all qubits Us = [] for i in range(n): Us.append(errop(t)) U = reduce(matmul, Us) v = Qu.random((2,)*n, "u"*n) v = P*v v.normalize() #print(v.flatstr()) u = U*v u.normalize() for i, op in enumerate(stabs): val, u = measure(op, u) print(fstr(val), end=" ") if val < 0: #print("*") u = T[i]*u #print() #for i, op in enumerate(stabs): #val, v = measure(op, v) #print(fstr(val), end=" ") #print() assert P*u == u assert P*v == v phase = None for uu in [u, Lx*u, Lz*u, Lx*Lz*u]: r = ~uu * v if abs(1. - abs(r)) < EPSILON: #write("+") phase = r #else: #write(".") #write("\n") if phase is not None: print(phase) else: print()