'Performs a change of variables from `x` to `u` using the relationship
given by `x` and `u` which will define the transformations `f` and `F`
(which are inverses of each other) as follows:
1) If `x` is a Symbol (which is a variable of integration) then `u`
will be interpreted as some function, f(u), with inverse F(u).
This, in effect, just makes the substitution of x with f(x).
2) If `u` is a Symbol then `x` will be interpreted as some function,
F(x), with inverse f(u). This is commonly referred to as
u-substitution.
Once f and F have been identified, the transformation is made as
follows:
.. math:: \int_a^b x \mathrm{d}x \rightarrow \int_{F(a)}^{F(b)} f(x)
\frac{\mathrm{d}}{\mathrm{d}x}
where `F(x)` is the inverse of `f(x)` and the limits and integrand have
been corrected so as to retain the same value after integration.
Notes
The mappings, F(x) or f(u), must lead to a unique integral. Linear
or rational linear expression, `2*x`, `1/x` and `sqrt(x)`, will
always work; quadratic expressions like `x**2 - 1` are acceptable
as long as the resulting integrand does not depend on the sign of
the solutions (see examples).
The integral will be returned unchanged if `x` is not a variable of
integration.
`x` must be (or contain) only one of of the integration variables. If
`u` has more than one free symbol then it should be sent as a tuple
(`u`, `uvar`) where `uvar` identifies which variable is replacing
the integration variable.
XXX can it contain another integration variable?
Examples
>>> from sympy.abc import a, b, c, d, x, u, y
>>> from sympy import Integral, S, cos, sqrt
>>> i = Integral(x*cos(x**2 - 1), (x, 0, 1))
transform can change the variable of integration
>>> i.transform(x, u)
Integral(u*cos(u**2 - 1), (u, 0, 1))
transform can perform u-substitution as long as a unique
integrand is obtained:
>>> i.transform(x**2 - 1, u)
Integral(cos(u)/2, (u, -1, 0))
This attempt fails because x = +/-sqrt(u + 1) and the
sign does not cancel out of the integrand:
>>> Integral(cos(x**2 - 1), (x, 0, 1)).transform(x**2 - 1, u)
Traceback (most recent call last):
ValueError:
The mapping between F(x) and f(u) did not give a unique integrand.
transform can do a substitution. Here, the previous
result is transformed back into the original expression
using "u-substitution":
>>> ui = _
>>> _.transform(sqrt(u + 1), x) == i
True
We can accomplish the same with a regular substitution:
>>> ui.transform(u, x**2 - 1) == i
True
If the `x` does not contain a symbol of integration then
the integral will be returned unchanged. Integral `i` does
not have an integration variable `a` so no change is made:
>>> i.transform(a, x) == i
True
When `u` has more than one free symbol the symbol that is
replacing `x` must be identified by passing `u` as a tuple:
>>> Integral(x, (x, 0, 1)).transform(x, (u + a, u))
Integral(a + u, (u, -a, -a + 1))
>>> Integral(x, (x, 0, 1)).transform(x, (u + a, a))
Integral(a + u, (a, -u, -u + 1))
See Also
variables : Lists the integration variables
as_dummy : Replace integration variables with dummy ones'

def transform(self, x, u):

    from sympy.solvers.solvers import solve, posify
    d = Dummy('d')
    xfree = x.free_symbols.intersection(self.variables)
    if (len(xfree) > 1):
        raise ValueError(('F(x)    can    only    contain    one    of:    %s' % self.variables))
    xvar = (xfree.pop() if xfree else d)
    if (xvar not in self.variables):
        return self
    u = sympify(u)
    if isinstance(u, Expr):
        ufree = u.free_symbols
        if (len(ufree) != 1):
            raise ValueError(filldedent('\n                                                                When    f(u)    has    more    than    one    free    symbol,    the    one    replacing    x\n                                                                must    be    identified:    pass    f(u)    as    (f(u),    u)'))
        uvar = ufree.pop()
    else:
        (u, uvar) = u
        if (uvar not in u.free_symbols):
            raise ValueError(filldedent("\n                                                                Expecting    a    tuple    (expr,    symbol)    where    symbol    identified\n                                                                a    free    symbol    in    expr,    but    symbol    is    not    in    expr's    free\n                                                                symbols."))
        if (not isinstance(uvar, Symbol)):
            raise ValueError(filldedent(("\n                                                                Expecting    a    tuple    (expr,    symbol)    but    didn't    get\n                                                                a    symbol;    got    %s" % uvar)))
    if (x.is_Symbol and u.is_Symbol):
        return self.xreplace({x: u})
    if ((not x.is_Symbol) and (not u.is_Symbol)):
        raise ValueError('either    x    or    u    must    be    a    symbol')
    if (uvar == xvar):
        return self.transform(x, (u.subs(uvar, d), d)).xreplace({d: uvar})
    if (uvar in self.limits):
        raise ValueError(filldedent('\n                                                u    must    contain    the    same    variable    as    in    x\n                                                or    a    variable    that    is    not    already    an    integration    variable'))
    if (not x.is_Symbol):
        F = [x.subs(xvar, d)]
        soln = solve((u - x), xvar, check=False)
        if (not soln):
            raise ValueError('no    solution    for    solve(F(x)    -    f(u),    x)')
        f = [fi.subs(uvar, d) for fi in soln]
    else:
        f = [u.subs(uvar, d)]
        (pdiff, reps) = posify((u - x))
        puvar = uvar.subs([(v, k) for (k, v) in reps.items()])
        soln = [s.subs(reps) for s in solve(pdiff, puvar)]
        if (not soln):
            raise ValueError('no    solution    for    solve(F(x)    -    f(u),    u)')
        F = [fi.subs(xvar, d) for fi in soln]
    newfuncs = set([(self.function.subs(xvar, fi) * fi.diff(d)).subs(d, uvar) for fi in f])
    if (len(newfuncs) > 1):
        raise ValueError(filldedent('\n                                                The    mapping    between    F(x)    and    f(u)    did    not    give\n                                                a    unique    integrand.'))
    newfunc = newfuncs.pop()
    def _calc_limit_1(F, a, b):
        '\n                                                replace    d    with    a,    using    subs    if    possible,    otherwise    limit\n                                                where    sign    of    b    is    considered\n                                                '
        wok = F.subs(d, a)
        if ((wok is S.NaN) or ((wok.is_finite is False) and a.is_finite)):
            return limit((sign(b) * F), d, a)
        return wok
    def _calc_limit(a, b):
        '\n                                                replace    d    with    a,    using    subs    if    possible,    otherwise    limit\n                                                where    sign    of    b    is    considered\n                                                '
        avals = list({_calc_limit_1(Fi, a, b) for Fi in F})
        if (len(avals) > 1):
            raise ValueError(filldedent('\n                                                                The    mapping    between    F(x)    and    f(u)    did    not\n                                                                give    a    unique    limit.'))
        return avals[0]
    newlimits = []
    for xab in self.limits:
        sym = xab[0]
        if (sym == xvar):
            if (len(xab) == 3):
                (a, b) = xab[1:]
                (a, b) = (_calc_limit(a, b), _calc_limit(b, a))
                if ((a - b) > 0):
                    (a, b) = (b, a)
                    newfunc = (- newfunc)
                newlimits.append((uvar, a, b))
            elif (len(xab) == 2):
                a = _calc_limit(xab[1], 1)
                newlimits.append((uvar, a))
            else:
                newlimits.append(uvar)
        else:
            newlimits.append(xab)
    return self.func(newfunc, *newlimits)
