def _create_(k, R): """ Initialization. We have to implement this as a static method in order to call ``__make_element_class__``. INPUT: - ``k`` -- the residue field of ``R``, or a residue ring of ``R``. - ``R`` -- a `p`-adic ring or field. EXAMPLES:: sage: f = Zp(3).convert_map_from(Zmod(81)) sage: TestSuite(f).run() """ from sage.categories.sets_cat import Sets from sage.categories.homset import Hom kfield = R.residue_field() N = k.cardinality() q = kfield.cardinality() n = N.exact_log(q) if N != q**n: raise RuntimeError("N must be a power of q") H = Hom(k, R, Sets()) f = H.__make_element_class__(ResidueLiftingMap)(H) f._n = n return f
def _convert_map_from_(self, R): """ Finds conversion maps from R to this ring. Currently, a conversion exists if the defining polynomial is the same. EXAMPLES:: sage: R.<a> = Zq(125) sage: S = R.change(type='capped-abs', prec=40, print_mode='terse', print_pos=False) sage: S(a - 15) -15 + a + O(5^20) We get conversions from the exact field:: sage: K = R.exact_field(); K Number Field in a with defining polynomial x^3 + 3*x + 3 sage: R(K.gen()) a + O(5^20) and its maximal order:: sage: OK = K.maximal_order() sage: R(OK.gen(1)) a + O(5^20) """ cat = None if self._implementation == 'NTL' and R == QQ: # Want to use DefaultConvertMap return None if isinstance(R, pAdicExtensionGeneric) and R.defining_polynomial(exact=True) == self.defining_polynomial(exact=True): if R.is_field() and not self.is_field(): cat = SetsWithPartialMaps() else: cat = R.category() elif isinstance(R, Order) and R.number_field().defining_polynomial() == self.defining_polynomial(): cat = IntegralDomains() elif isinstance(R, NumberField) and R.defining_polynomial() == self.defining_polynomial(): if self.is_field(): cat = Fields() else: cat = SetsWithPartialMaps() else: k = self.residue_field() if R is k: return ResidueLiftingMap._create_(R, self) if cat is not None: H = Hom(R, self, cat) return H.__make_element_class__(DefPolyConversion)(H)
def _create_(R, k): """ Initialization. We have to implement this as a static method in order to call ``__make_element_class__``. INPUT: - ``R`` -- a `p`-adic ring or field. - ``k`` -- the residue field of ``R``, or a residue ring of ``R``. EXAMPLES:: sage: f = Zmod(49).convert_map_from(Zp(7)) sage: TestSuite(f).run() sage: K.<a> = Qq(125); k = K.residue_field(); f = k.convert_map_from(K) sage: TestSuite(f).run() """ if R.is_field(): from sage.categories.sets_with_partial_maps import SetsWithPartialMaps cat = SetsWithPartialMaps() else: from sage.categories.rings import Rings cat = Rings() from sage.categories.homset import Hom kfield = R.residue_field() N = k.cardinality() q = kfield.cardinality() n = N.exact_log(q) if N != q**n: raise RuntimeError("N must be a power of q") H = Hom(R, k, cat) f = H.__make_element_class__(ResidueReductionMap)(H) f._n = n if kfield is k: f._field = True else: f._field = False return f
def __init__(self, domain, codomain): """ Initialize ``self``. EXAMPLES:: sage: L = LieAlgebras(QQ).FiniteDimensional().WithBasis().example() sage: f = L.lift We skip the category test since this is currently not an element of a homspace:: sage: TestSuite(f).run(skip="_test_category") """ Morphism.__init__(self, Hom(domain, codomain))
def __invert__(self): r""" Return the inverse of ``self``. EXAMPLES:: sage: RC = crystals.infinity.RiggedConfigurations(['A',3]) sage: T = crystals.infinity.Tableaux(['A',3]) sage: phi = RC.coerce_map_from(T) sage: ~phi Crystal Isomorphism morphism: From: The infinity crystal of rigged configurations of type ['A', 3] To: The infinity crystal of tableaux of type ['A', 3] """ return FromRCIsomorphism(Hom(self.codomain(), self.domain()))
def __init__(self, K, V): """ EXAMPLES:: sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^2 - x*y + 4*x^3) sage: V, f, t = L.vector_space(); type(t) <class 'sage.rings.function_field.maps.MapFunctionFieldToVectorSpace'> """ self._V = V self._K = K self._zero = K.base_ring()(0) self._n = K.degree() from sage.categories.homset import Hom FunctionFieldIsomorphism.__init__(self, Hom(K, V))
def __init__(self, K, L): r""" EXAMPLE:: sage: K.<a, b> = NumberField([x^2 - 3, x^2 + 7]) sage: L.<c, d> = K.change_names() sage: L.structure() (Isomorphism given by variable name change map: From: Number Field in c with defining polynomial x^2 - 3 over its base field To: Number Field in a with defining polynomial x^2 - 3 over its base field, Isomorphism given by variable name change map: From: Number Field in a with defining polynomial x^2 - 3 over its base field To: Number Field in c with defining polynomial x^2 - 3 over its base field) """ self.__K = K self.__L = L NumberFieldIsomorphism.__init__(self, Hom(K, L))
def __init__(self, L, V, to_K, to_V): r""" EXAMPLES:: sage: L.<a, b> = NumberField([x^2 + 3, x^2 + 5]) sage: V, fr, to = L.absolute_vector_space() # indirect doctest sage: to Isomorphism map: From: Number Field in a with defining polynomial x^2 + 3 over its base field To: Vector space of dimension 4 over Rational Field """ self.__L = L self.__V = V self.__to_K = to_K self.__to_V = to_V NumberFieldIsomorphism.__init__(self, Hom(L, V))
def __init__(self, V, K): r""" EXAMPLES:: sage: K.<c> = NumberField(x^9 + 3) sage: V, fr, to = K.vector_space(); fr # indirect doctest Isomorphism map: From: Vector space of dimension 9 over Rational Field To: Number Field in c with defining polynomial x^9 + 3 sage: type(fr) <class 'sage.rings.number_field.maps.MapVectorSpaceToNumberField'> """ self.__V = V self.__K = K self.__R = K.polynomial_ring() NumberFieldIsomorphism.__init__(self, Hom(V, K))
def __init__(self, A, R): r""" EXAMPLE:: sage: L.<a, b> = NumberField([x^2 + 3, x^2 + 5]) sage: K.<c> = L.absolute_field() sage: f = K.structure()[0] # indirect doctest sage: type(f) <class 'sage.rings.number_field.maps.MapAbsoluteToRelativeNumberField'> """ self.__A = A # absolute field self.__R = R # relative field self.__poly_ring = self.__A.polynomial_ring() self.__zero = QQ(0) self.__n = A.degree() NumberFieldIsomorphism.__init__(self, Hom(A, R))
def __init__(self, domain, codomain): """ Construct the morphism TESTS:: sage: Z4 = AbelianGroupWithValues([I], [4]) sage: from sage.groups.abelian_gps.values import AbelianGroupWithValuesEmbedding sage: AbelianGroupWithValuesEmbedding(Z4, Z4.values_group()) Generic morphism: From: Multiplicative Abelian group isomorphic to C4 To: Symbolic Ring """ assert domain.values_group() is codomain from sage.categories.homset import Hom Morphism.__init__(self, Hom(domain, codomain))
def __init__(self, original_code, subfield, embedding=None): r""" TESTS: ``subfield`` has to be a finite field, otherwise an error is raised:: sage: C = codes.random_linear_code(GF(16, 'aa'), 7, 3) sage: Cs = codes.SubfieldSubcode(C, RR) Traceback (most recent call last): ... ValueError: subfield has to be a finite field ``subfield`` has to be a subfield of ``original_code``'s base field, otherwise an error is raised:: sage: C = codes.random_linear_code(GF(16, 'aa'), 7, 3) sage: Cs = codes.SubfieldSubcode(C, GF(8, 'a')) Traceback (most recent call last): ... ValueError: subfield has to be a subfield of the base field of the original code """ if not isinstance(original_code, AbstractLinearCode): raise ValueError("original_code must be a linear code") if not subfield.is_finite(): raise ValueError("subfield has to be a finite field") p = subfield.characteristic() F = original_code.base_field() s = subfield.degree() sm = F.degree() if not s.divides(sm): raise ValueError( "subfield has to be a subfield of the base field of the original code" ) self._original_code = original_code H = Hom(subfield, F) if embedding is not None and not embedding in H: raise ValueError( "embedding has to be an embedding from subfield to original_code's base field" ) elif embedding is not None: self._embedding = RelativeFiniteFieldExtension( F, subfield, embedding) else: self._embedding = RelativeFiniteFieldExtension(F, subfield, H[0]) super(SubfieldSubcode, self).__init__(subfield, original_code.length(), "Systematic", "Syndrome")
def __init__(self, V, K): r""" EXAMPLE:: sage: K.<a, b> = NumberField([x^2 + 1, x^2 - 2]) sage: V, _, to = K.relative_vector_space(); to # indirect doctest Isomorphism map: From: Number Field in a with defining polynomial x^2 + 1 over its base field To: Vector space of dimension 2 over Number Field in b with defining polynomial x^2 - 2 """ self.__V = V self.__K = K self.__R = K.polynomial_ring() self.__rnf = K.pari_rnf() self.__B = K.base_field().absolute_field('a') NumberFieldIsomorphism.__init__(self, Hom(V, K))
def __init__(self, K, V): r""" Standard initialisation function. EXAMPLE:: sage: L.<a> = NumberField(x^3 - x + 1) sage: L.vector_space()[2] # indirect doctest Isomorphism map: From: Number Field in a with defining polynomial x^3 - x + 1 To: Vector space of dimension 3 over Rational Field """ self.__V = V self.__K = K self.__zero = QQ(0) self.__n = K.degree() NumberFieldIsomorphism.__init__(self, Hom(K, V))
def reversed(self): """ Return the corresponding homset, but with the domain and codomain reversed. EXAMPLES:: sage: H = Hom(ZZ^2, ZZ^3); H Set of Morphisms from Ambient free module of rank 2 over the principal ideal domain Integer Ring to Ambient free module of rank 3 over the principal ideal domain Integer Ring in Category of modules with basis over Integer Ring sage: type(H) <class 'sage.modules.free_module_homspace.FreeModuleHomspace_with_category'> sage: H.reversed() Set of Morphisms from Ambient free module of rank 3 over the principal ideal domain Integer Ring to Ambient free module of rank 2 over the principal ideal domain Integer Ring in Category of hom sets in Category of modules with basis over Integer Ring sage: type(H.reversed()) <class 'sage.modules.free_module_homspace.FreeModuleHomspace_with_category'> """ return Hom(self.codomain(), self.domain(), category=self.category())
def __init__(self, domain, codomain, ringembed): r""" Initialize this morphism. TESTS:: sage: k.<a> = GF(5^3) sage: S.<x> = SkewPolynomialRing(k, k.frobenius_endomorphism()) sage: K = S.fraction_field() sage: Z = K.center() sage: iota = K.coerce_map_from(Z) sage: TestSuite(iota).run(skip=['_test_category']) """ RingHomomorphism.__init__(self, Hom(domain, codomain)) self._codomain = codomain self._ringembed = ringembed self._section = SectionOreFunctionCenterInjection(self)
def __init__(self, K): r""" Initialize a derivation from ``K`` to ``K``. EXAMPLES:: sage: K.<x> = FunctionField(QQ) sage: d = K.derivation() # indirect doctest """ from .function_field import is_FunctionField if not is_FunctionField(K): raise ValueError("K must be a function field") self.__field = K from sage.categories.homset import Hom from sage.categories.sets_cat import Sets Map.__init__(self, Hom(K, K, Sets()))
def __init__(self, domain, codomain, embed, order): r""" Initialize this morphism. EXAMPLES:: sage: k.<a> = GF(5^3) sage: S.<x> = SkewPolynomialRing(k, k.frobenius_endomorphism()) sage: Z = S.center() sage: S.convert_map_from(Z) # indirect doctest Embedding of the center of Ore Polynomial Ring in x over Finite Field in a of size 5^3 twisted by a |--> a^5 into this ring """ RingHomomorphism.__init__(self, Hom(domain, codomain)) self._embed = embed self._order = order self._codomain = codomain self._section = SectionSkewPolynomialCenterInjection(self)
def _dualizing_sheaf(poset, degree, base_ring, rank): p = degree * -1 chains = sorted(filter(lambda chain: len(chain) == p + 1, poset.chains())) singleton = Poset({0: []}, {}) sheaf = LocallyFreeSheafFinitePoset({0: rank}, {}, base_ring=base_ring, domain_poset=singleton) result = None hom = Hom(singleton, poset) for c in chains: inclusion = hom(lambda point: {0: c[-1]}[point]) to_add = sheaf.pushforward(inclusion) if result is None: result = to_add else: result = result + to_add return result
def _generic_convert_map(self, S): """ Return a generic map from a given homset to ``self``. INPUT: - ``S`` -- a homset OUTPUT: A map (by default: a Call morphism) from ``S`` to ``self``. EXAMPLES:: sage: H = Hom(ZZ,QQ['t'], CommutativeAdditiveGroups()) sage: P.<t> = ZZ[] sage: f = P.hom([2*t]) sage: H._generic_convert_map(f.parent()) Call morphism: From: Set of Homomorphisms from Univariate Polynomial Ring in t over Integer Ring to Univariate Polynomial Ring in t over Integer Ring To: Set of Morphisms from Integer Ring to Univariate Polynomial Ring in t over Rational Field in Category of commutative additive groups sage: H._generic_convert_map(f.parent())(f) Composite map: From: Integer Ring To: Univariate Polynomial Ring in t over Rational Field Defn: Composite map: From: Integer Ring To: Univariate Polynomial Ring in t over Integer Ring Defn: Polynomial base injection morphism: From: Integer Ring To: Univariate Polynomial Ring in t over Integer Ring then Ring endomorphism of Univariate Polynomial Ring in t over Integer Ring Defn: t |--> 2*t then Conversion map: From: Univariate Polynomial Ring in t over Integer Ring To: Univariate Polynomial Ring in t over Rational Field """ if self._element_constructor is None: from sage.categories.morphism import CallMorphism from sage.categories.homset import Hom return CallMorphism(Hom(S, self)) else: return Parent._generic_convert_map(self, S)
def __init__(self, f, X, Y): """ Input is a dictionary ``f``, the domain ``X``, and the codomain ``Y``. One can define the dictionary on the vertices of `X`. EXAMPLES:: sage: S = SimplicialComplex([[0,1],[2],[3,4],[5]], is_mutable=False) sage: H = Hom(S,S) sage: f = {0:0,1:1,2:2,3:3,4:4,5:5} sage: g = {0:0,1:1,2:0,3:3,4:4,5:0} sage: x = H(f) sage: y = H(g) sage: x == y False sage: x.image() Simplicial complex with vertex set (0, 1, 2, 3, 4, 5) and facets {(2,), (5,), (0, 1), (3, 4)} sage: y.image() Simplicial complex with vertex set (0, 1, 3, 4) and facets {(0, 1), (3, 4)} sage: x.image() == y.image() False """ if not isinstance(X, SimplicialComplex) or not isinstance( Y, SimplicialComplex): raise ValueError("X and Y must be SimplicialComplexes") if not set(f.keys()) == set(X.vertices()): raise ValueError( "f must be a dictionary from the vertex set of X to single values in the vertex set of Y" ) dim = X.dimension() Y_faces = Y.faces() for k in range(dim + 1): for i in X.faces()[k]: tup = i.tuple() fi = [] for j in tup: fi.append(f[j]) v = Simplex(set(fi)) if v not in Y_faces[v.dimension()]: raise ValueError( "f must be a dictionary from the vertices of X to the vertices of Y" ) self._vertex_dictionary = f Morphism.__init__(self, Hom(X, Y, SimplicialComplexes()))
def _coerce_map_from_(self, P): """ Return ``True`` or the coerce map from ``P`` if a map exists. EXAMPLES:: sage: T = crystals.infinity.Tableaux(['A',3]) sage: RC = crystals.infinity.RiggedConfigurations(['A',3]) sage: T._coerce_map_from_(RC) Crystal Isomorphism morphism: From: The infinity crystal of rigged configurations of type ['A', 3] To: The infinity crystal of tableaux of type ['A', 3] """ from sage.combinat.rigged_configurations.rc_infinity import InfinityCrystalOfRiggedConfigurations if isinstance(P, InfinityCrystalOfRiggedConfigurations): from sage.combinat.rigged_configurations.bij_infinity import FromRCIsomorphism return FromRCIsomorphism(Hom(P, self)) return super(InfinityCrystalOfTableaux, self)._coerce_map_from_(P)
def End(X, category=None): r""" Create the set of endomorphisms of ``X`` in the category category. INPUT: - ``X`` -- anything - ``category`` -- (optional) category in which to coerce ``X`` OUTPUT: A set of endomorphisms in category EXAMPLES:: sage: V = VectorSpace(QQ, 3) sage: End(V) Set of Morphisms (Linear Transformations) from Vector space of dimension 3 over Rational Field to Vector space of dimension 3 over Rational Field :: sage: G = AlternatingGroup(3) sage: S = End(G); S Set of Morphisms from Alternating group of order 3!/2 as a permutation group to Alternating group of order 3!/2 as a permutation group in Category of finite permutation groups sage: from sage.categories.homset import is_Endset sage: is_Endset(S) True sage: S.domain() Alternating group of order 3!/2 as a permutation group To avoid creating superfluous categories, homsets are in the homset category of the lowest category which currently says something specific about its homsets. For example, ``S`` is not in the category of hom sets of the category of groups:: sage: S.category() Category of hom sets in Category of sets sage: End(QQ).category() Category of hom sets in Category of rings """ return Hom(X, X, category)
def __init__(self, I, L, names, index_set, category=None): r""" Initialize ``self``. TESTS:: sage: L.<x,y,z> = LieAlgebra(SR, {('x','y'): {'x':1}}) sage: K = L.quotient(y) sage: K.dimension() 1 sage: TestSuite(K).run() """ B = L.basis() sm = L.module().submodule_with_basis( [I.reduce(B[i]).to_vector() for i in index_set]) SB = sm.basis() # compute and normalize structural coefficients for the quotient s_coeff = {} for i, ind_i in enumerate(index_set): for j in range(i + 1, len(index_set)): ind_j = index_set[j] brkt = I.reduce(L.bracket(SB[i], SB[j])) brktvec = sm.coordinate_vector(brkt.to_vector()) s_coeff[(ind_i, ind_j)] = dict(zip(index_set, brktvec)) s_coeff = LieAlgebraWithStructureCoefficients._standardize_s_coeff( s_coeff, index_set) self._ambient = L self._I = I self._sm = sm LieAlgebraWithStructureCoefficients.__init__(self, L.base_ring(), s_coeff, names, index_set, category=category) # register the quotient morphism as a conversion H = Hom(L, self) f = SetMorphism(H, self.retract) self.register_conversion(f)
def __init__(self): """ TESTS:: sage: P = Sets().example("wrapper") sage: P.category() Category of sets sage: P(13) == 13 True sage: ZZ(P(13)) == 13 True sage: P(13) + 1 == 14 True """ Parent.__init__(self, category=Sets()) from sage.rings.integer_ring import IntegerRing from sage.categories.homset import Hom self.mor = Hom(self, IntegerRing())(lambda z: z.value) self._populate_coercion_lists_(embedding=self.mor)
def __init__(self, R, repr_var1 = 'x', repr_var2 = 'y', inversed_ring = None): self._coeffs_ring = MultivariatePolynomialAlgebra_generic(R, repr_var2, always_show_main_var = True) MultivariatePolynomialAlgebra_generic.__init__( self, self._coeffs_ring, repr_var1, always_show_main_var = True, extra_bases_category = Finite_rank_double_bases() ) self._repr_var1 = repr_var1 self._repr_var2 = repr_var2 self._coeffs_base_ring = R if(inversed_ring is None): self._inversed_ring = DoubleMultivariatePolynomialAlgebra_generic(R, repr_var2, repr_var1, self) else: self._inversed_ring = inversed_ring m = SetMorphism( Hom(self, self.inversed_ring()), lambda x : x.swap_coeffs_elements()) m.register_as_coercion()
def __init__(self, R, A): r""" EXAMPLE:: sage: L.<a, b> = NumberField([x^2 + 3, x^2 + 5]) sage: K.<c> = L.absolute_field() sage: f = K.structure()[1]; f Isomorphism map: From: Number Field in a with defining polynomial x^2 + 3 over its base field To: Number Field in c with defining polynomial x^4 + 16*x^2 + 4 sage: type(f) <class 'sage.rings.number_field.maps.MapRelativeToAbsoluteNumberField'> """ self.__R = R # relative field self.__A = A # absolute field self.__poly_ring = self.__A.polynomial_ring() self.__zero = QQ(0) self.__n = A.degree() NumberFieldIsomorphism.__init__(self, Hom(R, A))
def _coerce_map_from_(self, R): """ EXAMPLES:: sage: L.<x,y> = LaurentPolynomialRing(QQ) sage: L.coerce_map_from(QQ) Composite map: From: Rational Field To: Multivariate Laurent Polynomial Ring in x, y over Rational Field Defn: Polynomial base injection morphism: From: Rational Field To: Multivariate Polynomial Ring in x, y over Rational Field then Call morphism: From: Multivariate Polynomial Ring in x, y over Rational Field To: Multivariate Laurent Polynomial Ring in x, y over Rational Field Let us check that coercion between Laurent Polynomials over different base rings works (:trac:`15345`):: sage: R = LaurentPolynomialRing(ZZ, 'x') sage: T = LaurentPolynomialRing(QQ, 'x') sage: R.gen() + 3*T.gen() 4*x """ if R is self._R or (isinstance(R, LaurentPolynomialRing_generic) and self._R.has_coerce_map_from(R._R)): from sage.structure.coerce_maps import CallableConvertMap return CallableConvertMap(R, self, self._element_constructor_, parent_as_first_arg=False) elif isinstance(R, LaurentPolynomialRing_generic) and \ R.variable_names() == self.variable_names() and \ self.base_ring().has_coerce_map_from(R.base_ring()): return True f = self._R.coerce_map_from(R) if f is not None: from sage.categories.homset import Hom from sage.categories.morphism import CallMorphism return CallMorphism(Hom(self._R, self)) * f
def _coerce_map_from_(self, P): """ Return ``True`` or the coerce map from ``P`` if a map exists. EXAMPLES:: sage: T = crystals.infinity.Tableaux(['C',3]) sage: vct = CartanType(['C',3]).as_folding() sage: RC = crystals.infinity.RiggedConfigurations(vct) sage: RC._coerce_map_from_(T) Crystal Isomorphism morphism: From: The infinity crystal of tableaux of type ['C', 3] To: The infinity crystal of rigged configurations of type ['C', 3] """ if self.cartan_type().is_finite(): from sage.combinat.crystals.infinity_crystals import InfinityCrystalOfTableaux if isinstance(P, InfinityCrystalOfTableaux): from sage.combinat.rigged_configurations.bij_infinity import FromTableauIsomorphism return FromTableauIsomorphism(Hom(P, self)) return super(InfinityCrystalOfNonSimplyLacedRC, self)._coerce_map_from_(P)
def _composition(self, right): """ A helper for multiplying maps by composition. .. WARNING:: Do not override this method! Override :meth:`_composition_` instead. EXAMPLES:: sage: X = AffineSpace(QQ,2) sage: f = X.structure_morphism() sage: Y = Spec(QQ) sage: g = Y.structure_morphism() sage: g * f # indirect doctest Composite map: From: Affine Space of dimension 2 over Rational Field To: Spectrum of Integer Ring Defn: Generic morphism: From: Affine Space of dimension 2 over Rational Field To: Spectrum of Rational Field then Generic morphism: From: Spectrum of Rational Field To: Spectrum of Integer Ring sage: f * g Traceback (most recent call last): ... TypeError: self (=Scheme morphism: From: Affine Space of dimension 2 over Rational Field To: Spectrum of Rational Field Defn: Structure map) domain must equal right (=Scheme morphism: From: Spectrum of Rational Field To: Spectrum of Integer Ring Defn: Structure map) codomain """ category = self.category_for()._meet_(right.category_for()) H = Hom(right.domain(), self._codomain, category) return self._composition_(right, H)
def __init__(self, K, V): r""" EXAMPLE:: sage: L.<b> = NumberField(x^4 + 3*x^2 + 1) sage: K = L.relativize(L.subfields(2)[0][1], 'a') sage: V, fr, to = K.relative_vector_space() sage: to Isomorphism map: From: Number Field in a0 with defining polynomial x^2 - b0*x + 1 over its base field To: Vector space of dimension 2 over Number Field in b0 with defining polynomial x^2 + 1 """ self.__V = V self.__K = K self.__rnf = K.pari_rnf() self.__zero = QQ(0) self.__n = K.relative_degree() self.__x = pari("'x") self.__y = pari("'y") self.__B = K.absolute_base_field() NumberFieldIsomorphism.__init__(self, Hom(K, V))
def __init__(self, domain, codomain): r""" Initialize this morphism. EXAMPLES:: sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: K = S.fraction_field() sage: K.coerce_map_from(K.base_ring()) # indirect doctest Ore Function base injection morphism: From: Fraction Field of Univariate Polynomial Ring in t over Rational Field To: Ore Function Field in x over Fraction Field of Univariate Polynomial Ring in t over Rational Field twisted by t |--> t + 1 """ assert codomain.base_ring() is domain, \ "the domain of the injection must be the base ring of the Ore function field" Morphism.__init__(self, Hom(domain, codomain)) self._an_element = codomain.gen() self._repr_type_str = "Ore Function base injection"
def _coerce_map_from_(self, S): """ Define coercions. EXAMPLES: A place is converted to a prime divisor:: sage: K.<x> = FunctionField(GF(5)); R.<t> = PolynomialRing(K) sage: F.<y> = K.extension(t^2-x^3-1) sage: O = F.maximal_order() sage: I = O.ideal(x+1,y) sage: P = I.place() sage: y.divisor() + P -3*Place (1/x, 1/x^2*y) + 2*Place (x + 1, y) + Place (x^2 + 4*x + 1, y) """ if isinstance(S, PlaceSet): func = lambda place: prime_divisor(self._field, place) return SetMorphism(Hom(S, self), func)
def __init__(self): r""" EXAMPLES:: sage: A = RingOfIntegers(); A Integer Ring (redone) sage: TestSuite(A).run() TESTS:: sage: A = Sets().WithRealizations().example(); A The subset algebra of {1, 2, 3} over Rational Field sage: SageIntegers, LongIntegers = A.realizations() sage: type(LongIntegers.coerce_map_from(SageIntegers)) <type 'sage.categories.morphism.SetMorphism'> sage: type(SageIntegers.coerce_map_from(LongIntegers)) <type 'sage.categories.morphism.SetMorphism'> """ Parent.__init__(self, category = Rings().WithRealizations()) category = self.Notations() SageIntegers = self.SageIntegers() LongIntegers = self.LongIntegers() f_Sage_to_Long = lambda self: LongIntegers(str(self)) Sage_to_Long = \ Hom(SageIntegers, LongIntegers, Sets().Realizations())(f_Sage_to_Long) f_Long_to_Sage = lambda self:(SageIntegers(Integer(self.value))) Long_to_Sage = \ Hom(LongIntegers, SageIntegers, Sets().Realizations())(f_Long_to_Sage) # Tried: # Hom(LongIntegers, SageIntegers, Rings().Realizations())(f_Long_to_Sage) # Hom(LongIntegers, SageIntegers, category)(f_Long_to_Sage) Sage_to_Long.register_as_coercion() Long_to_Sage.register_as_coercion()
def Hom(X, Y, category=None): """ Create the space of homomorphisms from X to Y in the category ``category``. INPUT: - ``X`` -- an object of a category - ``Y`` -- an object of a category - ``category`` -- a category in which the morphisms must be. (default: the meet of the categories of ``X`` and ``Y``) Both ``X`` and ``Y`` must belong to that category. OUTPUT: a homset in category EXAMPLES:: sage: V = VectorSpace(QQ,3) sage: Hom(V, V) Set of Morphisms (Linear Transformations) from Vector space of dimension 3 over Rational Field to Vector space of dimension 3 over Rational Field sage: G = AlternatingGroup(3) sage: Hom(G, G) Set of Morphisms from Alternating group of order 3!/2 as a permutation group to Alternating group of order 3!/2 as a permutation group in Category of finite permutation groups sage: Hom(ZZ, QQ, Sets()) Set of Morphisms from Integer Ring to Rational Field in Category of sets sage: Hom(FreeModule(ZZ,1), FreeModule(QQ,1)) Set of Morphisms from Ambient free module of rank 1 over the principal ideal domain Integer Ring to Vector space of dimension 1 over Rational Field in Category of commutative additive groups sage: Hom(FreeModule(QQ,1), FreeModule(ZZ,1)) Set of Morphisms from Vector space of dimension 1 over Rational Field to Ambient free module of rank 1 over the principal ideal domain Integer Ring in Category of commutative additive groups Here, we test against a memory leak that has been fixed at :trac:`11521` by using a weak cache:: sage: for p in prime_range(10^3): ... K = GF(p) ... a = K(0) sage: import gc sage: gc.collect() # random 624 sage: from sage.rings.finite_rings.finite_field_prime_modn import FiniteField_prime_modn as FF sage: L = [x for x in gc.get_objects() if isinstance(x, FF)] sage: len(L), L[0], L[len(L)-1] (2, Finite Field of size 2, Finite Field of size 997) To illustrate the choice of the category, we consider the following parents as running examples:: sage: X = ZZ; X Integer Ring sage: Y = SymmetricGroup(3); Y Symmetric group of order 3! as a permutation group By default, the smallest category containing both ``X`` and ``Y``, is used:: sage: Hom(X, Y) Set of Morphisms from Integer Ring to Symmetric group of order 3! as a permutation group in Category of monoids Otherwise, if ``category`` is specified, then ``category`` is used, after checking that ``X`` and ``Y`` are indeed in ``category``:: sage: Hom(X, Y, Magmas()) Set of Morphisms from Integer Ring to Symmetric group of order 3! as a permutation group in Category of magmas sage: Hom(X, Y, Groups()) Traceback (most recent call last): ... TypeError: Integer Ring is not in Category of groups A parent (or a parent class of a category) may specify how to construct certain homsets by implementing a method ``_Hom_(self, codomain, category)``. This method should either construct the requested homset or raise a ``TypeError``. This hook is currently mostly used to create homsets in some specific subclass of :class:`Homset` (e.g. :class:`sage.rings.homset.RingHomset`):: sage: Hom(QQ,QQ).__class__ <class 'sage.rings.homset.RingHomset_generic_with_category'> Do not call this hook directly to create homsets, as it does not handle unique representation:: sage: Hom(QQ,QQ) == QQ._Hom_(QQ, category=QQ.category()) True sage: Hom(QQ,QQ) is QQ._Hom_(QQ, category=QQ.category()) False TESTS: Homset are unique parents:: sage: k = GF(5) sage: H1 = Hom(k,k) sage: H2 = Hom(k,k) sage: H1 is H2 True Moreover, if no category is provided, then the result is identical with the result for the meet of the categories of the domain and the codomain:: sage: Hom(QQ, ZZ) is Hom(QQ,ZZ, Category.meet([QQ.category(), ZZ.category()])) True Some doc tests in :mod:`sage.rings` (need to) break the unique parent assumption. But if domain or codomain are not unique parents, then the homset will not fit. That is to say, the hom set found in the cache will have a (co)domain that is equal to, but not identical with, the given (co)domain. By :trac:`9138`, we abandon the uniqueness of homsets, if the domain or codomain break uniqueness:: sage: from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_polydict_domain sage: P.<x,y,z>=MPolynomialRing_polydict_domain(QQ, 3, order='degrevlex') sage: Q.<x,y,z>=MPolynomialRing_polydict_domain(QQ, 3, order='degrevlex') sage: P == Q True sage: P is Q False Hence, ``P`` and ``Q`` are not unique parents. By consequence, the following homsets aren't either:: sage: H1 = Hom(QQ,P) sage: H2 = Hom(QQ,Q) sage: H1 == H2 True sage: H1 is H2 False It is always the most recently constructed homset that remains in the cache:: sage: H2 is Hom(QQ,Q) True Variation on the theme:: sage: U1 = FreeModule(ZZ,2) sage: U2 = FreeModule(ZZ,2,inner_product_matrix=matrix([[1,0],[0,-1]])) sage: U1 == U2, U1 is U2 (True, False) sage: V = ZZ^3 sage: H1 = Hom(U1, V); H2 = Hom(U2, V) sage: H1 == H2, H1 is H2 (True, False) sage: H1 = Hom(V, U1); H2 = Hom(V, U2) sage: H1 == H2, H1 is H2 (True, False) Since :trac:`11900`, the meet of the categories of the given arguments is used to determine the default category of the homset. This can also be a join category, as in the following example:: sage: PA = Parent(category=Algebras(QQ)) sage: PJ = Parent(category=Category.join([Fields(), ModulesWithBasis(QQ)])) sage: Hom(PA,PJ) Set of Homomorphisms from <type 'sage.structure.parent.Parent'> to <type 'sage.structure.parent.Parent'> sage: Hom(PA,PJ).category() Join of Category of hom sets in Category of modules over Rational Field and Category of hom sets in Category of rings sage: Hom(PA,PJ, Rngs()) Set of Morphisms from <type 'sage.structure.parent.Parent'> to <type 'sage.structure.parent.Parent'> in Category of rngs .. TODO:: - Design decision: how much of the homset comes from the category of ``X`` and ``Y``, and how much from the specific ``X`` and ``Y``. In particular, do we need several parent classes depending on ``X`` and ``Y``, or does the difference only lie in the elements (i.e. the morphism), and of course how the parent calls their constructors. - Specify the protocol for the ``_Hom_`` hook in case of ambiguity (e.g. if both a parent and some category thereof provide one). TESTS:: sage: R = sage.structure.parent.Set_PythonType(int) sage: S = sage.structure.parent.Set_PythonType(float) sage: Hom(R, S) Set of Morphisms from Set of Python objects of type 'int' to Set of Python objects of type 'float' in Category of sets """ # This should use cache_function instead # However some special handling is currently needed for # domains/docomains that break the unique parent condition. Also, # at some point, it somehow broke the coercion (see e.g. sage -t # sage.rings.real_mpfr). To be investigated. global _cache key = (X,Y,category) try: H = _cache[key] except KeyError: H = None if H is not None: # Return H unless the domain or codomain breaks the unique parent condition if H.domain() is X and H.codomain() is Y: return H # Determines the category if category is None: category = X.category()._meet_(Y.category()) # Recurse to make sure that Hom(X, Y) and Hom(X, Y, category) are identical H = Hom(X, Y, category) else: if not isinstance(category, Category): raise TypeError("Argument category (= {}) must be a category.".format(category)) # See trac #14793: It can happen, that Hom(X,X) is called during # unpickling of an instance X of a Python class at a time when # X.__dict__ is empty. In some of these cases, X.category() would # raise a error or would return a too large category (Sets(), for # example) and (worse!) would assign this larger category to the # X._category cdef attribute, so that it would subsequently seem that # X's category was properly initialised. # However, if the above scenario happens, then *before* calling # X.category(), X._is_category_initialised() will correctly say that # it is not initialised. Moreover, since X.__class__ is a Python # class, we will find that `isinstance(X, category.parent_class)`. If # this is the case, then we trust that we indeed are in the process of # unpickling X. Hence, we will trust that `category` has the correct # value, and we will thus skip the test whether `X in category`. try: unpickle_X = (not X._is_category_initialized()) and isinstance(X,category.parent_class) except AttributeError: # this happens for simplicial complexes unpickle_X = False try: unpickle_Y = (not Y._is_category_initialized()) and isinstance(Y,category.parent_class) except AttributeError: unpickle_Y = False if unpickle_X: cat_X = category else: try: cat_X = X.category() except BaseException: raise TypeError("%s is not in %s"%(X, category)) if unpickle_Y: cat_Y = category else: try: cat_Y = Y.category() except BaseException: raise TypeError("%s is not in %s"%(Y, category)) if not cat_X.is_subcategory(category): raise TypeError("%s is not in %s"%(X, category)) if not cat_Y.is_subcategory(category): raise TypeError("%s is not in %s"%(Y, category)) # Construct H try: # _Hom_ hook from the parent H = X._Hom_(Y, category) except (AttributeError, TypeError): try: # Workaround in case the above fails, but the category # also provides a _Hom_ hook. # FIXME: # - If X._Hom_ actually comes from category and fails, it # will be called twice. # - This is bound to fail if X is an extension type and # does not actually inherit from category.parent_class H = category.parent_class._Hom_(X, Y, category = category) except (AttributeError, TypeError): # By default, construct a plain homset. H = Homset(X, Y, category = category) _cache[key] = H if isinstance(X, UniqueRepresentation) and isinstance(Y, UniqueRepresentation): if not isinstance(H, WithEqualityById): try: H.__class__ = dynamic_class(H.__class__.__name__+"_with_equality_by_id", (WithEqualityById, H.__class__), doccls=H.__class__) except BaseException: pass return H
def Hom(X, Y, category=None, check=True): """ Create the space of homomorphisms from X to Y in the category ``category``. INPUT: - ``X`` -- an object of a category - ``Y`` -- an object of a category - ``category`` -- a category in which the morphisms must be. (default: the meet of the categories of ``X`` and ``Y``) Both ``X`` and ``Y`` must belong to that category. - ``check`` -- a boolean (default: ``True``): whether to check the input, and in particular that ``X`` and ``Y`` belong to ``category``. OUTPUT: a homset in category EXAMPLES:: sage: V = VectorSpace(QQ,3) sage: Hom(V, V) Set of Morphisms (Linear Transformations) from Vector space of dimension 3 over Rational Field to Vector space of dimension 3 over Rational Field sage: G = AlternatingGroup(3) sage: Hom(G, G) Set of Morphisms from Alternating group of order 3!/2 as a permutation group to Alternating group of order 3!/2 as a permutation group in Category of finite permutation groups sage: Hom(ZZ, QQ, Sets()) Set of Morphisms from Integer Ring to Rational Field in Category of sets sage: Hom(FreeModule(ZZ,1), FreeModule(QQ,1)) Set of Morphisms from Ambient free module of rank 1 over the principal ideal domain Integer Ring to Vector space of dimension 1 over Rational Field in Category of commutative additive groups sage: Hom(FreeModule(QQ,1), FreeModule(ZZ,1)) Set of Morphisms from Vector space of dimension 1 over Rational Field to Ambient free module of rank 1 over the principal ideal domain Integer Ring in Category of commutative additive groups Here, we test against a memory leak that has been fixed at :trac:`11521` by using a weak cache:: sage: for p in prime_range(10^3): ... K = GF(p) ... a = K(0) sage: import gc sage: gc.collect() # random 624 sage: from sage.rings.finite_rings.finite_field_prime_modn import FiniteField_prime_modn as FF sage: L = [x for x in gc.get_objects() if isinstance(x, FF)] sage: len(L), L[0] (1, Finite Field of size 997) To illustrate the choice of the category, we consider the following parents as running examples:: sage: X = ZZ; X Integer Ring sage: Y = SymmetricGroup(3); Y Symmetric group of order 3! as a permutation group By default, the smallest category containing both ``X`` and ``Y``, is used:: sage: Hom(X, Y) Set of Morphisms from Integer Ring to Symmetric group of order 3! as a permutation group in Join of Category of monoids and Category of enumerated sets Otherwise, if ``category`` is specified, then ``category`` is used, after checking that ``X`` and ``Y`` are indeed in ``category``:: sage: Hom(X, Y, Magmas()) Set of Morphisms from Integer Ring to Symmetric group of order 3! as a permutation group in Category of magmas sage: Hom(X, Y, Groups()) Traceback (most recent call last): ... ValueError: Integer Ring is not in Category of groups A parent (or a parent class of a category) may specify how to construct certain homsets by implementing a method ``_Hom_(self, codomain, category)``. This method should either construct the requested homset or raise a ``TypeError``. This hook is currently mostly used to create homsets in some specific subclass of :class:`Homset` (e.g. :class:`sage.rings.homset.RingHomset`):: sage: Hom(QQ,QQ).__class__ <class 'sage.rings.homset.RingHomset_generic_with_category'> Do not call this hook directly to create homsets, as it does not handle unique representation:: sage: Hom(QQ,QQ) == QQ._Hom_(QQ, category=QQ.category()) True sage: Hom(QQ,QQ) is QQ._Hom_(QQ, category=QQ.category()) False TESTS: Homset are unique parents:: sage: k = GF(5) sage: H1 = Hom(k,k) sage: H2 = Hom(k,k) sage: H1 is H2 True Moreover, if no category is provided, then the result is identical with the result for the meet of the categories of the domain and the codomain:: sage: Hom(QQ, ZZ) is Hom(QQ,ZZ, Category.meet([QQ.category(), ZZ.category()])) True Some doc tests in :mod:`sage.rings` (need to) break the unique parent assumption. But if domain or codomain are not unique parents, then the homset will not fit. That is to say, the hom set found in the cache will have a (co)domain that is equal to, but not identical with, the given (co)domain. By :trac:`9138`, we abandon the uniqueness of homsets, if the domain or codomain break uniqueness:: sage: from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_polydict_domain sage: P.<x,y,z>=MPolynomialRing_polydict_domain(QQ, 3, order='degrevlex') sage: Q.<x,y,z>=MPolynomialRing_polydict_domain(QQ, 3, order='degrevlex') sage: P == Q True sage: P is Q False Hence, ``P`` and ``Q`` are not unique parents. By consequence, the following homsets aren't either:: sage: H1 = Hom(QQ,P) sage: H2 = Hom(QQ,Q) sage: H1 == H2 True sage: H1 is H2 False It is always the most recently constructed homset that remains in the cache:: sage: H2 is Hom(QQ,Q) True Variation on the theme:: sage: U1 = FreeModule(ZZ,2) sage: U2 = FreeModule(ZZ,2,inner_product_matrix=matrix([[1,0],[0,-1]])) sage: U1 == U2, U1 is U2 (True, False) sage: V = ZZ^3 sage: H1 = Hom(U1, V); H2 = Hom(U2, V) sage: H1 == H2, H1 is H2 (True, False) sage: H1 = Hom(V, U1); H2 = Hom(V, U2) sage: H1 == H2, H1 is H2 (True, False) Since :trac:`11900`, the meet of the categories of the given arguments is used to determine the default category of the homset. This can also be a join category, as in the following example:: sage: PA = Parent(category=Algebras(QQ)) sage: PJ = Parent(category=Rings() & Modules(QQ)) sage: Hom(PA,PJ) Set of Homomorphisms from <type 'sage.structure.parent.Parent'> to <type 'sage.structure.parent.Parent'> sage: Hom(PA,PJ).category() Category of homsets of unital magmas and right modules over Rational Field and left modules over Rational Field sage: Hom(PA,PJ, Rngs()) Set of Morphisms from <type 'sage.structure.parent.Parent'> to <type 'sage.structure.parent.Parent'> in Category of rngs .. TODO:: - Design decision: how much of the homset comes from the category of ``X`` and ``Y``, and how much from the specific ``X`` and ``Y``. In particular, do we need several parent classes depending on ``X`` and ``Y``, or does the difference only lie in the elements (i.e. the morphism), and of course how the parent calls their constructors. - Specify the protocol for the ``_Hom_`` hook in case of ambiguity (e.g. if both a parent and some category thereof provide one). TESTS: Facade parents over plain Python types are supported:: sage: R = sage.structure.parent.Set_PythonType(int) sage: S = sage.structure.parent.Set_PythonType(float) sage: Hom(R, S) Set of Morphisms from Set of Python objects of type 'int' to Set of Python objects of type 'float' in Category of sets Checks that the domain and codomain are in the specified category. Case of a non parent:: sage: S = SimplicialComplex([[1,2], [1,4]]); S.rename("S") sage: Hom(S, S, SimplicialComplexes()) Set of Morphisms from S to S in Category of finite simplicial complexes sage: Hom(Set(), S, Sets()) Set of Morphisms from {} to S in Category of sets sage: Hom(S, Set(), Sets()) Set of Morphisms from S to {} in Category of sets sage: H = Hom(S, S, ChainComplexes(QQ)) Traceback (most recent call last): ... ValueError: S is not in Category of chain complexes over Rational Field Those checks are done with the natural idiom ``X in category``, and not ``X.category().is_subcategory(category)`` as it used to be before :trac:`16275` (see :trac:`15801` for a real use case):: sage: class PermissiveCategory(Category): ....: def super_categories(self): return [Objects()] ....: def __contains__(self, X): return True sage: C = PermissiveCategory(); C.rename("Permissive category") sage: S.category().is_subcategory(C) False sage: S in C True sage: Hom(S, S, C) Set of Morphisms from S to S in Permissive category With ``check=False``, unitialized parents, as can appear upon unpickling, are supported. Case of a parent:: sage: cls = type(Set()) sage: S = unpickle_newobj(cls, ()) # A non parent sage: H = Hom(S, S, SimplicialComplexes(), check=False); sage: H = Hom(S, S, Sets(), check=False) sage: H = Hom(S, S, ChainComplexes(QQ), check=False) Case of a non parent:: sage: cls = type(SimplicialComplex([[1,2], [1,4]])) sage: S = unpickle_newobj(cls, ()) sage: H = Hom(S, S, Sets(), check=False) sage: H = Hom(S, S, Groups(), check=False) sage: H = Hom(S, S, SimplicialComplexes(), check=False) Typical example where unpickling involves calling Hom on an unitialized parent:: sage: P.<x,y> = QQ['x,y'] sage: Q = P.quotient([x^2-1,y^2-1]) sage: q = Q.an_element() sage: explain_pickle(dumps(Q)) pg_... ... = pg_dynamic_class('QuotientRing_generic_with_category', (pg_QuotientRing_generic, pg_getattr(..., 'parent_class')), None, None, pg_QuotientRing_generic) si... = unpickle_newobj(..., ()) ... si... = pg_unpickle_MPolynomialRing_libsingular(..., ('x', 'y'), ...) si... = ... pg_Hom(si..., si..., ...) ... sage: Q == loads(dumps(Q)) True """ # This should use cache_function instead # However some special handling is currently needed for # domains/docomains that break the unique parent condition. Also, # at some point, it somehow broke the coercion (see e.g. sage -t # sage.rings.real_mpfr). To be investigated. global _cache key = (X, Y, category) try: H = _cache[key] except KeyError: H = None if H is not None: # Return H unless the domain or codomain breaks the unique parent condition if H.domain() is X and H.codomain() is Y: return H # Determines the category if category is None: category = X.category()._meet_(Y.category()) # Recurse to make sure that Hom(X, Y) and Hom(X, Y, category) are identical # No need to check the input again H = Hom(X, Y, category, check=False) else: if check: if not isinstance(category, Category): raise TypeError("Argument category (= {}) must be a category.".format(category)) for O in [X, Y]: try: category_mismatch = O not in category except Exception: # An error should not happen, this here is just to be on # the safe side. category_mismatch = True # A category mismatch does not necessarily mean that an error # should be raised. Instead, it could be the case that we are # unpickling an old pickle (that doesn't set the "check" # argument to False). In this case, it could be that the # (co)domain is not properly initialised, which we are # checking now. See trac #16275 and #14793. if category_mismatch and O._is_category_initialized(): # At this point, we can be rather sure that O is properly # initialised, and thus its string representation is # available for the following error message. It simply # belongs to the wrong category. raise ValueError("{} is not in {}".format(O, category)) # Construct H try: # _Hom_ hook from the parent H = X._Hom_(Y, category) except (AttributeError, TypeError): try: # Workaround in case the above fails, but the category # also provides a _Hom_ hook. # FIXME: # - If X._Hom_ actually comes from category and fails, it # will be called twice. # - This is bound to fail if X is an extension type and # does not actually inherit from category.parent_class H = category.parent_class._Hom_(X, Y, category=category) except (AttributeError, TypeError): # By default, construct a plain homset. H = Homset(X, Y, category=category, check=check) _cache[key] = H if isinstance(X, UniqueRepresentation) and isinstance(Y, UniqueRepresentation): if not isinstance(H, WithEqualityById): try: H.__class__ = dynamic_class( H.__class__.__name__ + "_with_equality_by_id", (WithEqualityById, H.__class__), doccls=H.__class__ ) except Exception: pass return H