]>
gitweb.michael.orlitzky.com - sage.d.git/blob - mjo/symbol_sequence.py
5 An iterable object which acts like a sequence of symbolic
6 expressions (variables).
10 - ``name`` -- The sequence name. For example, if you name the
11 sequence `x`, the variables will be called `x_0`, `x_1`,...
13 - ``latex_name`` -- An optional latex expression (string) to
14 use instead of `name` when converting the symbols to latex.
16 - ``domain`` -- A string representing the domain of the symbol,
17 either 'real', 'complex', or 'positive'.
21 An iterable object containing symbolic expressions.
25 sage: from mjo.symbol_sequence import SymbolSequence
29 The simplest use case::
31 sage: a = SymbolSequence('a')
37 Create polynomials with symbolic coefficients of arbitrary
40 sage: a = SymbolSequence('a')
41 sage: p = sum( a[i]*x^i for i in xrange(5) )
43 a_4*x^4 + a_3*x^3 + a_2*x^2 + a_1*x + a_0
45 Using a different latex name since 'lambda' is reserved::
47 sage: l = SymbolSequence('l', '\lambda')
53 Using multiple indices::
55 sage: a = SymbolSequence('a')
60 sage: [ a[i,j] for i in xrange(2) for j in xrange(2) ]
61 [a_0_0, a_0_1, a_1_0, a_1_1]
63 You can pass slices instead of integers to obtain a list of
66 sage: a = SymbolSequence('a')
70 This even works for the second, third, etc. indices::
72 sage: a = SymbolSequence('a')
74 [a_0_0, a_0_1, a_1_0, a_1_1]
78 We shouldn't overwrite variables in the global namespace::
80 sage: a = SymbolSequence('a')
87 The symbol at a given index should always be the same, even when
88 the symbols themselves are unnamed. We store the string
89 representation and compare because the output is unpredictable::
91 sage: a = SymbolSequence()
92 sage: a0str = str(a[0])
93 sage: str(a[0]) == a0str
96 Slices and single indices work when combined::
98 sage: a = SymbolSequence('a')
106 def __init__(self
, name
=None, latex_name
=None, domain
=None):
107 # We store a dict of already-created symbols so that we don't
108 # recreate a symbol which already exists. This is especially
109 # helpful when using unnamed variables, if you want e.g. a[0]
110 # to return the same variable each time.
114 self
._latex
_name
= latex_name
115 self
._domain
= domain
118 def _create_symbol_(self
, subscript
):
120 Return a symbol with the given subscript. Creates the
121 appropriate name and latex_name before delegating to
126 sage: from mjo.symbol_sequence import SymbolSequence
130 sage: a = SymbolSequence('a', 'alpha', 'real')
131 sage: a_1 = a._create_symbol_(1)
138 # Allow creating unnamed symbols, for consistency with
141 if self
._name
is not None:
142 name
= '%s_%d' % (self
._name
, subscript
)
145 if self
._latex
_name
is not None:
146 latex_name
= r
'%s_{%d}' % (self
._latex
_name
, subscript
)
148 return SR
.symbol(name
, latex_name
, self
._domain
)
151 def _flatten_list_(self
, l
):
153 Recursively flatten the given list, allowing for some elements
154 to be non-iterable. This is slow, but also works, which is
155 more than can be said about some of the snappier solutions of
160 sage: from mjo.symbol_sequence import SymbolSequence
164 sage: a = SymbolSequence('a')
165 sage: a._flatten_list_([1,2,3])
167 sage: a._flatten_list_([1,[2,3]])
169 sage: a._flatten_list_([1,[2,[3]]])
171 sage: a._flatten_list_([[[[[1,[2,[3]]]]]]])
180 result
+= self
._flatten
_list
_(item
)
187 def __getitem__(self
, key
):
189 This handles individual integer arguments, slices, and
190 tuples. It just hands off the real work to
191 self._subscript_foo_().
195 sage: from mjo.symbol_sequence import SymbolSequence
199 An integer argument::
201 sage: a = SymbolSequence('a')
202 sage: a.__getitem__(1)
207 sage: a = SymbolSequence('a')
208 sage: a.__getitem__((1,2))
213 sage: a = SymbolSequence('a')
214 sage: a.__getitem__(slice(1,4))
218 if isinstance(key
, tuple):
219 return self
._subscript
_tuple
_(key
)
221 if isinstance(key
, slice):
222 return self
._subscript
_slice
_(key
)
224 # This is the most common case so it would make sense to have
225 # this test first. But there are too many different "integer"
226 # classes that you have to check for.
227 return self
._subscript
_integer
_(key
)
230 def _subscript_integer_(self
, n
):
232 The subscript is a single integer, or something that acts like
237 sage: from mjo.symbol_sequence import SymbolSequence
241 sage: a = SymbolSequence('a')
242 sage: a._subscript_integer_(123)
247 # Cowardly refuse to create a variable named "a-1".
248 raise IndexError('Indices must be nonnegative')
251 return self
._symbols
[n
]
253 self
._symbols
[n
] = self
._create
_symbol
_(n
)
254 return self
._symbols
[n
]
257 def _subscript_slice_(self
, s
):
259 We were given a slice. Clean up some of its properties
260 first. The start/step are default for lists. We make
261 copies of these because they're read-only.
265 sage: from mjo.symbol_sequence import SymbolSequence
269 sage: a = SymbolSequence('a')
270 sage: a._subscript_slice_(slice(1,3))
274 (start
, step
) = (s
.start
, s
.step
)
278 # Would otherwise loop forever since our "length" is
280 raise ValueError('You must supply an terminal index')
284 # If the user asks for a slice, we'll be returning a list
286 return [ self
._subscript
_integer
_(idx
)
287 for idx
in xrange(start
, s
.stop
, step
) ]
291 def _subscript_tuple_(self
, args
):
293 When we have more than one level of subscripts, we pick off
294 the first one and generate the rest recursively.
298 sage: from mjo.symbol_sequence import SymbolSequence
304 sage: a = SymbolSequence('a')
305 sage: a._subscript_tuple_((1,8))
310 sage: a._subscript_tuple_(( (1,2), (3,(4,5,6)) ))
315 # We never call this method without an argument.
317 args
= args
[1:] # Peel off the first arg, which we've called 'key'
319 # We don't know the type of 'key', but __getitem__ will figure
320 # it out and dispatch properly.
323 # There was only one element left in the tuple.
326 # At this point, we know we were given at least a two-tuple.
327 # The symbols corresponding to the first entry are already
328 # computed, in 'v'. Here we recursively compute the symbols
329 # corresponding to the second coordinate, with the first
330 # coordinate(s) fixed.
331 if isinstance(key
, slice):
332 ss
= ( SymbolSequence(w
._repr
_(), w
._latex
_(), self
._domain
)
335 # This might be nested...
336 maybe_nested_list
= ( s
._subscript
_tuple
_(args
) for s
in ss
)
337 return self
._flatten
_list
_(maybe_nested_list
)
340 # If it's not a slice, it's an integer.
341 ss
= SymbolSequence(v
._repr
_(), v
._latex
_(), self
._domain
)
342 return ss
._subscript
_tuple
_(args
)