Why the derivative of an unknown function is 1 in SymPy - python

Now, I am learning SymPy. While trying some code about differential equation, I defined f as a function as follows:
from sympy import *
f=symbols('f',cls=Function)
x,y=symbols('x,y')
While trying to write the first derivative w.r.t. x I wrote this:
diff(f,x)
Which gives always 1. My question is Why? Does this mean that the default value of f is x? which is unlogic because when I try to find the derivative w.r.t. y it is also 1. The logic answer is that it should be zero as I think.
Also, when I am trying to find the second derivative, it gives me an error that meaning that f is 2 and it cannot be 2!!
diff(f,x,2)
Traceback (most recent call last):
File "<ipython-input-73-34a606e25841>", line 1, in <module>
diff(f,x,2)
File "C:\Users\osama\AppData\Local\Programs\Spyder\pkgs\sympy\core\function.py", line 2503, in diff
return f.diff(*symbols, **kwargs)
File "C:\Users\osama\AppData\Local\Programs\Spyder\pkgs\sympy\core\expr.py", line 3502, in diff
return _derivative_dispatch(self, *symbols, **assumptions)
File "C:\Users\osama\AppData\Local\Programs\Spyder\pkgs\sympy\core\function.py", line 1947, in _derivative_dispatch
return Derivative(expr, *variables, **kwargs)
File "C:\Users\osama\AppData\Local\Programs\Spyder\pkgs\sympy\core\function.py", line 1314, in __new__
raise ValueError("First variable cannot be a number: %i" % v)
ValueError: First variable cannot be a number: 2
EDIT: SymPy Version = 1.8
I found the solution "from the code point of view" that I should type it as a diff(f(x),x) and diff(f(x),x,2) but this is not the question.

TESTED IN SYMPY 1.7.1
It seems that if you do not provide an input to the function in its first parameter, the operation will be evaluated in a less symbolic form with dx-like = arg2, dy-like = arg3, and order = arg4.
diff(f, x, x) = 1 # == diff(f, x) == diff(f, x, x, 1)
diff(f, y, y) = 1 # == diff(f, y) == diff(f, y, y, 1)
diff(f, x, y) = diff(f, y, x) = 0
diff(f, x, x, 0) = x
diff(f, x, x, 1) = 1
diff(f, x, x, 2) = 0

Related

I have a simple question about the logic behind this Python code

I'm a beginner in Python, and I'm stuck in a function code.
def max_of_two( x, y ):
if x > y:
return x
return y
def max_of_three( x, y, z ):
return max_of_two( x, max_of_two( y, z ) )
print(max_of_three(30, 25, 50))
Can someone explain to me the logic behind putting the first function (max_of_two()) inside the parameters of the second function (max_of_three())? I've seen a function inside a function code, and that's not a problem, but I've never seen a function inside the parameters of another function... I'm very confused. I know what the code does, it basically shows the greater number. The first function I understood perfectly, but the second one confused me...
x = 1
y = 2
z = 3
max_of_two( y, z )
> 3
max_of_two( x, max_of_two( y, z ) )
# is the same as
max_of_two( x, z )
# is the same as
max_of_two( x, 3 )
The result of the inner function is used as a parameter for the outer function because the inner function is evaluated first.
This is not putting a function inside parameters. First I recommend you understand parameter vs argument, here's a quote from "Parameter" vs "Argument" :
Old post, but another way of saying it: argument is the value/variable/reference being passed in, parameter is the receiving variable used w/in the function/block
def max_of_three( x, y, z ):
return max_of_two( x, max_of_two( y, z ) )
For example, (x, y, z) are parameters of max_of_three, and (y, z) are arguments passed to max_of_two
——————————————————————————————————————————
Then you should understand function calls. max_of_two( y, z ) is an example of a function call, where you call the function max_of_two, by making a function call, you get the return value corresponding to your arguments.
In this case, when you write:
max_of_two( x, max_of_two( y, z ) )
you first get the return value corresponding to (y, z) from max_of_two, and the pass x and the return value above to another max_of_two function, then you return the new return value from max_of_three. This is equivalent to:
retval = max_of_two( y, z )
retval2 = max_of_two( x, retval )
return retval2
It's like a nested if in other languages. You have three arguments to the second function. These are passed to the first function that verifies them in pairs.
If you wanted to use a single function max_of_three(x, y, z) it should look like a succession of if statements with an intermediary variable.
def max_of_three(x,y,z):
if x > y:
temp = x
else:
temp = y
if temp > z:
result = temp
else:
result = z
return result

