# composite function simplify expressions and strings

I am using code like

x=simplify(f(g(g(h(f(g(f(g(f(k))))))))))


to explore some composite functions f, g and h in the example line above

I think the line f(x) = x^2-2x+3 (for example) returns f(x) as an 'expression'

I think my lack of understanding of the nature of my expressions may be causing me issues.

I would like to be able to generate a loop so that I can tabulate things like

f(x)


then gf(x)

then ggf(x), gggf(x) ... etc upto a large number of g's

without having to run the code with x=simplify(f(k))

and then

x=simplify(g(f(k))) etc etc all separately

How can I do this? Any help much appreciated (obvs).

BTW, feel free to correct my tags

edit retag close merge delete

Sort by » oldest newest most voted

The nature of $x^2-2x+3$ depends on the nature of $x$. If $x$ is a variable, then we have for instance:

sage: var('x');
sage: E = x^2 - 2*x + 3
sage: E
x^2 - 2*x + 3
sage: type(E)
<class 'sage.symbolic.expression.Expression'>
sage: f(x) = x^2 - 2*x + 3
sage: f
x |--> x^2 - 2*x + 3
sage: type(f)
<class 'sage.symbolic.expression.Expression'>
sage: type(f(x))
<class 'sage.symbolic.expression.Expression'>

sage: f(f(x))
(x^2 - 2*x + 3)^2 - 2*x^2 + 4*x - 3
sage: type( f(f(x)) )
<class 'sage.symbolic.expression.Expression'>


However, if all computations involve only polynomial (or up so some complexity rational) expressions, then it may be useful to work inside a polynomial ring (or respectively tacitly inside the related fraction field). Here, we define $x$ to be the transcendent generator of the polynomial ring over the needed field (of coefficients). I will work in the samples below over $\Bbb Q$. In this case:

R.<x> = PolynomialRing(QQ)
f(x) = x^2 - 2*x + 3
type(f)
f(f(x))
type( f(f(x)) )


delivers:

<class 'sage.symbolic.expression.Expression'>
(x^2 - 2*x + 3)^2 - 2*x^2 + 4*x - 3
<class 'sage.symbolic.expression.Expression'>


But we can "do better", work with $f$ as a polynomial. So replace f(x) which is in sage "something else" by f, so that f becomes a polynomial.

R.<x> = PolynomialRing(QQ)
f = x^2 - 2*x + 3
type(f)
f(f(x))
type( f(f(x)) )


This gives:

<class 'sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint'>
x^4 - 4*x^3 + 8*x^2 - 8*x + 6
<class 'sage.rings.polynomial.polynomial_rational_flint.Polynomial_rational_flint'>


Here, sage implements the "universal property of a polynomial", namely the fact that we can plug in inside $f=f(\cdot)=f(x)$. So we can plug in something like $x^2$ instead of $x$, written as f( x^2 ). Also, we can plug in the polynomial f(x) itself, so we write f( f(x) ) as above, and we get as a result also a polynomial, an element of the polynomial ring $R=\Bbb Q[x]$. And in this case there is no need for a simplification. For instance:

R.<x> = PolynomialRing(QQ)
f = x^2 - 2*x + 3
g = x + 4

f(g(f(g(f(g(f(g(x))))))))


This is:

x^16 + 48*x^15 + 1120*x^14 + 16800*x^13 + 180900*x^12 + 1480464*x^11
+ 9516352*x^10 + 48983520*x^9 + 204005360*x^8 + 689831040*x^7
+ 1888420352*x^6 + 4144340736*x^5 + 7156320280*x^4 + 9415022880*x^3
+ 8921080320*x^2 + 5457719232*x + 1632644838


Alternatively, we can build some recursion, to see also the in between results:

def compose(polynomial_list):
h = x
for pol in polynomial_list[::-1]:
h = pol(h)
print(h)


And this function delivers:

sage: compose( [f, f, g, g, f] )
x^2 - 2*x + 3
x^2 - 2*x + 7
x^2 - 2*x + 11
x^4 - 4*x^3 + 24*x^2 - 40*x + 102
x^8 - 8*x^7 + 64*x^6 - 272*x^5 + 1098*x^4 - 2728*x^3 + 6448*x^2 - 8080*x + 10203


Doing the same with bare hands:

sage: f(x)
x^2 - 2*x + 3
sage: g(f(x))
x^2 - 2*x + 7
sage: g(g(f(x)))
x^2 - 2*x + 11
sage: f(g(g(f(x))))
x^4 - 4*x^3 + 24*x^2 - 40*x + 102
sage: f(f(g(g(f(x)))))
x^8 - 8*x^7 + 64*x^6 - 272*x^5 + 1098*x^4 - 2728*x^3 + 6448*x^2 - 8080*x + 10203


Even if the expressions are not polynomial / rational, inserting a simplification in (a rewritten version of) the above code should be easy and lead to a good solution.

more