Base class for objects of a category - Parents and Elements

Skip to content
Back to top
View this page
Edit this page

# Base class for objects of a category

CLASS HIERARCHY:

- `SageObject`

  - CategoryObject

    - `Parent`

Many category objects in Sage are equipped with generators, which are usually special elements of the object. For example, the polynomial ring \(\ZZ[x,y,z]\) is generated by \(x\), \(y\), and \(z\). In Sage the `i` th generator of an object `X` is obtained using the notation `X.gen(i)`. From the Sage interactive prompt, the shorthand notation `X.i` is also allowed.

The following examples illustrate these functions in the context of multivariate polynomial rings and free modules.

EXAMPLES:

Sage

    sage: R = PolynomialRing(ZZ, 3, 'x')
    sage: R.ngens()
    3
    sage: R.gen(0)
    x0
    sage: R.gens()
    (x0, x1, x2)
    sage: R.variable_names()
    ('x0', 'x1', 'x2')

Python

    >>> from sage.all import *
    >>> R = PolynomialRing(ZZ, Integer(3), 'x')
    >>> R.ngens()
    3
    >>> R.gen(Integer(0))
    x0
    >>> R.gens()
    (x0, x1, x2)
    >>> R.variable_names()
    ('x0', 'x1', 'x2')

This example illustrates generators for a free module over \(\ZZ\).

Sage

    sage: # needs sage.modules
    sage: M = FreeModule(ZZ, 4)
    sage: M
    Ambient free module of rank 4 over the principal ideal domain Integer Ring
    sage: M.ngens()
    4
    sage: M.gen(0)
    (1, 0, 0, 0)
    sage: M.gens()
    ((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1))

[Python]

    >>> from sage.all import *
    >>> # needs sage.modules
    >>> M = FreeModule(ZZ, Integer(4))
    >>> M
    Ambient free module of rank 4 over the principal ideal domain Integer Ring
    >>> M.ngens()
    4
    >>> M.gen(Integer(0))
    (1, 0, 0, 0)
    >>> M.gens()
    ((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1))

