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

x*f(x).diff(x).diff(x).diff(x) AttributeError: 'Mul' object has no attribute 'p' #16776

Open
satels opened this issue May 5, 2019 · 7 comments
Labels

Comments

@satels
Copy link
Contributor

satels commented May 5, 2019

Python console for SymPy 1.4 (Python 2.7.12)

These commands were executed:
>>> from __future__ import division
>>> from sympy import *
>>> x, y, z, t = symbols('x y z t')
>>> k, m, n = symbols('k m n', integer=True)
>>> f, g, h = symbols('f g h', cls=Function)
>>> with evaluate(False): x*f(x).diff(x).diff(x).diff(x)
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/base/data/home/apps/s~sympy-live-hrd/57.417397408462217066/sympy/sympy/core/expr.py", line 3095, in diff
    return Derivative(self, *symbols, **assumptions)
  File "/base/data/home/apps/s~sympy-live-hrd/57.417397408462217066/sympy/sympy/core/function.py", line 1392, in __new__
    obj = expr._eval_derivative_n_times(v, count)
  File "/base/data/home/apps/s~sympy-live-hrd/57.417397408462217066/sympy/sympy/core/basic.py", line 1682, in _eval_derivative_n_times
    obj2 = obj._accept_eval_derivative(s)
  File "/base/data/home/apps/s~sympy-live-hrd/57.417397408462217066/sympy/sympy/core/basic.py", line 1658, in _accept_eval_derivative
    return s._visit_eval_derivative_scalar(self)
  File "/base/data/home/apps/s~sympy-live-hrd/57.417397408462217066/sympy/sympy/core/basic.py", line 1663, in _visit_eval_derivative_scalar
    return base._eval_derivative(self)
  File "/base/data/home/apps/s~sympy-live-hrd/57.417397408462217066/sympy/sympy/core/cache.py", line 94, in wrapper
    retval = cfunc(*args, **kwargs)
  File "/base/data/home/apps/s~sympy-live-hrd/57.417397408462217066/sympy/sympy/core/compatibility.py", line 888, in wrapper
    result = user_function(*args, **kwds)
  File "/base/data/home/apps/s~sympy-live-hrd/57.417397408462217066/sympy/sympy/core/add.py", line 394, in _eval_derivative
    return self.func(*[a.diff(s) for a in self.args])
  File "/base/data/home/apps/s~sympy-live-hrd/57.417397408462217066/sympy/sympy/core/expr.py", line 3095, in diff
    return Derivative(self, *symbols, **assumptions)
  File "/base/data/home/apps/s~sympy-live-hrd/57.417397408462217066/sympy/sympy/core/function.py", line 1392, in __new__
    obj = expr._eval_derivative_n_times(v, count)
  File "/base/data/home/apps/s~sympy-live-hrd/57.417397408462217066/sympy/sympy/core/cache.py", line 94, in wrapper
    retval = cfunc(*args, **kwargs)
  File "/base/data/home/apps/s~sympy-live-hrd/57.417397408462217066/sympy/sympy/core/compatibility.py", line 888, in wrapper
    result = user_function(*args, **kwds)
  File "/base/data/home/apps/s~sympy-live-hrd/57.417397408462217066/sympy/sympy/core/mul.py", line 918, in _eval_derivative_n_times
    p = prod([arg.diff((s, k)) for k, arg in zip(kvals, args)])
  File "/base/data/home/apps/s~sympy-live-hrd/57.417397408462217066/sympy/sympy/core/expr.py", line 3095, in diff
    return Derivative(self, *symbols, **assumptions)
  File "/base/data/home/apps/s~sympy-live-hrd/57.417397408462217066/sympy/sympy/core/function.py", line 1345, in __new__
    return Derivative(expr, *variable_count, **kwargs)
  File "/base/data/home/apps/s~sympy-live-hrd/57.417397408462217066/sympy/sympy/core/function.py", line 1430, in __new__
    expr = factor_terms(signsimp(expr))
  File "/base/data/home/apps/s~sympy-live-hrd/57.417397408462217066/sympy/sympy/core/exprtools.py", line 1202, in factor_terms
    return do(expr)
  File "/base/data/home/apps/s~sympy-live-hrd/57.417397408462217066/sympy/sympy/core/exprtools.py", line 1198, in do
    *[do(a) for a in p.args])
  File "/base/data/home/apps/s~sympy-live-hrd/57.417397408462217066/sympy/sympy/core/exprtools.py", line 1167, in do
    newargs = tuple([do(i) for i in args])
  File "/base/data/home/apps/s~sympy-live-hrd/57.417397408462217066/sympy/sympy/core/exprtools.py", line 1177, in do
    list_args = [do(a) for a in Add.make_args(p)]
  File "/base/data/home/apps/s~sympy-live-hrd/57.417397408462217066/sympy/sympy/core/exprtools.py", line 1175, in do
    cont, p = expr.as_content_primitive(radical=radical, clear=clear)
  File "/base/data/home/apps/s~sympy-live-hrd/57.417397408462217066/sympy/sympy/core/mul.py", line 1678, in as_content_primitive
    c, p = a.as_content_primitive(radical=radical, clear=clear)
  File "/base/data/home/apps/s~sympy-live-hrd/57.417397408462217066/sympy/sympy/core/mul.py", line 1678, in as_content_primitive
    c, p = a.as_content_primitive(radical=radical, clear=clear)
  File "/base/data/home/apps/s~sympy-live-hrd/57.417397408462217066/sympy/sympy/core/mul.py", line 1678, in as_content_primitive
    c, p = a.as_content_primitive(radical=radical, clear=clear)
  File "/base/data/home/apps/s~sympy-live-hrd/57.417397408462217066/sympy/sympy/core/power.py", line 1625, in as_content_primitive
    iceh, r = divmod(ceh.p, ceh.q)
