def test_eval_trace(): up = JzKet(S(1)/2,S(1)/2) down = JzKet(S(1)/2,-S(1)/2) d = Density((up,0.5),(down,0.5)) t = Tr(d) assert t.doit() == 1
def _eval_trace(self, **kwargs): indices = kwargs.get('indices', None) exp = tensor_product_simp(self) if indices is None or len(indices) == 0: return Mul(*[Tr(arg).doit() for arg in exp.args]) else: return Mul(*[Tr(value).doit() if idx in indices else value for idx, value in enumerate(exp.args)])
def fidelity(state1, state2): """ Computes the fidelity [1]_ between two quantum states The arguments provided to this function should be a square matrix or a Density object. If it is a square matrix, it is assumed to be diagonalizable. Parameters ========== state1, state2 : a density matrix or Matrix Examples ======== >>> from sympy import S, sqrt >>> from sympy.physics.quantum.dagger import Dagger >>> from sympy.physics.quantum.spin import JzKet >>> from sympy.physics.quantum.density import Density, fidelity >>> from sympy.physics.quantum.represent import represent >>> >>> up = JzKet(S(1)/2,S(1)/2) >>> down = JzKet(S(1)/2,-S(1)/2) >>> amp = 1/sqrt(2) >>> updown = (amp * up) + (amp * down) >>> >>> # represent turns Kets into matrices >>> up_dm = represent(up * Dagger(up)) >>> down_dm = represent(down * Dagger(down)) >>> updown_dm = represent(updown * Dagger(updown)) >>> >>> fidelity(up_dm, up_dm) 1 >>> fidelity(up_dm, down_dm) #orthogonal states 0 >>> fidelity(up_dm, updown_dm).evalf().round(3) 0.707 References ========== .. [1] https://en.wikipedia.org/wiki/Fidelity_of_quantum_states """ state1 = represent(state1) if isinstance(state1, Density) else state1 state2 = represent(state2) if isinstance(state2, Density) else state2 if (not isinstance(state1, Matrix) or not isinstance(state2, Matrix)): raise ValueError("state1 and state2 must be of type Density or Matrix " "received type=%s for state1 and type=%s for state2" % (type(state1), type(state2))) if ( state1.shape != state2.shape and state1.is_square): raise ValueError("The dimensions of both args should be equal and the " "matrix obtained should be a square matrix") sqrt_state1 = state1**S.Half return Tr((sqrt_state1 * state2 * sqrt_state1)**S.Half).doit()
def test_outer_product(): k = Ket('k') b = Bra('b') op = OuterProduct(k, b) assert isinstance(op, OuterProduct) assert isinstance(op, Operator) assert op.ket == k assert op.bra == b assert op.label == (k, b) assert op.is_commutative is False op = k*b assert isinstance(op, OuterProduct) assert isinstance(op, Operator) assert op.ket == k assert op.bra == b assert op.label == (k, b) assert op.is_commutative is False op = 2*k*b assert op == Mul(Integer(2), k, b) op = 2*(k*b) assert op == Mul(Integer(2), OuterProduct(k, b)) assert Dagger(k*b) == OuterProduct(Dagger(b), Dagger(k)) assert Dagger(k*b).is_commutative is False #test the _eval_trace assert Tr(OuterProduct(JzKet(1, 1), JzBra(1, 1))).doit() == 1 # test scaled kets and bras assert OuterProduct(2 * k, b) == 2 * OuterProduct(k, b) assert OuterProduct(k, 2 * b) == 2 * OuterProduct(k, b) # test sums of kets and bras k1, k2 = Ket('k1'), Ket('k2') b1, b2 = Bra('b1'), Bra('b2') assert (OuterProduct(k1 + k2, b1) == OuterProduct(k1, b1) + OuterProduct(k2, b1)) assert (OuterProduct(k1, b1 + b2) == OuterProduct(k1, b1) + OuterProduct(k1, b2)) assert (OuterProduct(1 * k1 + 2 * k2, 3 * b1 + 4 * b2) == 3 * OuterProduct(k1, b1) + 4 * OuterProduct(k1, b2) + 6 * OuterProduct(k2, b1) + 8 * OuterProduct(k2, b2))
def test_eval_trace(): up = JzKet(S(1)/2, S(1)/2) down = JzKet(S(1)/2, -S(1)/2) d = Density((up, 0.5), (down, 0.5)) t = Tr(d) assert t.doit() == 1 #test dummy time dependent states class TestTimeDepKet(TimeDepKet): def _eval_trace(self, bra, **options): return 1 x, t = symbols('x t') k1 = TestTimeDepKet(0, 0.5) k2 = TestTimeDepKet(0, 1) d = Density([k1, 0.5], [k2, 0.5]) assert d.doit() == (0.5 * OuterProduct(k1, k1.dual) + 0.5 * OuterProduct(k2, k2.dual)) t = Tr(d) assert t.doit() == 1
def test_eval_trace(): # This test includes tests with dependencies between TensorProducts #and density operators. Since, the test is more to test the behavior of #TensorProducts it remains here A, B, C, D, E, F = symbols('A B C D E F', commutative=False) # Density with simple tensor products as args t = TensorProduct(A, B) d = Density([t, 1.0]) tr = Tr(d) assert tr.doit() == 1.0*Tr(A*Dagger(A))*Tr(B*Dagger(B)) ## partial trace with simple tensor products as args t = TensorProduct(A, B, C) d = Density([t, 1.0]) tr = Tr(d, [1]) assert tr.doit() == 1.0*A*Dagger(A)*Tr(B*Dagger(B))*C*Dagger(C) tr = Tr(d, [0, 2]) assert tr.doit() == 1.0*Tr(A*Dagger(A))*B*Dagger(B)*Tr(C*Dagger(C)) # Density with multiple Tensorproducts as states t2 = TensorProduct(A, B) t3 = TensorProduct(C, D) d = Density([t2, 0.5], [t3, 0.5]) t = Tr(d) assert t.doit() == (0.5*Tr(A*Dagger(A))*Tr(B*Dagger(B)) + 0.5*Tr(C*Dagger(C))*Tr(D*Dagger(D))) t = Tr(d, [0]) assert t.doit() == (0.5*Tr(A*Dagger(A))*B*Dagger(B) + 0.5*Tr(C*Dagger(C))*D*Dagger(D)) #Density with mixed states d = Density([t2 + t3, 1.0]) t = Tr(d) assert t.doit() == ( 1.0*Tr(A*Dagger(A))*Tr(B*Dagger(B)) + 1.0*Tr(A*Dagger(C))*Tr(B*Dagger(D)) + 1.0*Tr(C*Dagger(A))*Tr(D*Dagger(B)) + 1.0*Tr(C*Dagger(C))*Tr(D*Dagger(D))) t = Tr(d, [1] ) assert t.doit() == ( 1.0*A*Dagger(A)*Tr(B*Dagger(B)) + 1.0*A*Dagger(C)*Tr(B*Dagger(D)) + 1.0*C*Dagger(A)*Tr(D*Dagger(B)) + 1.0*C*Dagger(C)*Tr(D*Dagger(D)))
def test_outer_product(): k = Ket('k') b = Bra('b') op = OuterProduct(k, b) assert isinstance(op, OuterProduct) assert isinstance(op, Operator) assert op.ket == k assert op.bra == b assert op.label == (k, b) assert op.is_commutative is False op = k * b assert isinstance(op, OuterProduct) assert isinstance(op, Operator) assert op.ket == k assert op.bra == b assert op.label == (k, b) assert op.is_commutative is False op = 2 * k * b assert op == Mul(Integer(2), k, b) op = 2 * (k * b) assert op == Mul(Integer(2), OuterProduct(k, b)) assert Dagger(k * b) == OuterProduct(Dagger(b), Dagger(k)) assert Dagger(k * b).is_commutative is False #test the _eval_trace assert Tr(OuterProduct(JzKet(1, 1), JzBra(1, 1))).doit() == 1
def test_eval_trace(): up = JzKet(S(1) / 2, S(1) / 2) down = JzKet(S(1) / 2, -S(1) / 2) d = Density((up, 0.5), (down, 0.5)) t = Tr(d) assert t.doit() == 1 #test dummy time dependent states class TestTimeDepKet(TimeDepKet): def _eval_trace(self, bra, **options): return 1 x, t = symbols('x t') k1 = TestTimeDepKet(0, 0.5) k2 = TestTimeDepKet(0, 1) d = Density([k1, 0.5], [k2, 0.5]) assert d.doit() == (0.5 * OuterProduct(k1, k1.dual) + 0.5 * OuterProduct(k2, k2.dual)) t = Tr(d) assert t.doit() == 1
def test_permute(): A, B, C, D, E, F, G = symbols('A B C D E F G', commutative=False) t = Tr(A * B * C * D * E * F * G) assert t.permute(0).args[0].args == (A, B, C, D, E, F, G) assert t.permute(2).args[0].args == (F, G, A, B, C, D, E) assert t.permute(4).args[0].args == (D, E, F, G, A, B, C) assert t.permute(6).args[0].args == (B, C, D, E, F, G, A) assert t.permute(8).args[0].args == t.permute(1).args[0].args assert t.permute(-1).args[0].args == (B, C, D, E, F, G, A) assert t.permute(-3).args[0].args == (D, E, F, G, A, B, C) assert t.permute(-5).args[0].args == (F, G, A, B, C, D, E) assert t.permute(-8).args[0].args == t.permute(-1).args[0].args t = Tr((A + B) * (B * B) * C * D) assert t.permute(2).args[0].args == (C, D, (A + B), (B**2)) t1 = Tr(A * B) t2 = t1.permute(1) assert id(t1) != id(t2) and t1 == t2
def test_doit(): x, y = symbols('x y') A, B, C, D, E, F = symbols('A B C D E F', commutative=False) d = Density([XKet(), 0.5], [PxKet(), 0.5]) assert (0.5 * (PxKet() * Dagger(PxKet())) + 0.5 * (XKet() * Dagger(XKet()))) == d.doit() # check for kets with expr in them d_with_sym = Density([XKet(x * y), 0.5], [PxKet(x * y), 0.5]) assert (0.5 * (PxKet(x * y) * Dagger(PxKet(x * y))) + 0.5 * (XKet(x * y) * Dagger(XKet(x * y)))) == d_with_sym.doit() d = Density([(A + B) * C, 1.0]) assert d.doit() == (1.0 * A * C * Dagger(C) * Dagger(A) + 1.0 * A * C * Dagger(C) * Dagger(B) + 1.0 * B * C * Dagger(C) * Dagger(A) + 1.0 * B * C * Dagger(C) * Dagger(B)) # With TensorProducts as args # Density with simple tensor products as args t = TensorProduct(A, B, C) d = Density([t, 1.0]) assert d.doit() == \ 1.0 * TensorProduct(A*Dagger(A), B*Dagger(B), C*Dagger(C)) # Density with multiple Tensorproducts as states t2 = TensorProduct(A, B) t3 = TensorProduct(C, D) d = Density([t2, 0.5], [t3, 0.5]) assert d.doit() == (0.5 * TensorProduct(A * Dagger(A), B * Dagger(B)) + 0.5 * TensorProduct(C * Dagger(C), D * Dagger(D))) #Density with mixed states d = Density([t2 + t3, 1.0]) assert d.doit() == (1.0 * TensorProduct(A * Dagger(A), B * Dagger(B)) + 1.0 * TensorProduct(A * Dagger(C), B * Dagger(D)) + 1.0 * TensorProduct(C * Dagger(A), D * Dagger(B)) + 1.0 * TensorProduct(C * Dagger(C), D * Dagger(D))) #Density operators with spin states tp1 = TensorProduct(JzKet(1, 1), JzKet(1, -1)) d = Density([tp1, 1]) # full trace t = Tr(d) assert t.doit() == 1 #Partial trace on density operators with spin states t = Tr(d, [0]) assert t.doit() == JzKet(1, -1) * Dagger(JzKet(1, -1)) t = Tr(d, [1]) assert t.doit() == JzKet(1, 1) * Dagger(JzKet(1, 1)) # with another spin state tp2 = TensorProduct(JzKet(S(1) / 2, S(1) / 2), JzKet(S(1) / 2, -S(1) / 2)) d = Density([tp2, 1]) #full trace t = Tr(d) assert t.doit() == 1 #Partial trace on density operators with spin states t = Tr(d, [0]) assert t.doit() == JzKet(S(1) / 2, -S(1) / 2) * Dagger( JzKet(S(1) / 2, -S(1) / 2)) t = Tr(d, [1]) assert t.doit() == JzKet(S(1) / 2, S(1) / 2) * Dagger(JzKet(S(1) / 2, S(1) / 2))
def test_Tr(): A, B = symbols('A B', commutative=False) t = Tr(A*B) assert str(t) == 'Tr(A*B)'
def test_trace_new(): a, b, c, d, Y = symbols('a b c d Y') A, B, C, D = symbols('A B C D', commutative=False) assert Tr(a + b) == a + b assert Tr(A + B) == Tr(A) + Tr(B) #check trace args not implicitly permuted assert Tr(C * D * A * B).args[0].args == (C, D, A, B) # check for mul and adds assert Tr((a * b) + (c * d)) == (a * b) + (c * d) # Tr(scalar*A) = scalar*Tr(A) assert Tr(a * A) == a * Tr(A) assert Tr(a * A * B * b) == a * b * Tr(A * B) # since A is symbol and not commutative assert isinstance(Tr(A), Tr) #POW assert Tr(pow(a, b)) == a**b assert isinstance(Tr(pow(A, a)), Tr) #Matrix M = Matrix([[1, 1], [2, 2]]) assert Tr(M) == 3 ##test indices in different forms #no index t = Tr(A) assert t.args[1] == Tuple() #single index t = Tr(A, 0) assert t.args[1] == Tuple(0) #index in a list t = Tr(A, [0]) assert t.args[1] == Tuple(0) t = Tr(A, [0, 1, 2]) assert t.args[1] == Tuple(0, 1, 2) #index is tuple t = Tr(A, (0)) assert t.args[1] == Tuple(0) t = Tr(A, (1, 2)) assert t.args[1] == Tuple(1, 2) #trace indices test t = Tr((A + B), [2]) assert t.args[0].args[1] == Tuple(2) and t.args[1].args[1] == Tuple(2) t = Tr(a * A, [2, 3]) assert t.args[1].args[1] == Tuple(2, 3) #class with trace method defined #to simulate numpy objects class Foo: def trace(self): return 1 assert Tr(Foo()) == 1 #argument test # check for value error, when either/both arguments are not provided raises(ValueError, lambda: Tr()) raises(ValueError, lambda: Tr(A, 1, 2))
def test_eval_trace(): q1 = Qubit('10110') q2 = Qubit('01010') d = Density([q1, 0.6], [q2, 0.4]) t = Tr(d) assert t.doit() == 1 # extreme bits t = Tr(d, 0) assert t.doit() == (0.4 * Density([Qubit('0101'), 1]) + 0.6 * Density([Qubit('1011'), 1])) t = Tr(d, 4) assert t.doit() == (0.4 * Density([Qubit('1010'), 1]) + 0.6 * Density([Qubit('0110'), 1])) # index somewhere in between t = Tr(d, 2) assert t.doit() == (0.4 * Density([Qubit('0110'), 1]) + 0.6 * Density([Qubit('1010'), 1])) #trace all indices t = Tr(d, [0, 1, 2, 3, 4]) assert t.doit() == 1 # trace some indices, initialized in # non-canonical order t = Tr(d, [2, 1, 3]) assert t.doit() == (0.4 * Density([Qubit('00'), 1]) + 0.6 * Density([Qubit('10'), 1])) # mixed states q = (1 / sqrt(2)) * (Qubit('00') + Qubit('11')) d = Density([q, 1.0]) t = Tr(d, 0) assert t.doit() == (0.5 * Density([Qubit('0'), 1]) + 0.5 * Density([Qubit('1'), 1]))
def _eval_trace(self, **kwargs): indices = kwargs.get('indices', []) return Tr(self.doit(), indices).doit()
def test_Tr(): #TODO: Handle indices A, B = symbols('A B', commutative=False) t = Tr(A * B) assert latex(t) == r'\mbox{Tr}\left(A B\right)'
def test_eval_trace(): q1 = Qubit('10110') q2 = Qubit('01010') d = Density([q1, 0.6], [q2, 0.4]) t = Tr(d) assert t.doit() == 1 # extreme bits t = Tr(d, 0) assert t.doit() == (0.4*Density([Qubit('0101'), 1]) + 0.6*Density([Qubit('1011'), 1])) t = Tr(d, 4) assert t.doit() == (0.4*Density([Qubit('1010'), 1]) + 0.6*Density([Qubit('0110'), 1])) # index somewhere in between t = Tr(d, 2) assert t.doit() == (0.4*Density([Qubit('0110'), 1]) + 0.6*Density([Qubit('1010'), 1])) #trace all indices t = Tr(d, [0, 1, 2, 3, 4]) assert t.doit() == 1 # trace some indices, initialized in # non-canonical order t = Tr(d, [2, 1, 3]) assert t.doit() == (0.4*Density([Qubit('00'), 1]) + 0.6*Density([Qubit('10'), 1])) # mixed states q = (1/sqrt(2)) * (Qubit('00') + Qubit('11')) d = Density( [q, 1.0] ) t = Tr(d, 0) assert t.doit() == (0.5*Density([Qubit('0'), 1]) + 0.5*Density([Qubit('1'), 1]))
def test_Tr(): A, B = symbols("A B", commutative=False) t = Tr(A * B) assert str(t) == "Tr(A*B)"
def test_permute(): A, B, C, D, E, F, G = symbols('A B C D E F G', commutative=False) t = Tr(A*B*C*D*E*F*G) assert t.permute(0).args[0].args == (A, B, C, D, E, F, G) assert t.permute(2).args[0].args == (F, G, A, B, C, D, E) assert t.permute(4).args[0].args == (D, E, F, G, A, B, C) assert t.permute(6).args[0].args == (B, C, D, E, F, G, A) assert t.permute(8).args[0].args == t.permute(1).args[0].args assert t.permute(-1).args[0].args == (B, C, D, E, F, G, A) assert t.permute(-3).args[0].args == (D, E, F, G, A, B, C) assert t.permute(-5).args[0].args == (F, G, A, B, C, D, E) assert t.permute(-8).args[0].args == t.permute(-1).args[0].args t = Tr((A + B)*(B*B)*C*D) assert t.permute(2).args[0].args == (C, D, (A + B), (B**2)) t1 = Tr(A*B) t2 = t1.permute(1) assert id(t1) != id(t2) and t1 == t2
def test_eval_trace(): # This test includes tests with dependencies between TensorProducts #and density operators. Since, the test is more to test the behavior of #TensorProducts it remains here A, B, C, D, E, F = symbols('A B C D E F', commutative=False) # Density with simple tensor products as args t = TensorProduct(A, B) d = Density([t, 1.0]) tr = Tr(d) assert tr.doit() == 1.0 * Tr(A * Dagger(A)) * Tr(B * Dagger(B)) ## partial trace with simple tensor products as args t = TensorProduct(A, B, C) d = Density([t, 1.0]) tr = Tr(d, [1]) assert tr.doit() == 1.0 * A * Dagger(A) * Tr(B * Dagger(B)) * C * Dagger(C) tr = Tr(d, [0, 2]) assert tr.doit() == 1.0 * Tr(A * Dagger(A)) * B * Dagger(B) * Tr( C * Dagger(C)) # Density with multiple Tensorproducts as states t2 = TensorProduct(A, B) t3 = TensorProduct(C, D) d = Density([t2, 0.5], [t3, 0.5]) t = Tr(d) assert t.doit() == (0.5 * Tr(A * Dagger(A)) * Tr(B * Dagger(B)) + 0.5 * Tr(C * Dagger(C)) * Tr(D * Dagger(D))) t = Tr(d, [0]) assert t.doit() == (0.5 * Tr(A * Dagger(A)) * B * Dagger(B) + 0.5 * Tr(C * Dagger(C)) * D * Dagger(D)) #Density with mixed states d = Density([t2 + t3, 1.0]) t = Tr(d) assert t.doit() == (1.0 * Tr(A * Dagger(A)) * Tr(B * Dagger(B)) + 1.0 * Tr(A * Dagger(C)) * Tr(B * Dagger(D)) + 1.0 * Tr(C * Dagger(A)) * Tr(D * Dagger(B)) + 1.0 * Tr(C * Dagger(C)) * Tr(D * Dagger(D))) t = Tr(d, [1]) assert t.doit() == (1.0 * A * Dagger(A) * Tr(B * Dagger(B)) + 1.0 * A * Dagger(C) * Tr(B * Dagger(D)) + 1.0 * C * Dagger(A) * Tr(D * Dagger(B)) + 1.0 * C * Dagger(C) * Tr(D * Dagger(D)))