Abstract base class for Sage objects#

class sage.structure.sage_object.SageObject[source]#

Bases: object

Base class for all (user-visible) objects in Sage

Every object that can end up being returned to the user should inherit from SageObject.

_ascii_art_()[source]#

Return an ASCII art representation.

To implement multi-line ASCII art output in a derived class you must override this method. Unlike _repr_(), which is sometimes used for the hash key, the output of _ascii_art_() may depend on settings and is allowed to change during runtime.

OUTPUT:

An AsciiArt object, see sage.typeset.ascii_art for details.

EXAMPLES:

You can use the ascii_art() function to get the ASCII art representation of any object in Sage:

sage: result = ascii_art(integral(exp(x+x^2)/(x+1), x))                     # needs sage.symbolic
...
sage: result                                                                # needs sage.symbolic
  /
 |
 |   2
 |  x  + x
 | e
 | ------- dx
 |  x + 1
 |
/
>>> from sage.all import *
>>> result = ascii_art(integral(exp(x+x**Integer(2))/(x+Integer(1)), x))                     # needs sage.symbolic
...
>>> result                                                                # needs sage.symbolic
  /
 |
 |   2
 |  x  + x
 | e
 | ------- dx
 |  x + 1
 |
/

Alternatively, you can use the %display ascii_art/simple magic to switch all output to ASCII art and back:

sage: # needs sage.combinat
sage: from sage.repl.interpreter import get_test_shell
sage: shell = get_test_shell()
sage: shell.run_cell('tab = StandardTableaux(3)[2]; tab')
[[1, 2], [3]]
sage: shell.run_cell('%display ascii_art')
sage: shell.run_cell('tab')
1  2
3
sage: shell.run_cell('Tableaux.options(ascii_art="table", convention="French")')
sage: shell.run_cell('tab')
+---+
| 3 |
+---+---+
| 1 | 2 |
+---+---+
sage: shell.run_cell('%display plain')
sage: shell.run_cell('Tableaux.options._reset()')
sage: shell.quit()
>>> from sage.all import *
>>> # needs sage.combinat
>>> from sage.repl.interpreter import get_test_shell
>>> shell = get_test_shell()
>>> shell.run_cell('tab = StandardTableaux(3)[2]; tab')
[[1, 2], [3]]
>>> shell.run_cell('%display ascii_art')
>>> shell.run_cell('tab')
1  2
3
>>> shell.run_cell('Tableaux.options(ascii_art="table", convention="French")')
>>> shell.run_cell('tab')
+---+
| 3 |
+---+---+
| 1 | 2 |
+---+---+
>>> shell.run_cell('%display plain')
>>> shell.run_cell('Tableaux.options._reset()')
>>> shell.quit()
_cache_key()[source]#

Return a hashable key which identifies this objects for caching. The output must be hashable itself, or a tuple of objects which are hashable or define a _cache_key.

This method will only be called if the object itself is not hashable.

Some immutable objects (such as \(p\)-adic numbers) cannot implement a reasonable hash function because their == operator has been modified to return True for objects which might behave differently in some computations:

sage: # needs sage.rings.padics
sage: K.<a> = Qq(9)
sage: b = a + O(3)
sage: c = a + 3
sage: b
a + O(3)
sage: c
a + 3 + O(3^20)
sage: b == c
True
sage: b == a
True
sage: c == a
False
>>> from sage.all import *
>>> # needs sage.rings.padics
>>> K = Qq(Integer(9), names=('a',)); (a,) = K._first_ngens(1)
>>> b = a + O(Integer(3))
>>> c = a + Integer(3)
>>> b
a + O(3)
>>> c
a + 3 + O(3^20)
>>> b == c
True
>>> b == a
True
>>> c == a
False

If such objects defined a non-trivial hash function, this would break caching in many places. However, such objects should still be usable in caches. This can be achieved by defining an appropriate _cache_key:

