(e, **options)
Apply operators to states in a quantum expression.

    Parameters
    ==========

    e : Expr
        The expression containing operators and states. This expression tree
        will be walked to find operators acting on states symbolically.
    options : dict
        A dict of key/value pairs that determine how the operator actions
        are carried out.

        The following options are valid:

        * ``dagger``: try to apply Dagger operators to the left
          (default: False).
        * ``ip_doit``: call ``.doit()`` in inner products when they are
          encountered (default: True).

    Returns
    =======

    e : Expr
        The original expression, but with the operators applied to states.
Apply operators to states in a quantum expression.
Apply operators to states in a quantum expression .
def qapply(e, **options):
    """Apply operators to states in a quantum expression.

    Parameters
    ==========

    e : Expr
        The expression containing operators and states. This expression tree
        will be walked to find operators acting on states symbolically.
    options : dict
        A dict of key/value pairs that determine how the operator actions
        are carried out.

        The following options are valid:

        * ``dagger``: try to apply Dagger operators to the left
          (default: False).
        * ``ip_doit``: call ``.doit()`` in inner products when they are
          encountered (default: True).

    Returns
    =======

    e : Expr
        The original expression, but with the operators applied to states.
    """
    from sympy.physics.quantum.density import Density

    dagger = options.get('dagger', False)

    if e == 0:
        return S.Zero

    # This may be a bit aggressive but ensures that everything gets expanded
    # to its simplest form before trying to apply operators. This includes
    # things like (A+B+C)*|a> and A*(|a>+|b>) and all Commutators and
    # TensorProducts. The only problem with this is that if we can't apply
    # all the Operators, we have just expanded everything.
    # TODO: don't expand the scalars in front of each Mul.
    e = e.expand(commutator=True, tensorproduct=True)

    # If we just have a raw ket, return it.
    if isinstance(e, KetBase):
        return e

    # We have an Add(a, b, c, ...) and compute
    # Add(qapply(a), qapply(b), ...)
    elif isinstance(e, Add):
        result = 0
        for arg in e.args:
            result += qapply(arg, **options)
        return result

    # For a Density operator call qapply on its state
    elif isinstance(e, Density):
        new_args = [(qapply(state, **options), prob) for (state,
                     prob) in e.args]
        return Density(*new_args)

    # For a raw TensorProduct, call qapply on its args.
    elif isinstance(e, TensorProduct):
        return TensorProduct(*[qapply(t, **options) for t in e.args])

    # For a Pow, call qapply on its base.
    elif isinstance(e, Pow):
        return qapply(e.base, **options)**e.exp

    # We have a Mul where there might be actual operators to apply to kets.
    elif isinstance(e, Mul):
        result = qapply_Mul(e, **options)
        if result == e and dagger:
            return Dagger(qapply_Mul(Dagger(e), **options))
        else:
            return result

    # In all other cases (State, Operator, Pow, Commutator, InnerProduct,
    # OuterProduct) we won't ever have operators to apply to kets.
    else:
        return e
def qapply ( e , * * options ) : from sympy . physics . quantum . density import Density dagger = options . get ( 'dagger' , False ) if e == 0 : return S . Zero # This may be a bit aggressive but ensures that everything gets expanded # to its simplest form before trying to apply operators. This includes # things like (A+B+C)*|a> and A*(|a>+|b>) and all Commutators and # TensorProducts. The only problem with this is that if we can't apply # all the Operators, we have just expanded everything. # TODO: don't expand the scalars in front of each Mul. e = e . expand ( commutator = True , tensorproduct = True ) # If we just have a raw ket, return it. if isinstance ( e , KetBase ) : return e # We have an Add(a, b, c, ...) and compute # Add(qapply(a), qapply(b), ...) elif isinstance ( e , Add ) : result = 0 for arg in e . args : result += qapply ( arg , * * options ) return result # For a Density operator call qapply on its state elif isinstance ( e , Density ) : new_args = [ ( qapply ( state , * * options ) , prob ) for ( state , prob ) in e . args ] return Density ( * new_args ) # For a raw TensorProduct, call qapply on its args. elif isinstance ( e , TensorProduct ) : return TensorProduct ( * [ qapply ( t , * * options ) for t in e . args ] ) # For a Pow, call qapply on its base. elif isinstance ( e , Pow ) : return qapply ( e . base , * * options ) ** e . exp # We have a Mul where there might be actual operators to apply to kets. elif isinstance ( e , Mul ) : result = qapply_Mul ( e , * * options ) if result == e and dagger : return Dagger ( qapply_Mul ( Dagger ( e ) , * * options ) ) else : return result # In all other cases (State, Operator, Pow, Commutator, InnerProduct, # OuterProduct) we won't ever have operators to apply to kets. else : return e