Coercion via Construction Functors¶

class
sage.categories.pushout.
AlgebraicClosureFunctor
¶ Bases:
sage.categories.pushout.ConstructionFunctor
Algebraic Closure.
EXAMPLES:
sage: F = CDF.construction()[0] sage: F(QQ) Algebraic Field sage: F(RR) Complex Field with 53 bits of precision sage: F(F(QQ)) is F(QQ) True

merge
(other)¶ Mathematically, Algebraic Closure subsumes Algebraic Extension. However, it seems that people do want to work with algebraic extensions of
RR
. Therefore, we do not merge with algebraic extension.


class
sage.categories.pushout.
AlgebraicExtensionFunctor
(polys, names, embeddings=None, structures=None, cyclotomic=None, precs=None, implementations=None, **kwds)¶ Bases:
sage.categories.pushout.ConstructionFunctor
Algebraic extension (univariate polynomial ring modulo principal ideal).
EXAMPLES:
sage: K.<a> = NumberField(x^3+x^2+1) sage: F = K.construction()[0] sage: F(ZZ['t']) Univariate Quotient Polynomial Ring in a over Univariate Polynomial Ring in t over Integer Ring with modulus a^3 + a^2 + 1
Note that, even if a field is algebraically closed, the algebraic extension will be constructed as the quotient of a univariate polynomial ring:
sage: F(CC) Univariate Quotient Polynomial Ring in a over Complex Field with 53 bits of precision with modulus a^3 + a^2 + 1.00000000000000 sage: F(RR) Univariate Quotient Polynomial Ring in a over Real Field with 53 bits of precision with modulus a^3 + a^2 + 1.00000000000000
Note that the construction functor of a number field applied to the integers returns an order (not necessarily maximal) of that field, similar to the behaviour of
ZZ.extension(...)
:sage: F(ZZ) Order in Number Field in a with defining polynomial x^3 + x^2 + 1
This also holds for nonabsolute number fields:
sage: K.<a,b> = NumberField([x^3+x^2+1,x^2+x+1]) sage: F = K.construction()[0] sage: O = F(ZZ); O Relative Order in Number Field in a with defining polynomial x^3 + x^2 + 1 over its base field sage: O.ambient() is K True

expand
()¶ Decompose the functor \(F\) into subfunctors, whose product returns \(F\).
EXAMPLES:
sage: P.<x> = QQ[] sage: K.<a> = NumberField(x^35,embedding=0) sage: L.<b> = K.extension(x^2+a) sage: F,R = L.construction() sage: prod(F.expand())(R) == L True sage: K = NumberField([x^22, x^23],'a') sage: F, R = K.construction() sage: F AlgebraicExtensionFunctor sage: L = F.expand(); L [AlgebraicExtensionFunctor, AlgebraicExtensionFunctor] sage: L[1](QQ) Number Field in a1 with defining polynomial x^2  3

merge
(other)¶ Merging with another
AlgebraicExtensionFunctor
.INPUT:
other
– Construction Functor.OUTPUT:
 If
self==other
,self
is returned.  If
self
andother
are simple extensions and both provide an embedding, then it is tested whether one of the number fields provided by the functors coerces into the other; the functor associated with the target of the coercion is returned. Otherwise, the construction functor associated with the pushout of the codomains of the two embeddings is returned, provided that it is a number field.  If these two extensions are defined by Conway polynomials over finite fields, merges them into a single extension of degree the lcm of the two degrees.
 Otherwise, None is returned.
REMARK:
Algebraic extension with embeddings currently only works when applied to the rational field. This is why we use the admittedly strange rule above for merging.
EXAMPLES:
The following demonstrate coercions for finite fields using Conway or pseudoConway polynomials:
sage: k = GF(3^2, prefix='z'); a = k.gen() sage: l = GF(3^3, prefix='z'); b = l.gen() sage: a + b # indirect doctest z6^5 + 2*z6^4 + 2*z6^3 + z6^2 + 2*z6 + 1
Note that embeddings are compatible in lattices of such finite fields:
sage: m = GF(3^5, prefix='z'); c = m.gen() sage: (a+b)+c == a+(b+c) # indirect doctest True sage: from sage.categories.pushout import pushout sage: n = pushout(k, l) sage: o = pushout(l, m) sage: q = pushout(n, o) sage: q(o(b)) == q(n(b)) # indirect doctest True
Coercion is also available for number fields:
sage: P.<x> = QQ[] sage: L.<b> = NumberField(x^8x^4+1, embedding=CDF.0) sage: M1.<c1> = NumberField(x^2+x+1, embedding=b^41) sage: M2.<c2> = NumberField(x^2+1, embedding=b^6) sage: M1.coerce_map_from(M2) sage: M2.coerce_map_from(M1) sage: c1+c2; parent(c1+c2) #indirect doctest b^6 + b^4  1 Number Field in b with defining polynomial x^8  x^4 + 1 with b = 0.2588190451025208? + 0.9659258262890683?*I sage: pushout(M1['x'],M2['x']) Univariate Polynomial Ring in x over Number Field in b with defining polynomial x^8  x^4 + 1 with b = 0.2588190451025208? + 0.9659258262890683?*I
In the previous example, the number field
L
becomes the pushout ofM1
andM2
since both are provided with an embedding intoL
, and sinceL
is a number field. If two number fields are embedded into a field that is not a numberfield, no merging occurs:sage: K.<a> = NumberField(x^32, embedding=CDF(1/2*I*2^(1/3)*sqrt(3)  1/2*2^(1/3))) sage: L.<b> = NumberField(x^62, embedding=1.1) sage: L.coerce_map_from(K) sage: K.coerce_map_from(L) sage: pushout(K,L) Traceback (most recent call last): ... CoercionException: ('Ambiguous Base Extension', Number Field in a with defining polynomial x^3  2 with a = 0.6299605249474365? + 1.091123635971722?*I, Number Field in b with defining polynomial x^6  2 with b = 1.122462048309373?)
 If


class
sage.categories.pushout.
BlackBoxConstructionFunctor
(box)¶ Bases:
sage.categories.pushout.ConstructionFunctor
Construction functor obtained from any callable object.
EXAMPLES:
sage: from sage.categories.pushout import BlackBoxConstructionFunctor sage: FG = BlackBoxConstructionFunctor(gap) sage: FS = BlackBoxConstructionFunctor(singular) sage: FG BlackBoxConstructionFunctor sage: FG(ZZ) Integers sage: FG(ZZ).parent() Gap sage: FS(QQ['t']) polynomial ring, over a field, global ordering // coefficients: QQ // number of vars : 1 // block 1 : ordering lp // : names t // block 2 : ordering C sage: FG == FS False sage: FG == loads(dumps(FG)) True

class
sage.categories.pushout.
CompletionFunctor
(p, prec, extras=None)¶ Bases:
sage.categories.pushout.ConstructionFunctor
Completion of a ring with respect to a given prime (including infinity).
EXAMPLES:
sage: R = Zp(5) sage: R 5adic Ring with capped relative precision 20 sage: F1 = R.construction()[0] sage: F1 Completion[5, prec=20] sage: F1(ZZ) is R True sage: F1(QQ) 5adic Field with capped relative precision 20 sage: F2 = RR.construction()[0] sage: F2 Completion[+Infinity, prec=53] sage: F2(QQ) is RR True sage: P.<x> = ZZ[] sage: Px = P.completion(x) # currently the only implemented completion of P sage: Px Power Series Ring in x over Integer Ring sage: F3 = Px.construction()[0] sage: F3(GF(3)['x']) Power Series Ring in x over Finite Field of size 3

commutes
(other)¶ Completion commutes with fraction fields.
EXAMPLES:
sage: F1 = Zp(5).construction()[0] sage: F2 = QQ.construction()[0] sage: F1.commutes(F2) True

merge
(other)¶ Two Completion functors are merged, if they are equal. If the precisions of both functors coincide, then a Completion functor is returned that results from updating the
extras
dictionary ofself
byother.extras
. Otherwise, if the completion is at infinity then merging does not increase the set precision, and if the completion is at a finite prime, merging does not decrease the capped precision.EXAMPLES:
sage: R1.<a> = Zp(5,prec=20)[] sage: R2 = Qp(5,prec=40) sage: R2(1)+a # indirect doctest (1 + O(5^20))*a + 1 + O(5^40) sage: R3 = RealField(30) sage: R4 = RealField(50) sage: R3(1) + R4(1) # indirect doctest 2.0000000 sage: (R3(1) + R4(1)).parent() Real Field with 30 bits of precision
sage: P0 = ZpFM(5, 10) sage: P1 = ZpFM(5, 20) sage: P2 = ZpCR(5, 10) sage: P3 = ZpCR(5, 20) sage: P4 = ZpCA(5, 10) sage: P5 = ZpCA(5, 20) sage: P6 = Qp(5, 10) sage: P7 = Qp(5, 20) sage: Plist = [P2,P3,P4,P5,P6,P7] sage: from sage.categories.pushout import pushout sage: pushouts = [P2,P3,P4,P5,P6,P7,P3,P3,P5,P5,P7,P7,P4,P5,P4,P5,P6,P7,P5,P5,P5,P5,P7,P7,P6,P7,P6,P7,P6,P7,P7,P7,P7,P7,P7,P7] sage: all(P is Q for P, Q in zip(pushouts, [pushout(a, b) for a in Plist for b in Plist])) True


class
sage.categories.pushout.
CompositeConstructionFunctor
(*args)¶ Bases:
sage.categories.pushout.ConstructionFunctor
A Construction Functor composed by other Construction Functors.
INPUT:
F1, F2,...
: A list of Construction Functors. The result is the compositionF1
followed byF2
followed by …EXAMPLES:
sage: from sage.categories.pushout import CompositeConstructionFunctor sage: F = CompositeConstructionFunctor(QQ.construction()[0],ZZ['x'].construction()[0],QQ.construction()[0],ZZ['y'].construction()[0]) sage: F Poly[y](FractionField(Poly[x](FractionField(...)))) sage: F == loads(dumps(F)) True sage: F == CompositeConstructionFunctor(*F.all) True sage: F(GF(2)['t']) Univariate Polynomial Ring in y over Fraction Field of Univariate Polynomial Ring in x over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 2 (using GF2X)

expand
()¶ Return expansion of a CompositeConstructionFunctor.
NOTE:
The product over the list of components, as returned by the
expand()
method, is equal toself
.EXAMPLES:
sage: from sage.categories.pushout import CompositeConstructionFunctor sage: F = CompositeConstructionFunctor(QQ.construction()[0],ZZ['x'].construction()[0],QQ.construction()[0],ZZ['y'].construction()[0]) sage: F Poly[y](FractionField(Poly[x](FractionField(...)))) sage: prod(F.expand()) == F True


class
sage.categories.pushout.
ConstructionFunctor
¶ Bases:
sage.categories.functor.Functor
Base class for construction functors.
A construction functor is a functorial algebraic construction, such as the construction of a matrix ring over a given ring or the fraction field of a given ring.
In addition to the class
Functor
, construction functors provide rules for combining and merging constructions. This is an important part of Sage’s coercion model, namely the pushout of two constructions: When a polynomialp
in a variablex
with integer coefficients is added to a rational numberq
, then Sage finds that the parentsZZ['x']
andQQ
are obtained fromZZ
by applying a polynomial ring construction respectively the fraction field construction. Each construction functor has an attributerank
, and the rank of the polynomial ring construction is higher than the rank of the fraction field construction. This means that the pushout ofQQ
andZZ['x']
, and thus a common parent in whichp
andq
can be added, isQQ['x']
, since the construction functor with a lower rank is applied first.sage: F1, R = QQ.construction() sage: F1 FractionField sage: R Integer Ring sage: F2, R = (ZZ['x']).construction() sage: F2 Poly[x] sage: R Integer Ring sage: F3 = F2.pushout(F1) sage: F3 Poly[x](FractionField(...)) sage: F3(R) Univariate Polynomial Ring in x over Rational Field sage: from sage.categories.pushout import pushout sage: P.<x> = ZZ[] sage: pushout(QQ,P) Univariate Polynomial Ring in x over Rational Field sage: ((x+1) + 1/2).parent() Univariate Polynomial Ring in x over Rational Field
When composing two construction functors, they are sometimes merged into one, as is the case in the Quotient construction:
sage: Q15, R = (ZZ.quo(15*ZZ)).construction() sage: Q15 QuotientFunctor sage: Q35, R = (ZZ.quo(35*ZZ)).construction() sage: Q35 QuotientFunctor sage: Q15.merge(Q35) QuotientFunctor sage: Q15.merge(Q35)(ZZ) Ring of integers modulo 5
Functors can not only be applied to objects, but also to morphisms in the respective categories. For example:
sage: P.<x,y> = ZZ[] sage: F = P.construction()[0]; F MPoly[x,y] sage: A.<a,b> = GF(5)[] sage: f = A.hom([a+b,ab],A) sage: F(A) Multivariate Polynomial Ring in x, y over Multivariate Polynomial Ring in a, b over Finite Field of size 5 sage: F(f) Ring endomorphism of Multivariate Polynomial Ring in x, y over Multivariate Polynomial Ring in a, b over Finite Field of size 5 Defn: Induced from base ring by Ring endomorphism of Multivariate Polynomial Ring in a, b over Finite Field of size 5 Defn: a > a + b b > a  b sage: F(f)(F(A)(x)*a) (a + b)*x

common_base
(other_functor, self_bases, other_bases)¶ This function is called by
pushout()
when no common parent is found in the construction tower.Note
The main use is for multivariate construction functors, which use this function to implement recursion for
pushout()
.INPUT:
other_functor
– a construction functor.self_bases
– the arguments passed to this functor.other_bases
– the arguments passed to the functorother_functor
.
OUTPUT:
Nothing, since a
CoercionException
is raised.Note
Overload this function in derived class, see e.e.
MultivariateConstructionFunctor
.

commutes
(other)¶ Determine whether
self
commutes with another construction functor.NOTE:
By default,
False
is returned in all cases (even if the two functors are the same, since in this casemerge()
will apply anyway). So far there is no construction functor that overloads this method. Anyway, this method only becomes relevant if two construction functors have the same rank.EXAMPLES:
sage: F = QQ.construction()[0] sage: P = ZZ['t'].construction()[0] sage: F.commutes(P) False sage: P.commutes(F) False sage: F.commutes(F) False

expand
()¶ Decompose
self
into a list of construction functors.NOTE:
The default is to return the list only containing
self
.EXAMPLES:
sage: F = QQ.construction()[0] sage: F.expand() [FractionField] sage: Q = ZZ.quo(2).construction()[0] sage: Q.expand() [QuotientFunctor] sage: P = ZZ['t'].construction()[0] sage: FP = F*P sage: FP.expand() [FractionField, Poly[t]]

merge
(other)¶ Merge
self
with another construction functor, or return None.Note
The default is to merge only if the two functors coincide. But this may be overloaded for subclasses, such as the quotient functor.
EXAMPLES:
sage: F = QQ.construction()[0] sage: P = ZZ['t'].construction()[0] sage: F.merge(F) FractionField sage: F.merge(P) sage: P.merge(F) sage: P.merge(P) Poly[t]

pushout
(other)¶ Composition of two construction functors, ordered by their ranks.
Note
 This method seems not to be used in the coercion model.
 By default, the functor with smaller rank is applied first.


class
sage.categories.pushout.
FractionField
¶ Bases:
sage.categories.pushout.ConstructionFunctor
Construction functor for fraction fields.
EXAMPLES:
sage: F = QQ.construction()[0] sage: F FractionField sage: F.domain() Category of integral domains sage: F.codomain() Category of fields sage: F(GF(5)) is GF(5) True sage: F(ZZ['t']) Fraction Field of Univariate Polynomial Ring in t over Integer Ring sage: P.<x,y> = QQ[] sage: f = P.hom([x+2*y,3*xy],P) sage: F(f) Ring endomorphism of Fraction Field of Multivariate Polynomial Ring in x, y over Rational Field Defn: x > x + 2*y y > 3*x  y sage: F(f)(1/x) 1/(x + 2*y) sage: F == loads(dumps(F)) True

class
sage.categories.pushout.
IdentityConstructionFunctor
¶ Bases:
sage.categories.pushout.ConstructionFunctor
A construction functor that is the identity functor.

class
sage.categories.pushout.
InfinitePolynomialFunctor
(gens, order, implementation)¶ Bases:
sage.categories.pushout.ConstructionFunctor
A Construction Functor for Infinite Polynomial Rings (see
infinite_polynomial_ring
).AUTHOR:
– Simon King
This construction functor is used to provide uniqueness of infinite polynomial rings as parent structures. As usual, the construction functor allows for constructing pushouts.
Another purpose is to avoid name conflicts of variables of the tobeconstructed infinite polynomial ring with variables of the base ring, and moreover to keep the internal structure of an Infinite Polynomial Ring as simple as possible: If variables \(v_1,...,v_n\) of the given base ring generate an ordered submonoid of the monomials of the ambient Infinite Polynomial Ring, then they are removed from the base ring and merged with the generators of the ambient ring. However, if the orders don’t match, an error is raised, since there was a name conflict without merging.
EXAMPLES:
sage: A.<a,b> = InfinitePolynomialRing(ZZ['t']) sage: A.construction() [InfPoly{[a,b], "lex", "dense"}, Univariate Polynomial Ring in t over Integer Ring] sage: type(_[0]) <class 'sage.categories.pushout.InfinitePolynomialFunctor'> sage: B.<x,y,a_3,a_1> = PolynomialRing(QQ, order='lex') sage: B.construction() (MPoly[x,y,a_3,a_1], Rational Field) sage: A.construction()[0]*B.construction()[0] InfPoly{[a,b], "lex", "dense"}(MPoly[x,y](...))
Apparently the variables \(a_1,a_3\) of the polynomial ring are merged with the variables \(a_0, a_1, a_2, ...\) of the infinite polynomial ring; indeed, they form an ordered substructure. However, if the polynomial ring was given a different ordering, merging would not be allowed, resulting in a name conflict:
sage: A.construction()[0]*PolynomialRing(QQ,names=['x','y','a_3','a_1']).construction()[0] Traceback (most recent call last): ... CoercionException: Incompatible term orders lex, degrevlex
In an infinite polynomial ring with generator \(a_\ast\), the variable \(a_3\) will always be greater than the variable \(a_1\). Hence, the orders are incompatible in the next example as well:
sage: A.construction()[0]*PolynomialRing(QQ,names=['x','y','a_1','a_3'], order='lex').construction()[0] Traceback (most recent call last): ... CoercionException: Overlapping variables (('a', 'b'),['a_1', 'a_3']) are incompatible
Another requirement is that after merging the order of the remaining variables must be unique. This is not the case in the following example, since it is not clear whether the variables \(x,y\) should be greater or smaller than the variables \(b_\ast\):
sage: A.construction()[0]*PolynomialRing(QQ,names=['a_3','a_1','x','y'], order='lex').construction()[0] Traceback (most recent call last): ... CoercionException: Overlapping variables (('a', 'b'),['a_3', 'a_1']) are incompatible
Since the construction functors are actually used to construct infinite polynomial rings, the following result is no surprise:
sage: C.<a,b> = InfinitePolynomialRing(B); C Infinite polynomial ring in a, b over Multivariate Polynomial Ring in x, y over Rational Field
There is also an overlap in the next example:
sage: X.<w,x,y> = InfinitePolynomialRing(ZZ) sage: Y.<x,y,z> = InfinitePolynomialRing(QQ)
\(X\) and \(Y\) have an overlapping generators \(x_\ast, y_\ast\). Since the default lexicographic order is used in both rings, it gives rise to isomorphic submonoids in both \(X\) and \(Y\). They are merged in the pushout, which also yields a common parent for doing arithmetic:
sage: P = sage.categories.pushout.pushout(Y,X); P Infinite polynomial ring in w, x, y, z over Rational Field sage: w[2]+z[3] w_2 + z_3 sage: _.parent() is P True

expand
()¶ Decompose the functor \(F\) into subfunctors, whose product returns \(F\).
EXAMPLES:
sage: F = InfinitePolynomialRing(QQ, ['x','y'],order='degrevlex').construction()[0]; F InfPoly{[x,y], "degrevlex", "dense"} sage: F.expand() [InfPoly{[y], "degrevlex", "dense"}, InfPoly{[x], "degrevlex", "dense"}] sage: F = InfinitePolynomialRing(QQ, ['x','y','z'],order='degrevlex').construction()[0]; F InfPoly{[x,y,z], "degrevlex", "dense"} sage: F.expand() [InfPoly{[z], "degrevlex", "dense"}, InfPoly{[y], "degrevlex", "dense"}, InfPoly{[x], "degrevlex", "dense"}] sage: prod(F.expand())==F True

merge
(other)¶ Merge two construction functors of infinite polynomial rings, regardless of monomial order and implementation.
The purpose is to have a pushout (and thus, arithmetic) even in cases when the parents are isomorphic as rings, but not as ordered rings.
EXAMPLES:
sage: X.<x,y> = InfinitePolynomialRing(QQ,implementation='sparse') sage: Y.<x,y> = InfinitePolynomialRing(QQ,order='degrevlex') sage: X.construction() [InfPoly{[x,y], "lex", "sparse"}, Rational Field] sage: Y.construction() [InfPoly{[x,y], "degrevlex", "dense"}, Rational Field] sage: Y.construction()[0].merge(Y.construction()[0]) InfPoly{[x,y], "degrevlex", "dense"} sage: y[3] + X(x[2]) x_2 + y_3 sage: _.parent().construction() [InfPoly{[x,y], "degrevlex", "dense"}, Rational Field]


class
sage.categories.pushout.
LaurentPolynomialFunctor
(var, multi_variate=False)¶ Bases:
sage.categories.pushout.ConstructionFunctor
Construction functor for Laurent polynomial rings.
EXAMPLES:
sage: L.<t> = LaurentPolynomialRing(ZZ) sage: F = L.construction()[0] sage: F LaurentPolynomialFunctor sage: F(QQ) Univariate Laurent Polynomial Ring in t over Rational Field sage: K.<x> = LaurentPolynomialRing(ZZ) sage: F(K) Univariate Laurent Polynomial Ring in t over Univariate Laurent Polynomial Ring in x over Integer Ring sage: P.<x,y> = ZZ[] sage: f = P.hom([x+2*y,3*xy],P) sage: F(f) Ring endomorphism of Univariate Laurent Polynomial Ring in t over Multivariate Polynomial Ring in x, y over Integer Ring Defn: Induced from base ring by Ring endomorphism of Multivariate Polynomial Ring in x, y over Integer Ring Defn: x > x + 2*y y > 3*x  y sage: F(f)(x*F(P).gen()^2+y*F(P).gen()^3) (x + 2*y)*t^2 + (3*x  y)*t^3

merge
(other)¶ Two Laurent polynomial construction functors merge if the variable names coincide. The result is multivariate if one of the arguments is multivariate.
EXAMPLES:
sage: from sage.categories.pushout import LaurentPolynomialFunctor sage: F1 = LaurentPolynomialFunctor('t') sage: F2 = LaurentPolynomialFunctor('t', multi_variate=True) sage: F1.merge(F2) LaurentPolynomialFunctor sage: F1.merge(F2)(LaurentPolynomialRing(GF(2),'a')) Multivariate Laurent Polynomial Ring in a, t over Finite Field of size 2 sage: F1.merge(F1)(LaurentPolynomialRing(GF(2),'a')) Univariate Laurent Polynomial Ring in t over Univariate Laurent Polynomial Ring in a over Finite Field of size 2


class
sage.categories.pushout.
MatrixFunctor
(nrows, ncols, is_sparse=False)¶ Bases:
sage.categories.pushout.ConstructionFunctor
A construction functor for matrices over rings.
EXAMPLES:
sage: MS = MatrixSpace(ZZ,2, 3) sage: F = MS.construction()[0]; F MatrixFunctor sage: MS = MatrixSpace(ZZ,2) sage: F = MS.construction()[0]; F MatrixFunctor sage: P.<x,y> = QQ[] sage: R = F(P); R Full MatrixSpace of 2 by 2 dense matrices over Multivariate Polynomial Ring in x, y over Rational Field sage: f = P.hom([x+y,xy],P); F(f) Ring endomorphism of Full MatrixSpace of 2 by 2 dense matrices over Multivariate Polynomial Ring in x, y over Rational Field Defn: Induced from base ring by Ring endomorphism of Multivariate Polynomial Ring in x, y over Rational Field Defn: x > x + y y > x  y sage: M = R([x,y,x*y,x+y]) sage: F(f)(M) [ x + y x  y] [x^2  y^2 2*x]

merge
(other)¶ Merging is only happening if both functors are matrix functors of the same dimension. The result is sparse if and only if both given functors are sparse.
EXAMPLES:
sage: F1 = MatrixSpace(ZZ,2,2).construction()[0] sage: F2 = MatrixSpace(ZZ,2,3).construction()[0] sage: F3 = MatrixSpace(ZZ,2,2,sparse=True).construction()[0] sage: F1.merge(F2) sage: F1.merge(F3) MatrixFunctor sage: F13 = F1.merge(F3) sage: F13.is_sparse False sage: F1.is_sparse False sage: F3.is_sparse True sage: F3.merge(F3).is_sparse True


class
sage.categories.pushout.
MultiPolynomialFunctor
(vars, term_order)¶ Bases:
sage.categories.pushout.ConstructionFunctor
A constructor for multivariate polynomial rings.
EXAMPLES:
sage: P.<x,y> = ZZ[] sage: F = P.construction()[0]; F MPoly[x,y] sage: A.<a,b> = GF(5)[] sage: F(A) Multivariate Polynomial Ring in x, y over Multivariate Polynomial Ring in a, b over Finite Field of size 5 sage: f = A.hom([a+b,ab],A) sage: F(f) Ring endomorphism of Multivariate Polynomial Ring in x, y over Multivariate Polynomial Ring in a, b over Finite Field of size 5 Defn: Induced from base ring by Ring endomorphism of Multivariate Polynomial Ring in a, b over Finite Field of size 5 Defn: a > a + b b > a  b sage: F(f)(F(A)(x)*a) (a + b)*x

expand
()¶ Decompose
self
into a list of construction functors.EXAMPLES:
sage: F = QQ['x,y,z,t'].construction()[0]; F MPoly[x,y,z,t] sage: F.expand() [MPoly[t], MPoly[z], MPoly[y], MPoly[x]]
Now an actual use case:
sage: R.<x,y,z> = ZZ[] sage: S.<z,t> = QQ[] sage: x+t x + t sage: parent(x+t) Multivariate Polynomial Ring in x, y, z, t over Rational Field sage: T.<y,s> = QQ[] sage: x + s Traceback (most recent call last): ... TypeError: unsupported operand parent(s) for +: 'Multivariate Polynomial Ring in x, y, z over Integer Ring' and 'Multivariate Polynomial Ring in y, s over Rational Field' sage: R = PolynomialRing(ZZ, 'x', 500) sage: S = PolynomialRing(GF(5), 'x', 200) sage: R.gen(0) + S.gen(0) 2*x0

merge
(other)¶ Merge
self
with another construction functor, or return None.EXAMPLES:
sage: F = sage.categories.pushout.MultiPolynomialFunctor(['x','y'], None) sage: G = sage.categories.pushout.MultiPolynomialFunctor(['t'], None) sage: F.merge(G) is None True sage: F.merge(F) MPoly[x,y]