sage: # needs sage.rings.padics
sage: hash(b)
Traceback (most recent call last):
...
TypeError: unhashable type: 'sage.rings.padics.qadic_flint_CR.qAdicCappedRelativeElement'
sage: @cached_method
....: def f(x): return x==a
sage: f(b)
True
sage: f(c)  # if b and c were hashable, this would return True
False
sage: b._cache_key()
(..., ((0, 1),), 0, 1)
sage: c._cache_key()
(..., ((0, 1), (1,)), 0, 20)
>>> from sage.all import *
>>> # needs sage.rings.padics
>>> hash(b)
Traceback (most recent call last):
...
TypeError: unhashable type: 'sage.rings.padics.qadic_flint_CR.qAdicCappedRelativeElement'
>>> @cached_method
... def f(x): return x==a
>>> f(b)
True
>>> f(c)  # if b and c were hashable, this would return True
False
>>> b._cache_key()
(..., ((0, 1),), 0, 1)
>>> c._cache_key()
(..., ((0, 1), (1,)), 0, 20)

An implementation must make sure that for elements a and b, if a != b, then also a._cache_key() != b._cache_key(). In practice this means that the _cache_key should always include the parent as its first argument:

sage: S.<a> = Qq(4)                                                         # needs sage.rings.padics
sage: d = a + O(2)                                                          # needs sage.rings.padics
sage: b._cache_key() == d._cache_key()  # this would be True if the parents were not included               # needs sage.rings.padics
False
>>> from sage.all import *
>>> S = Qq(Integer(4), names=('a',)); (a,) = S._first_ngens(1)# needs sage.rings.padics
>>> d = a + O(Integer(2))                                                          # needs sage.rings.padics
>>> b._cache_key() == d._cache_key()  # this would be True if the parents were not included               # needs sage.rings.padics
False
category()[source]#
dump(filename, compress=True)[source]#

Same as self.save(filename, compress)

dumps(compress=True)[source]#

Dump self to a string s, which can later be reconstituted as self using loads(s).

There is an optional boolean argument compress which defaults to True.

EXAMPLES:

sage: from sage.misc.persist import comp
sage: O = SageObject()
sage: p_comp = O.dumps()
sage: p_uncomp = O.dumps(compress=False)
sage: comp.decompress(p_comp) == p_uncomp
True
sage: import pickletools
sage: pickletools.dis(p_uncomp)
    0: \x80 PROTO      2
    2: c    GLOBAL     'sage.structure.sage_object SageObject'
   41: q    BINPUT     ...
   43: )    EMPTY_TUPLE
   44: \x81 NEWOBJ
   45: q    BINPUT     ...
   47: .    STOP
highest protocol among opcodes = 2
>>> from sage.all import *
>>> from sage.misc.persist import comp
>>> O = SageObject()
>>> p_comp = O.dumps()
>>> p_uncomp = O.dumps(compress=False)
>>> comp.decompress(p_comp) == p_uncomp
True
>>> import pickletools
>>> pickletools.dis(p_uncomp)
    0: \x80 PROTO      2
    2: c    GLOBAL     'sage.structure.sage_object SageObject'
   41: q    BINPUT     ...
   43: )    EMPTY_TUPLE
   44: \x81 NEWOBJ
   45: q    BINPUT     ...
   47: .    STOP
highest protocol among opcodes = 2
get_custom_name()[source]#

Return the custom name of this object, or None if it is not renamed.

EXAMPLES:

sage: P.<x> = QQ[]
sage: P.get_custom_name() is None
True
sage: P.rename('A polynomial ring')
sage: P.get_custom_name()
'A polynomial ring'
sage: P.reset_name()
sage: P.get_custom_name() is None
True
>>> from sage.all import *
>>> P = QQ['x']; (x,) = P._first_ngens(1)
>>> P.get_custom_name() is None
True
>>> P.rename('A polynomial ring')
>>> P.get_custom_name()
'A polynomial ring'
>>> P.reset_name()
>>> P.get_custom_name() is None
True
parent()[source]#

Return the type of self to support the coercion framework.

EXAMPLES:

