I am trying to convert this code into MATLAB but I am not sure how to do the subscripts (Y[i] = Y[i-1]) as well as the func and f_exact variables
heres the code:
def Forward_Euler(y0,t0,T,dt,f):
t = np.arange(t0,T+dt,dt)
Y = np.zeros(len(t))
Y[0] = y0
for i in range(1,len(t)):
Y[i] = Y[i-1]+dt*f(Y[i-1], t[i-1])
return Y, t
func = lambda y,t: y-t
f_exact = lambda t: t+1-1/2*np.exp(t)
You can use anonymous functions in matlab:
func = #(y,t)(y - t)
f_exact = #(t)(t + 1 - exp(t)/2) % it works with any matrix t as well
And you can use for matrices as well (they should keep matrix operation rules). For example, in func function, as there is a minus in the form of function, the dimension of y and t must be the same.
Related
Is there a way to locally bind functions within lambdas? I have a loop, and within each loop, I create an array of functions. I want to create another function which is the sum of all of these functions and store it in another array. This new array should hold the sum of all functions for each loop.
Then I want to create another function that is the sum over all the sum of functions.
However, the problem I have is that the original functions keep updating, so I am not getting my desired result. Can I locally bind the functions? Am I approaching this the wrong way?
import numpy as np
lmax = 4
lapprox = []
# Function to estimate
def curve_func(x):
return np.sin(x*np.pi)*x**2
# Initialise residual function
def residual_func(x):
return curve_func(x)
# For each l, create 2**l+1 nodes and determine new nodes.
for l in range(lmax):
nodes = np.linspace(0, 1, 2**l+1, endpoint = True)
if (l==0):
old_nodes = nodes
new_nodes = nodes
else:
old_nodes = np.linspace(0, 1, 2**(l-1)+1, endpoint = True)
new_nodes = [x for x in nodes if x not in old_nodes]
# Create basis function corresponding to each new node
if (l==0):
phi = [lambda x, i=i: max(1 - abs(2**l * x - i), 0) for i in range(len(new_nodes))]
else:
phi = [lambda x, i=i: max(1 - abs(2**l * x - (2*i+1)), 0) for i in range(len(new_nodes))]
# Calculate hierarchical surpluses
coeff = [residual_func(n) for n in new_nodes]
# Array of functions: coeff*phi
coeff_phi = [lambda x, func=func, alpha=alpha: coeff[alpha]*func(x) for alpha, func in enumerate(phi)]
# Array of length lmax, where each value is sum of functions in coeff_phi for fixed l
lapprox.append(lambda x: sum(f(x) for f in coeff_phi))
# Sum of all functions in lapprox
totapprox = lambda x: sum(f(x) for f in lapprox)
# Compute new residual function
residual_func = lambda x: curve_func(x) - totapprox(x)
Extra detail on what the code is doing: The code is designed to approximate a function, such as sin(pi*x)*x^2 using hierarchical linear splines. For each level l, there are some basis functions, given by the array phi. The function is approximated using a linear combination of some coefficients multiplied by these basis functions. The approximation is done sequentially, starting from a low-level, with few basis functions, until a high-level, with many basis functions. I need to keep track of the rolling approximation of the function to determine the values of the new coefficients.
Edit 2: I've defined the functions outside the loop. However, I am struggling in working out how to create a function to keep track of the residual_function. I have attached the 'dirty' solution that works as intended for lmax=3, but I would like to generalise it for any lmax. How can I do that?
def curve_func(x):
return np.sin(x*np.pi)*x**2
def residual_func_0(x):
return curve_func(x)
# Define nodes function
def make_nodes(l):
return np.linspace(0, 1, 2**l+1, endpoint = True)
# Define new_nodes function
def make_new_nodes(l):
if (l==0):
new_nodes = np.linspace(0, 1, 2**l+1, endpoint = True)
else:
old_nodes = np.linspace(0, 1, 2**(l-1)+1, endpoint = True)
new_nodes = [x for x in make_nodes(l) if x not in old_nodes]
return new_nodes
# Define basis functions
def make_basis(l, i):
if l == 0:
return lambda x: max(1 - abs(2**l * x - i), 0)
else:
return lambda x: max(1 - abs(2**l * x - (2*i+1)), 0)
# Define coeff*basis functions
def make_scaled_basis(alpha, fn):
return lambda x: alpha * fn(x)
new_nodes_0 = make_new_nodes(0)
new_nodes_1 = make_new_nodes(1)
new_nodes_2 = make_new_nodes(2)
new_nodes_3 = make_new_nodes(3)
phi_0 = [make_basis(0, i) for i in range(len(new_nodes_0))]
phi_1 = [make_basis(1, i) for i in range(len(new_nodes_1))]
phi_2 = [make_basis(2, i) for i in range(len(new_nodes_2))]
phi_3 = [make_basis(3, i) for i in range(len(new_nodes_3))]
coeff_0 = [curve_func(n) for n in new_nodes_0]
coeff_phi_0 = [make_scaled_basis(alpha, fn) for alpha, fn in zip(coeff_0, phi_0)]
residual_func_0 = lambda x: curve_func(x) - sum(f(x) for f in coeff_phi_0)
coeff_1 = [residual_func_0(n) for n in new_nodes_1]
coeff_phi_1 = [make_scaled_basis(alpha, fn) for alpha, fn in zip(coeff_1, phi_1)]
residual_func_1 = lambda x: residual_func_0(x) - sum(f(x) for f in coeff_phi_1)
coeff_2 = [residual_func_1(n) for n in new_nodes_2]
coeff_phi_2 = [make_scaled_basis(alpha, fn) for alpha, fn in zip(coeff_2, phi_2)]
residual_func_2 = lambda x: residual_func_1(x) - sum(f(x) for f in coeff_phi_2)
coeff_3 = [residual_func_2(n) for n in new_nodes_3]
coeff_phi_3 = [make_scaled_basis(alpha, fn) for alpha, fn in zip(coeff_3, phi_3)]
residual_func_3 = lambda x: residual_func_2(x) - sum(f(x) for f in coeff_phi_3)
A simple way to localize both l and i in the body of a function is to create a function that returns a function which closes over the local variables l and i.
For example:
def make_basis(l, i):
if l == 0:
return lambda x: max(1 - abs(2**l * x - i), 0)
else:
return lambda x: max(1 - abs(2**l * x - (2*i+1)), 0)
...
for l in range(lmax):
...
phi = [make_basis(l, i) for i in range(len(new_nodes))]
Loops do not create new scopes; only function bodies do.
My first py file is the function that I want to find the roots, like this:
def myfun(unknowns,a,b):
x = unknowns[0]
y = unknowns[1]
eq1 = a*y+b
eq2 = x**b
z = x*y + y/x
return eq1, eq2
And my second one is to find the value of x and y from a starting point, given the parameter value of a and b:
a = 3
b = 2
x0 = 1
y0 = 1
x, y = scipy.optimize.fsolve(myfun, (x0,y0), args= (a,b))
My question is: I actually need the value of z after plugging in the result of found x and y, and I don't want to repeat again z = x*y + y/x + ..., which in my real case it's a middle step variable without an explicit expression.
However, I cannot replace the last line of fun with return eq1, eq2, z, since fslove only find the roots of eq1 and eq2.
The only solution now is to rewrite this function and let it return z, and plug in x and y to get z.
Is there a good solution to this problem?
I believe that's the wrong approach. Since you have z as a direct function of x and y, then what you need is to retrieve those two values. In the listed case, it's easy enough: given b you can derive x as the inverse of eqn2; also given a, you can invert eqn1 to get y.
For clarity, I'm changing the names of your return variables:
ret1, ret2 = scipy.optimize.fsolve(myfun, (x0,y0), args= (a,b))
Now, invert the two functions:
# eq2 = x**b
x = ret2**(1/b)
# eq1 = a*y+b
y = (ret1 - b) / a
... and finally ...
z = x*y + y/x
Note that you should remove the z computation from your function, as it serves no purpose.
I am trying to define a function of n variables to fit to a data set. The function looks like this.
Kelly Function
I then want to find the optimal ai's and bj's to fit my data set using scipy.optimize.leastsq
Here's my code so far.
from scipy.optimize import leastsq
import numpy as np
def kellyFunc(a, b, x): #Function to fit.
top = 0
bot = 0
a = [a]
b = [b]
for i in range(len(a)):
top = top + a[i]*x**(2*i)
bot = bot + b[i]*x**(2*i)
return(top/bot)
def fitKelly(x, y, n):
line = lambda params, x : kellyFunc(params[0,:], params[1,:], x) #Lambda Function to minimize
error = lambda params, x, y : line(params, x) - y #Kelly - dataset
paramsInit = [[1 for x in range(n)] for y in range(2)] #define all ai and bi = 1 for initial guess
paramsFin, success = leastsq(error, paramsInit, args = (x,y)) #run leastsq optimization
#line of best fit
xx = np.linspace(x.min(), x.max(), 100)
yy = line(paramsFin, xx)
return(paramsFin, xx, yy)
At the moment it's giving me the error:
"IndexError: too many indices" because of the way I've defined my initial lambda function with params[0,:] and params[1,:].
There are a few problems with your approach that makes me write a full answer.
As for your specific question: leastsq doesn't really expect multidimensional arrays as parameter input. The documentation doesn't make this clear, but parameter inputs are flattened when passed to the objective function. You can verify this by using full functions instead of lambdas:
from scipy.optimize import leastsq
import numpy as np
def kellyFunc(a, b, x): #Function to fit.
top = 0
bot = 0
for i in range(len(a)):
top = top + a[i]*x**(2*i)
bot = bot + b[i]*x**(2*i)
return(top/bot)
def line(params,x):
print(repr(params)) # params is 1d!
params = params.reshape(2,-1) # need to reshape back
return kellyFunc(params[0,:], params[1,:], x)
def error(params,x,y):
print(repr(params)) # params is 1d!
return line(params, x) - y # pass it on, reshape in line()
def fitKelly(x, y, n):
#paramsInit = [[1 for x in range(n)] for y in range(2)] #define all ai and bi = 1 for initial guess
paramsInit = np.ones((n,2)) #better
paramsFin, success = leastsq(error, paramsInit, args = (x,y)) #run leastsq optimization
#line of best fit
xx = np.linspace(x.min(), x.max(), 100)
yy = line(paramsFin, xx)
return(paramsFin, xx, yy)
Now, as you see, the shape of the params array is (2*n,) instead of (2,n). By doing the re-reshape ourselves, your code (almost) works. Of course the print calls are only there to show you this fact; they are not needed for the code to run (and will produce bunch of needless output in each iteration).
See my other changes, related to other errors: you had a=[a] and b=[b] in your kellyFunc, for no good reason. This turned the input arrays into lists containing arrays, which made the next loop do something very different from what you intended.
Finally, the sneakiest error: you have input variables named x, y in fitKelly, then you use x and y is loop variables in a list comprehension. Please be aware that this only works as you expect it to in python 3; in python 2 the internal variables of list comprehensions actually leak outside the outer scope, overwriting your input variables named x and y.
I am trying to understand a Python program that solves differential equations numerically using the Runge-Kutta method. I have developed my own solution but was looking for other implementations. I found several but this one intrigued me as I am having a difficult time understanding how lambda works.
Here is the code:
def RK4(f):
return lambda t, y, dt: (
lambda dy1: (
lambda dy2: (
lambda dy3: (
lambda dy4: (dy1 + 2*dy2 + 2*dy3 + dy4)/6
)( dt * f( t + dt , y + dy3 ) )
)( dt * f( t + dt/2, y + dy2/2 ) )
)( dt * f( t + dt/2, y + dy1/2 ) )
)( dt * f( t , y ) )
def theory(t): return (t**2 + 4)**2 /16
from math import sqrt
dy = RK4(lambda t, y: t*sqrt(y))
t, y, dt = 0., 1., .1
while t <= 10:
if abs(round(t) - t) < 1e-5:
print("y(%2.1f)\t= %4.6f \t error: %4.6g" % ( t, y, abs(y - theory(t))))
t, y = t + dt, y + dy( t, y, dt )
The long strings of lambdas and the dy function is confusing me.
First: How is the function RK4 receiving (t, y, dt) when dy is called? It looks appears that the lambda in dy = RK4(..) is only taking two parameters.
Second: How do the repeated lambda calls in RK4 work?
First of all, read about higher-order functions.
First: How is the function RK4 receiving (t, y, dt) when dy is called?
It looks appears that the lambda in dy = RK4(..) is only taking two
parameters.
Ok, simple facts:
def RK4(f)
RK4 is recieving one argument. Which, in this case, is a (lambda) function:
dy = RK4(lambda t, y: t*sqrt(y))
So in this case, f is going to be lambda t, y: t*sqrt(y).
RK4 returns a function, which takes 3 arguments:
return lambda t, y, dt: ( ... )
So the call dy( t, y, dt ) is fine.
A lambda is syntactic sugar for creating a simple function with minimal boilerplate.
For example:
f = lamdbda x: x + 5
The above is morally equivalent to:
def __lambda_123_line_567(x): # name is for illustrative purposes, only
return x + 5 # Python internally may name it however it
# chooses to do so
f = __lambda_123_line_567
The general syntax of a lambda is the keyword "lambda", followed by a list of parameters, followed by a colon, followed by the expression that should be returned by the function.
The lambda operator or lambda function is a way to create small anonymous functions. Here's the general format:
lambda(variable: test for, apply to)
I am trying to evaluate a function for different values of a variable n, I created a np.linspace for this vairiable and plugged it into a function Q:
def Q(z_i, z_min,f_gamma, mDM, sigma_v,n, with_ucmh):
dQdz_z = lambda z : dQdz(f_gamma, mDM, sigma_v, z,n, with_ucmh)
integrand = lambda z: ((1/((1+z)*H_z(z)))* (dQdz_z(z)) * np.exp(-tau(z)))
second_part = const.C*const.B*integrate.romberg(integrand,z_min,z_i)
return second_part
z_i = 2.0e6
z_min = 5.0e4
sigma_v = 3.0e-27
f_gamma = 1.
mDM = 10.
with_ucmh = True
n = np.linspace(1.,1.3,100)
mu = Q(z_i, z_min,f_gamma, mDM, sigma_v,n, with_ucmh)
I get ValueError: setting an array element with a sequence that point me to the line where I use the integrate.romberg method of scipy, but I don't understand how come I get here this sort of error..