AttributeError: 'Mul' object has no attribute 'p'

@jksuom
Copy link
Member

jksuom commented May 5, 2019

An iterated derivative like f(x).diff(x).diff(x) is computed by adding variable counts on this line

c += merged[-1][1]

The sum 1 + 1 will be unevaluated because of with evaluate(False) and the unexpected Add expression seems to confuse the algorithm. This could probably be fixed by something like c = Add(c, merged[-1][1], evaluate=True) but I am not sure if that would be worth-while.

@KuldeepBorkar
Copy link
Contributor

@satels
This does not seems to be an issue.
I just implemented the same thing in Python 3 and it just works fine

@oscarbenjamin
Copy link
Contributor

With current master I get a different error:

$ isympy -c python
Python console for SymPy 1.10.dev (Python 3.8.5-64-bit) (ground types: python)

These commands were executed:
>>> from __future__ import division
>>> from sympy import *
>>> x, y, z, t = symbols('x y z t')
>>> k, m, n = symbols('k m n', integer=True)
>>> f, g, h = symbols('f g h', cls=Function)
>>> init_printing()

Documentation can be found at https://docs.sympy.org/dev

Python 3.8.5 (v3.8.5:580fbb018f, Jul 20 2020, 12:11:27) 
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
(SymPyConsole)
>>> with evaluate(False): x*f(x).diff(x).diff(x).diff(x)
... 
Traceback (most recent call last):
  File "/Users/enojb/current/sympy/sympy/sympy/core/assumptions.py", line 479, in getit
    return self._assumptions[fact]
KeyError: 'zero'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/enojb/current/sympy/sympy/sympy/core/assumptions.py", line 479, in getit
    return self._assumptions[fact]
KeyError: 'extended_real'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/enojb/current/sympy/sympy/sympy/core/assumptions.py", line 479, in getit
    return self._assumptions[fact]