class
sage.categories.pushout.
MultivariateConstructionFunctor
¶ Bases:
sage.categories.pushout.ConstructionFunctor
An abstract base class for functors that take multiple inputs (e.g. Cartesian products).

common_base
(other_functor, self_bases, other_bases)¶ This function is called by
pushout()
when no common parent is found in the construction tower.INPUT:
other_functor
– a construction functor.self_bases
– the arguments passed to this functor.other_bases
– the arguments passed to the functorother_functor
.
OUTPUT:
A parent.
If no common base is found a
sage.structure.coerce_exceptions.CoercionException
is raised.Note
Overload this function in derived class, see e.g.
MultivariateConstructionFunctor
.


class
sage.categories.pushout.
PermutationGroupFunctor
(gens, domain)¶ Bases:
sage.categories.pushout.ConstructionFunctor
EXAMPLES:
sage: from sage.categories.pushout import PermutationGroupFunctor sage: PF = PermutationGroupFunctor([PermutationGroupElement([(1,2)])], [1,2]); PF PermutationGroupFunctor[(1,2)]

gens
()¶ EXAMPLES:
sage: P1 = PermutationGroup([[(1,2)]]) sage: PF, P = P1.construction() sage: PF.gens() [(1,2)]

merge
(other)¶ Merge
self
with another construction functor, or return None.EXAMPLES:
sage: P1 = PermutationGroup([[(1,2)]]) sage: PF1, P = P1.construction() sage: P2 = PermutationGroup([[(1,3)]]) sage: PF2, P = P2.construction() sage: PF1.merge(PF2) PermutationGroupFunctor[(1,2), (1,3)]


class
sage.categories.pushout.
PolynomialFunctor
(var, multi_variate=False, sparse=False)¶ Bases:
sage.categories.pushout.ConstructionFunctor
Construction functor for univariate polynomial rings.
EXAMPLES:
sage: P = ZZ['t'].construction()[0] sage: P(GF(3)) Univariate Polynomial Ring in t over Finite Field of size 3 sage: P == loads(dumps(P)) True sage: R.<x,y> = GF(5)[] sage: f = R.hom([x+2*y,3*xy],R) sage: P(f)((x+y)*P(R).0) (x + y)*t
By trac ticket #9944, the construction functor distinguishes sparse and dense polynomial rings. Before, the following example failed:
sage: R.<x> = PolynomialRing(GF(5), sparse=True) sage: F,B = R.construction() sage: F(B) is R True sage: S.<x> = PolynomialRing(ZZ) sage: R.has_coerce_map_from(S) False sage: S.has_coerce_map_from(R) False sage: S.0 + R.0 2*x sage: (S.0 + R.0).parent() Univariate Polynomial Ring in x over Finite Field of size 5 sage: (S.0 + R.0).parent().is_sparse() False

merge
(other)¶ Merge
self
with another construction functor, or return None.NOTE:
Internally, the merging is delegated to the merging of multipolynomial construction functors. But in effect, this does the same as the default implementation, that returns
None
unless the tobemerged functors coincide.EXAMPLES:
sage: P = ZZ['x'].construction()[0] sage: Q = ZZ['y','x'].construction()[0] sage: P.merge(Q) sage: P.merge(P) is P True


class
sage.categories.pushout.
QuotientFunctor
(I, names=None, as_field=False)¶ Bases:
sage.categories.pushout.ConstructionFunctor
Construction functor for quotient rings.
NOTE:
The functor keeps track of variable names.
EXAMPLES:
sage: P.<x,y> = ZZ[] sage: Q = P.quo([x^2+y^2]*P) sage: F = Q.construction()[0] sage: F(QQ['x','y']) Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x^2 + y^2) sage: F(QQ['x','y']) == QQ['x','y'].quo([x^2+y^2]*QQ['x','y']) True sage: F(QQ['x','y','z']) Traceback (most recent call last): ... CoercionException: Can not apply this quotient functor to Multivariate Polynomial Ring in x, y, z over Rational Field sage: F(QQ['y','z']) Traceback (most recent call last): ... TypeError: Could not find a mapping of the passed element to this ring.

merge
(other)¶ Two quotient functors with coinciding names are merged by taking the gcd of their moduli.
EXAMPLES:
sage: P.<x> = QQ[] sage: Q1 = P.quo([(x^2+1)^2*(x^23)]) sage: Q2 = P.quo([(x^2+1)^2*(x^5+3)]) sage: from sage.categories.pushout import pushout sage: pushout(Q1,Q2) # indirect doctest Univariate Quotient Polynomial Ring in xbar over Rational Field with modulus x^4 + 2*x^2 + 1
The following was fixed in trac ticket #8800:
sage: pushout(GF(5), Integers(5)) Finite Field of size 5


class
sage.categories.pushout.
SubspaceFunctor
(basis)¶ Bases:
sage.categories.pushout.ConstructionFunctor
Constructing a subspace of an ambient free module, given by a basis.
NOTE:
This construction functor keeps track of the basis. It can only be applied to free modules into which this basis coerces.
EXAMPLES:
sage: M = ZZ^3 sage: S = M.submodule([(1,2,3),(4,5,6)]); S Free module of degree 3 and rank 2 over Integer Ring Echelon basis matrix: [1 2 3] [0 3 6] sage: F = S.construction()[0] sage: F(GF(2)^3) Vector space of degree 3 and dimension 2 over Finite Field of size 2 User basis matrix: [1 0 1] [0 1 0]

merge
(other)¶ Two Subspace Functors are merged into a construction functor of the sum of two subspaces.
EXAMPLES:
sage: M = GF(5)^3 sage: S1 = M.submodule([(1,2,3),(4,5,6)]) sage: S2 = M.submodule([(2,2,3)]) sage: F1 = S1.construction()[0] sage: F2 = S2.construction()[0] sage: F1.merge(F2) SubspaceFunctor sage: F1.merge(F2)(GF(5)^3) == S1+S2 True sage: F1.merge(F2)(GF(5)['t']^3) Free module of degree 3 and rank 3 over Univariate Polynomial Ring in t over Finite Field of size 5 User basis matrix: [1 0 0] [0 1 0] [0 0 1]


class
sage.categories.pushout.
VectorFunctor
(n, is_sparse=False, inner_product_matrix=None)¶ Bases:
sage.categories.pushout.ConstructionFunctor
A construction functor for free modules over commutative rings.
EXAMPLES:
sage: F = (ZZ^3).construction()[0] sage: F VectorFunctor sage: F(GF(2)['t']) Ambient free module of rank 3 over the principal ideal domain Univariate Polynomial Ring in t over Finite Field of size 2 (using GF2X)