class sage.structure.category_object.CategoryObject

  Bases: `SageObject`

  An object in some category.

  Hom(codomain, cat=None)

    Return the homspace `Hom(self, codomain, cat)` of all homomorphisms from `self` to `codomain` in the category `cat`.

    The default category is determined by `self.category()` and `codomain.category()`.

    EXAMPLES:

    Sage

        sage: R.<x,y> = PolynomialRing(QQ, 2)
        sage: R.Hom(QQ)
        Set of Homomorphisms
         from Multivariate Polynomial Ring in x, y over Rational Field
           to Rational Field

    Python

        >>> from sage.all import *
        >>> R = PolynomialRing(QQ, Integer(2), names=('x', 'y',)); (x, y,) = R._first_ngens(2)
        >>> R.Hom(QQ)
        Set of Homomorphisms
         from Multivariate Polynomial Ring in x, y over Rational Field
           to Rational Field

    Homspaces are defined for very general Sage objects, even elements of familiar rings.

    Sage

        sage: n = 5; Hom(n,7)
        Set of Morphisms from 5 to 7 in Category of elements of Integer Ring
        sage: z = 2/3; Hom(z, 8/1)
        Set of Morphisms from 2/3 to 8 in Category of elements of Rational Field

    [Python]

        >>> from sage.all import *
        >>> n = Integer(5); Hom(n,Integer(7))
        Set of Morphisms from 5 to 7 in Category of elements of Integer Ring
        >>> z = Integer(2)/Integer(3); Hom(z, Integer(8)/Integer(1))
        Set of Morphisms from 2/3 to 8 in Category of elements of Rational Field

    This example illustrates the optional third argument:

    Sage

        sage: QQ.Hom(ZZ, Sets())
        Set of Morphisms from Rational Field to Integer Ring in Category of sets

    Python

        >>> from sage.all import *
        >>> QQ.Hom(ZZ, Sets())
        Set of Morphisms from Rational Field to Integer Ring in Category of sets

  base()
  base_ring()

    Return the base ring of `self`.

    INPUT:

    - `self` – an object over a base ring; typically a module

    EXAMPLES:

    Sage

        sage: from sage.modules.module import Module
        sage: Module(ZZ).base_ring()
        Integer Ring

        sage: F = FreeModule(ZZ, 3)                                                 # needs sage.modules
        sage: F.base_ring()                                                         # needs sage.modules
        Integer Ring
        sage: F.__class__.base_ring                                                 # needs sage.modules
        <cyfunction CategoryObject.base_ring at ...>

    Python

        >>> from sage.all import *
        >>> from sage.modules.module import Module
        >>> Module(ZZ).base_ring()
        Integer Ring

        >>> F = FreeModule(ZZ, Integer(3))                                                 # needs sage.modules
        >>> F.base_ring()                                                         # needs sage.modules
        Integer Ring
        >>> F.__class__.base_ring                                                 # needs sage.modules
        <cyfunction CategoryObject.base_ring at ...>

    Note that the coordinates of the elements of a module can lie in a bigger ring, the `coordinate_ring`:

    Sage

        sage: # needs sage.modules
        sage: M = (ZZ^2) * (1/2)
        sage: v = M([1/2, 0])
        sage: v.base_ring()
        Integer Ring
        sage: parent(v[0])
        Rational Field
        sage: v.coordinate_ring()
        Rational Field

    [Python]

        >>> from sage.all import *
        >>> # needs sage.modules
        >>> M = (ZZ**Integer(2)) * (Integer(1)/Integer(2))
        >>> v = M([Integer(1)/Integer(2), Integer(0)])
        >>> v.base_ring()
        Integer Ring
        >>> parent(v[Integer(0)])
        Rational Field
        >>> v.coordinate_ring()
        Rational Field

    More examples:

    Sage

        sage: F = FreeAlgebra(QQ, 'x')                                              # needs sage.combinat sage.modules
        sage: F.base_ring()                                                         # needs sage.combinat sage.modules
        Rational Field
        sage: F.__class__.base_ring                                                 # needs sage.combinat sage.modules
        <cyfunction CategoryObject.base_ring at ...>

        sage: # needs sage.modules
        sage: E = CombinatorialFreeModule(ZZ, [1,2,3])
        sage: F = CombinatorialFreeModule(ZZ, [2,3,4])
        sage: H = Hom(E, F)
        sage: H.base_ring()
        Integer Ring
        sage: H.__class__.base_ring
        <cyfunction CategoryObject.base_ring at ...>

    Python

        >>> from sage.all import *
        >>> F = FreeAlgebra(QQ, 'x')                                              # needs sage.combinat sage.modules
        >>> F.base_ring()                                                         # needs sage.combinat sage.modules
        Rational Field
        >>> F.__class__.base_ring                                                 # needs sage.combinat sage.modules
        <cyfunction CategoryObject.base_ring at ...>

        >>> # needs sage.modules
        >>> E = CombinatorialFreeModule(ZZ, [Integer(1),Integer(2),Integer(3)])
        >>> F = CombinatorialFreeModule(ZZ, [Integer(2),Integer(3),Integer(4)])
        >>> H = Hom(E, F)
        >>> H.base_ring()
        Integer Ring
        >>> H.__class__.base_ring
        <cyfunction CategoryObject.base_ring at ...>

    Todo

    Move this method elsewhere (typically in the Modules category) so as not to pollute the namespace of all category objects.

  categories()

    Return the categories of `self`.

    EXAMPLES:

    Sage

        sage: ZZ.categories()
        [Join of Category of Dedekind domains
             and Category of euclidean domains
             and Category of noetherian rings
             and Category of infinite enumerated sets
             and Category of metric spaces,
         Category of Dedekind domains,
         Category of euclidean domains,
         Category of principal ideal domains,
         Category of unique factorization domains,
         Category of gcd domains,
         Category of integral domains,
         Category of domains, ...
         Category of commutative rings, ...
         Category of monoids, ...,
         Category of commutative additive groups, ...,
         Category of sets, ...,
         Category of objects]

    Python

        >>> from sage.all import *
        >>> ZZ.categories()
        [Join of Category of Dedekind domains
             and Category of euclidean domains
             and Category of noetherian rings
             and Category of infinite enumerated sets
             and Category of metric spaces,
         Category of Dedekind domains,
         Category of euclidean domains,
         Category of principal ideal domains,
         Category of unique factorization domains,
         Category of gcd domains,
         Category of integral domains,
         Category of domains, ...
         Category of commutative rings, ...
         Category of monoids, ...,
         Category of commutative additive groups, ...,
         Category of sets, ...,
         Category of objects]

  category()
  gens_dict(copy=True)

    Return a dictionary whose entries are `{name:variable,...}`, where `name` stands for the variable names of this object (as strings) and `variable` stands for the corresponding defining generators (as elements of this object).

    EXAMPLES:

    Sage

        sage: B.<a,b,c,d> = BooleanPolynomialRing()                                 # needs brial
        sage: B.gens_dict()                                                         # needs brial
        {'a': a, 'b': b, 'c': c, 'd': d}

    Python

        >>> from sage.all import *
        >>> B = BooleanPolynomialRing(names=('a', 'b', 'c', 'd',)); (a, b, c, d,) = B._first_ngens(4)# needs brial
        >>> B.gens_dict()                                                         # needs brial
        {'a': a, 'b': b, 'c': c, 'd': d}

  gens_dict_recursive()

    Return the dictionary of generators of `self` and its base rings.

    OUTPUT:

    - a dictionary with string names of generators as keys and generators of `self` and its base rings as values.

    EXAMPLES:

    Sage

        sage: R = QQ['x,y']['z,w']
        sage: sorted(R.gens_dict_recursive().items())
        [('w', w), ('x', x), ('y', y), ('z', z)]

    Python

        >>> from sage.all import *
        >>> R = QQ['x,y']['z,w']
        >>> sorted(R.gens_dict_recursive().items())
        [('w', w), ('x', x), ('y', y), ('z', z)]

  inject_variables(scope=None, verbose=True)

    Inject the generators of `self` with their names into the namespace of the Python code from which this function is called.

    Thus, e.g., if the generators of `self` are labeled ‘a’, ‘b’, and ‘c’, then after calling this method the variables a, b, and c in the current scope will be set equal to the generators of `self`.

    NOTE: If Foo is a constructor for a Sage object with generators, and Foo is defined in Cython, then it would typically call `inject_variables()` on the object it creates. E.g., `PolynomialRing(QQ, 'y')` does this so that the variable y is the generator of the polynomial ring.

  latex_name()
  latex_variable_names()

    Return the list of variable names suitable for latex output.

    All `_SOMETHING` substrings are replaced by `_{SOMETHING}` recursively so that subscripts of subscripts work.

    EXAMPLES:

    Sage

        sage: R, x = PolynomialRing(QQ, 'x', 12).objgens()
        sage: x
        (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11)
        sage: R.latex_variable_names ()
        ['x_{0}', 'x_{1}', 'x_{2}', 'x_{3}', 'x_{4}', 'x_{5}', 'x_{6}',
         'x_{7}', 'x_{8}', 'x_{9}', 'x_{10}', 'x_{11}']
        sage: f = x[0]^3 + 15/3 * x[1]^10
        sage: print(latex(f))
        5 x_{1}^{10} + x_{0}^{3}

    Python

        >>> from sage.all import *
        >>> R, x = PolynomialRing(QQ, 'x', Integer(12)).objgens()
        >>> x
        (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11)
        >>> R.latex_variable_names ()
        ['x_{0}', 'x_{1}', 'x_{2}', 'x_{3}', 'x_{4}', 'x_{5}', 'x_{6}',
         'x_{7}', 'x_{8}', 'x_{9}', 'x_{10}', 'x_{11}']
        >>> f = x[Integer(0)]**Integer(3) + Integer(15)/Integer(3) * x[Integer(1)]**Integer(10)
        >>> print(latex(f))
        5 x_{1}^{10} + x_{0}^{3}

  objgen()

    Return the tuple `(self, self.gen())`.

    EXAMPLES:

    Sage

        sage: R, x = PolynomialRing(QQ,'x').objgen()
        sage: R
        Univariate Polynomial Ring in x over Rational Field
        sage: x
        x

    Python

        >>> from sage.all import *
        >>> R, x = PolynomialRing(QQ,'x').objgen()
        >>> R
        Univariate Polynomial Ring in x over Rational Field
        >>> x
        x

  objgens()

    Return the tuple `(self, self.gens())`.

    EXAMPLES:

    Sage

        sage: R = PolynomialRing(QQ, 3, 'x'); R
        Multivariate Polynomial Ring in x0, x1, x2 over Rational Field
        sage: R.objgens()
        (Multivariate Polynomial Ring in x0, x1, x2 over Rational Field, (x0, x1, x2))

    Python

        >>> from sage.all import *
        >>> R = PolynomialRing(QQ, Integer(3), 'x'); R
        Multivariate Polynomial Ring in x0, x1, x2 over Rational Field
        >>> R.objgens()
        (Multivariate Polynomial Ring in x0, x1, x2 over Rational Field, (x0, x1, x2))

  variable_name()

    Return the first variable name.

    OUTPUT: string

    EXAMPLES:

    Sage

        sage: R.<z,y,a42> = ZZ[]
        sage: R.variable_name()
        'z'
        sage: R.<x> = InfinitePolynomialRing(ZZ)
        sage: R.variable_name()
        'x'

    Python

        >>> from sage.all import *
        >>> R = ZZ['z, y, a42']; (z, y, a42,) = R._first_ngens(3)
        >>> R.variable_name()
        'z'
        >>> R = InfinitePolynomialRing(ZZ, names=('x',)); (x,) = R._first_ngens(1)
        >>> R.variable_name()
        'x'

  variable_names()

    Return the list of variable names corresponding to the generators.

    OUTPUT: a tuple of strings

    EXAMPLES:

    Sage

        sage: R.<z,y,a42> = QQ[]
        sage: R.variable_names()
        ('z', 'y', 'a42')
        sage: S = R.quotient_ring(z+y)
        sage: S.variable_names()
        ('zbar', 'ybar', 'a42bar')

    Python

        >>> from sage.all import *
        >>> R = QQ['z, y, a42']; (z, y, a42,) = R._first_ngens(3)
        >>> R.variable_names()
        ('z', 'y', 'a42')
        >>> S = R.quotient_ring(z+y)
        >>> S.variable_names()
        ('zbar', 'ybar', 'a42bar')

    Sage

        sage: T.<x> = InfinitePolynomialRing(ZZ)
        sage: T.variable_names()
        ('x',)

    [Python]

        >>> from sage.all import *
        >>> T = InfinitePolynomialRing(ZZ, names=('x',)); (x,) = T._first_ngens(1)
        >>> T.variable_names()
        ('x',)