Getting the derivative of a function as a function with sympy (for later evaluation and substitution)

I want to work with generic functions as long as possible, and only substitute functions at the end.
I'd like to define a function as the derivative of another one, define a generic expression with the function and its derivative, and substitute the function at the end.
Right now my attempts is as follows, but I get the error 'Derivative' object is not callable:
from sympy import Function
x, y, z = symbols('x y z')
f = Function('f')
df = f(x).diff(x) # <<< I'd like this to be a function of dummy variable x
expr = f(x) * df(z) + df(y) + df(0) # df is unfortunately not callable
# At the end, substitute with example function
expr.replace(f, Lambda(X, cos(X))) # should return: -cos(x)*sin(z) - sin(y) - sin(0)
I think I got it to work with integrals as follows:
I= Lambda( x, integrate( f(y), (y, 0, x))) but that won't work for derivatives.
If that helps, I'm fine restricting myself to functions of a single variable for now.
As a bonus, I'd like to get this to work with any combination (products, derivatives, integrals) of the original function.
It's pretty disappointing that f.diff(x) doesn't work, as you say. Maybe someone will create support it sometime in the future. In the mean time, there are 2 ways to go about it: either substitute x for your y, z, ... OR lambdify df.
I think the first option will work more consistently in the long run (for example, if you decide to extend to multivariate calculus). But the expr in second option is far more natural.
Using substitution:
from sympy import *
x, y, z = symbols('x y z')
X = Symbol('X')
f = Function('f')
df = f(x).diff(x)
expr = f(x) * df.subs(x, z) + df.subs(x, y) + df.subs(x, 0)
print(expr.replace(f, Lambda(X, cos(X))).doit())
Lambdifying df:
from sympy import *
x, y, z = symbols('x y z')
X = Symbol('X')
f = Function('f')
df = lambda t: f(t).diff(t) if isinstance(t, Symbol) else f(X).diff(X).subs(X, t)
expr = f(x) * df(z) + df(y) + df(0)
print(expr.replace(f, Lambda(X, cos(X))).doit())
Both give the desired output.

Sympy ValueError: First variable cannot be a number

So I am coding a Kinematics problem for physics. I have a formula for the displacement. The code correctly gives me the derivative (velocity) and second derivative (acceleration). But when I try to solve for a variable out of any of the derivatives I get weird errors. It will give me the value of the displacement though!
import numpy as np
import sympy
import matplotlib.pyplot as plt
from sympy import *
x, y, z, t = symbols('x y z t')
i, j, k = symbols('i j k')
init_printing(use_unicode=True)
# **********************************************************************************
#Question 1 - The position of an electron is given by r = 3.0t(i) − 4.0t^2(j) + 2.0(k) (where t is in
#seconds and the coefficients have the proper units for r to be in meters).
#(a) What is v(t) for the electron?
#(b) In unit–vector notation, what is v at t = 2.0 s?
#(c) What are the magnitude and direction of v just then?
def r(t):
return (3*t)*i-(4*t*t)*j+2*k
def v(t):
return diff(r(t), t)
def a(t):
return diff(v(t), t)
print("Questions 1 -")
print("a)")
print("r(t) = ", r(t))
print("v(t) = ", v(t))
print("a(t) = ", a(t))
print("")
print('b)')
print("R(2) = ", r(2))
print("v(2) = ", v(2))
When I hit run, this is the output:
Questions 1 -
a)
r(t) = 3*i*t - 4*j*t**2 + 2*k
v(t) = 3*i - 8*j*t
a(t) = -8*j
b)
R(2) = 6*i - 16*j + 2*k
Traceback (most recent call last):
File "/tmp/sessions/b12e4bdebdf741f3/main.py", line 48, in <module>
print("v(2) = ", v(2))
File "/tmp/sessions/b12e4bdebdf741f3/main.py", line 35, in v
return diff(r(t), t)
File "/usr/local/lib/python3.6/dist-packages/sympy/core/function.py", line 1979, in diff
return Derivative(f, *symbols, **kwargs)
File "/usr/local/lib/python3.6/dist-packages/sympy/core/function.py", line 1156, in __new__
raise ValueError("First variable cannot be a number: %i" % v)
ValueError: First variable cannot be a number: 2
Short answer:
v(2) means differentiate r(2) with respect to 2.
2 is not a symbol so you get the error. You need an additional argument in your function v().
def v(t,at_point):
return diff(r(t), t, at_point)
v(t,2)
#-8⋅j
Long answer:
The problem is the following is that when you do:
v(2)
you are asking for:
diff(r(2), 2)
The last means to Differentiate r(2) with respect to 2. 2 is not a symbol so you get the error. You need an additional argument.
def v(t,at_point):
return diff(r(t), t, at_point)
You should define your function as follows:
def v(t,t0):
return diff(r(t), t, t0)
and then call it using v(t,2)

