Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeError on function_range of Abs(((log(x))**Rational(1, 3))) #26518

Open
satels opened this issue Apr 18, 2024 · 4 comments
Open

TypeError on function_range of Abs(((log(x))**Rational(1, 3))) #26518

satels opened this issue Apr 18, 2024 · 4 comments

Comments

@satels
Copy link
Contributor

satels commented Apr 18, 2024

from sympy import Symbol, Abs, Rational, log, Interval
from sympy.calculus.util import function_range 

x = Symbol('x', real=True) 
func_expr = Abs(((log(x))**Rational(1, 3)))

function_range(func_expr, x, Interval.Lopen(0, 1))


Traceback (most recent call last):
  File "/sympy/calculus/util.py", line 208, in function_range
    for critical_point in critical_points:
  File "sympy/sets/sets.py", line 1756, in __iter__
    for a in A:
TypeError: 'ConditionSet' object is not iterable
 

But if i change

solution = solveset(f.diff(symbol), symbol, interval)

to

solution = solveset(f.diff(symbol).simplify(), symbol, interval)

— it work fine

@satels
Copy link
Contributor Author

satels commented Apr 18, 2024

Other example (with different error)

from sympy import Symbol, Abs, Rational, log, Interval
from sympy.calculus.util import function_range 

x = Symbol('x', real=True) 
func_expr = log(1+x)/(x**(Rational(1, 3))*(2+x))

function_range(func_expr, x, Interval.Lopen(0, 1))

Traceback (most recent call last):
  File "sympy/calculus/util.py", line 197, in function_range
    solution = solveset(f.diff(symbol), symbol, interval)
  File "sympy/solvers/solveset.py", line 2252, in solveset
    rv = solveset(f.xreplace({symbol: x}), x, domain)
  File "sympy/solvers/solveset.py", line 2276, in solveset
    return _solveset(f, symbol, domain, _check=True)
  File "sympy/solvers/solveset.py", line 1148, in _solveset
    _result = _solveset(num, symbol, domain)
  File "sympy/solvers/solveset.py", line 1106, in _solveset
    result += _solve_radical(equation, u,
  File "sympy/solvers/solveset.py", line 879, in _solve_radical
    result = Union(*[imageset(Lambda(y, g_y), f_y_sols)
  File "sympy/solvers/solveset.py", line 879, in <listcomp>
    result = Union(*[imageset(Lambda(y, g_y), f_y_sols)
  File "sympy/sets/sets.py", line 1561, in __iter__
    raise TypeError(
TypeError: The computation had not completed because of the undecidable set membership is found in every candidates.

@oscarbenjamin
Copy link
Contributor

The first issue is the naive implementation of function_range in terms of solveset. Unfortunately solveset is not very well designed to be actually useful when used in other functions. Attempting to use the output can often blow up like this. Probably function_range should check a bit better what sort of object solveset returned. Ideally there would be an alternative to solveset that returns results in a structured format suitable for computational processing.

The second case is just a bug in solveset although it is related to the problem of solveset output being hard to use: even solveset itself struggles to use its own intermediate results.

@SarthakNikhal
Copy link

@oscarbenjamin Is there anything that should be done here? I'd like to contribute

@oscarbenjamin
Copy link
Contributor

The simple fix in each case is just to add some checking somewhere.

If you check in the debugger for the second bug you can see this:

sympy/sympy/solvers/solveset.py(1106)_solve_radical()
   1104         g_y_s = solveset_solver(yeq, symbol)
   1105         f_y_sols = solveset_solver(eq, y)
-> 1106         result = Union(*[imageset(Lambda(y, g_y), f_y_sols)
   1107                          for g_y in g_y_s])
   1108 

ipdb> p g_y_s
Intersection({_yreal**3}, Interval.Lopen(0, 1))

It is trying to loop over g_y_s but there is no way to loop over that set because we don't know if it is the empty set or not.

There are all kinds of other problems though like why is there a symbol called _yreal and why is the intersection here in the middle of solveset and so on. The implementation of function_range using

solveset(f.diff(symbol), symbol, interval)

is hopelessly naive.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants