# How to realize the composition of rational function mappings with Sagemath?

If I have two rational function mappings : f(x,y): (x,y )------>( x^2+15x-2 / x+15, x^2y+xy+y / x^2+30x-1 ); g(x,y): (x,y )------>( x^2+20x-18 / x+20, x^2y+xy+32y / x^2-31x+14 );

how to compute the f(g(x,y)) with sagemath?

edit retag close merge delete

Sort by » oldest newest most voted

In addition to @slelievre 's answer, a possibility is to consider f and g as functions on the Euclidean plane:

sage: E.<x,y> = EuclideanSpace()
sage: f = E.diff_map(E, [(x^2+15*x-2) / (x+15), (x^2*y+x*y+y) / (x^2+30*x-1)])
sage: f.display()
E^2 --> E^2
(x, y) |--> ((x^2 + 15*x - 2)/(x + 15), (x^2*y + x*y + y)/(x^2 + 30*x - 1))
sage: g = E.diff_map(E, [(x^2+20*x-18) / (x+20), (x^2*y+x*y+32*y) / (x^2-31*x+14)])
sage: g.display()
E^2 --> E^2
(x, y) |--> ((x^2 + 20*x - 18)/(x + 20), (x^2*y + x*y + 32*y)/(x^2 - 31*x + 14))


Then you may compose f and g via the * operator:

sage: h = f * g
sage: h.display()
E^2 --> E^2
(x, y) |--> ((x^4 + 55*x^3 + 962*x^2 + 4930*x - 5876)/(x^3 + 55*x^2 + 982*x + 5640), (x^6 + 42*x^5 + 478*x^4 + 1419*x^3 + 13026*x^2 - 9172*x + 11648)*y/(x^6 + 39*x^5 - 593*x^4 - 36773*x^3 - 320694*x^2 + 486956*x - 152264))


Note that the result is automatically simplified. You may access to the symbolic expressions composing the result via the method expr():

sage: h.expr()
((x^4 + 55*x^3 + 962*x^2 + 4930*x - 5876)/(x^3 + 55*x^2 + 982*x + 5640),
(x^6 + 42*x^5 + 478*x^4 + 1419*x^3 + 13026*x^2 - 9172*x + 11648)*y/(x^6 + 39*x^5 - 593*x^4 - 36773*x^3 - 320694*x^2 + 486956*x - 152264))
sage: h.expr()[0]
(x^4 + 55*x^3 + 962*x^2 + 4930*x - 5876)/(x^3 + 55*x^2 + 982*x + 5640)
sage: h.expr()[1]
(x^6 + 42*x^5 + 478*x^4 + 1419*x^3 + 13026*x^2 - 9172*x + 11648)*y/(x^6 + 39*x^5 - 593*x^4 - 36773*x^3 - 320694*x^2 + 486956*x - 152264)

more

One thing is that in mathematics we usually identify a function of two variables and a function of a two-dimensional vector variable. When programming however, these are slightly different.

So if we define:

def f(x, y):
return vector([(x^2+15*x-2) / (x+15), (x^2*y+x*y+y) / (x^2+30*x-1)])

def g(x, y):
return vector([(x^2+20*x-18) / (x+20), (x^2*y+x*y+32*y) / (x^2-31*x+14)])


then we can't do f(g(x, y)) and instead have to do f(*g(x, y)) and so we can define:

def fog(x, y):
return f(*g(x, y))


From there, there are several approaches to computing with rational functions:

• naive approach using the symbolic ring
• using polynomial rings and their fraction fields
• using arithmetic dynamical systems

## Naive approach using the symbolic ring

One problem here is that the expressions are not simplified.

sage: x, y = var('x y')
sage: f(x, y)
((x^2 + 15*x - 2)/(x + 15), (x^2*y + x*y + y)/(x^2 + 30*x - 1))
sage: g(x, y)
((x^2 + 20*x - 18)/(x + 20), (x^2*y + x*y + 32*y)/(x^2 - 31*x + 14))
sage: f(*g(x, y))
(((x^2 + 20*x - 18)^2/(x + 20)^2 + 15*(x^2 + 20*x - 18)/(x + 20) - 2)/((x^2 + 20*x - 18)/(x + 20) + 15), ((x^2*y + x*y + 32*y)/(x^2 - 31*x + 14) + (x^2*y + x*y + 32*y)*(x^2 + 20*x - 18)^2/((x^2 - 31*x + 14)*(x + 20)^2) + (x^2*y + x*y + 32*y)*(x^2 + 20*x - 18)/((x^2 - 31*x + 14)*(x + 20)))/((x^2 + 20*x - 18)^2/(x + 20)^2 + 30*(x^2 + 20*x - 18)/(x + 20) - 1))


## Using polynomial rings and their fraction fields

This is much better.

sage: R.<x, y> = PolynomialRing(QQ)
sage: S = R.fraction_field()
sage: x, y = S.gens()
sage: f(x, y)
((x^2 + 15*x - 2)/(x + 15), (x^2*y + x*y + y)/(x^2 + 30*x - 1))
sage: g(x, y)
((x^2 + 20*x - 18)/(x + 20), (x^2*y + x*y + 32*y)/(x^2 - 31*x + 14))
sage: f(*g(x, y))
((x^4 + 55*x^3 + 962*x^2 + 4930*x - 5876)/(x^3 + 55*x^2 + 982*x + 5640),
(x^6*y + 42*x^5*y + 478*x^4*y + 1419*x^3*y + 13026*x^2*y - 9172*x*y
+ 11648*y)/(x^6 + 39*x^5 - 593*x^4 - 36773*x^3 - 320694*x^2 + 486956*x
- 152264))


## Using arithmetic dynamical systems

This is probably the best approach for studying composition of rational maps.

more