# 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], [1]
[1]
[1], [3]
[1]
[1]}


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], [1]
[1]
[1], [3]
[1]
[1]}


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

more

This works well. Thank you!

( 2017-01-04 21:47:04 -0500 )edit

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