def test_unrad(): s = symbols('s', cls=Dummy) # checkers to deal with possibility of answer coming # back with a sign change (cf issue 2104) def check(rv, ans): rv, ans = list(rv), list(ans) rv[0] = rv[0].expand() ans[0] = ans[0].expand() return rv[0] in [ans[0], -ans[0]] and rv[1:] == ans[1:] def s_check(rv, ans): # get the dummy rv = list(rv) d = rv[0].atoms(Dummy) reps = zip(d, [s]*len(d)) # replace s with this dummy rv = (rv[0].subs(reps).expand(), [(p[0].subs(reps), p[1].subs(reps)) for p in rv[1]], [a.subs(reps) for a in rv[2]]) ans = (ans[0].subs(reps).expand(), [(p[0].subs(reps), p[1].subs(reps)) for p in ans[1]], [a.subs(reps) for a in ans[2]]) return str(rv[0]) in [str(ans[0]), str(-ans[0])] and \ str(rv[1:]) == str(ans[1:]) assert check(unrad(sqrt(x)), (x, [], [])) assert check(unrad(sqrt(x) + 1), (x - 1, [], [])) assert s_check(unrad(sqrt(x) + x**Rational(1, 3) + 2), (2 + s**2 + s**3, [(s, x - s**6)], [])) assert check(unrad(sqrt(x)*x**Rational(1, 3) + 2), (x**5 - 64, [], [])) assert check(unrad(sqrt(x) + (x + 1)**Rational(1, 3)), (x**3 - (x + 1)**2, [], [])) assert check(unrad(sqrt(x) + sqrt(x + 1) + sqrt(2*x)), (-2*sqrt(2)*x - 2*x + 1, [], [])) assert check(unrad(sqrt(x) + sqrt(x + 1) + 2), (16*x - 9, [], [])) assert check(unrad(sqrt(x) + sqrt(x + 1) + sqrt(1 - x)), (-4*x + 5*x**2, [], [])) assert check(unrad(a*sqrt(x) + b*sqrt(x) + c*sqrt(y) + d*sqrt(y)), ((a*sqrt(x) + b*sqrt(x))**2 - (c*sqrt(y) + d*sqrt(y))**2, [], [])) assert check(unrad(sqrt(x) + sqrt(1 - x)), (2*x - 1, [], [])) assert check(unrad(sqrt(x) + sqrt(1 - x) - 3), (9*x + (x - 5)**2 - 9, [], [])) assert check(unrad(sqrt(x) + sqrt(1 - x) + sqrt(2 + x)), (-5*x**2 + 2*x - 1, [], [])) assert check(unrad(sqrt(x) + sqrt(1 - x) + sqrt(2 + x) - 3), (-25*x**4 - 376*x**3 - 1256*x**2 + 2272*x - 784, [], [])) assert check(unrad(sqrt(x) + sqrt(1 - x) + sqrt(2 + x) - sqrt(1 - 2*x)), (-41*x**4 - 40*x**3 - 232*x**2 + 160*x - 16, [], [])) assert check(unrad(sqrt(x) + sqrt(x + 1)), (S(1), [], [])) eq = sqrt(x) + sqrt(x + 1) + sqrt(1 - sqrt(x)) assert check(unrad(eq), (16*x**3 - 9*x**2, [], [])) assert set(solve(eq, check=False)) == set([S(0), S(9)/16]) assert solve(eq) == [] # but this one really does have those solutions assert set(solve(sqrt(x) - sqrt(x + 1) + sqrt(1 - sqrt(x)))) == \ set([S.Zero, S(9)/16]) '''NOTE real_root changes the value of the result if the solution is simplified; `a` in the text below is the root that is not 4/5: >>> eq sqrt(x) + sqrt(-x + 1) + sqrt(x + 1) - 6*sqrt(5)/5 >>> eq.subs(x, a).n() -0.e-123 + 0.e-127*I >>> real_root(eq.subs(x, a)).n() -0.e-123 + 0.e-127*I >>> (eq.subs(x,simplify(a))).n() -0.e-126 >>> real_root(eq.subs(x, simplify(a))).n() 0.194825975605452 + 2.15093623885838*I >>> sqrt(x).subs(x, real_root(a)).n() 0.809823827278194 - 0.e-25*I >>> sqrt(x).subs(x, (a)).n() 0.809823827278194 - 0.e-25*I >>> sqrt(x).subs(x, simplify(a)).n() 0.809823827278194 - 5.32999467690853e-25*I >>> sqrt(x).subs(x, real_root(simplify(a))).n() 0.49864610868139 + 1.44572604257047*I ''' eq = (sqrt(x) + sqrt(x + 1) + sqrt(1 - x) - 6*sqrt(5)/5) ra = S('''-1484/375 - 4*(-1/2 + sqrt(3)*I/2)*(-12459439/52734375 + 114*sqrt(12657)/78125)**(1/3) - 172564/(140625*(-1/2 + sqrt(3)*I/2)*(-12459439/52734375 + 114*sqrt(12657)/78125)**(1/3))''') rb = S(4)/5 ans = solve(sqrt(x) + sqrt(x + 1) + sqrt(1 - x) - 6*sqrt(5)/5) assert all(abs(eq.subs(x, i).n()) < 1e-10 for i in (ra, rb)) and \ len(ans) == 2 and \ set([i.n(chop=True) for i in ans]) == \ set([i.n(chop=True) for i in (ra, rb)]) raises(ValueError, lambda: unrad(-root(x,3)**2 + 2**pi*root(x,3) - x + 2**pi)) raises(ValueError, lambda: unrad(sqrt(x) + sqrt(x + 1) + sqrt(1 - sqrt(x)) + 3)) raises(ValueError, lambda: unrad(sqrt(x) + (x + 1)**Rational(1, 3) + 2*sqrt(y))) # same as last but consider only y assert check(unrad(sqrt(x) + (x + 1)**Rational(1, 3) + 2*sqrt(y), y), (4*y - (sqrt(x) + (x + 1)**(S(1)/3))**2, [], [])) assert check(unrad(sqrt(x/(1 - x)) + (x + 1)**Rational(1, 3)), (x**3/(-x + 1)**3 - (x + 1)**2, [], [(-x + 1)**3])) # same as last but consider only y; no y-containing denominators now assert s_check(unrad(sqrt(x/(1 - x)) + 2*sqrt(y), y), (x/(-x + 1) - 4*y, [], [])) assert check(unrad(sqrt(x)*sqrt(1 - x) + 2, x), (x*(-x + 1) - 4, [], [])) # http://tutorial.math.lamar.edu/ # Classes/Alg/SolveRadicalEqns.aspx#Solve_Rad_Ex2_a assert solve(Eq(x, sqrt(x + 6))) == [3] assert solve(Eq(x + sqrt(x - 4), 4)) == [4] assert solve(Eq(1, x + sqrt(2*x - 3))) == [] assert set(solve(Eq(sqrt(5*x + 6) - 2, x))) == set([-S(1), S(2)]) assert set(solve(Eq(sqrt(2*x - 1) - sqrt(x - 4), 2))) == set([S(5), S(13)]) assert solve(Eq(sqrt(x + 7) + 2, sqrt(3 - x))) == [-6] # http://www.purplemath.com/modules/solverad.htm assert solve((2*x - 5)**Rational(1, 3) - 3) == [16] assert solve((x**3 - 3*x**2)**Rational(1, 3) + 1 - x) == [] assert set(solve(x + 1 - (x**4 + 4*x**3 - x)**Rational(1, 4))) == \ set([-S(1)/2, -S(1)/3]) assert set(solve(sqrt(2*x**2 - 7) - (3 - x))) == set([-S(8), S(2)]) assert solve(sqrt(2*x + 9) - sqrt(x + 1) - sqrt(x + 4)) == [0] assert solve(sqrt(x + 4) + sqrt(2*x - 1) - 3*sqrt(x - 1)) == [5] assert solve(sqrt(x)*sqrt(x - 7) - 12) == [16] assert solve(sqrt(x - 3) + sqrt(x) - 3) == [4] assert solve(sqrt(9*x**2 + 4) - (3*x + 2)) == [0] assert solve(sqrt(x) - 2 - 5) == [49] assert solve(sqrt(x - 3) - sqrt(x) - 3) == [] assert solve(sqrt(x - 1) - x + 7) == [10] assert solve(sqrt(x - 2) - 5) == [27] assert solve(sqrt(17*x - sqrt(x**2 - 5)) - 7) == [3] assert solve(sqrt(x) - sqrt(x - 1) + sqrt(sqrt(x))) == [] # don't posify the expression in unrad and use _mexpand z = sqrt(2*x + 1)/sqrt(x) - sqrt(2 + 1/x) p = posify(z)[0] assert solve(p) == [] assert solve(z) == [] assert solve(z + 6*I) == [-S(1)/11] assert solve(p + 6*I) == [] eq = sqrt(2 + I) + 2*I assert unrad(eq - x, x, all=True) == (x**4 + 4*x**2 + 8*x + 37, [], []) ans = (81*x**8 - 2268*x**6 - 4536*x**5 + 22644*x**4 + 63216*x**3 - 31608*x**2 - 189648*x + 141358, [], []) r = sqrt(sqrt(2)/3 + 7) eq = sqrt(r) + r - x assert unrad(eq, all=1) r2 = sqrt(sqrt(2) + 21)/sqrt(3) assert r != r2 and r.equals(r2) assert unrad(eq - r + r2, all=True) == ans
def transform(self, x, u, inverse=False): r""" 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. The `inverse` option will reverse `x` and `u`. It is a deprecated option since `x` and `u` can just be passed in reverse order. 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 """ if inverse: # when this is removed, update the docstring from sympy.utilities.exceptions import SymPyDeprecationWarning SymPyDeprecationWarning( feature="transform(x, f(x), inverse=True)", useinstead="transform(f(x), x)", issue=3380, deprecated_since_version="0.7.2", ).warn() # in the old style x and u contained the same variable so # don't worry about using the old-style feature with the # new style input...but it will still work: # i.transform(x, u).transform(x, u, inverse=True) -> i x, u = u, x 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(''' When f(u) has more than one free symbol, the one replacing x 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(''' Expecting a tuple (expr, symbol) where symbol identified a free symbol in expr, but symbol is not in expr's free symbols.''')) if not isinstance(uvar, Symbol): raise ValueError(filldedent(''' Expecting a tuple (expr, symbol) but didn't get 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)).xreplace({d: uvar}) if uvar in self.limits: raise ValueError(filldedent(''' u must contain the same variable as in x 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(''' The mapping between F(x) and f(u) did not give a unique integrand.''')) newfunc = newfuncs.pop() def _calc_limit_1(F, a, b): """ replace d with a, using subs if possible, otherwise limit where sign of b is considered """ wok = F.subs(d, a) if wok is S.NaN or wok.is_bounded is False and a.is_bounded: return limit(sign(b)*F, d, a) return wok def _calc_limit(a, b): """ replace d with a, using subs if possible, otherwise limit where sign of b is considered """ avals = list(set([_calc_limit_1(Fi, a, b) for Fi in F])) if len(avals) > 1: raise ValueError(filldedent(''' The mapping between F(x) and f(u) did not 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: 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)
def test_unrad(): s = symbols('s', cls=Dummy) # checkers to deal with possibility of answer coming # back with a sign change (cf issue 2104) def check(rv, ans): rv, ans = list(rv), list(ans) rv[0] = rv[0].expand() ans[0] = ans[0].expand() return rv[0] in [ans[0], -ans[0]] and rv[1:] == ans[1:] def s_check(rv, ans): # get the dummy rv = list(rv) d = rv[0].atoms(Dummy) reps = zip(d, [s] * len(d)) # replace s with this dummy rv = (rv[0].subs(reps).expand(), [ (p[0].subs(reps), p[1].subs(reps)) for p in rv[1] ], [a.subs(reps) for a in rv[2]]) ans = (ans[0].subs(reps).expand(), [ (p[0].subs(reps), p[1].subs(reps)) for p in ans[1] ], [a.subs(reps) for a in ans[2]]) return str(rv[0]) in [str(ans[0]), str(-ans[0])] and \ str(rv[1:]) == str(ans[1:]) assert check(unrad(sqrt(x)), (x, [], [])) assert check(unrad(sqrt(x) + 1), (x - 1, [], [])) assert s_check(unrad(sqrt(x) + x**Rational(1, 3) + 2), (2 + s**2 + s**3, [(s, x - s**6)], [])) assert check(unrad(sqrt(x) * x**Rational(1, 3) + 2), (x**5 - 64, [], [])) assert check(unrad(sqrt(x) + (x + 1)**Rational(1, 3)), (x**3 - (x + 1)**2, [], [])) assert check(unrad(sqrt(x) + sqrt(x + 1) + sqrt(2 * x)), (-2 * sqrt(2) * x - 2 * x + 1, [], [])) assert check(unrad(sqrt(x) + sqrt(x + 1) + 2), (16 * x - 9, [], [])) assert check(unrad(sqrt(x) + sqrt(x + 1) + sqrt(1 - x)), (-4 * x + 5 * x**2, [], [])) assert check(unrad(a * sqrt(x) + b * sqrt(x) + c * sqrt(y) + d * sqrt(y)), ((a * sqrt(x) + b * sqrt(x))**2 - (c * sqrt(y) + d * sqrt(y))**2, [], [])) assert check(unrad(sqrt(x) + sqrt(1 - x)), (2 * x - 1, [], [])) assert check(unrad(sqrt(x) + sqrt(1 - x) - 3), (9 * x + (x - 5)**2 - 9, [], [])) assert check(unrad(sqrt(x) + sqrt(1 - x) + sqrt(2 + x)), (-5 * x**2 + 2 * x - 1, [], [])) assert check( unrad(sqrt(x) + sqrt(1 - x) + sqrt(2 + x) - 3), (-25 * x**4 - 376 * x**3 - 1256 * x**2 + 2272 * x - 784, [], [])) assert check(unrad(sqrt(x) + sqrt(1 - x) + sqrt(2 + x) - sqrt(1 - 2 * x)), (-41 * x**4 - 40 * x**3 - 232 * x**2 + 160 * x - 16, [], [])) assert check(unrad(sqrt(x) + sqrt(x + 1)), (S(1), [], [])) eq = sqrt(x) + sqrt(x + 1) + sqrt(1 - sqrt(x)) assert check(unrad(eq), (16 * x**3 - 9 * x**2, [], [])) assert set(solve(eq, check=False)) == set([S(0), S(9) / 16]) assert solve(eq) == [] # but this one really does have those solutions assert set(solve(sqrt(x) - sqrt(x + 1) + sqrt(1 - sqrt(x)))) == \ set([S.Zero, S(9)/16]) '''NOTE real_root changes the value of the result if the solution is simplified; `a` in the text below is the root that is not 4/5: >>> eq sqrt(x) + sqrt(-x + 1) + sqrt(x + 1) - 6*sqrt(5)/5 >>> eq.subs(x, a).n() -0.e-123 + 0.e-127*I >>> real_root(eq.subs(x, a)).n() -0.e-123 + 0.e-127*I >>> (eq.subs(x,simplify(a))).n() -0.e-126 >>> real_root(eq.subs(x, simplify(a))).n() 0.194825975605452 + 2.15093623885838*I >>> sqrt(x).subs(x, real_root(a)).n() 0.809823827278194 - 0.e-25*I >>> sqrt(x).subs(x, (a)).n() 0.809823827278194 - 0.e-25*I >>> sqrt(x).subs(x, simplify(a)).n() 0.809823827278194 - 5.32999467690853e-25*I >>> sqrt(x).subs(x, real_root(simplify(a))).n() 0.49864610868139 + 1.44572604257047*I ''' eq = (sqrt(x) + sqrt(x + 1) + sqrt(1 - x) - 6 * sqrt(5) / 5) ra = S('''-1484/375 - 4*(-1/2 + sqrt(3)*I/2)*(-12459439/52734375 + 114*sqrt(12657)/78125)**(1/3) - 172564/(140625*(-1/2 + sqrt(3)*I/2)*(-12459439/52734375 + 114*sqrt(12657)/78125)**(1/3))''') rb = S(4) / 5 ans = solve(sqrt(x) + sqrt(x + 1) + sqrt(1 - x) - 6 * sqrt(5) / 5) assert all(abs(eq.subs(x, i).n()) < 1e-10 for i in (ra, rb)) and \ len(ans) == 2 and \ set([i.n(chop=True) for i in ans]) == \ set([i.n(chop=True) for i in (ra, rb)]) raises(ValueError, lambda: unrad(-root(x, 3)**2 + 2**pi * root(x, 3) - x + 2**pi)) raises(ValueError, lambda: unrad(sqrt(x) + sqrt(x + 1) + sqrt(1 - sqrt(x)) + 3)) raises(ValueError, lambda: unrad(sqrt(x) + (x + 1)**Rational(1, 3) + 2 * sqrt(y))) # same as last but consider only y assert check(unrad(sqrt(x) + (x + 1)**Rational(1, 3) + 2 * sqrt(y), y), (4 * y - (sqrt(x) + (x + 1)**(S(1) / 3))**2, [], [])) assert check(unrad(sqrt(x / (1 - x)) + (x + 1)**Rational(1, 3)), (x**3 / (-x + 1)**3 - (x + 1)**2, [], [(-x + 1)**3])) # same as last but consider only y; no y-containing denominators now assert s_check(unrad(sqrt(x / (1 - x)) + 2 * sqrt(y), y), (x / (-x + 1) - 4 * y, [], [])) assert check(unrad(sqrt(x) * sqrt(1 - x) + 2, x), (x * (-x + 1) - 4, [], [])) # http://tutorial.math.lamar.edu/ # Classes/Alg/SolveRadicalEqns.aspx#Solve_Rad_Ex2_a assert solve(Eq(x, sqrt(x + 6))) == [3] assert solve(Eq(x + sqrt(x - 4), 4)) == [4] assert solve(Eq(1, x + sqrt(2 * x - 3))) == [] assert set(solve(Eq(sqrt(5 * x + 6) - 2, x))) == set([-S(1), S(2)]) assert set(solve(Eq(sqrt(2 * x - 1) - sqrt(x - 4), 2))) == set([S(5), S(13)]) assert solve(Eq(sqrt(x + 7) + 2, sqrt(3 - x))) == [-6] # http://www.purplemath.com/modules/solverad.htm assert solve((2 * x - 5)**Rational(1, 3) - 3) == [16] assert solve((x**3 - 3 * x**2)**Rational(1, 3) + 1 - x) == [] assert set(solve(x + 1 - (x**4 + 4*x**3 - x)**Rational(1, 4))) == \ set([-S(1)/2, -S(1)/3]) assert set(solve(sqrt(2 * x**2 - 7) - (3 - x))) == set([-S(8), S(2)]) assert solve(sqrt(2 * x + 9) - sqrt(x + 1) - sqrt(x + 4)) == [0] assert solve(sqrt(x + 4) + sqrt(2 * x - 1) - 3 * sqrt(x - 1)) == [5] assert solve(sqrt(x) * sqrt(x - 7) - 12) == [16] assert solve(sqrt(x - 3) + sqrt(x) - 3) == [4] assert solve(sqrt(9 * x**2 + 4) - (3 * x + 2)) == [0] assert solve(sqrt(x) - 2 - 5) == [49] assert solve(sqrt(x - 3) - sqrt(x) - 3) == [] assert solve(sqrt(x - 1) - x + 7) == [10] assert solve(sqrt(x - 2) - 5) == [27] assert solve(sqrt(17 * x - sqrt(x**2 - 5)) - 7) == [3] assert solve(sqrt(x) - sqrt(x - 1) + sqrt(sqrt(x))) == [] # don't posify the expression in unrad and use _mexpand z = sqrt(2 * x + 1) / sqrt(x) - sqrt(2 + 1 / x) p = posify(z)[0] assert solve(p) == [] assert solve(z) == [] assert solve(z + 6 * I) == [-S(1) / 11] assert solve(p + 6 * I) == [] eq = sqrt(2 + I) + 2 * I assert unrad(eq - x, x, all=True) == (x**4 + 4 * x**2 + 8 * x + 37, [], []) ans = (81 * x**8 - 2268 * x**6 - 4536 * x**5 + 22644 * x**4 + 63216 * x**3 - 31608 * x**2 - 189648 * x + 141358, [], []) r = sqrt(sqrt(2) / 3 + 7) eq = sqrt(r) + r - x assert unrad(eq, all=1) r2 = sqrt(sqrt(2) + 21) / sqrt(3) assert r != r2 and r.equals(r2) assert unrad(eq - r + r2, all=True) == ans
def test_unrad(): s = symbols('s', cls=Dummy) # checkers to deal with possibility of answer coming # back with a sign change (cf issue 2104) def check(rv, ans): rv, ans = list(rv), list(ans) rv[0] = rv[0].expand() ans[0] = ans[0].expand() return rv[0] in [ans[0], -ans[0]] and rv[1:] == ans[1:] def s_check(rv, ans): # get the dummy rv = list(rv) d = rv[0].atoms(Dummy) reps = zip(d, [s]*len(d)) # replace s with this dummy rv = (rv[0].subs(reps).expand(), [(p[0].subs(reps), p[1].subs(reps)) for p in rv[1]], [a.subs(reps) for a in rv[2]]) ans = (ans[0].subs(reps).expand(), [(p[0].subs(reps), p[1].subs(reps)) for p in ans[1]], [a.subs(reps) for a in ans[2]]) return str(rv[0]) in [str(ans[0]), str(-ans[0])] and \ str(rv[1:]) == str(ans[1:]) assert check(unrad(sqrt(x)), (x, [], [])) assert check(unrad(sqrt(x) + 1), (x - 1, [], [])) assert s_check(unrad(sqrt(x) + x**Rational(1, 3) + 2), (2 + s**2 + s**3, [(s, x - s**6)], [])) assert check(unrad(sqrt(x)*x**Rational(1, 3) + 2), (x**5 - 64, [], [])) assert check(unrad(sqrt(x) + (x + 1)**Rational(1, 3)), (x**3 - (x + 1)**2, [], [])) assert check(unrad(sqrt(x) + sqrt(x + 1) + sqrt(2*x)), (-2*sqrt(2)*x - 2*x + 1, [], [])) assert check(unrad(sqrt(x) + sqrt(x + 1) + 2), (16*x - 9, [], [])) assert check(unrad(sqrt(x) + sqrt(x + 1) + sqrt(1 - x)), (-4*x + 5*x**2, [], [])) assert check(unrad(a*sqrt(x) + b*sqrt(x) + c*sqrt(y) + d*sqrt(y)), ((a*sqrt(x) + b*sqrt(x))**2 - (c*sqrt(y) + d*sqrt(y))**2, [], [])) assert check(unrad(sqrt(x) + sqrt(1 - x)), (2*x - 1, [], [])) assert check(unrad(sqrt(x) + sqrt(1 - x) - 3), (36*x + (2*x - 10)**2 - 36, [], [])) assert check(unrad(sqrt(x) + sqrt(1 - x) + sqrt(2 + x)), (-5*x**2 + 2*x - 1, [], [])) assert check(unrad(sqrt(x) + sqrt(1 - x) + sqrt(2 + x) - 3), (-25*x**4 - 376*x**3 - 1256*x**2 + 2272*x - 784, [], [])) assert check(unrad(sqrt(x) + sqrt(1 - x) + sqrt(2 + x) - sqrt(1 - 2*x)), (-41*x**4 - 40*x**3 - 232*x**2 + 160*x - 16, [], [])) assert check(unrad(sqrt(x) + sqrt(x + 1)), (S(1), [], [])) eq = sqrt(x) + sqrt(x + 1) + sqrt(1 - sqrt(x)) assert check(unrad(eq), (16*x**3 - 9*x**2, [], [])) assert set(solve(eq, check=False)) == set([S(0), S(9)/16]) assert solve(eq) == [] # but this one really does have those solutions assert set(solve(sqrt(x) - sqrt(x + 1) + sqrt(1 - sqrt(x)))) == \ set([S.Zero, S(9)/16]) '''real_root changes the value of the result if the solution is simplified; `a` in the text below is the root that is not 4/5: >>> eq sqrt(x) + sqrt(-x + 1) + sqrt(x + 1) - 6*sqrt(5)/5 >>> eq.subs(x, a).n() -0.e-123 + 0.e-127*I >>> real_root(eq.subs(x, a)).n() -0.e-123 + 0.e-127*I >>> (eq.subs(x,simplify(a))).n() -0.e-126 >>> real_root(eq.subs(x, simplify(a))).n() 0.194825975605452 + 2.15093623885838*I >>> sqrt(x).subs(x, real_root(a)).n() 0.809823827278194 - 0.e-25*I >>> sqrt(x).subs(x, (a)).n() 0.809823827278194 - 0.e-25*I >>> sqrt(x).subs(x, simplify(a)).n() 0.809823827278194 - 5.32999467690853e-25*I >>> sqrt(x).subs(x, real_root(simplify(a))).n() 0.49864610868139 + 1.44572604257047*I ''' eq = (sqrt(x) + sqrt(x + 1) + sqrt(1 - x) - 6*sqrt(5)/5) ra = S('''-1484/375 - 4*(-1/2 + sqrt(3)*I/2)*(-12459439/52734375 + 114*sqrt(12657)/78125)**(1/3) - 172564/(140625*(-1/2 + sqrt(3)*I/2)*(-12459439/52734375 + 114*sqrt(12657)/78125)**(1/3))''') rb = S(4)/5 ans = solve(sqrt(x) + sqrt(x + 1) + sqrt(1 - x) - 6*sqrt(5)/5) assert all(abs(eq.subs(x, i).n()) < 1e-10 for i in (ra, rb)) and \ len(ans) == 2 and \ set([i.n(chop=True) for i in ans]) == \ set([i.n(chop=True) for i in (ra, rb)]) ans = solve(sqrt(x) + sqrt(x + 1) - sqrt(1 - x) - sqrt(2 + x)) assert len(ans) == 1 and NS(ans[0])[:4] == '0.73' # the fence optimization problem # http://code.google.com/p/sympy/issues/detail?id=1694#c159 F = Symbol('F') eq = F - (2*x + 2*y + sqrt(x**2 + y**2)) X = solve(eq, x, hint='minimal')[0] Y = solve((x*y).subs(x, X).diff(y), y, simplify=False, minimal=True) ans = 2*F/7 - sqrt(2)*F/14 assert any((a - ans).expand().is_zero for a in Y) raises( ValueError, lambda: unrad(sqrt(x) + sqrt(x + 1) + sqrt(1 - sqrt(x)) + 3)) raises(ValueError, lambda: unrad(sqrt(x) + (x + 1)**Rational(1, 3) + 2*sqrt(y))) # same as last but consider only y assert check(unrad(sqrt(x) + (x + 1)**Rational(1, 3) + 2*sqrt(y), y), (4*y - (sqrt(x) + (x + 1)**(S(1)/3))**2, [], [])) assert check(unrad(sqrt(x/(1 - x)) + (x + 1)**Rational(1, 3)), (x**3/(-x + 1)**3 - (x + 1)**2, [], [(-x + 1)**3])) # same as last but consider only y; no y-containing denominators now assert s_check(unrad(sqrt(x/(1 - x)) + 2*sqrt(y), y), (x/(-x + 1) - 4*y, [], [])) assert check(unrad(sqrt(x)*sqrt(1 - x) + 2, x), (x*(-x + 1) - 4, [], [])) # http://tutorial.math.lamar.edu/ # Classes/Alg/SolveRadicalEqns.aspx#Solve_Rad_Ex2_a assert solve(Eq(x, sqrt(x + 6))) == [3] assert solve(Eq(x + sqrt(x - 4), 4)) == [4] assert solve(Eq(1, x + sqrt(2*x - 3))) == [] assert set(solve(Eq(sqrt(5*x + 6) - 2, x))) == set([-S(1), S(2)]) assert set(solve(Eq(sqrt(2*x - 1) - sqrt(x - 4), 2))) == set([S(5), S(13)]) assert solve(Eq(sqrt(x + 7) + 2, sqrt(3 - x))) == [-6] # http://www.purplemath.com/modules/solverad.htm assert solve((2*x - 5)**Rational(1, 3) - 3) == [16] assert solve((x**3 - 3*x**2)**Rational(1, 3) + 1 - x) == [] assert set(solve(x + 1 - (x**4 + 4*x**3 - x)**Rational(1, 4))) == \ set([-S(1)/2, -S(1)/3]) assert set(solve(sqrt(2*x**2 - 7) - (3 - x))) == set([-S(8), S(2)]) assert solve(sqrt(2*x + 9) - sqrt(x + 1) - sqrt(x + 4)) == [0] assert solve(sqrt(x + 4) + sqrt(2*x - 1) - 3*sqrt(x - 1)) == [5] assert solve(sqrt(x)*sqrt(x - 7) - 12) == [16] assert solve(sqrt(x - 3) + sqrt(x) - 3) == [4] assert solve(sqrt(9*x**2 + 4) - (3*x + 2)) == [0] assert solve(sqrt(x) - 2 - 5) == [49] assert solve(sqrt(x - 3) - sqrt(x) - 3) == [] assert solve(sqrt(x - 1) - x + 7) == [10] assert solve(sqrt(x - 2) - 5) == [27] assert solve(sqrt(17*x - sqrt(x**2 - 5)) - 7) == [3] assert solve(sqrt(x) - sqrt(x - 1) + sqrt(sqrt(x))) == [] # don't posify the expession in unrad and use _mexpand z = sqrt(2*x + 1)/sqrt(x) - sqrt(2 + 1/x) p = posify(z)[0] assert solve(p) == [] assert solve(z) == [] assert solve(z + 6*I) == [-S(1)/11] assert solve(p + 6*I) == [] eq = S(''' -x + (1/2 - sqrt(3)*I/2)*(3*x**3/2 - x*(3*x**2 - 34)/2 + sqrt((-3*x**3 + x*(3*x**2 - 34) + 90)**2/4 - 39304/27) - 45)**(1/3) + 34/(3*(1/2 - sqrt(3)*I/2)*(3*x**3/2 - x*(3*x**2 - 34)/2 + sqrt((-3*x**3 + x*(3*x**2 - 34) + 90)**2/4 - 39304/27) - 45)**(1/3))''') raises(NotImplementedError, lambda: solve(eq)) # not other code errors
def transform(self, x, u): r""" 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 """ 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(''' When f(u) has more than one free symbol, the one replacing x 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(''' Expecting a tuple (expr, symbol) where symbol identified a free symbol in expr, but symbol is not in expr's free symbols.''')) if not isinstance(uvar, Symbol): raise ValueError( filldedent(''' Expecting a tuple (expr, symbol) but didn't get 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)).xreplace({d: uvar}) if uvar in self.limits: raise ValueError( filldedent(''' u must contain the same variable as in x 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(''' The mapping between F(x) and f(u) did not give a unique integrand.''')) newfunc = newfuncs.pop() def _calc_limit_1(F, a, b): """ replace d with a, using subs if possible, otherwise limit where sign of b is considered """ wok = F.subs(d, a) if wok is S.NaN or wok.is_bounded is False and a.is_bounded: return limit(sign(b) * F, d, a) return wok def _calc_limit(a, b): """ replace d with a, using subs if possible, otherwise limit where sign of b is considered """ avals = list(set([_calc_limit_1(Fi, a, b) for Fi in F])) if len(avals) > 1: raise ValueError( filldedent(''' The mapping between F(x) and f(u) did not 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: 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)
def test_unrad(): s = symbols('s', cls=Dummy) # checkers to deal with possibility of answer coming # back with a sign change (cf issue 2104) def check(rv, ans): rv, ans = list(rv), list(ans) rv[0] = rv[0].expand() ans[0] = ans[0].expand() return rv[0] in [ans[0], -ans[0]] and rv[1:] == ans[1:] def s_check(rv, ans): # get the dummy rv = list(rv) d = rv[0].atoms(Dummy) reps = zip(d, [s] * len(d)) # replace s with this dummy rv = (rv[0].subs(reps).expand(), [ (p[0].subs(reps), p[1].subs(reps)) for p in rv[1] ], [a.subs(reps) for a in rv[2]]) ans = (ans[0].subs(reps).expand(), [ (p[0].subs(reps), p[1].subs(reps)) for p in ans[1] ], [a.subs(reps) for a in ans[2]]) return str(rv[0]) in [str(ans[0]), str(-ans[0])] and \ str(rv[1:]) == str(ans[1:]) assert check(unrad(sqrt(x)), (x, [], [])) assert check(unrad(sqrt(x) + 1), (x - 1, [], [])) assert s_check(unrad(sqrt(x) + x**Rational(1, 3) + 2), (2 + s**2 + s**3, [(s, x - s**6)], [])) assert check(unrad(sqrt(x) * x**Rational(1, 3) + 2), (x**5 - 64, [], [])) assert check(unrad(sqrt(x) + (x + 1)**Rational(1, 3)), (x**3 - (x + 1)**2, [], [])) assert check(unrad(sqrt(x) + sqrt(x + 1) + sqrt(2 * x)), (-2 * sqrt(2) * x - 2 * x + 1, [], [])) assert check(unrad(sqrt(x) + sqrt(x + 1) + 2), (16 * x - 9, [], [])) assert check(unrad(sqrt(x) + sqrt(x + 1) + sqrt(1 - x)), (-4 * x + 5 * x**2, [], [])) assert check(unrad(a * sqrt(x) + b * sqrt(x) + c * sqrt(y) + d * sqrt(y)), ((a * sqrt(x) + b * sqrt(x))**2 - (c * sqrt(y) + d * sqrt(y))**2, [], [])) assert check(unrad(sqrt(x) + sqrt(1 - x)), (2 * x - 1, [], [])) assert check(unrad(sqrt(x) + sqrt(1 - x) - 3), (36 * x + (2 * x - 10)**2 - 36, [], [])) assert check(unrad(sqrt(x) + sqrt(1 - x) + sqrt(2 + x)), (-5 * x**2 + 2 * x - 1, [], [])) assert check( unrad(sqrt(x) + sqrt(1 - x) + sqrt(2 + x) - 3), (-25 * x**4 - 376 * x**3 - 1256 * x**2 + 2272 * x - 784, [], [])) assert check(unrad(sqrt(x) + sqrt(1 - x) + sqrt(2 + x) - sqrt(1 - 2 * x)), (-41 * x**4 - 40 * x**3 - 232 * x**2 + 160 * x - 16, [], [])) assert check(unrad(sqrt(x) + sqrt(x + 1)), (S(1), [], [])) eq = sqrt(x) + sqrt(x + 1) + sqrt(1 - sqrt(x)) assert check(unrad(eq), (16 * x**3 - 9 * x**2, [], [])) assert solve(eq, check=False) == [0, S(9) / 16] assert solve(eq) == [] # but this one really does have those solutions assert solve(sqrt(x) - sqrt(x + 1) + sqrt(1 - sqrt(x))) == [0, S(9) / 16] '''real_root changes the value of the result if the solution is simplified; `a` in the text below is the root that is not 4/5: >>> eq sqrt(x) + sqrt(-x + 1) + sqrt(x + 1) - 6*sqrt(5)/5 >>> eq.subs(x, a).n() -0.e-123 + 0.e-127*I >>> real_root(eq.subs(x, a)).n() -0.e-123 + 0.e-127*I >>> (eq.subs(x,simplify(a))).n() -0.e-126 >>> real_root(eq.subs(x, simplify(a))).n() 0.194825975605452 + 2.15093623885838*I >>> sqrt(x).subs(x, real_root(a)).n() 0.809823827278194 - 0.e-25*I >>> sqrt(x).subs(x, (a)).n() 0.809823827278194 - 0.e-25*I >>> sqrt(x).subs(x, simplify(a)).n() 0.809823827278194 - 5.32999467690853e-25*I >>> sqrt(x).subs(x, real_root(simplify(a))).n() 0.49864610868139 + 1.44572604257047*I ''' eq = (sqrt(x) + sqrt(x + 1) + sqrt(1 - x) - 6 * sqrt(5) / 5) ra = S('''-1484/375 - 4*(-1/2 + sqrt(3)*I/2)*(-12459439/52734375 + 114*sqrt(12657)/78125)**(1/3) - 172564/(140625*(-1/2 + sqrt(3)*I/2)*(-12459439/52734375 + 114*sqrt(12657)/78125)**(1/3))''') rb = S(4) / 5 ans = solve(sqrt(x) + sqrt(x + 1) + sqrt(1 - x) - 6 * sqrt(5) / 5) assert all(abs(eq.subs(x, i).n()) < 1e-10 for i in (ra, rb)) and \ len(ans) == 2 and \ sorted([i.n(chop=True) for i in ans]) == \ sorted([i.n(chop=True) for i in (ra, rb)]) ans = solve(sqrt(x) + sqrt(x + 1) - \ sqrt(1 - x) - sqrt(2 + x)) assert len(ans) == 1 and NS(ans[0])[:4] == '0.73' # the fence optimization problem # http://code.google.com/p/sympy/issues/detail?id=1694#c159 F = Symbol('F') eq = F - (2 * x + 2 * y + sqrt(x**2 + y**2)) X = solve(eq, x, hint='minimal')[0] Y = solve((x * y).subs(x, X).diff(y), y, simplify=False, minimal=True) ans = 2 * F / 7 - sqrt(2) * F / 14 assert any((a - ans).expand().is_zero for a in Y) raises(ValueError, lambda: unrad(sqrt(x) + sqrt(x + 1) + sqrt(1 - sqrt(x)) + 3)) raises(ValueError, lambda: unrad(sqrt(x) + (x + 1)**Rational(1, 3) + 2 * sqrt(y))) # same as last but consider only y assert check(unrad(sqrt(x) + (x + 1)**Rational(1, 3) + 2 * sqrt(y), y), (4 * y - (sqrt(x) + (x + 1)**(S(1) / 3))**2, [], [])) assert check(unrad(sqrt(x / (1 - x)) + (x + 1)**Rational(1, 3)), (x**3 / (-x + 1)**3 - (x + 1)**2, [], [(-x + 1)**3])) # same as last but consider only y; no y-containing denominators now assert s_check(unrad(sqrt(x / (1 - x)) + 2 * sqrt(y), y), (x / (-x + 1) - 4 * y, [], [])) assert check(unrad(sqrt(x) * sqrt(1 - x) + 2, x), (x * (-x + 1) - 4, [], [])) # http://tutorial.math.lamar.edu/ # Classes/Alg/SolveRadicalEqns.aspx#Solve_Rad_Ex2_a assert solve(Eq(x, sqrt(x + 6))) == [3] assert solve(Eq(x + sqrt(x - 4), 4)) == [4] assert solve(Eq(1, x + sqrt(2 * x - 3))) == [] assert solve(Eq(sqrt(5 * x + 6) - 2, x)) == [-1, 2] assert solve(Eq(sqrt(2 * x - 1) - sqrt(x - 4), 2)) == [5, 13] assert solve(Eq(sqrt(x + 7) + 2, sqrt(3 - x))) == [-6] # http://www.purplemath.com/modules/solverad.htm assert solve((2 * x - 5)**Rational(1, 3) - 3) == [16] assert solve((x**3 - 3 * x**2)**Rational(1, 3) + 1 - x) == [] assert solve(x + 1 - (x**4 + 4*x**3 - x)**Rational(1, 4)) == \ [-S(1)/2, -S(1)/3] assert solve(sqrt(2 * x**2 - 7) - (3 - x)) == [-8, 2] assert solve(sqrt(2 * x + 9) - sqrt(x + 1) - sqrt(x + 4)) == [0] assert solve(sqrt(x + 4) + sqrt(2 * x - 1) - 3 * sqrt(x - 1)) == [5] assert solve(sqrt(x) * sqrt(x - 7) - 12) == [16] assert solve(sqrt(x - 3) + sqrt(x) - 3) == [4] assert solve(sqrt(9 * x**2 + 4) - (3 * x + 2)) == [0] assert solve(sqrt(x) - 2 - 5) == [49] assert solve(sqrt(x - 3) - sqrt(x) - 3) == [] assert solve(sqrt(x - 1) - x + 7) == [10] assert solve(sqrt(x - 2) - 5) == [27] assert solve(sqrt(17 * x - sqrt(x**2 - 5)) - 7) == [3] assert solve(sqrt(x) - sqrt(x - 1) + sqrt(sqrt(x))) == [] # don't posify the expession in unrad and use _mexpand z = sqrt(2 * x + 1) / sqrt(x) - sqrt(2 + 1 / x) p = posify(z)[0] assert solve(p) == [] assert solve(z) == [] assert solve(z + 6 * I) == [-S(1) / 11] assert solve(p + 6 * I) == []