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_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 qapply_Mul(e, **options): ip_doit = options.get('ip_doit', True) args = list(e.args) # If we only have 0 or 1 args, we have nothing to do and return. if len(args) <= 1 or not isinstance(e, Mul): return e rhs = args.pop() lhs = args.pop() # Make sure we have two non-commutative objects before proceeding. if (sympify(rhs).is_commutative and not isinstance(rhs, Wavefunction)) or \ (sympify(lhs).is_commutative and not isinstance(lhs, Wavefunction)): return e # For a Pow with an integer exponent, apply one of them and reduce the # exponent by one. if isinstance(lhs, Pow) and lhs.exp.is_Integer: args.append(lhs.base**(lhs.exp-1)) lhs = lhs.base # Pull OuterProduct apart if isinstance(lhs, OuterProduct): args.append(lhs.ket) lhs = lhs.bra # Call .doit() on Commutator/AntiCommutator. if isinstance(lhs, (Commutator, AntiCommutator)): comm = lhs.doit() if isinstance(comm, Add): return qapply( e._new_rawargs(*(args + [comm.args[0], rhs])) +\ e._new_rawargs(*(args + [comm.args[1], rhs])), **options ) else: return qapply(e._new_rawargs(*args)*comm*rhs, **options) # Apply tensor products of operators to states if isinstance(lhs, TensorProduct) and all([isinstance(arg,Operator) or arg == 1 for arg in lhs.args]) and \ isinstance(rhs, TensorProduct) and all([isinstance(arg,State) or arg == 1 for arg in rhs.args]) and \ len(lhs.args) == len(rhs.args): result = TensorProduct(*[qapply(lhs.args[n]*rhs.args[n], **options) for n in range(len(lhs.args))]).expand(tensorproduct=True) return qapply_Mul(e._new_rawargs(*args), **options)*result # Now try to actually apply the operator and build an inner product. try: result = lhs._apply_operator(rhs, **options) except (NotImplementedError, AttributeError): try: result = rhs._apply_operator(lhs, **options) except (NotImplementedError, AttributeError): if isinstance(lhs, BraBase) and isinstance(rhs, KetBase): result = InnerProduct(lhs, rhs) if ip_doit: result = result.doit() else: result = None # TODO: I may need to expand before returning the final result. if result == 0: return S.Zero elif result is None: if len(args) == 0: # We had two args to begin with so args=[]. return e else: return qapply_Mul(e._new_rawargs(*(args+[lhs])), **options)*rhs elif isinstance(result, InnerProduct): return result*qapply_Mul(e._new_rawargs(*args), **options) else: # result is a scalar times a Mul, Add or TensorProduct return qapply(e._new_rawargs(*args)*result, **options)
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_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 qapply_Mul(e, **options): ip_doit = options.get('ip_doit', True) args = list(e.args) # If we only have 0 or 1 args, we have nothing to do and return. if len(args) <= 1 or not isinstance(e, Mul): return e rhs = args.pop() lhs = args.pop() # Make sure we have two non-commutative objects before proceeding. if (sympify(rhs).is_commutative and not isinstance(rhs, Wavefunction)) or \ (sympify(lhs).is_commutative and not isinstance(lhs, Wavefunction)): return e # For a Pow with an integer exponent, apply one of them and reduce the # exponent by one. if isinstance(lhs, Pow) and lhs.exp.is_Integer: args.append(lhs.base**(lhs.exp - 1)) lhs = lhs.base # Pull OuterProduct apart if isinstance(lhs, OuterProduct): args.append(lhs.ket) lhs = lhs.bra # Call .doit() on Commutator/AntiCommutator. if isinstance(lhs, (Commutator, AntiCommutator)): comm = lhs.doit() if isinstance(comm, Add): return qapply( e.func(*(args + [comm.args[0], rhs])) + e.func(*(args + [comm.args[1], rhs])), **options ) else: return qapply(e.func(*args)*comm*rhs, **options) # Apply tensor products of operators to states if isinstance(lhs, TensorProduct) and all(isinstance(arg, (Operator, State, Mul, Pow)) or arg == 1 for arg in lhs.args) and \ isinstance(rhs, TensorProduct) and all(isinstance(arg, (Operator, State, Mul, Pow)) or arg == 1 for arg in rhs.args) and \ len(lhs.args) == len(rhs.args): result = TensorProduct(*[qapply(lhs.args[n]*rhs.args[n], **options) for n in range(len(lhs.args))]).expand(tensorproduct=True) return qapply_Mul(e.func(*args), **options)*result # Now try to actually apply the operator and build an inner product. try: result = lhs._apply_operator(rhs, **options) except (NotImplementedError, AttributeError): try: result = rhs._apply_operator(lhs, **options) except (NotImplementedError, AttributeError): if isinstance(lhs, BraBase) and isinstance(rhs, KetBase): result = InnerProduct(lhs, rhs) if ip_doit: result = result.doit() else: result = None # TODO: I may need to expand before returning the final result. if result == 0: return S.Zero elif result is None: if len(args) == 0: # We had two args to begin with so args=[]. return e else: return qapply_Mul(e.func(*(args + [lhs])), **options)*rhs elif isinstance(result, InnerProduct): return result*qapply_Mul(e.func(*args), **options) else: # result is a scalar times a Mul, Add or TensorProduct return qapply(e.func(*args)*result, **options)