Sage Input Formatting#
This module provides the function sage_input()
that takes an
arbitrary sage value and produces a sequence of commands that, if typed
at the sage:
prompt, will recreate the value. If this is not
implemented for a particular value, then an exception is raised instead.
This might be useful in understanding a part of Sage, or for debugging.
For instance, if you have a value produced in a complicated way in the
middle of a debugging session, you could use sage_input()
to find
a simple way to produce the same value. We attempt to produce commands
that are readable and idiomatic.:
sage: sage_input(3)
3
sage: sage_input((polygen(RR) + RR(pi))^2, verify=True)
# Verified
R.<x> = RR[]
x^2 + 6.2831853071795862*x + 9.869604401089358
With verify=True
, sage_input()
also verifies the results, by
calling sage_eval()
on the result and
verifying that it is equal to the input.:
sage: sage_input(GF(2)(1), verify=True)
# Verified
GF(2)(1)
We can generate code that works without the preparser, with
preparse=False
; or we can generate code that will work whether or
not the preparser is enabled, with preparse=None
. Generating code
with preparse=False
may be useful to see how to create a certain
value in a Python or Cython source file.:
sage: sage_input(5, verify=True)
# Verified
5
sage: sage_input(5, preparse=False)
ZZ(5)
sage: sage_input(5, preparse=None)
ZZ(5)
sage: sage_input(5r, verify=True)
# Verified
5r
sage: sage_input(5r, preparse=False)
5
sage: sage_input(5r, preparse=None)
int(5)
Adding sage_input()
support to your own classes is
straightforward. You need to add a _sage_input_()
method which
returns a SageInputExpression
(henceforth abbreviated as SIE)
which will reconstruct this instance of your class.
A _sage_input_
method takes two parameters, conventionally named
sib
and coerced
. The first argument is a
SageInputBuilder
; it has methods to build SIEs. The second
argument, coerced
, is a boolean. This is only useful if your class
is a subclass of Element
(although it is always present). If
coerced
is False
, then your method must generate an expression
which will evaluate to a value of the correct type with the correct
parent. If coerced
is True
, then your method may generate an
expression of a type that has a canonical coercion to your type; and if
coerced
is 2, then your method may generate an expression of a type
that has a conversion to your type.
Let’s work through some examples. We’ll build a sequence of functions
that would be acceptable as _sage_input_
methods for the
Rational
class.
Here’s the first and simplest version.:
sage: def qq_sage_input_v1(self, sib, coerced):
....: return sib(self.numerator())/sib(self.denominator())
We see that given a SageInputBuilder
sib
, you can construct
a SIE for a value v
simply with sib(v)
, and you can construct a
SIE for a quotient with the division operator. Of course, the other
operators also work, and so do function calls, method calls, subscripts,
etc.
We’ll test with the following code, which you don’t need to understand. (It produces a list of 8 results, showing the formatted versions of -5/7 and 3, with the preparser either enabled or disabled and either with or without an automatic coercion to QQ.):
sage: from sage.misc.sage_input import SageInputBuilder
sage: def test_qq_formatter(fmt):
....: results = []
....: for v in [-5/7, QQ(3)]:
....: for pp in [False, True]:
....: for coerced in [False, True]:
....: sib = SageInputBuilder(preparse=pp)
....: results.append(sib.result(fmt(v, sib, coerced)))
....: return results
sage: test_qq_formatter(qq_sage_input_v1)
[-ZZ(5)/ZZ(7), -ZZ(5)/ZZ(7), -5/7, -5/7, ZZ(3)/ZZ(1), ZZ(3)/ZZ(1), 3/1, 3/1]
Let’s try for some shorter, perhaps nicer-looking output. We’ll start
by getting rid of the ZZ
in the denominators; even without the
preparser, -ZZ(5)/7 == -ZZ(5)/ZZ(7)
.:
sage: def qq_sage_input_v2(self, sib, coerced):
....: return sib(self.numerator())/sib.int(self.denominator())
The int
method on SageInputBuilder
returns a SIE for an
integer that is always represented in the simple way, without coercions.
(So, depending on the preparser mode, it might read in as an
Integer
, an int
, or a long
.):
sage: test_qq_formatter(qq_sage_input_v2)
[-ZZ(5)/7, -ZZ(5)/7, -5/7, -5/7, ZZ(3)/1, ZZ(3)/1, 3/1, 3/1]
Next let us get rid of the divisions by 1. These are more complicated, since if we are not careful we will get results in \(\ZZ\) instead of \(\QQ\):
sage: def qq_sage_input_v3(self, sib, coerced):
....: if self.denominator() == 1:
....: if coerced:
....: return sib.int(self.numerator())
....: else:
....: return sib.name('QQ')(sib.int(self.numerator()))
....: return sib(self.numerator())/sib.int(self.denominator())
We see that the method{name} method gives an SIE representing a sage constant or function.:
sage: test_qq_formatter(qq_sage_input_v3)
[-ZZ(5)/7, -ZZ(5)/7, -5/7, -5/7, QQ(3), 3, QQ(3), 3]
This is the prettiest output we’re going to get, but let’s make one
further refinement. Other _sage_input_
methods, like the one
for polynomials, analyze the structure of SIEs; they work better (give
prettier output) if negations are at the outside. If the above code
were used for rationals, then sage_input(polygen(QQ) - 2/3)
would
produce x + (-2/3)
; if we change to the following code, then we
would get x - 2/3
instead.:
sage: def qq_sage_input_v4(self, sib, coerced):
....: num = self.numerator()
....: neg = (num < 0)
....: if neg: num = -num
....: if self.denominator() == 1:
....: if coerced:
....: v = sib.int(num)
....: else:
....: v = sib.name('QQ')(sib.int(num))
....: else:
....: v = sib(num)/sib.int(self.denominator())
....: if neg: v = -v
....: return v
sage: test_qq_formatter(qq_sage_input_v4)
[-ZZ(5)/7, -ZZ(5)/7, -5/7, -5/7, QQ(3), 3, QQ(3), 3]
AUTHORS:
Carl Witty (2008-04): new file
Vincent Delecroix (2015-02): documentation formatting
- class sage.misc.sage_input.SIE_assign(sib, lhs, rhs)#
Bases:
sage.misc.sage_input.SageInputExpression
This class represents an assignment command.
EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: sib.assign(sib.name('foo').x, sib.name('pi')) {assign: {getattr: {atomic:foo}.x} {atomic:pi}}
- class sage.misc.sage_input.SIE_binary(sib, op, lhs, rhs)#
Bases:
sage.misc.sage_input.SageInputExpression
This class represents an arithmetic expression with a binary operator and its two arguments, in a
sage_input()
expression tree.EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: sib(3)+5 {binop:+ {atomic:3} {atomic:5}}
- class sage.misc.sage_input.SIE_call(sib, func, args, kwargs)#
Bases:
sage.misc.sage_input.SageInputExpression
This class represents a function-call node in a
sage_input()
expression tree.EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: sie = sib.name('GF') sage: sie(49) {call: {atomic:GF}({atomic:49})}
- class sage.misc.sage_input.SIE_dict(sib, entries)#
Bases:
sage.misc.sage_input.SageInputExpression
This class represents a dict node in a
sage_input()
expression tree.EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: sib.dict([('TeX', RR(pi)), ('Metafont', RR(e))]) {dict: {{atomic:'TeX'}:{call: {atomic:RR}({atomic:3.1415926535897931})}, {atomic:'Metafont'}:{call: {atomic:RR}({atomic:2.7182818284590451})}}} sage: sib.dict({-40:-40, 0:32, 100:212}) {dict: {{unop:- {atomic:40}}:{unop:- {atomic:40}}, {atomic:0}:{atomic:32}, {atomic:100}:{atomic:212}}}
- class sage.misc.sage_input.SIE_gen(sib, parent, name)#
Bases:
sage.misc.sage_input.SageInputExpression
This class represents a named generator of a parent with named generators.
EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: sib.gen(ZZ['x']) {gen:x {constr_parent: {subscr: {atomic:ZZ}[{atomic:'x'}]} with gens: ('x',)}}
- class sage.misc.sage_input.SIE_gens_constructor(sib, constr, gen_names, gens_syntax=None)#
Bases:
sage.misc.sage_input.SageInputExpression
This class represents an expression that can create a sage parent with named generators, optionally using the sage preparser generators syntax (like
K.<x> = QQ[]
).EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: qq = sib.name('QQ') sage: sib.parent_with_gens("some parent", qq['x'], ....: ('x',), 'QQx', ....: gens_syntax=sib.empty_subscript(qq)) {constr_parent: {subscr: {atomic:QQ}[{atomic:'x'}]} with gens: ('x',)}
- class sage.misc.sage_input.SIE_getattr(sib, obj, attr)#
Bases:
sage.misc.sage_input.SageInputExpression
This class represents a getattr node in a
sage_input()
expression tree.EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: sie = sib.name('CC').gen() sage: sie {call: {getattr: {atomic:CC}.gen}()}
- class sage.misc.sage_input.SIE_import_name(sib, module, name, alt_name=None)#
Bases:
sage.misc.sage_input.SageInputExpression
This class represents a name which has been imported from a module.
EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: sib.import_name('sage.rings.integer', 'make_integer') {import:sage.rings.integer/make_integer} sage: sib.import_name('sage.foo', 'happy', 'sad') {import:sage.foo/happy as sad}
- class sage.misc.sage_input.SIE_literal(sib)#
Bases:
sage.misc.sage_input.SageInputExpression
An abstract base class for
literals
(basically, values which consist of a single token).EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder, SIE_literal sage: sib = SageInputBuilder() sage: sie = sib(3) sage: sie {atomic:3} sage: isinstance(sie, SIE_literal) True
- class sage.misc.sage_input.SIE_literal_stringrep(sib, n)#
Bases:
sage.misc.sage_input.SIE_literal
Values in this class are leaves in a
sage_input()
expression tree. Typically they represent a single token, and consist of the string representation of that token. They are used for integer, floating-point, and string literals, and for name expressions.EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder, SIE_literal_stringrep sage: sib = SageInputBuilder() sage: isinstance(sib(3), SIE_literal_stringrep) True sage: isinstance(sib(3.14159, True), SIE_literal_stringrep) True sage: isinstance(sib.name('pi'), SIE_literal_stringrep) True sage: isinstance(sib(False), SIE_literal_stringrep) True sage: sib(False) {atomic:False}
- class sage.misc.sage_input.SIE_subscript(sib, coll, key)#
Bases:
sage.misc.sage_input.SageInputExpression
This class represents a subscript node in a
sage_input()
expression tree.EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: sie = sib.name('QQ')['x,y'] sage: sie {subscr: {atomic:QQ}[{atomic:'x,y'}]}
- class sage.misc.sage_input.SIE_tuple(sib, values, is_list)#
Bases:
sage.misc.sage_input.SageInputExpression
This class represents a tuple or list node in a
sage_input()
expression tree.EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: sib((1, 'howdy')) {tuple: ({atomic:1}, {atomic:'howdy'})} sage: sib(["lists"]) {list: ({atomic:'lists'})}
- class sage.misc.sage_input.SIE_unary(sib, op, operand)#
Bases:
sage.misc.sage_input.SageInputExpression
This class represents an arithmetic expression with a unary operator and its argument, in a
sage_input()
expression tree.EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: -sib(256) {unop:- {atomic:256}}
- class sage.misc.sage_input.SageInputAnswer#
Bases:
tuple
This class inherits from tuple, so it acts like a tuple when passed to
sage_eval()
; but it prints as a sequence of commands.EXAMPLES:
sage: from sage.misc.sage_input import SageInputAnswer sage: v = SageInputAnswer('x = 22\n', 'x/7'); v x = 22 x/7 sage: isinstance(v, tuple) True sage: v[0] 'x = 22\n' sage: v[1] 'x/7' sage: len(v) 2 sage: v = SageInputAnswer('', 'sin(3.14)', {'sin': math.sin}); v LOCALS: sin: <built-in function sin> sin(3.14) sage: v[0] '' sage: v[1] 'sin(3.14)' sage: v[2] {'sin': <built-in function sin>}
- class sage.misc.sage_input.SageInputBuilder(allow_locals=False, preparse=True)#
Bases:
object
An instance of this class is passed to
_sage_input_
methods. It keeps track of the current state of the_sage_input_
process, and contains many utility methods for buildingSageInputExpression
objects.In normal use, instances of
SageInputBuilder
are created internally bysage_input()
, but it may be useful to create an instance directly for testing or doctesting.EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder
We can create a
SageInputBuilder
, use it to create someSageInputExpression
s, and get a result. (As mentioned above, this is only useful for testing or doctesting; normally you would just usesage_input()
.):sage: sib = SageInputBuilder() sage: sib.result((sib(3) + sib(4)) * (sib(5) + sib(6))) (3 + 4)*(5 + 6)
- assign(e, val)#
Constructs a command that performs the assignment
e=val
.Can only be used as an argument to the
command
method.INPUT:
e
,val
– SageInputExpression
EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: circular = sib([None]) sage: sib.command(circular, sib.assign(circular[0], circular)) sage: sib.result(circular) si = [None] si[0] = si si
- cache(x, sie, name)#
INPUT:
x
- an arbitrary valuesie
- aSageInputExpression
name
- a requested variable name
Enters
x
andsie
in a cache, so that subsequent callsself(x)
will directly returnsie
. Also, marks the requested name of thissie
to bename
.This should almost always be called as part of the method{_sage_input_} method of a parent. It may also be called on values of an arbitrary type, which may be useful if the values are both large and likely to be used multiple times in a single expression.
EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: sie42 = sib(GF(101)(42)) sage: sib.cache(GF(101)(42), sie42, 'the_ultimate_answer') sage: sib.result(sib(GF(101)(42)) + sib(GF(101)(42))) the_ultimate_answer = GF(101)(42) the_ultimate_answer + the_ultimate_answer
Note that we don’t assign the result to a variable if the value is only used once.:
sage: sib = SageInputBuilder() sage: sie42 = sib(GF(101)(42)) sage: sib.cache(GF(101)(42), sie42, 'the_ultimate_answer') sage: sib.result(sib(GF(101)(42)) + sib(GF(101)(43))) GF_101 = GF(101) GF_101(42) + GF_101(43)
- command(v, cmd)#
INPUT:
v
,cmd
– SageInputExpression
Attaches a command to v, which will be executed before v is used. Multiple commands will be executed in the order added.
EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: incr_list = sib([]) sage: sib.command(incr_list, incr_list.append(1)) sage: sib.command(incr_list, incr_list.extend([2, 3])) sage: sib.result(incr_list) si = [] si.append(1) si.extend([2, 3]) si
- dict(entries)#
Given a dictionary, or a list of (key, value) pairs, produces a
SageInputExpression
representing the dictionary.EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: sib.result(sib.dict({1:1, 2:5/2, 3:100/3})) {1:1, 2:5/2, 3:100/3} sage: sib.result(sib.dict([('hello', 'sunshine'), ('goodbye', 'rain')])) {'hello':'sunshine', 'goodbye':'rain'}
- empty_subscript(parent)#
Given a
SageInputExpression
representingfoo
, produces aSageInputExpression
representingfoo[]
. Since this is not legal Python syntax, it is useful only for producing the sage generator syntax for a polynomial ring.EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: sib.result(sib.empty_subscript(sib(2) + sib(3))) (2 + 3)[]
The following calls this method indirectly.:
sage: sage_input(polygen(ZZ['y'])) R.<x> = ZZ['y'][] x
- float_str(n)#
Given a string representing a floating-point number, produces a
SageInputExpression
that formats as that string.EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: sib.result(sib.float_str(repr(RR(e)))) 2.71828182845905
- gen(parent, n=0)#
Given a parent, returns a
SageInputExpression
for the \(n\)-th (default 0) generator of the parent.EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: sib.result(sib.gen(ZZ['y'])) R.<y> = ZZ[] y
- getattr(sie, attr)#
Given a
SageInputExpression
representingfoo
and an attribute name bar, produce aSageInputExpression
representingfoo.bar
. Normally, you could just use attribute-access syntax, but that doesn’t work if bar is some attribute that bypasses __getattr__ (such as if bar is ‘__getattr__’ itself).EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: sib.getattr(ZZ, '__getattr__') {getattr: {atomic:ZZ}.__getattr__} sage: sib.getattr(sib.name('foo'), '__new__') {getattr: {atomic:foo}.__new__}
- id_cache(x, sie, name)#
INPUT:
x
- an arbitrary valuesie
- aSageInputExpression
name
- a requested variable name
Enters
x
andsie
in a cache, so that subsequent callsself(x)
will directly returnsie
. Also, marks the requested name of thissie
to bename
. Differs from the method{cache} method in that the cache is keyed byid(x)
instead of byx
.This may be called on values of an arbitrary type, which may be useful if the values are both large and likely to be used multiple times in a single expression; it should be preferred to method{cache} if equality on the values is difficult or impossible to compute.
EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: x = polygen(ZZ) sage: sib = SageInputBuilder() sage: my_42 = 42*x sage: sie42 = sib(my_42) sage: sib.id_cache(my_42, sie42, 'the_ultimate_answer') sage: sib.result(sib(my_42) + sib(my_42)) R.<x> = ZZ[] the_ultimate_answer = 42*x the_ultimate_answer + the_ultimate_answer
Since id_cache keys off of object identity (“is”), the following does not trigger the cache.:
sage: sib.result(sib(42*x) + sib(42*x)) 42*x + 42*x
Note that we don’t assign the result to a variable if the value is only used once.:
sage: sib = SageInputBuilder() sage: my_42 = 42*x sage: sie42 = sib(my_42) sage: sib.id_cache(my_42, sie42, 'the_ultimate_answer') sage: sib.result(sib(my_42) + sib(43*x)) R.<x> = ZZ[] 42*x + 43*x
- import_name(module, name, alt_name=None)#
INPUT:
module
,name
,alt_name
– strings
Creates an expression that will import a name from a module and then use that name.
EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: v1 = sib.import_name('sage.foo.bar', 'baz') sage: v2 = sib.import_name('sage.foo.bar', 'ZZ', 'not_the_real_ZZ') sage: sib.result(v1+v2) from sage.foo.bar import baz from sage.foo.bar import ZZ as not_the_real_ZZ baz + not_the_real_ZZ
We adjust the names if there is a conflict.:
sage: sib = SageInputBuilder() sage: v1 = sib.import_name('sage.foo', 'poly') sage: v2 = sib.import_name('sage.bar', 'poly') sage: sib.result(v1+v2) from sage.foo import poly as poly1 from sage.bar import poly as poly2 poly1 + poly2
- int(n)#
Return a raw SIE from the integer
n
As it is raw, it may read back as a Sage Integer, a Python int or a Python long, depending on its size and whether the preparser is enabled.
INPUT:
n
- a Sage Integer, a Python int or a Python long
EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: sib.result(sib.int(-3^50)) -717897987691852588770249 sage: sib = SageInputBuilder() sage: sib.result(sib.int(-42r)) -42
- name(n)#
Given a string representing a Python name, produces a
SageInputExpression
for that name.EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: sib.result(sib.name('pi') + sib.name('e')) pi + e
- parent_with_gens(parent, sie, gen_names, name, gens_syntax=None)#
This method is used for parents with generators, to manage the sage preparser generator syntax (like
K.<x> = QQ[]
).The method{_sage_input_} method of a parent class with generators should construct a
SageInputExpression
for the parent, and then call this method with the parent itself, the constructed SIE, a sequence containing the names of the generators, and (optionally) another SIE to use if the sage generator syntax is used; typically this will be the same as the first SIE except omitting anames
parameter.EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: def test_setup(use_gens=True, preparse=True): ....: sib = SageInputBuilder(preparse=preparse) ....: gen_names=('foo', 'bar') ....: parent = "some parent" ....: normal_sie = sib.name('make_a_parent')(names=gen_names) ....: if use_gens: ....: gens_sie = sib.name('make_a_parent')() ....: else: ....: gens_sie = None ....: name = 'the_thing' ....: result = sib.parent_with_gens(parent, normal_sie, ....: gen_names, name, ....: gens_syntax=gens_sie) ....: return sib, result sage: sib, par_sie = test_setup() sage: sib.result(par_sie) make_a_parent(names=('foo', 'bar')) sage: sib, par_sie = test_setup() sage: sib.result(sib(3) * sib.gen("some parent", 0)) the_thing.<foo,bar> = make_a_parent() 3*foo sage: sib, par_sie = test_setup(preparse=False) sage: sib.result(par_sie) make_a_parent(names=('foo', 'bar')) sage: sib, par_sie = test_setup(preparse=False) sage: sib.result(sib(3) * sib.gen("some parent", 0)) the_thing = make_a_parent(names=('foo', 'bar')) foo,bar = the_thing.gens() ZZ(3)*foo sage: sib, par_sie = test_setup(use_gens=False) sage: sib.result(par_sie) make_a_parent(names=('foo', 'bar')) sage: sib, par_sie = test_setup(use_gens=False) sage: sib.result(sib(3) * sib.gen("some parent", 0)) the_thing = make_a_parent(names=('foo', 'bar')) foo,bar = the_thing.gens() 3*foo sage: sib, par_sie = test_setup() sage: sib.result(par_sie - sib.gen("some parent", 1)) the_thing.<foo,bar> = make_a_parent() the_thing - bar
- preparse()#
Checks the preparse status.
It returns
True
if the preparser will be enabled,False
if it will be disabled, andNone
if the result must work whether or not the preparser is enabled.For example, this is useful in the method{_sage_input_} methods of
Integer
andRealNumber
; but most method{_sage_input_} methods will not need to examine this.EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: SageInputBuilder().preparse() True sage: SageInputBuilder(preparse=False).preparse() False
- prod(factors, simplify=False)#
Given a sequence, returns a
SageInputExpression
for the product of the elements.With
simplify=True
, performs some simplifications first. If any element is formatted as a string'0'
, then that element is returned directly. If any element is formatted as a string'1'
, then it is removed from the sequence (unless it is the only element in the sequence). And any negations are removed from the elements and moved to the outside of the product.EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: sib.result(sib.prod([-1, 0, 1, -2])) -1*0*1*-2 sage: sib = SageInputBuilder() sage: sib.result(sib.prod([-1, 0, 1, 2], simplify=True)) 0 sage: sib = SageInputBuilder() sage: sib.result(sib.prod([-1, 2, -3, -4], simplify=True)) -2*3*4 sage: sib = SageInputBuilder() sage: sib.result(sib.prod([-1, 1, -1, -1], simplify=True)) -1 sage: sib = SageInputBuilder() sage: sib.result(sib.prod([1, 1, 1], simplify=True)) 1
- result(e)#
Given a
SageInputExpression
constructed usingself
, returns a tuple of a list of commands and an expression (and possibly a dictionary of local variables) suitable forsage_eval()
.EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: r = sib.result(sib(6) * sib(7)); r 6*7 sage: tuple(r) ('', '6*7')
Mark the given expression as sharable, so that it will be replaced by a variable if it occurs multiple times in the expression. (Most non-single-token expressions are already sharable.)
EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder
Without explicitly using .share(), string literals are not shared:
sage: sib = SageInputBuilder() sage: e = sib('hello') sage: sib.result(sib((e, e))) ('hello', 'hello')
See the difference if we use .share():
sage: sib = SageInputBuilder() sage: e = sib('hello') sage: sib.share(e) sage: sib.result(sib((e, e))) si = 'hello' (si, si)
- sum(terms, simplify=False)#
Given a sequence, returns a
SageInputExpression
for the product of the elements.With
simplify=True
, performs some simplifications first. If any element is formatted as a string'0'
, then it is removed from the sequence (unless it is the only element in the sequence); and any instances ofa + -b
are changed toa - b
.EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: sib.result(sib.sum([-1, 0, 1, 0, -1])) -1 + 0 + 1 + 0 + -1 sage: sib = SageInputBuilder() sage: sib.result(sib.sum([-1, 0, 1, 0, -1], simplify=True)) -1 + 1 - 1 sage: sib = SageInputBuilder() sage: sib.result(sib.sum([0, 0, 0], simplify=True)) 0
- use_variable(sie, name)#
Marks the
SageInputExpression
sie
to use a variable even if it is only referenced once. (Ifsie
is the final top-level expression, though, it will not use a variable.)EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder sage: sib = SageInputBuilder() sage: e = sib.name('MatrixSpace')(ZZ, 10, 10) sage: sib.use_variable(e, 'MS') sage: sib.result(e.zero_matrix()) MS = MatrixSpace(ZZ, 10, 10) MS.zero_matrix()
Without the call to use_variable, we get this instead:
sage: sib = SageInputBuilder() sage: e = sib.name('MatrixSpace')(ZZ, 10, 10) sage: sib.result(e.zero_matrix()) MatrixSpace(ZZ, 10, 10).zero_matrix()
And even with the call to use_variable, we don’t use a variable here:
sage: sib = SageInputBuilder() sage: e = sib.name('MatrixSpace')(ZZ, 10, 10) sage: sib.use_variable(e, 'MS') sage: sib.result(e) MatrixSpace(ZZ, 10, 10)
- class sage.misc.sage_input.SageInputExpression(sib)#
Bases:
object
Subclasses of this class represent expressions for
sage_input()
. sage classes should define a method{_sage_input_} method, which will return an instance ofSageInputExpression
, created using methods ofSageInputBuilder
.To the extent possible, operations on
SageInputExpression
objects construct a newSageInputExpression
representing that operation. That is, ifa
is aSageInputExpression
, thena + b
constructs aSageInputExpression
representing this sum. This also works for attribute access, function calls, subscripts, etc. Since arbitrary attribute accesses might be used to construct a new attribute-access expression, all internal attributes and methods have names that begin with_sie_
to reduce the chance of collisions.It is expected that instances of this class will not be directly created outside this module; instead, instances will be created using methods of
SageInputBuilder
andSageInputExpression
.Values of type
SageInputExpression
print in a fairly ugly way, that reveals the internal structure of the expression tree.
- class sage.misc.sage_input.SageInputFormatter#
Bases:
object
An instance of this class is used to keep track of variable names and a sequence of generated commands during the
sage_input()
formatting process.- format(e, prec)#
Format a Sage input expression into a string.
INPUT:
e
- aSageInputExpression
prec
- an integer representing a precedence level
First, we check to see if
e
should be replaced by a variable. If so, we generate the command to assign the variable, and return the name of the variable.Otherwise, we format the expression by calling its method{_sie_format} method, and add parentheses if necessary.
EXAMPLES:
sage: from sage.misc.sage_input import SageInputBuilder, SageInputFormatter sage: sib = SageInputBuilder() sage: sif = SageInputFormatter() sage: sie = sib(GF(5))
Here we
cheat
by calling method{_sie_prepare} twice, to make it use a variable.:sage: sie._sie_prepare(sif) sage: sie._sie_prepare(sif) sage: sif._commands '' sage: sif.format(sie, 0) 'GF_5' sage: sif._commands 'GF_5 = GF(5)\n'
We demonstrate the use of commands, by showing how to construct code that will produce a random matrix:
sage: sib = SageInputBuilder() sage: sif = SageInputFormatter() sage: sie = sib.name('matrix')(sib.name('ZZ'), 10, 10) sage: sib.command(sie, sie.randomize()) sage: sie._sie_prepare(sif) sage: sif._commands '' sage: sif.format(sie, 0) 'si' sage: sif._commands 'si = matrix(ZZ, 10, 10)\nsi.randomize()\n'
- get_name(name)#
Return a name corresponding to a given requested name. If only one request for a name is received, then we will use the requested name; otherwise, we will add numbers to the end of the name to make it unique.
If the input name is
None
, then it is treated as a name of'si'
.EXAMPLES:
sage: from sage.misc.sage_input import SageInputFormatter sage: sif = SageInputFormatter() sage: names = ('x', 'x', 'y', 'z') sage: for n in names: sif.register_name(n) sage: for n in names: sif.get_name(n) 'x1' 'x2' 'y' 'z'
- register_name(name)#
Register that some value would like to use a given name. If only one request for a name is received, then we will use the requested name; otherwise, we will add numbers to the end of the name to make it unique.
If the input name is
None
, then it is treated as a name of'si'
.EXAMPLES:
sage: from sage.misc.sage_input import SageInputFormatter sage: sif = SageInputFormatter() sage: sif._names, sif._dup_names (set(), {}) sage: sif.register_name('x') sage: sif.register_name('y') sage: sif._names, sif._dup_names ({'x', 'y'}, {}) sage: sif.register_name('x') sage: sif._names, sif._dup_names ({'x', 'y'}, {'x': 0})
- sage.misc.sage_input.sage_input(x, preparse=True, verify=False, allow_locals=False)#
Return a sequence of commands that can be used to rebuild the object
x
.INPUT:
x
- the value we want to find an input form forpreparse
- (defaultTrue
) Whether to generate code that requires the preparser. WithTrue
, generated code requires the preparser. WithFalse
, generated code requires that the preparser not be used. WithNone
, generated code will work whether or not the preparser is used.verify
- (defaultFalse
) IfTrue
, then the answer will be evaluated withsage_eval()
, and an exception will be raised if the result is not equal to the original value. (In fact, forverify=True
,sage_input()
is effectively run three times, withpreparse
set toTrue
,False
, andNone
, and all three results are checked.) This is particularly useful for doctests.allow_locals
- (defaultFalse
) IfTrue
, then values thatsage_input()
cannot handle are returned in a dictionary, and the returned code assumes that this dictionary is passed as thelocals
parameter ofsage_eval()
. (Otherwise, ifsage_input()
cannot handle a value, an exception is raised.)
EXAMPLES:
sage: sage_input(GF(2)(1)) GF(2)(1) sage: sage_input((GF(2)(0), GF(2)(1)), verify=True) # Verified GF_2 = GF(2) (GF_2(0), GF_2(1))
When the preparser is enabled, we use the sage generator syntax.:
sage: K.<x> = GF(5)[] sage: sage_input(x^3 + 2*x, verify=True) # Verified R.<x> = GF(5)[] x^3 + 2*x sage: sage_input(x^3 + 2*x, preparse=False) R = GF(5)['x'] x = R.gen() x**3 + 2*x
The result of
sage_input()
is actually a pair of strings with a special__repr__
method to print nicely.:sage: r = sage_input(RealField(20)(pi), verify=True) sage: r # Verified RealField(20)(3.1415939) sage: isinstance(r, tuple) True sage: len(r) 2 sage: tuple(r) ('# Verified\n', 'RealField(20)(3.1415939)')
We cannot find an input form for a function.:
sage: sage_input((3, lambda x: x)) Traceback (most recent call last): ... ValueError: cannot convert <function <lambda> at 0x...> to sage_input form
But we can have
sage_input()
continue anyway, and return an input form for the rest of the expression, withallow_locals=True
.:sage: r = sage_input((3, lambda x: x), verify=True, allow_locals=True) sage: r LOCALS: _sil1: <function <lambda> at 0x...> # Verified (3, _sil1) sage: tuple(r) ('# Verified\n', '(3, _sil1)', {'_sil1': <function <lambda> at 0x...>})
- sage.misc.sage_input.verify_same(a, b)#
Verify that two Sage values are the same. This is an extended equality test; it checks that the values are equal and that their parents are equal. (For values which are not Elements, the types are checked instead.)
If the values are the same, we return
None
; otherwise, we raise an exception.EXAMPLES:
sage: from sage.misc.sage_input import verify_same sage: verify_same(1, 1) sage: verify_same(1, 2) Traceback (most recent call last): ... AssertionError: Expected 1 == 2 sage: verify_same(1, 1r) Traceback (most recent call last): ... AttributeError: 'int' object has no attribute 'parent' sage: verify_same(1r, 1) Traceback (most recent call last): ... assert(type(a) == type(b)) AssertionError sage: verify_same(5, GF(7)(5)) Traceback (most recent call last): ... assert(a.parent() == b.parent()) AssertionError
- sage.misc.sage_input.verify_si_answer(x, answer, preparse)#
Verify that evaluating
answer
gives a value equal tox
(with the same parent/type). Ifpreparse
isTrue
orFalse
, then we evaluateanswer
with the preparser enabled or disabled, respectively; ifpreparse
isNone
, then we evaluateanswer
both with the preparser enabled and disabled and check both results.On success, we return
None
; on failure, we raise an exception.INPUT:
x
- an arbitrary Sage valueanswer
- a string, or aSageInputAnswer
preparse
–True
,False
, orNone
EXAMPLES:
sage: from sage.misc.sage_input import verify_si_answer sage: verify_si_answer(1, '1', True) sage: verify_si_answer(1, '1', False) Traceback (most recent call last): ... AttributeError: 'int' object has no attribute 'parent' sage: verify_si_answer(1, 'ZZ(1)', None)