Suppose I have the following lambda function
import numpy as np
f = lambda x,t : np.cos(t)
Now I want to obtain a symbolic expression of f (the ultimate goal is to obtain a primitive of that function f). So
import sympy as sym
x_s = sym.Symbol('x')
t_s = sym.Symbol('t')
sym.integrate(f(x_s,t_s), t_s)
But that fails with the error:
TypeError: loop of ufunc does not support argument 0 of type Symbol
which has no callable cos method
I want to be able to translate any Closed-form expression to sympy.
Thanks.
Edit: What I am trying to achieve at the end is to numerically solve a PDE using Dedalus. For the moment I just need a linear reaction diffusion equation with non-constant coefficients. That function f(x,t) is one of the coefficients. Since the equation is linear, I have the analytic solution, which is a function that depends on the primitive with respect to t of that function f(x,t). So I want to input the function f(x,t) in one place, and then use it to construct the numerical solution (in this case I just need to call the f(x,t) and also the analytic solution (in this case I need to call the primitive of f(x,t)).
So bottom line:
I need to define a lambda function that depends on 2 arguments x and t for the following purpose:
1) compute values given x and t.
2) convert that function definition to text to be used to solve the numerical equation using dedalus (and replace every reference to sym to np, otherwise dedalus will give error).
3) be able to obtain the primitive of that function (that's why I am using sympy) and then define a lambda function of that primitive in order to compute values for getting the analytical solution.
You are getting error because numpy`s cos is not compatible with sympy.Symbol. To get rid of this error you should rewrite your lambda like this:
import sympy as sym
f = lambda x,t : sym.cos(t)
De-lambdify is performed like this:
x_s = sym.Symbol('x')
t_s = sym.Symbol('t')
sym.integrate(f(x_s,t_s), t_s)
When you call f, it returns sympy cos function.
P.S. Check if you really need x parameter in f function.
So, full code will be:
import sympy as sym
f = lambda x,t : sym.cos(t)
x_s = sym.Symbol('x')
t_s = sym.Symbol('t')
sym.integrate(f(x_s,t_s), t_s)
Related
I am trying to replicate the mathematical operations from the link using Python.
I managed to integrate the function but I am unable to plot it for the specified intervals. I've tried to use arrange to get values for arguments and plot it against the function but it doesn't work.
Does anyone know how to get it work?
My snippet code:
from scipy.integrate import quad
def f(x):
if x >= 0 and x <= 2:
return x ** 2
elif x > 2 and x <= 4:
return 4
else:
return 0
res = quad(f, 0, 5)
print(res)
I assume you want to plot the function, f(x), rather than the results of integrating it. To do that you will want to create a list of x values (sounds like you did this), evaluate f for each of those values, and then use matplotlib's plot function to display the result.
The documentation for arange says that "When using a non-integer step, such as 0.1, the results will often not be consistent. It is better to use linspace for these cases." You probably want to plot with a non-integer step in x, otherwise you will use most of the details of your plot. So I would suggest switching to linspace.
import numpy as np
from matplotlib.pyplot import plot
xvals = np.linspace(0,6,100) #100 points from 0 to 6 in ndarray
yvals = list(map(f, xvals)) #evaluate f for each point in xvals
plot(xvals, yvals)
Most likely where you ran into a problem was directly applying your function f to an ndarray. The way it is written, f expects a single value as an input rather than an array. Map solves this problem by applying f to each value in your ndarray individually.
Edit: To use a sympy symbolic function:
You can also define a piecewise function in sympy. For the things you are trying to accomplish in your question, this won't be any different from using the original method described. However, if you want to do further symbolic manipulations with your function this could be useful.
import sympy
x = sympy.symbols('x')
f = sympy.Piecewise((0, x>4),(4, x>2) ,(x**2, x>=0)) #defines f as a symbolic function
sympy.plot(f, (x, 0,6)) #Plots f on the interval 0 to 6
Note in the definition of a piecewise function, the conditions are evaluated in order, so the order you define them in does matter. If, for example you swapper the first two conditions, the x>4 condition would never be reached because x>2 would always be satisfied first. This is why the conditions are defined in the reverse order from your original function.
I'm currently working through some exercises on multivariable function calculus and thought I would have a go at making my own function to determine gradient and hessian at a defined point for any function. I'm currently having issues when attempting to substitute the resulting matrices with coordinate values for an arbitrary function. I've already managed to solve specific examples, but my attempt to make a function to solve a user defined function isn't working correctly.
def multivariable_function(function, variables, substitute=(0,0)):
"""Determines Gradient and Hessian vectors for multivariable function.
Args:
function: Enter the multivariable function
variables: Enter list of variable names
substitute: Default = (0,0)
Returns:
gradient/hessian matrices for given coordinate
To do:
Include sympy symbol() generation within function
"""
#derive_by_array returns a gradient matrix for multivariable function
Gradient = simplify(derive_by_array(function, variables))
#derive_by_array returns a Hessian matrix for multivariable function
Hessian = simplify(derive_by_array(derive_by_array(function, variables), variables))
#Line currently isn't doing anything
Gradient.subs(zip(variables, substitute))
return Gradient, Hessian
This is the basic function so far in operation.
multivariable_function((x**2)*(y**3) + exp(2*x + x*y - 1) - (x**3 + 3*y**2)**2, (x,y))`
which yields the following result, I am however aiming to substitute the desired values into the gradient and hessian matrices to achieve the following desired result. I managed to achieved the desired result using the following.
from sympy import *
x, y, z, K, T, r, σ, h, a, f, μ, c, t, m, x1, x2, x3 = symbols('x, y, z, K, T, r, σ, h, a, f, μ, c, t, m, x1, x2, x3') # Variables used must be defined in sympy.
init_printing(use_unicode=False) #Print the answers in unicode characters
function = (x**2)*(y**3) + exp(2*x + x*y - 1) - (x**3 + 3*y**2)**2
Gradient_1 = simplify(derive_by_array(function, (x, y)))
Hessian_1 = simplify(derive_by_array(derive_by_array(function, (x, y)), (x, y)))
Gradient_1.subs(x, 0).subs(y,0), Hessian_1.subs(x,0).subs(y,0)
After viewing the issue raised here, it seems zipping the two lists should enable the subs() function to work, but it currently isn't for me. I attempted to loop through 'variables and 'substitute' to sequentially apply .subs(), however I'm finding the function only works if the method is chained for all replacement variables, as in the example above.
Does anyone know how I can apply the .subs() n times for a given coordinate to yield the relevant gradient/hessian matrices?
The variable Gradient is of type
sympy.tensor.array.dense_ndim_array.ImmutableDenseNDimArray
Like almost all SymPy objects, with exception of mutable matrices, it is immutable. The method subs does not modify it in place; it returns a new object, which needs to be assigned.
Gradient = Gradient.subs(zip(variables, substitute))
Hessian = Hessian.subs(zip(variables, substitute))
Then the function works as expected, returning
([2*exp(-1), 0], [[4*exp(-1), exp(-1)], [exp(-1), 0]])
But I suggest not passing generators to subs; there are outstanding issues involving that. Convert to a list or a dict first, to be safe. (There is also a difference there: should substitutions be consecutive or simultaneous, although this does not matter when substituting numbers for symbols.)
subs_dict = dict(zip(variables, substitute))
Gradient = Gradient.subs(subs_dict)
Hessian = Hessian.subs(subs_dict)
I have a function for acceleration a(t) which I know if I integrate twice with respect to t, I can find position x(t). I am trying to find position at t = 10 seconds.
Since a(t) is not multivariable I am having trouble using the Scipy dblquad function to calculate the double integral I need. Please see what I have so far:
def a(t):
return (2.5 / (1 + math.exp((t-8)/0.8)))
def upperbound():
return 10
def lowerbound():
return 0
x = dblquad(a,0,10,lowerbound,upperbound)
This does not work as from what I can gather dblquad needs a multivariabled a(t). Can anyone help?
You can use scipy's single variable integration twice to accomplish this
import math
from scipy.integrate import quad
def a(t):
return (2.5 / (1 + math.exp((t-8)/0.8)))
lb, ub = 0, 10
integral = quad(lambda t: quad(a, 0, t)[0], lb, ub)[0]
print(integral)
# 86.28470375472537
This is necessary because what you want to achieve is not to integrate a function of two variables but rather to integrate a function of one variable twice. In the integral statement above, the inner quad integrates the function once but maintains the integral as a function of t. The outer quad integrates the function the second time over the defined limits.
Note that it is necessary to take the first argument from the output of quad because it outputs a tuple. The second argument is an upper bound on the error of the numerical integration.
So I want to calculate the gradient and Hessian of the following sum. Afaik Theano should be able to do that, however I can't figure out how.
X is a Matrix of size M x N; y M sized vector; beta a N sized vector.
One way to compute the sum is using the scan() function, which I did like this:
res,ups = theano.scan(lambda v,w: v*np.log(1/(1+np.exp(-1*w.dot(beta))))
+((1-v)*(np.log(1/(1+np.exp(w.dot(beta)))))), sequences = [y,X])
t7 = theano.function(inputs = [X,y,beta],outputs = res)
and that works fine as far as I can tell. However, I can't use this as an Input for the grad() function with respect to beta.
So what I would like to know is if there is a way to either use the scan function as input of the grad function or a different way to compute the sum.
(I first tried in sympy, but sympy can't lambdify Indexedbase objects, so I can compute the grad but can't use it as a function, maybe that helps? )
The Sum adds up a function of the Dot Product of a line in X and beta while the binary vector y decides which of two functions will be used.
log(1/(1+exp(-X_i*beta)))
Hope that helps?
Problem: I want to numerically integrate a function f(t,N) that may be written as a linear combination of N other known functions g_1(t), ..., g_N(t).
My Solution I: I know the functions g_i and also the coefficients, so my initial idea was to create an row vector of coefficients and a column vector containing the lambda functions g_i and then use np.dot for the inner product to get the function object I want. Unfortunately, you cannot just add two function objects nor multiply a function object by a scalar.
My Solution II: Of course I can do something like (basically defining point wise what I want):
def f(t,N,a,g):
"""
a = numpy array of coefficients
g = numpy array of lambda functions corresponding to functions g_i
"""
res = 0
for i in xrange(N):
res += a[i] * g[i](t)
return res
But the for loop is of course not very great, especially when:
I need to run this function at many many time steps t
I pass this function f into a numerical integration routine like scipy.integrate.quad.
briefly:
In Cython You could speed up indexing using memoryviews.
If these equations are linear You could superimpose them using sympy:
example:
import sympy as sy
x,y = sy.symbols('x y')
g0 = x*0.33 + 6
g1 = x*0.72 + 1.3
g2 = x*11.2 - 6.5
gn = x*3.3 - 7.3
G = [g0,g1,g2,gn]
#this is superimposition
print sum(G).subs(x,15.1)
print sum(gi.subs(x,15.1) for gi in G)
'''
output:
228.305000000000
228.305000000000
'''
If its not what You want, give some example input and output, so that I can try and dont go blind...
With low ram avaiable You could get finall equation to numexpr and evaluate it with some input. Otherwise its best to work on numpy arrays.