sage: t = log(sqrt(2) - 1) + log(sqrt(2) + 1); t                            # needs sage.symbolic
log(sqrt(2) + 1) + log(sqrt(2) - 1)
sage: u = t.maxima_methods()                                                # needs sage.symbolic
sage: u.parent()                                                            # needs sage.symbolic
<class 'sage.symbolic.maxima_wrapper.MaximaWrapper'>
>>> from sage.all import *
>>> t = log(sqrt(Integer(2)) - Integer(1)) + log(sqrt(Integer(2)) + Integer(1)); t                            # needs sage.symbolic
log(sqrt(2) + 1) + log(sqrt(2) - 1)
>>> u = t.maxima_methods()                                                # needs sage.symbolic
>>> u.parent()                                                            # needs sage.symbolic
<class 'sage.symbolic.maxima_wrapper.MaximaWrapper'>
rename(x=None)[source]#

Change self so it prints as x, where x is a string.

If x is None, the existing custom name is removed.

Note

This is only supported for Python classes that derive from SageObject.

EXAMPLES:

sage: x = PolynomialRing(QQ, 'x', sparse=True).gen()
sage: g = x^3 + x - 5
sage: g
x^3 + x - 5
sage: g.rename('a polynomial')
sage: g
a polynomial
sage: g + x
x^3 + 2*x - 5
sage: h = g^100
sage: str(h)[:20]
'x^300 + 100*x^298 - '
sage: h.rename('x^300 + ...')
sage: h
x^300 + ...
sage: g.rename(None)
sage: g
x^3 + x - 5
>>> from sage.all import *
>>> x = PolynomialRing(QQ, 'x', sparse=True).gen()
>>> g = x**Integer(3) + x - Integer(5)
>>> g
x^3 + x - 5
>>> g.rename('a polynomial')
>>> g
a polynomial
>>> g + x
x^3 + 2*x - 5
>>> h = g**Integer(100)
>>> str(h)[:Integer(20)]
'x^300 + 100*x^298 - '
>>> h.rename('x^300 + ...')
>>> h
x^300 + ...
>>> g.rename(None)
>>> g
x^3 + x - 5

Real numbers are not Python classes, so rename is not supported:

sage: a = 3.14
sage: type(a)                                                               # needs sage.rings.real_mpfr
<... 'sage.rings.real_mpfr.RealLiteral'>
sage: a.rename('pi')                                                        # needs sage.rings.real_mpfr
Traceback (most recent call last):
...
NotImplementedError: object does not support renaming: 3.14000000000000
>>> from sage.all import *
>>> a = RealNumber('3.14')
>>> type(a)                                                               # needs sage.rings.real_mpfr
<... 'sage.rings.real_mpfr.RealLiteral'>
>>> a.rename('pi')                                                        # needs sage.rings.real_mpfr
Traceback (most recent call last):
...
NotImplementedError: object does not support renaming: 3.14000000000000

Note

The reason C-extension types are not supported by default is if they were then every single one would have to carry around an extra attribute, which would be slower and waste a lot of memory.

To support them for a specific class, add a cdef public _SageObject__custom_name attribute.

reset_name()[source]#

Remove the custom name of an object.

EXAMPLES:

sage: P.<x> = QQ[]
sage: P
Univariate Polynomial Ring in x over Rational Field
sage: P.rename('A polynomial ring')
sage: P
A polynomial ring
sage: P.reset_name()
sage: P
Univariate Polynomial Ring in x over Rational Field
>>> from sage.all import *
>>> P = QQ['x']; (x,) = P._first_ngens(1)
>>> P
Univariate Polynomial Ring in x over Rational Field
>>> P.rename('A polynomial ring')
>>> P
A polynomial ring
>>> P.reset_name()
>>> P
Univariate Polynomial Ring in x over Rational Field
save(filename=None, compress=True)[source]#

Save self to the given filename.

EXAMPLES:

sage: # needs sage.symbolic
sage: x = SR.var("x")
sage: f = x^3 + 5
sage: from tempfile import NamedTemporaryFile
sage: with NamedTemporaryFile(suffix=".sobj") as t:
....:     f.save(t.name)
....:     load(t.name)
x^3 + 5
>>> from sage.all import *
>>> # needs sage.symbolic
>>> x = SR.var("x")
>>> f = x**Integer(3) + Integer(5)
>>> from tempfile import NamedTemporaryFile
>>> with NamedTemporaryFile(suffix=".sobj") as t:
...     f.save(t.name)
...     load(t.name)
x^3 + 5