KeyError: 'integer'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/Users/enojb/current/sympy/sympy/sympy/core/expr.py", line 3544, in diff
    return _derivative_dispatch(self, *symbols, **assumptions)
  File "/Users/enojb/current/sympy/sympy/sympy/core/function.py", line 1921, in _derivative_dispatch
    return Derivative(expr, *variables, **kwargs)
  File "/Users/enojb/current/sympy/sympy/sympy/core/function.py", line 1450, in __new__
    if obj is not None and obj.is_zero:
  File "/Users/enojb/current/sympy/sympy/sympy/core/assumptions.py", line 483, in getit
    return _ask(fact, self)
  File "/Users/enojb/current/sympy/sympy/sympy/core/assumptions.py", line 526, in _ask
    a = evaluate(obj)
  File "/Users/enojb/current/sympy/sympy/sympy/core/add.py", line 720, in _eval_is_zero
    elif (S.ImaginaryUnit*a).is_extended_real:
  File "/Users/enojb/current/sympy/sympy/sympy/core/assumptions.py", line 483, in getit
    return _ask(fact, self)
  File "/Users/enojb/current/sympy/sympy/sympy/core/assumptions.py", line 538, in _ask
    _ask(pk, obj)
  File "/Users/enojb/current/sympy/sympy/sympy/core/assumptions.py", line 526, in _ask
    a = evaluate(obj)
  File "/Users/enojb/current/sympy/sympy/sympy/core/mul.py", line 1599, in _eval_is_odd
    is_integer = self.is_integer
  File "/Users/enojb/current/sympy/sympy/sympy/core/assumptions.py", line 483, in getit
    return _ask(fact, self)
  File "/Users/enojb/current/sympy/sympy/sympy/core/assumptions.py", line 538, in _ask
    _ask(pk, obj)
  File "/Users/enojb/current/sympy/sympy/sympy/core/assumptions.py", line 538, in _ask
    _ask(pk, obj)
  File "/Users/enojb/current/sympy/sympy/sympy/core/assumptions.py", line 526, in _ask
    a = evaluate(obj)
  File "/Users/enojb/current/sympy/sympy/sympy/core/mul.py", line 1638, in _eval_is_even
    n, d = fraction(self)
  File "/Users/enojb/current/sympy/sympy/sympy/simplify/radsimp.py", line 1112, in fraction
    return Mul(*numer, evaluate=not exact), Mul(*denom, evaluate=not exact)
  File "/Users/enojb/current/sympy/sympy/sympy/core/cache.py", line 70, in wrapper
    retval = cfunc(*args, **kwargs)
  File "/Users/enojb/current/sympy/sympy/sympy/core/operations.py", line 83, in __new__
    c_part, nc_part, order_symbols = cls.flatten(args)
  File "/Users/enojb/current/sympy/sympy/sympy/core/mul.py", line 626, in flatten
    p, q =  neg1e.as_numer_denom()
  File "/Users/enojb/current/sympy/sympy/sympy/core/add.py", line 624, in as_numer_denom
    denoms, numers = [list(i) for i in zip(*iter(nd.items()))]
ValueError: not enough values to unpack (expected 2, got 0)

@anutosh491
Copy link
Member

With current master I get a different error:

True , I just verified this and the above error persists !

@ThePauliPrinciple
Copy link
Contributor

afbeelding
This works on Colab

@sudoer-Huatao
Copy link

@satels
This does not seems to be an issue.
I just implemented the same thing in Python 3 and it just works fine

When I ran it in a Python 3 Shell I got this monstrosity:

x*((1*(0*(Piecewise((x, Eq(1, 0)), (1, Eq(1, 1)), (0, True))*Derivative(f(x), (x, 1 + 1)))) + 1*(1*(1*(Piecewise((x, Eq(1, 0)), (1, Eq(1, 1)), (0, True))*Derivative(f(x), (x, 1 + (1 + 1)))) + 1*(Piecewise((Piecewise((x, Eq(1, 0)), (1, Eq(1, 1)), (0, True)), Eq(1, 0)), (0, Eq(1, 1)), (0, True))*Derivative(f(x), (x, 1 + 1)))))) + (1*(0*(Piecewise((Piecewise((x, Eq(1, 0)), (1, Eq(1, 1)), (0, True)), Eq(1, 0)), (0, Eq(1, 1)), (0, True))*Derivative(f(x), x))) + 1*(1*(1*(Piecewise((Piecewise((x, Eq(1, 0)), (1, Eq(1, 1)), (0, True)), Eq(1, 0)), (0, Eq(1, 1)), (0, True))*Derivative(f(x), (x, 1 + 1))) + 1*(Piecewise((Piecewise((Piecewise((x, Eq(1, 0)), (1, Eq(1, 1)), (0, True)), Eq(1, 0)), (0, Eq(1, 1)), (0, True)), Eq(1, 0)), (0, Eq(1, 1)), (0, True))*Derivative(f(x), x))))))

@oscarbenjamin
Copy link
Contributor

I think that under evaluate(False) the .diff method should just return an unevaluated Derivative. If you construct the `Derivative directly then this does what is expected:

In [8]: with evaluate(False): e = x*Derivative(f(x), (x, 3))

In [9]: e
Out[9]: 
    3      
   d       
x⋅───(f(x))
    3      
  dx  

In general evaluate(False) does not work very well or rather does not do what many users seem to expect or want. Too much code depends on evaluation so having it globally disabled breaks any nontrivial symbolic manipulation. The use of evaluate(False) should be confined to situations in which the enclosed code does nothing apart from create an expression.

It is not intuitive that .diff does more than just create an expression but it does: nontrivial evaluation is involved in computing derivatives.

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

7 participants