(a, d, DE, z=None)
return True
There exists a v in K(x)* such that f = dv/v
    where f a rational function if and only if f can be written as f = A/D
    where D is squarefree,deg(A) < deg(D), gcd(A, D) = 1,
    and all the roots of the Rothstein-Trager resultant are integers. In that case,
    any of the Rothstein-Trager, Lazard-Rioboo-Trager or Czichowski algorithm
    produces u in K(x) such that du/dx = uf.
There exists a v in K(x)* such that f = dv/v
    where f a rational function if and only if f can be written as f = A/D
    where D is squarefree,deg(A) < deg(D), gcd(A, D) = 1,
    and all the roots of the Rothstein-Trager resultant are integers. In that case,
    any of the Rothstein-Trager, Lazard-Rioboo-Trager or Czichowski algorithm
    produces u in K(x) such that du/dx = uf.
There exists a v in K ( x ) * such that f = dv / v where f a rational function if and only if f can be written as f = A / D where D is squarefree deg ( A ) < deg ( D ) gcd ( A D ) = 1 and all the roots of the Rothstein - Trager resultant are integers . In that case any of the Rothstein - Trager Lazard - Rioboo - Trager or Czichowski algorithm produces u in K ( x ) such that du / dx = uf .
def recognize_log_derivative(a, d, DE, z=None):
    """
    There exists a v in K(x)* such that f = dv/v
    where f a rational function if and only if f can be written as f = A/D
    where D is squarefree,deg(A) < deg(D), gcd(A, D) = 1,
    and all the roots of the Rothstein-Trager resultant are integers. In that case,
    any of the Rothstein-Trager, Lazard-Rioboo-Trager or Czichowski algorithm
    produces u in K(x) such that du/dx = uf.
    """

    z = z or Dummy('z')
    a, d = a.cancel(d, include=True)
    p, a = a.div(d)

    pz = Poly(z, DE.t)
    Dd = derivation(d, DE)
    q = a - pz*Dd
    r, R = d.resultant(q, includePRS=True)
    r = Poly(r, z)
    Np, Sp = splitfactor_sqf(r, DE, coefficientD=True, z=z)

    for s, i in Sp:
        # TODO also consider the complex roots
        # incase we have complex roots it should turn the flag false
        a = real_roots(s.as_poly(z))

        if any(not j.is_Integer for j in a):
            return False
    return True
def recognize_log_derivative ( a , d , DE , z = None ) : z = z or Dummy ( 'z' ) a , d = a . cancel ( d , include = True ) p , a = a . div ( d ) pz = Poly ( z , DE . t ) Dd = derivation ( d , DE ) q = a - pz * Dd r , R = d . resultant ( q , includePRS = True ) r = Poly ( r , z ) Np , Sp = splitfactor_sqf ( r , DE , coefficientD = True , z = z ) for s , i in Sp : # TODO also consider the complex roots # incase we have complex roots it should turn the flag false a = real_roots ( s . as_poly ( z ) ) if any ( not j . is_Integer for j in a ) : return False return True