Python Iterative Function Generation

Consider the following idea: I want to generate a sequence of f_k functions, for k = 1,...,50 and save them in a Python dictionary. To give a concrete example, let's say

 f_k(x) = f_{k-1}(x) * sqrt(x) 

This is just an example, my problem is more complicated, but it does not matter for my question. Since in my real problem f_{k-1} very noisy and contains rounding errors, I don’t want to build f_k directly from f_{k-1} , but instead, first we approximate f_{k-1} through the spline approximation, and then define f_k from this spline approximation. Oddly enough, this results in an error message indicating that the maximum recursion depth has been exceeded. Here is a sample code:

 import numpy as np from scipy.interpolate import interp1d n = 50 # number of functions I want to create args = np.linspace(1,4,20) # where to evaluate for spline approximation fdict = dict() # dictionary that stores all the functions fdict[0] = lambda x: x**2 # the first function # generate function f_k as follows: First, take function f_{k-1} and # approximate it through a spline. Multiply that spline approximation # by sqrt(x) and store this as function f_k. for k in range(1,n+1): spline_approx = lambda x: interp1d( args,fdict[k-1](args) )(x) fdict[k] = lambda x: spline_approx(x) * np.sqrt(x) print('test evalutation: ', fdict[n](3)) 

This results in an error.

 RecursionError: maximum recursion depth exceeded 

My problem should be very specific to Python. This should have something to do with interpolation via interp1d. For instance. If I replace the string

 spline_approx = lambda x: interp1d( args,fdict[k-1](args) )(x) 

using polyphyte

 coefs = np.polyfit(args,fdict[k-1](args),10) # polyfit coefficients spline_approx = lambda x: np.polyval(coefs,x) # approximation of f_{k-1} 

the code is working fine. I suspect that the problem arises because fdict[k-1] is not directly evaluated, but only passed as a reference. But how can I solve this problem?

+6
source share
1 answer

The line that raises the RecursionError is indeed:

 spline_approx = lambda x: interp1d( args,fdict[k-1](args) )(x) 

This line means that spline_approx is a function that, when given x returns interp1d(args, fdict[k-1](args) to x .

Since interp1d returns the function you want to put in spline_approx , this line can be simplified:

 spline_approx = interp1d( args,fdict[k-1](args) ) 

which will stop throwing a RecursionError .


Why did your source code choose RecursionError ?

In the original line, interp1d(args, fdict[k-1](args)) is not evaluated because it is inside the lambda expression. This evaluation carries over to calling this lambda expression.

In other words, every time you call a function from fdict , all previous functions should evaluate interp1d(args, fdict[k-1](args)) . The problem is that args is a sequence, so fdict[k-1] is called as many times as args has elements.

The number of calls, of course, is exponential, since each function must evaluate the use-case function len(args) times. The result is a RecursionError .

On the other hand, the new expression does evaluate interp1d(args, fdict[k-1](args)) . After this evaluation, a call to fdict[k] will no longer cause a call to fdict[k-1] .

+4
source

Source: https://habr.com/ru/post/1014280/


All Articles