1"""Hermitian conjugation."""
2
3from sympy.core import Expr, Mul
4from sympy.functions.elementary.complexes import adjoint
5
6__all__ = [
7    'Dagger'
8]
9
10
11class Dagger(adjoint):
12    """General Hermitian conjugate operation.
13
14    Explanation
15    ===========
16
17    Take the Hermetian conjugate of an argument [1]_. For matrices this
18    operation is equivalent to transpose and complex conjugate [2]_.
19
20    Parameters
21    ==========
22
23    arg : Expr
24        The sympy expression that we want to take the dagger of.
25
26    Examples
27    ========
28
29    Daggering various quantum objects:
30
31        >>> from sympy.physics.quantum.dagger import Dagger
32        >>> from sympy.physics.quantum.state import Ket, Bra
33        >>> from sympy.physics.quantum.operator import Operator
34        >>> Dagger(Ket('psi'))
35        <psi|
36        >>> Dagger(Bra('phi'))
37        |phi>
38        >>> Dagger(Operator('A'))
39        Dagger(A)
40
41    Inner and outer products::
42
43        >>> from sympy.physics.quantum import InnerProduct, OuterProduct
44        >>> Dagger(InnerProduct(Bra('a'), Ket('b')))
45        <b|a>
46        >>> Dagger(OuterProduct(Ket('a'), Bra('b')))
47        |b><a|
48
49    Powers, sums and products::
50
51        >>> A = Operator('A')
52        >>> B = Operator('B')
53        >>> Dagger(A*B)
54        Dagger(B)*Dagger(A)
55        >>> Dagger(A+B)
56        Dagger(A) + Dagger(B)
57        >>> Dagger(A**2)
58        Dagger(A)**2
59
60    Dagger also seamlessly handles complex numbers and matrices::
61
62        >>> from sympy import Matrix, I
63        >>> m = Matrix([[1,I],[2,I]])
64        >>> m
65        Matrix([
66        [1, I],
67        [2, I]])
68        >>> Dagger(m)
69        Matrix([
70        [ 1,  2],
71        [-I, -I]])
72
73    References
74    ==========
75
76    .. [1] https://en.wikipedia.org/wiki/Hermitian_adjoint
77    .. [2] https://en.wikipedia.org/wiki/Hermitian_transpose
78    """
79
80    def __new__(cls, arg):
81        if hasattr(arg, 'adjoint'):
82            obj = arg.adjoint()
83        elif hasattr(arg, 'conjugate') and hasattr(arg, 'transpose'):
84            obj = arg.conjugate().transpose()
85        if obj is not None:
86            return obj
87        return Expr.__new__(cls, arg)
88
89    def __mul__(self, other):
90        from sympy.physics.quantum import IdentityOperator
91        if isinstance(other, IdentityOperator):
92            return self
93
94        return Mul(self, other)
95
96adjoint.__name__ = "Dagger"
97adjoint._sympyrepr = lambda a, b: "Dagger(%s)" % b._print(a.args[0])
98