How to pass an array of input parameters in scipy.optimize.minimize?

I want to use scipy.optimize.minimize to solve for a set of parameters by minimizing an error function.
The function called "error" returns the squared error for the function that I am trying to find z1,z2,z3(the parameters) for.
I have an array of x(called "b" in the function) and y(called "real" in the function) values.
The code below works fine if I set x and y to some integer, but not if I try to pass in an array of x and y values, to act as the variable "b" and "real" in the equation to be minimized.
Trying to pass in an array of X and Y values results in the error pasted below.
Is there a way to pass in arrays to act as a variable in an equation for the minimize function, instead of just a single integer?
Here is what my code looks like:
import numpy as np
import pandas as pd
from scipy.optimize import minimize
#dataset file, with a column named x,y with 1000 rows
f = pd.read_csv('Test_Data_.txt', sep='\t')
#initial guess
x0 = [1, 2, 3]
#f['x'] and f['y'] are columns with 1000 rows
#x = f['x'].values
#y = f['y'].values
x = 1 #these parameters work fine
y = 4
#a function called inside the function to be minimized
def est(z1, z2, z3, b):
return z1 * b**2 + z2 * b + z3
#function to minimize
def error(x, real, b):
return (real - est(x[0], x[1], x[2], b))**2
print(minimize(error, x0, args = ( x, y), method='BFGS', tol=1e-6))
Feeding in the array of x and y values produces the error:
Traceback (most recent call last):
File "problem1.py", line 24, in <module>
minimize(error, x0, args = ( np.array(list(f['y'].values)), np.array(list(f['x'].values))), method='BFGS', tol=1e-6)
File "/usr/local/lib/python3.5/dist-packages/scipy/optimize/_minimize.py", line 595, in minimize
return _minimize_bfgs(fun, x0, args, jac, callback, **options)
File "/usr/local/lib/python3.5/dist-packages/scipy/optimize/optimize.py", line 970, in _minimize_bfgs
gfk = myfprime(x0)
File "/usr/local/lib/python3.5/dist-packages/scipy/optimize/optimize.py", line 300, in function_wrapper
return function(*(wrapper_args + args))
File "/usr/local/lib/python3.5/dist-packages/scipy/optimize/optimize.py", line 730, in approx_fprime
return _approx_fprime_helper(xk, f, epsilon, args=args)
File "/usr/local/lib/python3.5/dist-packages/scipy/optimize/optimize.py", line 670, in _approx_fprime_helper
grad[k] = (f(*((xk + d,) + args)) - f0) / d[k]
ValueError: setting an array element with a sequence.

python complex_ode pass matrix-valued parameters

