In a sympy expression I would like to gather all sub expressions of (x*y)
and replace it by z, wherever possible. In a very simple example, that means performing the map
x*a*y+ (x*y**2) -> a*(x*y) + (x*y)*y -> a*z + z*y
The full code is with another example is
from sympy import symbols,Function,Derivative
from sympy import simplify, exp, cos, sin,log
x,y,z = symbols('x y z')
a,b,c = symbols('a b c')
f,g = Function('f')(x),Function('g')(x)
# Simplify the expression such that all combinations of (x*y) can be replaced by c
expr_1 = ((x**2+y)*y*exp(-c+2*log(x*c*y)))/(x**3*c*y**2)
#simplify(expr_1) ?
In a final step, I would like to replace two functions f*g by h
expr_2 = f*g + f*Derivative(g,x) + Derivative(f*g, x) -> h + f*Derivative(g,x) + Derivative(h, x)
Sometimes an algebraic substitution will do what you want:
>>> eq
a*x*y + x*y**2
>>> eq.subs(x,z/y)
a*z + y*z
But you could just as well have done subs(y,z/x) but that would not have led to as simple of an expression. In such cases you can try both and take the simpler of the two:
>>> from sympy import ordered
>>> next(ordered([eq.subs(x,z/y),eq.subs(y,z/x)]))
a*z + y*z
For expr_1
>>> eq=((x**2+y)*y*exp(-c+2*log(x*c*y)))/(x**3*c*y**2)
>>> next(ordered([eq.subs(x,z/y),eq.subs(y,z/x)]))
c*z*(x**2 + z/x)*exp(-c)/x**2
>>> next(ordered([eq.subs(x,c/y),eq.subs(y,c/x)]))
y**2*(c**2/y**2 + y)*exp(-c)
>>> simplify(_)
(c**2 + y**3)*exp(-c)
The ordered strategy should also work for expr_2.
I'm using python 3.7
How do you handle multiple "returned" values from an imported function after being called? Is there a way to set the return values to variables?
File = 'Func_File'
In 'Func_File':
def how():
x = x
y = y
z = z
return x, y z
So now I import the function from 'func_file' to the script i'm using it on.
From func_file import how
When I call how(), how can I show the returned values individually?
a, b, c = how ()
print (a)
print (b)
print (c)
As the title suggests, I'm trying to fit a piecewise equation to a large data set. The equations I would like to fit to my data are as follows:
y(x) = b, when x < c
else:
y(x) = b + exp(a(x-c)) - 1, when x >= c
There are multiple answers to how such an issue can be addressed, but as a Python beginner I can't figure out how to apply them to my problem:
Curve fit with a piecewise function?
Conditional curve fit with scipy?
The problem is that all variables (a,b and c) have to be calculated by the fitting algorithm.
Thank you for your help!
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
# Reduced Dataset
y = np.array([23.032, 21.765, 20.525, 21.856, 21.592, 20.754, 20.345, 20.534,
23.502, 21.725, 20.126, 21.381, 20.217, 21.553, 21.176, 20.976,
20.723, 20.401, 22.898, 22.02 , 21.09 , 22.543, 22.584, 22.799,
20.623, 20.529, 20.921, 22.505, 22.793, 20.845, 20.584, 22.026,
20.621, 23.316, 22.748, 20.253, 21.218, 23.422, 23.79 , 21.371,
24.318, 22.484, 24.775, 23.773, 25.623, 23.204, 25.729, 26.861,
27.268, 27.436, 29.471, 31.836, 34.034, 34.057, 35.674, 41.512,
48.249])
x = np.array([3756., 3759., 3762., 3765., 3768., 3771., 3774., 3777., 3780.,
3783., 3786., 3789., 3792., 3795., 3798., 3801., 3804., 3807.,
3810., 3813., 3816., 3819., 3822., 3825., 3828., 3831., 3834.,
3837., 3840., 3843., 3846., 3849., 3852., 3855., 3858., 3861.,
3864., 3867., 3870., 3873., 3876., 3879., 3882., 3885., 3888.,
3891., 3894., 3897., 3900., 3903., 3906., 3909., 3912., 3915.,
3918., 3921., 3924.])
# Simple exponential function without conditions (works so far)
def exponential_fit(x,a,b,c):
return b + np.exp(a*(x-c))
popt, pcov = curve_fit(exponential_fit, x, y, p0 = [0.1, 20,3800])
plt.plot(x, y, 'bo')
plt.plot(x, exponential_fit(x, *popt), 'r-')
plt.show()
You should change your function to something like
def exponential_fit(x, a, b, c):
if x >= c:
return b + np.exp(a*(x-c))-1
else:
return b
Edit: As chaosink pointed out in the comments, this approach no longer works as the the above function assumes that x is a scalar. However, curve_fit evaluates the function for array-like x. Consequently, one should use vectorised operations instead, see here for more details. To do so, one can either use
def exponential_fit(x, a, b, c):
return np.where(x >= c, b + np.exp(a*(x-c))-1, b)
or chaosink's suggestion in the comments:
def exponential_fit(x, a, b, c):
mask = (x >= c)
return mask * (b + np.exp(a*(x-c)) - 1) + ~mask * b
Both give:
I have a loss function L(u1,...,un) that takes the form
L(u) = Integral( (I**2 + J**2) * h, (t,c,d) ) //h=h(t), I=I(t,u)
where
I = Integral( f, (x,a,b) ) // f=f(x,t,u)
J = Integral( g, (x,a,b) ) // g=g(x,t,u)
I want to numerically minimize L with scipy, hence I need to lambdify the expression.
However at this point in time lambdify does not natively support translating integrals. With some tricks one can get it to work with single parametric integrals, see Lambdify A Parametric Integral. However I don't see how the proposed solution could possibly be extended to this generalised case.
One idea that in principle should work is the following:
Take the computational graph defining L. Recursively, starting from the leaves, replace each symbolic operation with the corresponding numerical operation, expressed as a lambda function. However this would lead to an immense nesting of lambda function, which I suspect has a very bad influence on performance.
Ideally we would want to arrive at the same result as one would by hand crafting:
L = lambda u: quad(lambda t: (quad(lambda x: f,a,b)[0]**2
+ quad(lambda x: g,a,b)[0]**2)*h, c, d)[0]
MWE: (using code from old thread)
from sympy import *
from scipy.integrate import quad
import numpy as np
def integral_as_quad(function, limits):
x, a, b = limits
param = tuple(function.free_symbols - {x})
f = sp.lambdify((x, *param), function, modules=['numpy'])
return quad(f, a, b, args=param)[0]
x,a,b,t = sp.symbols('x a b t')
f = (x/t-a)**2
g = (x/t-b)**2
h = exp(-t)
I = Integral( f**2,(x,0,1))
J = Integral( g**2,(x,0,1))
K = Integral( (I**2 + J**2)*h,(t,1,+oo))
F = lambdify( (a,b), K, modules=['sympy',{"Integral": integral_as_quad}])
L = lambda a,b: quad(lambda t: (quad(lambda x: (x/t-a)**2,0,1)[0]**2
+ quad(lambda x: (x/t-b)**2,0,1)[0]**2)*np.exp(-t), 1, np.inf)[0]
display(F(1,1))
display(type(F(1,1)))
display(L(1,1))
I am trying to implement this function in theano.
This is not about solving the integral (which is immediate) but rather how to implement it.
So far I have gotten this
import theano
from theano import tensor as T
import numpy as np
import scipy.integrate as integrate
x = T.vector('x')
h = T.vector('h')
t = T.scalar('t')
A = np.asarray([[0,1],[1,0]])
A = theano.shared(name='A', value=A)
B = np.asarray([[-1,0],[0,-1]])
B = theano.shared(name='B', value=B)
xn = A.dot(x)
hn = B.dot(h)
res = (t + xn.dot(hn))**(-2)
g = theano.function([t,x,h],res) # this computes the integrand
f = theano.function([x,h], integrate.quad(lambda t: g(t,x,h), 10, np.inf))
Unfortunately, this doesn't work. I am getting the error missing 2 required positional arguments: 'x' and 'h'. Maybe the integrate.quad function cannot "see" the inputs x,h.
Thanks a lot for the help!