merge
(other)¶ Two constructors of free modules merge, if the module ranks and the inner products coincide. If both have explicitly given inner product matrices, they must coincide as well.
EXAMPLES:
Two modules without explicitly given inner product allow coercion:
sage: M1 = QQ^3 sage: P.<t> = ZZ[] sage: M2 = FreeModule(P,3) sage: M1([1,1/2,1/3]) + M2([t,t^2+t,3]) # indirect doctest (t + 1, t^2 + t + 1/2, 10/3)
If only one summand has an explicit inner product, the result will be provided with it:
sage: M3 = FreeModule(P,3, inner_product_matrix = Matrix(3,3,range(9))) sage: M1([1,1/2,1/3]) + M3([t,t^2+t,3]) (t + 1, t^2 + t + 1/2, 10/3) sage: (M1([1,1/2,1/3]) + M3([t,t^2+t,3])).parent().inner_product_matrix() [0 1 2] [3 4 5] [6 7 8]
If both summands have an explicit inner product (even if it is the standard inner product), then the products must coincide. The only difference between
M1
andM4
in the following example is the fact that the default inner product was explicitly requested forM4
. It is therefore not possible to coerce with a different inner product:sage: M4 = FreeModule(QQ,3, inner_product_matrix = Matrix(3,3,1)) sage: M4 == M1 True sage: M4.inner_product_matrix() == M1.inner_product_matrix() True sage: M4([1,1/2,1/3]) + M3([t,t^2+t,3]) # indirect doctest Traceback (most recent call last): ... TypeError: unsupported operand parent(s) for +: 'Ambient quadratic space of dimension 3 over Rational Field Inner product matrix: [1 0 0] [0 1 0] [0 0 1]' and 'Ambient free quadratic module of rank 3 over the integral domain Univariate Polynomial Ring in t over Integer Ring Inner product matrix: [0 1 2] [3 4 5] [6 7 8]'


sage.categories.pushout.
construction_tower
(R)¶ An auxiliary function that is used in
pushout()
andpushout_lattice()
.INPUT:
An object
OUTPUT:
A constructive description of the object from scratch, by a list of pairs of a construction functor and an object to which the construction functor is to be applied. The first pair is formed by
None
and the given object.EXAMPLES:
sage: from sage.categories.pushout import construction_tower sage: construction_tower(MatrixSpace(FractionField(QQ['t']),2)) [(None, Full MatrixSpace of 2 by 2 dense matrices over Fraction Field of Univariate Polynomial Ring in t over Rational Field), (MatrixFunctor, Fraction Field of Univariate Polynomial Ring in t over Rational Field), (FractionField, Univariate Polynomial Ring in t over Rational Field), (Poly[t], Rational Field), (FractionField, Integer Ring)]

sage.categories.pushout.
expand_tower
(tower)¶ An auxiliary function that is used in
pushout()
.INPUT:
A construction tower as returned by
construction_tower()
.OUTPUT:
A new construction tower with all the construction functors expanded.
EXAMPLES:
sage: from sage.categories.pushout import construction_tower, expand_tower sage: construction_tower(QQ['x,y,z']) [(None, Multivariate Polynomial Ring in x, y, z over Rational Field), (MPoly[x,y,z], Rational Field), (FractionField, Integer Ring)] sage: expand_tower(construction_tower(QQ['x,y,z'])) [(None, Multivariate Polynomial Ring in x, y, z over Rational Field), (MPoly[z], Univariate Polynomial Ring in y over Univariate Polynomial Ring in x over Rational Field), (MPoly[y], Univariate Polynomial Ring in x over Rational Field), (MPoly[x], Rational Field), (FractionField, Integer Ring)]

sage.categories.pushout.
pushout
(R, S)¶ Given a pair of objects \(R\) and \(S\), try to construct a reasonable object \(Y\) and return maps such that canonically \(R \leftarrow Y \rightarrow S\).
ALGORITHM:
This incorporates the idea of functors discussed at Sage Days 4. Every object \(R\) can be viewed as an initial object and a series of functors (e.g. polynomial, quotient, extension, completion, vector/matrix, etc.). Call the series of increasingly simple objects (with the associated functors) the “tower” of \(R\). The construction method is used to create the tower.
Given two objects \(R\) and \(S\), try to find a common initial object \(Z\). If the towers of \(R\) and \(S\) meet, let \(Z\) be their join. Otherwise, see if the top of one coerces naturally into the other.
Now we have an initial object and two ordered lists of functors to apply. We wish to merge these in an unambiguous order, popping elements off the top of one or the other tower as we apply them to \(Z\).
 If the functors are of distinct types, there is an absolute ordering given by the rank attribute. Use this.
 Otherwise:
 If the tops are equal, we (try to) merge them.
 If exactly one occurs lower in the other tower, we may unambiguously apply the other (hoping for a later merge).
 If the tops commute, we can apply either first.
 Otherwise fail due to ambiguity.