sage.structure.category_object.certify_names(names)

  Check that `names` are valid variable names.

  INPUT:

  - `names` – an iterable with strings representing variable names

  OUTPUT: `True` (for efficiency of the Cython call)

  EXAMPLES:

  Sage

      sage: from sage.structure.category_object import certify_names as cn
      sage: cn(["a", "b", "c"])
      1
      sage: cn("abc")
      1
      sage: cn([])
      1
      sage: cn([""])
      Traceback (most recent call last):
      ...
      ValueError: variable name must be nonempty
      sage: cn(["_foo"])
      Traceback (most recent call last):
      ...
      ValueError: variable name '_foo' does not start with a letter
      sage: cn(["x'"])
      Traceback (most recent call last):
      ...
      ValueError: variable name "x'" is not alphanumeric
      sage: cn(["a", "b", "b"])
      Traceback (most recent call last):
      ...
      ValueError: variable name 'b' appears more than once

  Python

      >>> from sage.all import *
      >>> from sage.structure.category_object import certify_names as cn
      >>> cn(["a", "b", "c"])
      1
      >>> cn("abc")
      1
      >>> cn([])
      1
      >>> cn([""])
      Traceback (most recent call last):
      ...
      ValueError: variable name must be nonempty
      >>> cn(["_foo"])
      Traceback (most recent call last):
      ...
      ValueError: variable name '_foo' does not start with a letter
      >>> cn(["x'"])
      Traceback (most recent call last):
      ...
      ValueError: variable name "x'" is not alphanumeric
      >>> cn(["a", "b", "b"])
      Traceback (most recent call last):
      ...
      ValueError: variable name 'b' appears more than once

