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, seesage.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 returnTrue
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
andb
, ifa != b
, then alsoa._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
- dumps(compress=True)[source]¶
Dump
self
to a strings
, which can later be reconstituted asself
usingloads(s)
.There is an optional boolean argument
compress
which defaults toTrue
.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