I'm having some trouble with python's complex_ode solver.
I'm trying to solve the following equation:
dy/dt = -iAy - icos(Omegat)By
where A and B are NxN arrays and the unknown y is an Nx1 array, i is the imaginary unit and Omega is a parameter.
Here's my code:
import numpy as np
from scipy.integrate import ode,complex_ode
N = 3 #linear matrix dim
Omega = 1.0 #parameter
# define symmetric matrices A and B
A = np.random.ranf((N,N))
A = (A + A.T)/2.0
B = np.random.ranf((N,N))
B = (B + B.T)/2.0
# define RHS of ODE
def f(t,y,Omega,A,B):
return -1j*A.dot(y)-1j*np.cos(Omega*t)*B.dot(y)
# define list of parameter
params=[Omega,A,B]
# choose solver: need complex_ode for this ODE
#solver = ode(f)
solver = complex_ode(f)
solver.set_f_params(*params)
solver.set_integrator("dop853")
# set initial value
v0 = np.zeros((N,),dtype=np.float64)
v0[0] = 1.0
# check that the function f works properly
print f(0,v0,Omega,A,B)
# solve-check the ODE
solver.set_initial_value(v0)
solver.integrate(10.0)
print solver.successful()
Running this script produces the error
capi_return is NULL
Call-back cb_fcn_in___user__routines failed.
Traceback (most recent call last):
File "ode_test.py", line 37, in <module>
solver.integrate(10.0)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/_ode.py", line 515, in integrate
y = ode.integrate(self, t, step, relax)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/_ode.py", line 388, in integrate
self.f_params, self.jac_params)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/_ode.py", line 946, in run
tuple(self.call_args) + (f_params,)))
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/_ode.py", line 472, in _wrap
f = self.cf(*((t, y[::2] + 1j * y[1::2]) + f_args))
TypeError: f() takes exactly 5 arguments (2 given)
If instead I use solver = ode(f), ie. the real-valued solver, it runs fine. Except that it doesn't solve the ODE I want which is complex-valued :(
I then tried to reduce the number of parameters by making the matrices A and B global variables. This way the only parameter the function f accepts is Omega. The error changes to
capi_return is NULL
Call-back cb_fcn_in___user__routines failed.
Traceback (most recent call last):
File "ode_test.py", line 37, in <module>
solver.integrate(10.0)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/_ode.py", line 515, in integrate
y = ode.integrate(self, t, step, relax)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/_ode.py", line 388, in integrate
self.f_params, self.jac_params)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/_ode.py", line 946, in run
tuple(self.call_args) + (f_params,)))
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/_ode.py", line 472, in _wrap
f = self.cf(*((t, y[::2] + 1j * y[1::2]) + f_args))
TypeError: 'float' object has no attribute '__getitem__'
where I figured out that float refers to the parameter Omega [by trying an integer]. Again, "ode" alone works in this case as well.
Last, I tried the same complex valued equation, but now A and B are just numbers. I tried to pass them both as parameters, i.e. params = [Omega,A,B], as well as making them global variables in which case params=[Omega]. The error is the
TypeError: 'float' object has no attribute '__getitem__'
error - the full error is the same as above. And once again this problem does not occur for the real-valued "ode".
I know zvode is an alternative, but it appears to become quite slow for large N. In the real problem I have, A is a diagonal matrix but B is a non-sparse full matrix.
Any insights are much appreciated! I'm interested both in (i) alternative ways to solve this complex-valued ODE with array-valued parameters, and (ii) how to get complex_ode to run :)
Thanks!
It seems like the link that Reti43 posted contains the answer, so let me put it here for the benefit of future users:
from scipy.integrate import complex_ode
import numpy as np
N = 3
Omega = 1.0;
class myfuncs(object):
def __init__(self, f, fargs=[]):
self._f = f
self.fargs=fargs
def f(self, t, y):
return self._f(t, y, *self.fargs)
def f(t, y, Omega,A,B):
return -1j*(A+np.cos(Omega*t)*B).dot(y)
A = np.random.ranf((N,N))
A = (A + A.T)/2.0
B = np.random.ranf((N,N))
B = (B + B.T)/2.0
v0 = np.zeros((N,),dtype=np.float64)
v0[0] = 1.0
t0 = 0
case = myfuncs(f, fargs=[Omega, A, B] )
solver = complex_ode(case.f)
solver.set_initial_value(v0, t0)
solver.integrate([10.0])
print solver.successful()
"""
t1 = 10
dt = 1
while solver.successful() and solver.t < t1:
solver.integrate(solver.t+dt)
print(solver.t, solver.y)
"""
Could maybe someone comment on why this trick does the job?

Categories