(rv, first=True)
return bottom_up(rv, f)
Converting products of ``cos`` and/or ``sin`` to a sum or
    difference of ``cos`` and or ``sin`` terms.

    Examples
    ========

    >>> from sympy.simplify.fu import TR8, TR7
    >>> from sympy import cos, sin
    >>> TR8(cos(2)*cos(3))
    cos(5)/2 + cos(1)/2
    >>> TR8(cos(2)*sin(3))
    sin(5)/2 + sin(1)/2
    >>> TR8(sin(2)*sin(3))
    -cos(5)/2 + cos(1)/2
Converting products of ``cos`` and/or ``sin`` to a sum or
    difference of ``cos`` and or ``sin`` terms.
Converting products of cos and / or sin to a sum or difference of cos and or sin terms .
def TR8(rv, first=True):
    """Converting products of ``cos`` and/or ``sin`` to a sum or
    difference of ``cos`` and or ``sin`` terms.

    Examples
    ========

    >>> from sympy.simplify.fu import TR8, TR7
    >>> from sympy import cos, sin
    >>> TR8(cos(2)*cos(3))
    cos(5)/2 + cos(1)/2
    >>> TR8(cos(2)*sin(3))
    sin(5)/2 + sin(1)/2
    >>> TR8(sin(2)*sin(3))
    -cos(5)/2 + cos(1)/2
    """

    def f(rv):
        if not (
            rv.is_Mul or
            rv.is_Pow and
            rv.base.func in (cos, sin) and
            (rv.exp.is_integer or rv.base.is_positive)):
            return rv

        if first:
            n, d = [expand_mul(i) for i in rv.as_numer_denom()]
            newn = TR8(n, first=False)
            newd = TR8(d, first=False)
            if newn != n or newd != d:
                rv = gcd_terms(newn/newd)
                if rv.is_Mul and rv.args[0].is_Rational and \
                        len(rv.args) == 2 and rv.args[1].is_Add:
                    rv = Mul(*rv.as_coeff_Mul())
            return rv

        args = {cos: [], sin: [], None: []}
        for a in ordered(Mul.make_args(rv)):
            if a.func in (cos, sin):
                args[a.func].append(a.args[0])
            elif (a.is_Pow and a.exp.is_Integer and a.exp > 0 and \
                    a.base.func in (cos, sin)):
                # XXX this is ok but pathological expression could be handled
                # more efficiently as in TRmorrie
                args[a.base.func].extend([a.base.args[0]]*a.exp)
            else:
                args[None].append(a)
        c = args[cos]
        s = args[sin]
        if not (c and s or len(c) > 1 or len(s) > 1):
            return rv

        args = args[None]
        n = min(len(c), len(s))
        for i in range(n):
            a1 = s.pop()
            a2 = c.pop()
            args.append((sin(a1 + a2) + sin(a1 - a2))/2)
        while len(c) > 1:
            a1 = c.pop()
            a2 = c.pop()
            args.append((cos(a1 + a2) + cos(a1 - a2))/2)
        if c:
            args.append(cos(c.pop()))
        while len(s) > 1:
            a1 = s.pop()
            a2 = s.pop()
            args.append((-cos(a1 + a2) + cos(a1 - a2))/2)
        if s:
            args.append(sin(s.pop()))
        return TR8(expand_mul(Mul(*args)))

    return bottom_up(rv, f)
def TR8 ( rv , first = True ) : def f ( rv ) : if not ( rv . is_Mul or rv . is_Pow and rv . base . func in ( cos , sin ) and ( rv . exp . is_integer or rv . base . is_positive ) ) : return rv if first : n , d = [ expand_mul ( i ) for i in rv . as_numer_denom ( ) ] newn = TR8 ( n , first = False ) newd = TR8 ( d , first = False ) if newn != n or newd != d : rv = gcd_terms ( newn / newd ) if rv . is_Mul and rv . args [ 0 ] . is_Rational and len ( rv . args ) == 2 and rv . args [ 1 ] . is_Add : rv = Mul ( * rv . as_coeff_Mul ( ) ) return rv args = { cos : [ ] , sin : [ ] , None : [ ] } for a in ordered ( Mul . make_args ( rv ) ) : if a . func in ( cos , sin ) : args [ a . func ] . append ( a . args [ 0 ] ) elif ( a . is_Pow and a . exp . is_Integer and a . exp > 0 and a . base . func in ( cos , sin ) ) : # XXX this is ok but pathological expression could be handled # more efficiently as in TRmorrie args [ a . base . func ] . extend ( [ a . base . args [ 0 ] ] * a . exp ) else : args [ None ] . append ( a ) c = args [ cos ] s = args [ sin ] if not ( c and s or len ( c ) > 1 or len ( s ) > 1 ) : return rv args = args [ None ] n = min ( len ( c ) , len ( s ) ) for i in range ( n ) : a1 = s . pop ( ) a2 = c . pop ( ) args . append ( ( sin ( a1 + a2 ) + sin ( a1 - a2 ) ) / 2 ) while len ( c ) > 1 : a1 = c . pop ( ) a2 = c . pop ( ) args . append ( ( cos ( a1 + a2 ) + cos ( a1 - a2 ) ) / 2 ) if c : args . append ( cos ( c . pop ( ) ) ) while len ( s ) > 1 : a1 = s . pop ( ) a2 = s . pop ( ) args . append ( ( - cos ( a1 + a2 ) + cos ( a1 - a2 ) ) / 2 ) if s : args . append ( sin ( s . pop ( ) ) ) return TR8 ( expand_mul ( Mul ( * args ) ) ) return bottom_up ( rv , f )