SymPy's "function_range" doesn't work for seemingly simply functions

Viewed 84

I'm trying to determine the range of a function, in this case a polynomial. My program already uses a lot of SymPy functions so I thought I could use the function_range function from the sympy.calculus.util module. For the polynomial 1/2*x**4-2*x**2-1/4*x over the domain R doesn't work, and outputs this error:

>>> from sympy import S
>>> from sympy.abc import x
>>> expr = S(1)/2*x**4-2*x**2-S(1)/4*x
>>> function_range(expr, x, S.Reals)
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/base/data/home/apps/s~sympy-live-hrd/66.426491309333028408/sympy/sympy/calculus/util.py", line 223, in function_range
    for critical_point in critical_points:
  File "/base/data/home/apps/s~sympy-live-hrd/66.426491309333028408/sympy/sympy/sets/sets.py", line 1375, in __iter__
    "The computation had not completed because of the "
TypeError: The computation had not completed because of the undecidable set membership is found in every candidates.

Considering that this function is perfectly continuous and not very complex, I really don't understand why SymPy can't determine the Range, as it's a rather simple one. Am I doing something wrong with the input? Are there alternatives to SymPy for doing this?

[edited to use Rationals instead of Floats]

1 Answers

The exact solution of the cubic equation needed to find the max/min of the quartic expression does not lend itself well to making comparisons needed to find which extremum is the lowest. You can calculate the value on your own by telling solve not to use exact cubic solutions like this:

>>> maxmin = FiniteSet(*[eq.subs(x,i) for i in solve(eq.diff(), cubics=False)])

The limits of the quartic are both positive and infinite at +/-oo

>>> limit(eq,x,-oo)
oo
>>> limit(eq,x,oo)  # must also be oo since function is even
oo

The minimum value the function attains is

>>> maxmin.inf
-2*CRootOf(8*x**3 - 16*x - 1, 2)**2 - CRootOf(8*x**3 - 16*x - 1, 2)/4 +
CRootOf(8*x**3 - 16*x - 1, 2)**4/2
>>> _.n()
-2.35737693115205
Related