Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

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

(Result was manually adjusted.)

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.