1

I'd like to figure out how to code the following pseudo-code:

# Base-case
u_0(x) = x^3

for i in [0,5):
    u_(i+1)(x) = u_(i)(x)^2

So that in the end I can call u_5(x), for example.

The difficulty I'm having with accomplishing the above is finding a way to index Python functions by i so that I can iteratively define each function.

I tried using recursion with two functions in place of indexing but I get "maximum recursion depth exceeded".

Here is a minimal working example:

import math
import sympy as sym

a,b = sym.symbols('x y')

def f1(x,y):
    return sym.sin(x) + sym.cos(y)*sym.tan(x*y)

for i in range(0,5):
    def f2(x,y):
    return sym.diff(f1(x,y),x) + sym.cos(sym.diff(f1(x,y),y,y))

    def f1(x,y):
        return f2(x,y)

print(f2(a,b))
GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • 1
    Your question is too vague, is u_i(x) is a function or a variable ? – Sanju Jun 01 '17 at 03:14
  • 2
    Can you show what you're actually trying to do? Recursion is the natural solution to your problem. You can use an explicit stack if the depth is too large. – GManNickG Jun 01 '17 at 03:23
  • One step (directly to the base case) is not deep. Did you debug the program to verify you didn't accidentally have infinite recursion? In any case, recursion (or an explicit stack version) appears to be the solution. Please include a [MCVE](https://stackoverflow.com/help/mcve) to clarify. – GManNickG Jun 01 '17 at 03:29
  • `u_(i)(x) = u_0(x)^(2^i)` Why do you need recursion or any loop here? – Jithin Pavithran Jun 01 '17 at 03:34
  • @user46944: Your example needs to be minimal, *complete*, and verifiable. :) Please take a few minutes to slice down your existing program to the smallest Python script that reproduces the error, and edit your question to include it. Ideally people could just copy that and run it locally. Often you will find the problem yourself as you remove irrelevant parts of the program. – GManNickG Jun 01 '17 at 03:34
  • @user46944: Thanks. Two things: 1) Try not to share variable names in examples. Here you have `x` and `y` both as globals and as the names of function parameters, which can be confusion. I changed these to `a` and `b` for clarity. 2) Now that you have the minimal example, try adding some `print` calls to get a better idea of what's going on. Observe: https://repl.it/I0xa/0. You can see you indeed have mutual infinite recursion. That cause of this is the way closure captures work in Python, which can be surprising. See: https://stackoverflow.com/questions/2295290/. Let me know if that helps! – GManNickG Jun 01 '17 at 05:24
  • (Not posting as an answer because it's kind of up to you how you decide to resolve this situation. Maybe someone will jump in with a canonical solution.) – GManNickG Jun 01 '17 at 05:27

2 Answers2

1

Yes, the general idea would be to "index" the results in order to avoid recalculating them. The simplest way to achieve that is to "memoize", meaning telling a function to remember the result for values it has already calculated.

If f(i+1) is based on f(i) where i is a natural number, that can be especially effective.

In Python3, doing it for a 1 variable function is surprisingly simple, with a decorator:

import functools @functools.lru_cache(maxsize=None) def f(x): ..... return .... To know more about this, you can consult What is memoization and how can I use it in Python?. (If you are using Python 2.7, there is also a way to do it with a prepackaged decorator.)

Your specific case (if my understanding of your pseudo-code is correct) relies on a two variables function, where i is an integer variable and x is a symbol (i.e. not supposed to be resolved here). So you would need to memoize along i.

To avoid blowing the stack up when you brutally ask for the image of 5 (not sure why, but no doubt there is more recursion than meets the eye), then use a for loop to calculate your images on the range from 0 to 5 (in that order: 0, 1, 2...).

I hope this helps.

fralau
  • 3,279
  • 3
  • 28
  • 41
0

The answer is actually pretty simple:

Pseudocode:

u_0(x) = x^3

for i in [0,5):
     u_(i+1)(x) = u_(i)(x)^2

Actual code:

import sympy as sym

u = [None]*6 #Creates an empty array of 6 entries, i.e., u[0], u[1], ..., u[5]

x=sym.symbols('x')

u[0] = lambda x: x**3

for i in range(0,5):
    u[i+1] = lambda x, i=i: (u[i](x))**2 #the i=i in the argument of the lambda function is 
     #necessary in Python; for more about this, see this question.

#Now, the functions are stores in the array u.  However, to call them (e.g., evaluate them, 
#plot them, print them, etc) requires that we "lambdify" them, i.e., replace sympy 
#functions with numpy functions, which the following for loop accomplishes:

for i in range(0,6):
    ulambdified[i] = sym.lambdify(x,u[i](x),"numpy")

for i in range(0,6):
    print(ulambdified[i](x))
  • **My mistake**: You don't have to lambdify to print. print(u[2](x)) works just fine. –  Jun 13 '17 at 13:56