sage.structure.category_object.check_default_category(default_category, category)

  The resulting category is guaranteed to be a sub-category of the default.

sage.structure.category_object.normalize_names(ngens, names)

  Return a tuple of strings of variable names of length ngens given the input names.

  INPUT:

  - `ngens` – integer; number of generators. The value `ngens=-1` means that the number of generators is unknown a priori.

  - `names` – any of the following:

    - a tuple or list of strings, such as `('x', 'y')`

    - a comma-separated string, such as `x,y`

    - a string prefix, such as ‘alpha’

    - a string of single character names, such as ‘xyz’

  OUTPUT: a tuple of `ngens` strings to be used as variable names

  EXAMPLES:

  Sage

      sage: from sage.structure.category_object import normalize_names as nn
      sage: nn(0, "")
      ()
      sage: nn(0, [])
      ()
      sage: nn(0, None)
      ()
      sage: nn(1, 'a')
      ('a',)
      sage: nn(2, 'z_z')
      ('z_z0', 'z_z1')
      sage: nn(3, 'x, y, z')
      ('x', 'y', 'z')
      sage: nn(2, 'ab')
      ('a', 'b')
      sage: nn(2, 'x0')
      ('x00', 'x01')
      sage: nn(3, (' a ', ' bb ', ' ccc '))
      ('a', 'bb', 'ccc')
      sage: nn(4, ['a1', 'a2', 'b1', 'b11'])
      ('a1', 'a2', 'b1', 'b11')

  Python

      >>> from sage.all import *
      >>> from sage.structure.category_object import normalize_names as nn
      >>> nn(Integer(0), "")
      ()
      >>> nn(Integer(0), [])
      ()
      >>> nn(Integer(0), None)
      ()
      >>> nn(Integer(1), 'a')
      ('a',)
      >>> nn(Integer(2), 'z_z')
      ('z_z0', 'z_z1')
      >>> nn(Integer(3), 'x, y, z')
      ('x', 'y', 'z')
      >>> nn(Integer(2), 'ab')
      ('a', 'b')
      >>> nn(Integer(2), 'x0')
      ('x00', 'x01')
      >>> nn(Integer(3), (' a ', ' bb ', ' ccc '))
      ('a', 'bb', 'ccc')
      >>> nn(Integer(4), ['a1', 'a2', 'b1', 'b11'])
      ('a1', 'a2', 'b1', 'b11')

  Arguments are converted to strings:

  Sage

      sage: nn(1, u'a')
      ('a',)
      sage: var('alpha')                                                              # needs sage.symbolic
      alpha
      sage: nn(2, alpha)                                                              # needs sage.symbolic
      ('alpha0', 'alpha1')
      sage: nn(1, [alpha])                                                            # needs sage.symbolic
      ('alpha',)

  [Python]

      >>> from sage.all import *
      >>> nn(Integer(1), u'a')
      ('a',)
      >>> var('alpha')                                                              # needs sage.symbolic
      alpha
      >>> nn(Integer(2), alpha)                                                              # needs sage.symbolic
      ('alpha0', 'alpha1')
      >>> nn(Integer(1), [alpha])                                                            # needs sage.symbolic
      ('alpha',)

  With an unknown number of generators:

  Sage

      sage: nn(-1, 'a')
      ('a',)
      sage: nn(-1, 'x, y, z')
      ('x', 'y', 'z')

  Python

      >>> from sage.all import *
      >>> nn(-Integer(1), 'a')
      ('a',)
      >>> nn(-Integer(1), 'x, y, z')
      ('x', 'y', 'z')

  Test errors:

  Sage

      sage: nn(3, ["x", "y"])
      Traceback (most recent call last):
      ...
      IndexError: the number of names must equal the number of generators
      sage: nn(None, "a")
      Traceback (most recent call last):
      ...
      TypeError: 'NoneType' object cannot be interpreted as an integer
      sage: nn(1, "")
      Traceback (most recent call last):
      ...
      ValueError: variable name must be nonempty
      sage: nn(1, "foo@")
      Traceback (most recent call last):
      ...
      ValueError: variable name 'foo@' is not alphanumeric
      sage: nn(2, "_foo")
      Traceback (most recent call last):
      ...
      ValueError: variable name '_foo0' does not start with a letter
      sage: nn(1, 3/2)
      Traceback (most recent call last):
      ...
      ValueError: variable name '3/2' is not alphanumeric

  [Python]

      >>> from sage.all import *
      >>> nn(Integer(3), ["x", "y"])
      Traceback (most recent call last):
      ...
      IndexError: the number of names must equal the number of generators
      >>> nn(None, "a")
      Traceback (most recent call last):
      ...
      TypeError: 'NoneType' object cannot be interpreted as an integer
      >>> nn(Integer(1), "")
      Traceback (most recent call last):
      ...
      ValueError: variable name must be nonempty
      >>> nn(Integer(1), "foo@")
      Traceback (most recent call last):
      ...
      ValueError: variable name 'foo@' is not alphanumeric
      >>> nn(Integer(2), "_foo")
      Traceback (most recent call last):
      ...
      ValueError: variable name '_foo0' does not start with a letter
      >>> nn(Integer(1), Integer(3)/Integer(2))
      Traceback (most recent call last):
      ...
      ValueError: variable name '3/2' is not alphanumeric