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)
Related
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
The aim of the program is to:
"Write a python function J(m,x) that calculates the value of Jm(x) using the trapezium rule, with N = 10000. Use your function in a program to make a plot of the Bessel functions J0(x), J1(x) and J2(x) as a function of x from x = 0 to x = 20."
Jm(x) = (1/pi) . integrate[cos(m.theta - x.sin(theta))] from 0 --> pi
and is part of an intro to python module for a 1st year physics degree.
The line the type error originates from is from my function to integrate a function using the trapezium rule:
def integrate(f, a, b, N:int):
h = (b-a) / N
s = 0
for i in range(1,N):
c = f(a + i*h)
s = s + c
Area = h*(0.5*f(a) + 0.5*f(b) + s)
return Area
The error refers to the line " c = f(a + i*h) ": "TypeError: 'numpy.float64' object is not callable".
Given this function works in other programs I've made, I'm not sure what the origin of this error is. I am aware that scipy.integrate.quad could do the integration better, however we've been asked not to use it to demonstrate learning different techniques.
One possibility is that the problem is caused by other parts of the larger program. As someone very new to programming in general it seems likely that other problems exist which I haven't run into yet as the program doesn't reach them before turning up an error. The rest of the code is as follows:
import numpy as np
#Defining how to integrate a function using the trapezium rule
def integrate(f, a, b, N:int):
h = (b-a) / N
s = 0
for i in range(1,N):
c = f(a + i*h)
s = s + c
Area = h*(0.5*f(a) + 0.5*f(b) + s)
return Area
def func(o, m, x):
return np.cos(m*o - x*np.sin(o)) #1st attempt at defining the bessel function
def J(m,x):
return (1 / np.pi) * integrate(func(0, m, x), 0, np.pi, 10000)
#Produce range of x-values from 0 to 20.
xvals = np.linspace(0,20,200)
#Calculating the value of the bessel function for each value of x and m
for i in range(200):
for j in range(3):
bessel = J(j, xvals[i])
print("x: {}, m: {}, Val: {}".format(xvals[i], j, bessel)) #Print statement to check the program is functioning correctly before moving on to the next stage
return (1 / np.pi) * integrate(func(0, m, x), 0, np.pi, 10000)
In your function J, you are giving a function call as a parameter, i.e. its return value. Change func(0, m, x) to func and it should work.
Edit:
The correct answer was to pass a lambda expression: lambda i: func(i, m, x). Credit goes to Barmar.
I wanted to make a function to get a quadratic equation given the vertex and a point. I got all of this right until, I was using sympy to simplify the expression because that's how it gets to standard form, but it gave me an error. Here is my code:
from math import sort
from sympy import *
x = Symbol('x')
def point_cd_vertex_hk(c,d,h,k):
a = (d - k) / (c - h) ** 2
equation = a * (x + h) ** 2 + k
print(f"Your equation is y = {equation}")
point_cd_vertex_hk(2,4,6,8)
And with this I got the error:
Traceback (most recent call last):
File "/Users/michaeldavid/Desktop/Coding/Python/Standard/quadratic_for_project.py",
line 11, in
quad_point_cd_vertex_hk(2,4,6,8)
File "/Users/michaeldavid/Desktop/Coding/Python/Standard/quadratic_for_project.py",
line 8, in quad_point_cd_vertex_hk
equation = a (x + h) ** 2 + k
TypeError: 'float' object is not callable
I have an idea that it might be something with the fact that the "a" value is a floating point number, but I don't know what is really causing the problem.
What does it mean and how do I fix this?
It seems you are typo in this line equation = a (x + h) ** 2 + k. 'a' is not a function. May be a * (x+h) is what you are looking for
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?
I'm trying to learn SymPy, and I'd like to figure out how to do a cool task, deriving the normal equations for a least-squares problem symbolically.
from sympy import *
init_session()
x, y, b = Matrix(), Matrix(), Matrix()
sqNorm = (y - x*b).dot(y- x*b)
solve(diff(sqNorm, b), b)
When I run that, I get
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/sympy/core/function.py", line 1638, in diff
return Derivative(f, *symbols, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/sympy/core/function.py", line 1005, in __new__
if v._diff_wrt:
File "/usr/local/lib/python2.7/dist-packages/sympy/matrices/matrices.py", line 3084, in __getattr__
"%s has no attribute %s." % (self.__class__.__name__, attr))
AttributeError: ImmutableMatrix has no attribute _diff_wrt.
I am hoping for a result like (x'x)^{-1}x'y or something. Is that possible in SymPy?
No, SymPy doesn't come with this level of abstract matrix calculus built-in. To be able to differentiate matrices, they have to have specific size and be filled with things you can differentiate in: I give an example below. That said, you may be interested in this project, which implements elements of abstract matrix calculus in SymPy by axiomatizing certain rules.
Here is a sample of you can actually do in terms of symbolic least squares with SymPy. Filling matrices with symbolic variables can be done with symarray (which uses a_0_0 notation). Then compute the residuals, differentiate, and solve.
from sympy import *
m = 3
n = 2
x = Matrix(symarray('x', (m, n)))
y = Matrix(symarray('y', (m, 1)))
b = Matrix(symarray('b', (n, 1)))
z = (y-x*b).dot(y-x*b)
vars = [b[i,0] for i in range(n)]
eqs = [z.diff(b) for b in vars]
print solve(eqs, vars)
The output, though correct, is not enlightening:
{b_0_0: ((x_0_1**2 + x_1_1**2 + x_2_1**2)*(x_0_0*y_0_0 + x_1_0*y_1_0 + x_2_0*y_2_0) - (x_0_0*x_0_1 + x_1_0*x_1_1 + x_2_0*x_2_1)*(x_0_1*y_0_0 + x_1_1*y_1_0 + x_2_1*y_2_0))/((x_0_0**2 + x_1_0**2 + x_2_0**2)*(x_0_1**2 + x_1_1**2 + x_2_1**2) - (x_0_0*x_0_1 + x_1_0*x_1_1 + x_2_0*x_2_1)**2), b_1_0: ((x_0_0**2 + x_1_0**2 + x_2_0**2)*(x_0_1*y_0_0 + x_1_1*y_1_0 + x_2_1*y_2_0) - (x_0_0*x_0_1 + x_1_0*x_1_1 + x_2_0*x_2_1)*(x_0_0*y_0_0 + x_1_0*y_1_0 + x_2_0*y_2_0))/((x_0_0**2 + x_1_0**2 + x_2_0**2)*(x_0_1**2 + x_1_1**2 + x_2_1**2) - (x_0_0*x_0_1 + x_1_0*x_1_1 + x_2_0*x_2_1)**2)}