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

NotImplementedError: Unable to find critical points for Abs(f(x)) #21956

Open
galenseilis opened this issue Aug 26, 2021 · 5 comments
Open

NotImplementedError: Unable to find critical points for Abs(f(x)) #21956

galenseilis opened this issue Aug 26, 2021 · 5 comments
Labels

Comments

@galenseilis
Copy link

It would be particularly useful to some of my projects if it were possible for me to find the maximum of the absolute value of a single variable function. Here is a reproducible example:

from sympy import *
x = Symbol('x')
maximum(Abs(x**3), x, Interval(0,3))

I've noted that max(|f|) = max(|min(f)|, |max(f)|) is a useful simplification that can be implemented explicitly.

from sympy import *
x = Symbol('x')
Max(Abs(minimum(x**3, x, Interval(0,3))), Abs(maximum(x**3, x, Interval(0,3))))

As a feature request, it would be beneficial if SymPy did this (or something better) automatically.

@sidhu1012 sidhu1012 added the core label Aug 28, 2021
@oscargus
Copy link
Contributor

If you define x to be real as x = Symbol('x', real=True) it returns the correct result.

Here, one could think that the code would replace your x with another x that has real assumptions (as is done in e.g. the integral code).

However, your observation should be relevant in addition to that.

@oscargus
Copy link
Contributor

An example where your observation is useful is maximum(Abs(x**3*y), x, Interval(0,3)) with x and y both real.

Although

Max(Abs(minimum(x**3*y, x, Interval(0,3))), Abs(maximum(x**3*y, x, Interval(0,3)))))

gives Max(27*y, -Min(0, 27*y)) it is clearly better than NotImplementedError: relationship did not evaluate: y >= 0...

The function function_range computes both the maximum and minimum values, so something similar should be applied for the minimum value by checking the sign of the min and max without abs and figure our what the abs min is.

@oscarbenjamin
Copy link
Contributor

If you define x to be real as x = Symbol('x', real=True) it returns the correct result.

Here the function is differentiated:

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

Depending on whether x has real assumptions different results are obtained:

In [2]: x = Symbol('x')

In [3]: Abs(x**3).diff(x)
Out[3]: 
⎛⎛    2              3   ⎞ ⎛    2    d                         d               2    d        ⎞   ⎛  3                2   ⎞ ⎛    2    d                      
⎜⎝3re (x)⋅im(x) - im (x)⎠⋅⎜3re (x)⋅──(im(x)) + 6re(x)⋅im(x)⋅──(re(x)) - 3im (x)⋅──(im(x))⎟ +re (x) - 3re(x)⋅im (x)⎠⋅⎜3re (x)⋅──(re(x)) - 6re(x)⋅im(
⎝                          ⎝         dx                        dx                   dx       ⎠                             ⎝         dx                     
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
                                                                                                    3                                                       
                                                                                                   x                                                        

   d               2    d        ⎞⎞     ⎛ 3x)⋅──(im(x)) - 3im (x)⋅──(re(x))⎟⎟⋅signxdx                   dx       ⎠⎠         
────────────────────────────────────────────
                                            
                                            

In [4]: x = Symbol('x', real=True)

In [5]: Abs(x**3).diff(x)
Out[5]: 
 2                  
xsign(x) + 2x⋅│x

Without the real assumption we get:

In [6]: x = Symbol('x')

In [7]: solveset(Abs(x**3).diff(x), x, Reals)
Out[7]: 
      ⎧  │               ⎛ 2 d        ⎞⎫   ⎧  │              ⎛ 2 d        ⎞⎫
{0} ∪ ⎨xx ∊ (-∞, 0) ∧ ⎜x ⋅──(x) = 0⎟⎬ ∪ ⎨xx ∊ (0, ∞) ∧ ⎜x ⋅──(x) = 0⎟⎬
      ⎩  │               ⎝   dx       ⎠⎭   ⎩  │              ⎝   dx       ⎠⎭

In [8]: solveset(Abs(x**3).diff(x), x, Interval(0, 3))
Out[8]: 
      ⎧  │              ⎛ 2 d        ⎞⎫
{0} ∪ ⎨xx ∊ (0, 3] ∧ ⎜x ⋅──(x) = 0⎟⎬
      ⎩  │              ⎝   dx       ⎠⎭

In [9]: _.doit()
Out[9]: 
      ⎧  │              ⎛ 2    ⎞⎫
{0} ∪ ⎨xx ∊ (0, 3] ∧ ⎝x  = 0⎠⎬
      ⎩  │                      ⎭

I think it should be possible to resolve that ConditionSet further.

@pranjii
Copy link

pranjii commented Sep 3, 2021

Can I get this?

@oscargus
Copy link
Contributor

oscargus commented Sep 3, 2021

@pranjii there is a solution in #21985 so probably you better spend your efforts on some other issue.

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

No branches or pull requests

5 participants