#NEWLINE# def is_deriv_k( fa , fd , DE ) : #NEWLINE# #INDENT# '\n    Checks if Df/f is the derivative of an element of k(t).\n\n    a in k(t) is the derivative of an element of k(t) if there exists b in k(t)\n    such that a = Db.  Either returns (ans, u), such that Df/f == Du, or None,\n    which means that Df/f is not the derivative of an element of k(t).  ans is\n    a list of tuples such that Add(*[i*j for i, j in ans]) == u.  This is useful\n    for seeing exactly which elements of k(t) produce u.\n\n    This function uses the structure theorem approach, which says that for any\n    f in K, Df/f is the derivative of a element of K if and only if there are ri\n    in QQ such that::\n\n            ---               ---       Dt\n            \\    r  * Dt   +  \\    r  *   i      Df\n            /     i     i     /     i   ---   =  --.\n            ---               ---        t        f\n         i in L            i in E         i\n               K/C(x)            K/C(x)\n\n\n    Where C = Const(K), L_K/C(x) = { i in {1, ..., n} such that t_i is\n    transcendental over C(x)(t_1, ..., t_i-1) and Dt_i = Da_i/a_i, for some a_i\n    in C(x)(t_1, ..., t_i-1)* } (i.e., the set of all indices of logarithmic\n    monomials of K over C(x)), and E_K/C(x) = { i in {1, ..., n} such that t_i\n    is transcendental over C(x)(t_1, ..., t_i-1) and Dt_i/t_i = Da_i, for some\n    a_i in C(x)(t_1, ..., t_i-1) } (i.e., the set of all indices of\n    hyperexponential monomials of K over C(x)).  If K is an elementary extension\n    over C(x), then the cardinality of L_K/C(x) U E_K/C(x) is exactly the\n    transcendence degree of K over C(x).  Furthermore, because Const_D(K) ==\n    Const_D(C(x)) == C, deg(Dt_i) == 1 when t_i is in E_K/C(x) and\n    deg(Dt_i) == 0 when t_i is in L_K/C(x), implying in particular that E_K/C(x)\n    and L_K/C(x) are disjoint.\n\n    The sets L_K/C(x) and E_K/C(x) must, by their nature, be computed\n    recursively using this same function.  Therefore, it is required to pass\n    them as indices to D (or T).  E_args are the arguments of the\n    hyperexponentials indexed by E_K (i.e., if i is in E_K, then T[i] ==\n    exp(E_args[i])).  This is needed to compute the final answer u such that\n    Df/f == Du.\n\n    log(f) will be the same as u up to a additive constant.  This is because\n    they will both behave the same as monomials. For example, both log(x) and\n    log(2*x) == log(x) + log(2) satisfy Dt == 1/x, because log(2) is constant.\n    Therefore, the term const is returned.  const is such that\n    log(const) + f == u.  This is calculated by dividing the arguments of one\n    logarithm from the other.  Therefore, it is necessary to pass the arguments\n    of the logarithmic terms in L_args.\n\n    To handle the case where we are given Df/f, not f, use is_deriv_k_in_field().\n    ' #NEWLINE# ( dfa , dfd ) = ( ( fd * ( ( fd * derivation ( fa , DE ) ) - ( fa * derivation ( fd , DE ) ) ) ) , ( ( fd ** 2 ) * fa ) ) #NEWLINE# ( dfa , dfd ) = dfa . cancel ( dfd , include = True ) #NEWLINE# if ( ( len ( DE . L_K ) + len ( DE . E_K ) ) != ( len ( DE . D ) - 1 ) ) : #NEWLINE# #INDENT# if ( [ i for i in DE . cases if ( i == 'tan' ) ] or ( set ( [ i for i in DE . cases if ( i == 'primitive' ) ] ) - set ( DE . L_K ) ) ) : #NEWLINE# #INDENT# raise NotImplementedError ( 'Real version of the structure theorems with hypertangent support is not yet implemented.' ) #NEWLINE# #UNINDENT# raise NotImplementedError ( 'Nonelementary extensions not supported in the structure theorems.' ) #NEWLINE# #UNINDENT# E_part = [ DE . D [ i ] . quo ( Poly ( DE . T [ i ] , DE . T [ i ] ) ) . as_expr ( ) for i in DE . E_K ] #NEWLINE# L_part = [ DE . D [ i ] . as_expr ( ) for i in DE . L_K ] #NEWLINE# lhs = Matrix ( [ ( E_part + L_part ) ] ) #NEWLINE# rhs = Matrix ( [ ( dfa . as_expr ( ) / dfd . as_expr ( ) ) ] ) #NEWLINE# ( A , u ) = constant_system ( lhs , rhs , DE ) #NEWLINE# if ( ( not all ( ( derivation ( i , DE , basic = True ) . is_zero for i in u ) ) ) or ( not A ) ) : #NEWLINE# #INDENT# return None #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if ( not all ( ( i . is_Rational for i in u ) ) ) : #NEWLINE# #INDENT# raise NotImplementedError ( 'Cannot work with non-rational coefficients in this case.' ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# terms = ( DE . E_args + [ DE . T [ i ] for i in DE . L_K ] ) #NEWLINE# ans = list ( zip ( terms , u ) ) #NEWLINE# result = Add ( * [ Mul ( i , j ) for ( i , j ) in ans ] ) #NEWLINE# argterms = ( [ DE . T [ i ] for i in DE . E_K ] + DE . L_args ) #NEWLINE# l = [ ] #NEWLINE# ld = [ ] #NEWLINE# for ( i , j ) in zip ( argterms , u ) : #NEWLINE# #INDENT# ( i , d ) = i . as_numer_denom ( ) #NEWLINE# ( icoeff , iterms ) = sqf_list ( i ) #NEWLINE# l . append ( Mul ( * ( [ Pow ( icoeff , j ) ] + [ Pow ( b , ( e * j ) ) for ( b , e ) in iterms ] ) ) ) #NEWLINE# ( dcoeff , dterms ) = sqf_list ( d ) #NEWLINE# ld . append ( Mul ( * ( [ Pow ( dcoeff , j ) ] + [ Pow ( b , ( e * j ) ) for ( b , e ) in dterms ] ) ) ) #NEWLINE# #UNINDENT# const = cancel ( ( ( ( fa . as_expr ( ) / fd . as_expr ( ) ) / Mul ( * l ) ) * Mul ( * ld ) ) ) #NEWLINE# return ( ans , result , const )