'Tries to build a transcendental extension tower from f with respect to x.
If it is successful, creates a DifferentialExtension object with, among
others, the attributes fa, fd, D, T, Tfuncs, and backsubs such that
fa and fd are Polys in T[-1] with rational coefficients in T[:-1],
fa/fd == f, and D[i] is a Poly in T[i] with rational coefficients in
T[:i] representing the derivative of T[i] for each i from 1 to len(T).
Tfuncs is a list of Lambda objects for back replacing the functions
after integrating.  Lambda() is only used (instead of lambda) to make
them easier to test and debug. Note that Tfuncs corresponds to the
elements of T, except for T[0] == x, but they should be back-substituted
in reverse order.  backsubs is a (possibly empty) back-substitution list
that should be applied on the completed integral to make it look more
like the original integrand.
If it is unsuccessful, it raises NotImplementedError.
You can also create an object by manually setting the attributes as a
dictionary to the extension keyword argument.  You must include at least
D.  Warning, any attribute that is not given will be set to None. The
attributes T, t, d, cases, case, x, and level are set automatically and
do not need to be given.  The functions in the Risch Algorithm will NOT
check to see if an attribute is None before using it.  This also does not
check to see if the extension is valid (non-algebraic) or even if it is
self-consistent.  Therefore, this should only be used for
testing/debugging purposes.'

def __init__(self, f=None, x=None, handle_first='log', dummy=False, extension=None, rewrite_complex=False):

    if extension:
        if ('D' not in extension):
            raise ValueError('At    least    the    key    D    must    be    included    with    the    extension    flag    to    DifferentialExtension.')
        for attr in extension:
            setattr(self, attr, extension[attr])
        self._auto_attrs()
        return
    elif ((f is None) or (x is None)):
        raise ValueError('Either    both    f    and    x    or    a    manual    extension    must    be    given.')
    if (handle_first not in ['log', 'exp']):
        raise ValueError(("handle_first    must    be    'log'    or    'exp',    not    %s." % str(handle_first)))
    self.f = f
    self.x = x
    self.dummy = dummy
    self.reset()
    (exp_new_extension, log_new_extension) = (True, True)
    if rewrite_complex:
        rewritables = {(sin, cos, cot, tan, sinh, cosh, coth, tanh): exp, (asin, acos, acot, atan): log}
        for (candidates, rule) in rewritables.items():
            self.newf = self.newf.rewrite(candidates, rule)
    elif any((i.has(x) for i in self.f.atoms(sin, cos, tan, atan, asin, acos))):
        raise NotImplementedError('Trigonometric    extensions    are    not    supported    (yet!)')
    exps = set()
    pows = set()
    numpows = set()
    sympows = set()
    logs = set()
    symlogs = set()
    while True:
        if self.newf.is_rational_function(*self.T):
            break
        if ((not exp_new_extension) and (not log_new_extension)):
            raise NotImplementedError((("Couldn't    find    an    elementary    transcendental    extension    for    %s.        Try    using    a    " % str(f)) + 'manual    extension    with    the    extension    flag.'))
        (exps, pows, numpows, sympows, log_new_extension) = self._rewrite_exps_pows(exps, pows, numpows, sympows, log_new_extension)
        (logs, symlogs) = self._rewrite_logs(logs, symlogs)
        if ((handle_first == 'exp') or (not log_new_extension)):
            exp_new_extension = self._exp_part(exps)
            if (exp_new_extension is None):
                self.f = self.newf
                self.reset()
                exp_new_extension = True
                continue
        if ((handle_first == 'log') or (not exp_new_extension)):
            log_new_extension = self._log_part(logs)
    (self.fa, self.fd) = frac_in(self.newf, self.t)
    self._auto_attrs()
    return