The algorithm assumes by default that when a construction \(F\) is applied to an object \(X\), the object \(F(X)\) admits a coercion map from \(X\). However, the algorithm can also handle the case where \(F(X)\) has a coercion map to \(X\) instead. In this case, the attribute
coercion_reversed
of the class implementing \(F\) should be set toTrue
.EXAMPLES:
Here our “towers” are \(R = Complete_7(Frac(\ZZ))\) and \(Frac(Poly_x(\ZZ))\), which give us \(Frac(Poly_x(Complete_7(Frac(\ZZ))))\):
sage: from sage.categories.pushout import pushout sage: pushout(Qp(7), Frac(ZZ['x'])) Fraction Field of Univariate Polynomial Ring in x over 7adic Field with capped relative precision 20
Note we get the same thing with
sage: pushout(Zp(7), Frac(QQ['x'])) Fraction Field of Univariate Polynomial Ring in x over 7adic Field with capped relative precision 20 sage: pushout(Zp(7)['x'], Frac(QQ['x'])) Fraction Field of Univariate Polynomial Ring in x over 7adic Field with capped relative precision 20
Note that polynomial variable ordering must be unambiguously determined.
sage: pushout(ZZ['x,y,z'], QQ['w,z,t']) Traceback (most recent call last): ... CoercionException: ('Ambiguous Base Extension', Multivariate Polynomial Ring in x, y, z over Integer Ring, Multivariate Polynomial Ring in w, z, t over Rational Field) sage: pushout(ZZ['x,y,z'], QQ['w,x,z,t']) Multivariate Polynomial Ring in w, x, y, z, t over Rational Field
Some other examples:
sage: pushout(Zp(7)['y'], Frac(QQ['t'])['x,y,z']) Multivariate Polynomial Ring in x, y, z over Fraction Field of Univariate Polynomial Ring in t over 7adic Field with capped relative precision 20 sage: pushout(ZZ['x,y,z'], Frac(ZZ['x'])['y']) Multivariate Polynomial Ring in y, z over Fraction Field of Univariate Polynomial Ring in x over Integer Ring sage: pushout(MatrixSpace(RDF, 2, 2), Frac(ZZ['x'])) Full MatrixSpace of 2 by 2 dense matrices over Fraction Field of Univariate Polynomial Ring in x over Real Double Field sage: pushout(ZZ, MatrixSpace(ZZ[['x']], 3, 3)) Full MatrixSpace of 3 by 3 dense matrices over Power Series Ring in x over Integer Ring sage: pushout(QQ['x,y'], ZZ[['x']]) Univariate Polynomial Ring in y over Power Series Ring in x over Rational Field sage: pushout(Frac(ZZ['x']), QQ[['x']]) Laurent Series Ring in x over Rational Field
A construction with
coercion_reversed = True
(currently only theSubspaceFunctor
construction) is only applied if it leads to a valid coercion:sage: A = ZZ^2 sage: V = span([[1, 2]], QQ) sage: P = sage.categories.pushout.pushout(A, V) sage: P Vector space of dimension 2 over Rational Field sage: P.has_coerce_map_from(A) True sage: V = (QQ^3).span([[1, 2, 3/4]]) sage: A = ZZ^3 sage: pushout(A, V) Vector space of dimension 3 over Rational Field sage: B = A.span([[0, 0, 2/3]]) sage: pushout(B, V) Vector space of degree 3 and dimension 2 over Rational Field User basis matrix: [1 2 0] [0 0 1]
Some more tests with
coercion_reversed = True
:sage: from sage.categories.pushout import ConstructionFunctor sage: class EvenPolynomialRing(type(QQ['x'])): ....: def __init__(self, base, var): ....: super(EvenPolynomialRing, self).__init__(base, var) ....: self.register_embedding(base[var]) ....: def __repr__(self): ....: return "Even Power " + super(EvenPolynomialRing, self).__repr__() ....: def construction(self): ....: return EvenPolynomialFunctor(), self.base()[self.variable_name()] ....: def _coerce_map_from_(self, R): ....: return self.base().has_coerce_map_from(R) sage: class EvenPolynomialFunctor(ConstructionFunctor): ....: rank = 10 ....: coercion_reversed = True ....: def __init__(self): ....: ConstructionFunctor.__init__(self, Rings(), Rings()) ....: def _apply_functor(self, R): ....: return EvenPolynomialRing(R.base(), R.variable_name()) sage: pushout(EvenPolynomialRing(QQ, 'x'), ZZ) Even Power Univariate Polynomial Ring in x over Rational Field sage: pushout(EvenPolynomialRing(QQ, 'x'), QQ) Even Power Univariate Polynomial Ring in x over Rational Field sage: pushout(EvenPolynomialRing(QQ, 'x'), RR) Even Power Univariate Polynomial Ring in x over Real Field with 53 bits of precision sage: pushout(EvenPolynomialRing(QQ, 'x'), ZZ['x']) Univariate Polynomial Ring in x over Rational Field sage: pushout(EvenPolynomialRing(QQ, 'x'), QQ['x']) Univariate Polynomial Ring in x over Rational Field sage: pushout(EvenPolynomialRing(QQ, 'x'), RR['x']) Univariate Polynomial Ring in x over Real Field with 53 bits of precision sage: pushout(EvenPolynomialRing(QQ, 'x'), EvenPolynomialRing(QQ, 'x')) Even Power Univariate Polynomial Ring in x over Rational Field sage: pushout(EvenPolynomialRing(QQ, 'x'), EvenPolynomialRing(RR, 'x')) Even Power Univariate Polynomial Ring in x over Real Field with 53 bits of precision sage: pushout(EvenPolynomialRing(QQ, 'x')^2, RR^2) Ambient free module of rank 2 over the principal ideal domain Even Power Univariate Polynomial Ring in x over Real Field with 53 bits of precision sage: pushout(EvenPolynomialRing(QQ, 'x')^2, RR['x']^2) Ambient free module of rank 2 over the principal ideal domain Univariate Polynomial Ring in x over Real Field with 53 bits of precision
Some more tests related to univariate/multivariate constructions. We consider a generalization of polynomial rings, where in addition to the coefficient ring \(C\) we also specify an additive monoid \(E\) for the exponents of the indeterminate. In particular, the elements of such a parent are given by
\[\sum_{i=0}^I c_i X^{e_i}\]with \(c_i \in C\) and \(e_i \in E\). We define
sage: class GPolynomialRing(Parent): ....: def __init__(self, coefficients, var, exponents): ....: self.coefficients = coefficients ....: self.var = var ....: self.exponents = exponents ....: super(GPolynomialRing, self).__init__(category=Rings()) ....: def _repr_(self): ....: return 'Generalized Polynomial Ring in %s^(%s) over %s' % ( ....: self.var, self.exponents, self.coefficients) ....: def construction(self): ....: return GPolynomialFunctor(self.var, self.exponents), self.coefficients ....: def _coerce_map_from_(self, R): ....: return self.coefficients.has_coerce_map_from(R)
and
sage: class GPolynomialFunctor(ConstructionFunctor): ....: rank = 10 ....: def __init__(self, var, exponents): ....: self.var = var ....: self.exponents = exponents ....: ConstructionFunctor.__init__(self, Rings(), Rings()) ....: def _repr_(self): ....: return 'GPoly[%s^(%s)]' % (self.var, self.exponents) ....: def _apply_functor(self, coefficients): ....: return GPolynomialRing(coefficients, self.var, self.exponents) ....: def merge(self, other): ....: if isinstance(other, GPolynomialFunctor) and self.var == other.var: ....: exponents = pushout(self.exponents, other.exponents) ....: return GPolynomialFunctor(self.var, exponents)
We can construct a parent now in two different ways:
sage: GPolynomialRing(QQ, 'X', ZZ) Generalized Polynomial Ring in X^(Integer Ring) over Rational Field sage: GP_ZZ = GPolynomialFunctor('X', ZZ); GP_ZZ GPoly[X^(Integer Ring)] sage: GP_ZZ(QQ) Generalized Polynomial Ring in X^(Integer Ring) over Rational Field
Since the construction
sage: GP_ZZ(QQ).construction() (GPoly[X^(Integer Ring)], Rational Field)
uses the coefficient ring, we have the usual coercion with respect to this parameter:
sage: pushout(GP_ZZ(ZZ), GP_ZZ(QQ)) Generalized Polynomial Ring in X^(Integer Ring) over Rational Field sage: pushout(GP_ZZ(ZZ['t']), GP_ZZ(QQ)) Generalized Polynomial Ring in X^(Integer Ring) over Univariate Polynomial Ring in t over Rational Field sage: pushout(GP_ZZ(ZZ['a,b']), GP_ZZ(ZZ['b,c'])) Generalized Polynomial Ring in X^(Integer Ring) over Multivariate Polynomial Ring in a, b, c over Integer Ring sage: pushout(GP_ZZ(ZZ['a,b']), GP_ZZ(QQ['b,c'])) Generalized Polynomial Ring in X^(Integer Ring) over Multivariate Polynomial Ring in a, b, c over Rational Field sage: pushout(GP_ZZ(ZZ['a,b']), GP_ZZ(ZZ['c,d'])) Traceback (most recent call last): ... CoercionException: ('Ambiguous Base Extension', ...)
sage: GP_QQ = GPolynomialFunctor('X', QQ) sage: pushout(GP_ZZ(ZZ), GP_QQ(ZZ)) Generalized Polynomial Ring in X^(Rational Field) over Integer Ring sage: pushout(GP_QQ(ZZ), GP_ZZ(ZZ)) Generalized Polynomial Ring in X^(Rational Field) over Integer Ring
sage: GP_ZZt = GPolynomialFunctor('X', ZZ['t']) sage: pushout(GP_ZZt(ZZ), GP_QQ(ZZ)) Generalized Polynomial Ring in X^(Univariate Polynomial Ring in t over Rational Field) over Integer Ring
sage: pushout(GP_ZZ(ZZ), GP_QQ(QQ)) Generalized Polynomial Ring in X^(Rational Field) over Rational Field sage: pushout(GP_ZZ(QQ), GP_QQ(ZZ)) Generalized Polynomial Ring in X^(Rational Field) over Rational Field sage: pushout(GP_ZZt(QQ), GP_QQ(ZZ)) Generalized Polynomial Ring in X^(Univariate Polynomial Ring in t over Rational Field) over Rational Field sage: pushout(GP_ZZt(ZZ), GP_QQ(QQ)) Generalized Polynomial Ring in X^(Univariate Polynomial Ring in t over Rational Field) over Rational Field sage: pushout(GP_ZZt(ZZ['a,b']), GP_QQ(ZZ['c,d'])) Traceback (most recent call last): ... CoercionException: ('Ambiguous Base Extension', ...) sage: pushout(GP_ZZt(ZZ['a,b']), GP_QQ(ZZ['b,c'])) Generalized Polynomial Ring in X^(Univariate Polynomial Ring in t over Rational Field) over Multivariate Polynomial Ring in a, b, c over Integer Ring
Some tests with Cartesian products:
sage: from sage.sets.cartesian_product import CartesianProduct sage: A = CartesianProduct((ZZ['x'], QQ['y'], QQ['z']), Sets().CartesianProducts()) sage: B = CartesianProduct((ZZ['x'], ZZ['y'], ZZ['t']['z']), Sets().CartesianProducts()) sage: A.construction() (The cartesian_product functorial construction, (Univariate Polynomial Ring in x over Integer Ring, Univariate Polynomial Ring in y over Rational Field, Univariate Polynomial Ring in z over Rational Field)) sage: pushout(A, B) The Cartesian product of (Univariate Polynomial Ring in x over Integer Ring, Univariate Polynomial Ring in y over Rational Field, Univariate Polynomial Ring in z over Univariate Polynomial Ring in t over Rational Field) sage: pushout(ZZ, cartesian_product([ZZ, QQ])) Traceback (most recent call last): ... CoercionException: 'NoneType' object is not iterable
sage: from sage.categories.pushout import PolynomialFunctor sage: from sage.sets.cartesian_product import CartesianProduct sage: class CartesianProductPoly(CartesianProduct): ....: def __init__(self, polynomial_rings): ....: sort = sorted(polynomial_rings, key=lambda P: P.variable_name()) ....: super(CartesianProductPoly, self).__init__(sort, Sets().CartesianProducts()) ....: def vars(self): ....: return tuple(P.variable_name() for P in self.cartesian_factors()) ....: def _pushout_(self, other): ....: if isinstance(other, CartesianProductPoly): ....: s_vars = self.vars() ....: o_vars = other.vars() ....: if s_vars == o_vars: ....: return ....: return pushout(CartesianProductPoly( ....: self.cartesian_factors() + ....: tuple(f for f in other.cartesian_factors() ....: if f.variable_name() not in s_vars)), ....: CartesianProductPoly( ....: other.cartesian_factors() + ....: tuple(f for f in self.cartesian_factors() ....: if f.variable_name() not in o_vars))) ....: C = other.construction() ....: if C is None: ....: return ....: elif isinstance(C[0], PolynomialFunctor): ....: return pushout(self, CartesianProductPoly((other,)))
sage: pushout(CartesianProductPoly((ZZ['x'],)), ....: CartesianProductPoly((ZZ['y'],))) The Cartesian product of (Univariate Polynomial Ring in x over Integer Ring, Univariate Polynomial Ring in y over Integer Ring) sage: pushout(CartesianProductPoly((ZZ['x'], ZZ['y'])), ....: CartesianProductPoly((ZZ['x'], ZZ['z']))) The Cartesian product of (Univariate Polynomial Ring in x over Integer Ring, Univariate Polynomial Ring in y over Integer Ring, Univariate Polynomial Ring in z over Integer Ring) sage: pushout(CartesianProductPoly((QQ['a,b']['x'], QQ['y'])), ....: CartesianProductPoly((ZZ['b,c']['x'], SR['z']))) The Cartesian product of (Univariate Polynomial Ring in x over Multivariate Polynomial Ring in a, b, c over Rational Field, Univariate Polynomial Ring in y over Rational Field, Univariate Polynomial Ring in z over Symbolic Ring)
sage: pushout(CartesianProductPoly((ZZ['x'],)), ZZ['y']) The Cartesian product of (Univariate Polynomial Ring in x over Integer Ring, Univariate Polynomial Ring in y over Integer Ring) sage: pushout(QQ['b,c']['y'], CartesianProductPoly((ZZ['a,b']['x'],))) The Cartesian product of (Univariate Polynomial Ring in x over Multivariate Polynomial Ring in a, b over Integer Ring, Univariate Polynomial Ring in y over Multivariate Polynomial Ring in b, c over Rational Field)
sage: pushout(CartesianProductPoly((ZZ['x'],)), ZZ) Traceback (most recent call last): ... CoercionException: No common base ("join") found for The cartesian_product functorial construction(...) and None(Integer Ring): (Multivariate) functors are incompatible.
AUTHORS:
 Robert Bradshaw
 Peter Bruin
 Simon King
 Daniel Krenn
 David Roe

sage.categories.pushout.
pushout_lattice
(R, S)¶ Given a pair of objects \(R\) and \(S\), try to construct a reasonable object \(Y\) and return maps such that canonically \(R \leftarrow Y \rightarrow S\).
ALGORITHM:
This is based on the model that arose from much discussion at Sage Days 4. Going up the tower of constructions of \(R\) and \(S\) (e.g. the reals come from the rationals come from the integers), try to find a common parent, and then try to fill in a lattice with these two towers as sides with the top as the common ancestor and the bottom will be the desired ring.
See the code for a specific workedout example.
EXAMPLES:
sage: from sage.categories.pushout import pushout_lattice sage: A, B = pushout_lattice(Qp(7), Frac(ZZ['x'])) sage: A.codomain() Fraction Field of Univariate Polynomial Ring in x over 7adic Field with capped relative precision 20 sage: A.codomain() is B.codomain() True sage: A, B = pushout_lattice(ZZ, MatrixSpace(ZZ[['x']], 3, 3)) sage: B Identity endomorphism of Full MatrixSpace of 3 by 3 dense matrices over Power Series Ring in x over Integer Ring
AUTHOR:
 Robert Bradshaw