I have done more digging. If I am not mistaken, what governs the coercion is the function `pushout` in `categories/pushout.py`. For each construction functor there is a hardcoded rank, such as 9.5 for the InfinitePolynomialFunctor, 10 for the MatrixFunctor, or 9 for the PolynomialFunctor and the MultiPolynomialFunctor. SymmetricFunctions do not have a construction functor.
First the two parents are decomposed into their construction tower - a list of (functor, object) pairs, for example
[(None,
Univariate Polynomial Ring in z over Infinite polynomial ring in a over Integer Ring),
(Poly[z], Infinite polynomial ring in a over Integer Ring),
(InfPoly{[a], "lex", "dense"}, Integer Ring)]
or
[(None, Univariate Polynomial Ring in z over Integer Ring),
(Poly[z], Integer Ring)]
Next (in this case), these two towers are merged, essentially by preferring lower rank construction functors. In the case at hand, we obtain the construction tower
[(None,
Univariate Polynomial Ring in z over Infinite polynomial ring in a over Univariate Polynomial Ring in z over Integer Ring),
(Poly[z],
Infinite polynomial ring in a over Univariate Polynomial Ring in z over Integer Ring),
(InfPoly{[a], "lex", "dense"},
Univariate Polynomial Ring in z over Integer Ring),
(Poly[z], Integer Ring)]
However, if the ranks of two construction functors are equal, such as the PolynomialFunctor and the MultiPolynomialFunctor, a look ahead is done, whether one of the two functors to be applied next appears later in the other tower anyway. If so, application of this functor is postponed.
Now it is unclear to me, why this look ahead is only done when the ranks are equal. In any case, it does not look like a quick andd easy project to me.
Might it be easier to create a copy of the InfinitePolynomialRing, so that I can guarantee that the common parent of anything with base ring R and anything with base ring InfinitePolynomialRing(R) is simply the latter?
Help still greatly appreciated.
Martin