# apply functions iteratively (modified re-post)

(This is a modified re-post of Apply Functions Iteratively since my original question wasn't answered)

I have a few functions R1,R2,R3,R4 which act on vectors. If X = matrix(3,1,(x0,y0,r)) then I have

def R1(X): return matrix(3,1,(X[0,0]/(X[0,0]^2+X[1,0]^2-X[2,0]^2),X[1,0]/(X[0,0]^2+X[1,0]^2-X[2,0]^2),X[2,0]/abs(X[0,0]^2+X[1,0]^2-X[2,0]^2)))

def R2(X): return matrix(3,1,(-X[0,0],X[1,0],X[2,0]))

def R3(X): return matrix(3,1,(-X[0,0]+2,X[1,0],X[2,0]))

def R4(X): return matrix(3,1,(X[0,0],-X[1,0]+2,X[2,0]))

For instance, if v = matrix(3,1,(1,1,1)), then applying R2 to v gives the matrix $(-1,1,1)$.

I'd like to apply about 10 "levels" of iteration of these functions and have the output as a list of vectors. So, the list should be $R1(v), R2(v),R3(v),R4(v),R1^2(v),R2(R1(v)),R3(R1(v)),R4(R1(v)),R1^3(v),...,R1^{10}(v)\,...,R4^{10}(v)$ (as vectors) where $R_j^n = R_j \circ \cdots \circ R_j$ $n$ times.

I know how to apply a single function iteratively, but I don't know how to combine/loop the four together. Thanks.

edit retag close merge delete

Sort by » oldest newest most voted

Let me assume that you want all possible compositions of length say n=3.

First, let us put the four functions into a list L:

sage: L = [R1,R2,R3,R4] ; L
[<function R1 at 0x7fc150827320>,
<function R2 at 0x7fc1508272a8>,
<function R3 at 0x7fc150827a28>,
<function R4 at 0x7fc150827aa0>]


Then, we want to look at the product of L with itself n times, and for each n-uple i, we want to appy each element of i (which is a function) iteratively starting from the vector v:

sage: n = 3
sage: from itertools import product
sage: for i in product(L, repeat=3):
....:     w = v
....:     print i        # to see which functions are applied (from left to right)
....:     for f in i:
....:         w = f(w)
....:     print w      # to see the composition applied to v


EDIT If you want to avoid redundency, you can put your results in a set. However, matrices are unhashable by default, so they can not be elements of sets. Hence you have to make them immutable first:

sage: S = set()
sage: for i in product(L, repeat=3):
....:     w = v
....:     for f in i:
....:         w = f(w)
....:         w.set_immutable()
sage: S
{[-3]
[ 1]
[ 1], [-1]
[ 1]
[ 1], [1/3]
[1/9]
[1/9], 

, 

}


In case there are a lot of equalities in the partial compotitions we can an iterative approach (as @nbruin's answer) so that the simplification is done at each step:

sage: v.set_immutable()
sage: Sold = {v}
sage: for i in range(n):
....:     Snew = set()
....:     for f in L:
....:         for u in Sold:
....:             w = f(u)
....:             w.set_immutable()
....:     Sold = Snew
sage: Sold
{[-3]
[ 1]
[ 1], [-1]
[ 1]
[ 1], [1/3]
[1/9]
[1/9], 

, 

}


In your example, you will save a lot of redundent computations, therefore you will be able to go way further.

more

If you want various levels in the list, you probably want the original as well. You could do

ops=[R1,R2,R3,R4]
T=[v]
L=[]
for i in range(10):
L += T
T = [f(v) for v in T for f in ops]

more