1 """Provides Basic class and classes object.
4 __docformat__
= 'restructuredtext'
5 __all__
= ['classes', 'Expr', 'defined_functions', 'DefinedFunction',
6 'objects', 'Pair', 'IntegerList']
15 from . import expr_ext
as expr_module
17 except ImportError, msg
:
19 if msg
!='No module named expr_ext' and msg
!='cannot import name expr_ext':
21 from . import expr
as expr_module
23 Expr
= expr_module
.Expr
24 Pair
= expr_module
.Pair
27 def _reconstruct(version
, state
):
28 # Returned by <Expr instance>.__reduce__
30 cls
, (head
, data
), hashvalue
= state
33 obj
._sethash
(hashvalue
)
36 from .utils
import get_head
37 cls
, (head
, data
), hashvalue
= state
38 if type(cls
) is tuple:
42 obj
._sethash
(hashvalue
)
45 cls
, (head
, data
), hashvalue
= state
46 if type(cls
) is tuple:
48 head
= getattr(head
, 'as_unique_head', lambda head
=head
: head
)()
50 obj
._sethash
(hashvalue
)
52 raise NotImplementedError('pickle _reconstruct version=%r' % (version
))
55 # To add support pickling pure Expr instances, uncomment the
56 # following line (but it is hackish):
58 #__builtins__['Expr'] = Expr
60 # Pickling Python classes derived from Expr should work fine
64 def get_base_attribute(cls
, name
):
66 Get attribute from cls base classes.
68 if name
in cls
.__dict
__:
69 return cls
, cls
.__dict
__[name
]
70 for base
in cls
.__bases
__:
71 r
= get_base_attribute(base
, name
)
76 def inheritdoc(obj
, cls
):
78 If obj is a function intance then update its documentation string
79 from the corresponding function documentation string defined in
80 cls or one of its base classes.
84 if isinstance(obj
, types
.FunctionType
):
85 base_cls
, base_func
, base_doc
= None, None, None
86 for base
in cls
.__bases
__:
87 r
= get_base_attribute(base
, obj
.__name
__)
89 base_cls
, base_func
= r
90 base_doc
= base_func
.__doc
__
92 if base_doc
is not None:
93 doc
= obj
.__doc
__ or ''
94 title
= '### doc-string inherited from %s.%s ###'\
95 % (base_cls
.__name
__, obj
.__name
__)
97 obj
.__doc
__ = '%s\n%s\n%s' % (textwrap
.dedent(doc
),
99 textwrap
.dedent(base_doc
).strip())
100 if obj
.__doc
__ is None:
101 print '%s.%s does not define documentation string'\
102 % (cls
.__name
__, obj
.__name
__)
105 def fcopy(func
, name
):
107 Return a copy of a function func with a new name.
109 return types
.FunctionType(func
.func_code
, func
.func_globals
, name
, func
.func_closure
)
111 class MetaCopyMethods(type):
113 Metaclass that makes copies of class methods that are defined
114 by equality. For example,
117 __metaclass__ = MetaCopyMethods
129 bar = fcopy(foo, 'bar')
131 def __init__(cls
, name
, bases
, dict):
132 cls
.copy_methods(dict)
133 type.__init
__(cls
, name
, bases
, dict)
135 def copy_methods(cls
, dict):
136 for name
in dict.keys():
138 if isinstance(attr
, types
.FunctionType
):
139 if name
!= attr
.__name
__:
140 dict[name
] = fcopy(attr
, name
)
142 class MetaInheritDocs(type):
144 Metaclass that sets undefined documentation strings of methods to
145 the documentation strings of base class methods. For example,
152 __metaclass__ = MetaCopyMethods
164 '''### doc-string inherited from A.foo ###
169 def __init__(cls
, name
, bases
, dict):
170 type.__init
__(cls
, name
, bases
, dict)
171 cls
.inherit_docs(dict)
173 def inherit_docs(cls
, dict):
174 for name
in dict.keys():
176 if hasattr(attr
, '__doc__'):
177 inheritdoc(attr
, cls
)
179 class MetaCopyMethodsInheritDocs(MetaCopyMethods
, MetaInheritDocs
):
181 A composite of MetaCopyMethods and MetaInheritDocs meta classes.
183 def __init__(cls
, name
, bases
, dict):
184 cls
.copy_methods(dict)
185 type.__init
__(cls
, name
, bases
, dict)
186 cls
.inherit_docs(dict)
189 """ Holds pairs ``(name, value)`` as instance attributes.
191 The set of Holder pairs is extendable by
195 <Holder instance>.<name> = <value>
197 and the values are accessible as
201 value = <Holder instance>.<name>
203 def __init__(self
, descr
):
208 return self
._descr
% (self
.__dict
__)
211 return '%s(%r)' % (self
.__class
__.__name
__, str(self
))
213 def __setattr__(self
, name
, obj
):
214 if not self
.__dict
__.has_key(name
) and self
.__dict
__.has_key('_counter'):
216 self
.__dict
__[name
] = obj
218 def iterNameValue(self
):
219 for k
,v
in self
.__dict
__.iteritems():
220 if k
.startswith('_'):
224 classes
= Holder('SympyCore classes holder (%(_counter)s classes)')
225 objects
= Holder('SympyCore objects holder (%(_counter)s classes)')
226 heads
= Holder('SympyCore expression heads holder (%(_counter)s heads)')
227 heads_precedence
= Holder('SympyCore heads precedence holder (%(_counter)s items).')
228 defined_functions
= Holder('SympyCore defined functions holder (%(_counter)s classes)')
230 class FunctionType(type):
231 """ Metaclass to Function class.
233 FunctionType implements the following features:
235 1. If a class derived from ``Function`` has a name containing
236 substring ``Function`` then the class will be saved as an
237 attribute to ``classes`` holder. Such classes are assumed to
238 be base classes to defined functions.
240 2. Otherwise, ``Function`` subclasses are saved as attributes to
241 ``defined_functions`` holder.
245 def __new__(typ
, name
, bases
, attrdict
):
246 cls
= type.__new
__(typ
, name
, bases
, attrdict
)
247 if 'Function' in name
:
248 setattr(classes
, name
, cls
)
250 setattr(defined_functions
, name
, cls
)
253 class DefinedFunction(object):
254 """ Base class to symbolic functions.
256 __metaclass__
= FunctionType
259 def derivative(cls
, arg
):
260 """ Return derivative function of cls at arg.
262 raise NotImplementedError(`cls
, arg`
)
265 def get_argument_algebras(cls
):
266 raise NotImplementedError(`cls`
)
269 assert callable(obj
),`obj`
270 if isinstance(obj
, classes
.FunctionRing
):
272 if inspect
.isclass(obj
):
273 return len(inspect
.getargspec(obj
.__new
__)[0])-1
274 if inspect
.isfunction(obj
):
275 return len(inspect
.getargspec(obj
)[0])
276 if inspect
.ismethod(obj
):
277 return len(inspect
.getargspec(obj
)[0]) - 1
278 raise NotImplementedError(`obj
, type(obj
)`
)
283 class SymbolicEquality
:
284 """ Contex for logical operations.
286 In the ``SymbolicEquality(<Algebra class>)`` context relational
287 operations return ``Logic`` instances instead of computing
288 lexicographic value of relational operations.
292 >>> x = Calculus('x')
293 >>> with SymbolicEquality(Calculus):
301 Add ``from __future__ import with_statement`` to the header of
302 python file when using Python version 2.5.
306 def __init__(self
, *classes
):
307 self
.classes
= classes
310 for cls
in self
.classes
:
311 cls
.enable_symbolic_comparison()
313 def __exit__(self
, type, value
, tb
):
314 for cls
in self
.classes
:
315 cls
.disable_symbolic_comparison()
318 class UnevaluatedAddition
:
319 """ Contex for not evaluating additive group operations.
323 >>> x = Calculus('x')
324 >>> with UnevaluatedAddition(AdditiveGroup):
332 Add ``from __future__ import with_statement`` to the header of
333 python file when using Python version 2.5.
337 def __init__(self
, *classes
):
338 self
.classes
= classes
341 for cls
in self
.classes
:
342 cls
.algebra_options
['evaluate_addition'] = False
343 cls
.algebra_options
['evaluate_multiplication'] = False
345 def __exit__(self
, type, value
, tb
):
346 for cls
in self
.classes
:
347 cls
.algebra_options
['evaluate_addition'] = True
348 cls
.algebra_options
['evaluate_multiplication'] = True
353 """ Holds a list of functions (or callable objects), composed by
354 that are called exactly once by the execute methods. Functions are
355 assumed to take one argument holding a module object. InitModule
356 instance can be used as a decorator or functions can be added to
357 the list using the register method.
363 def register(self
, init_module_func
):
364 """ Register a function for execution.
366 if callable(init_module_func
):
367 self
.func_list
.append(init_module_func
)
369 raise NotImplementedError(`init_module_func`
)
372 """ Execute registered functions and discard them.
374 while self
.func_list
:
375 func
= self
.func_list
.pop(0)
376 module_name
= func
.__module
__
377 module
= sys
.modules
[module_name
]
378 #print 'Executing %s(%s):' % (func.__name__, module.__name__)
381 def __call__(self
, func
):
382 """ Register function via decorating it.
386 def import_heads(self
):
387 """Registers a function that adds heads symbols to a calling
390 frame
= sys
._getframe
(1)
391 module_name
= frame
.f_locals
['__name__']
393 def _import_heads(module
):
394 from sympycore
.core
import heads
395 for n
,h
in heads
.iterNameValue():
396 setattr(module
, n
, h
)
398 _import_heads
.__module
__ = module_name
400 self
.register(_import_heads
)
402 def import_lowlevel_operations(self
):
403 """Registers a function that adds lowlevel operation functions
404 like dict_get_item, dict_add_item, etc to a calling module.
406 frame
= sys
._getframe
(1)
407 module_name
= frame
.f_locals
['__name__']
409 def _import_lowlevel_operations(module
):
410 for n
in dir(expr_module
):
411 if (('dict' in n
or 'new' in n
) and not n
.startswith('_')) \
412 or n
in ['add', 'mul', 'term_coeff']:
413 setattr(module
, n
, getattr(expr_module
, n
))
414 module
.IntegerList
= IntegerList
416 _import_lowlevel_operations
.__module
__ = module_name
418 self
.register(_import_lowlevel_operations
)
420 def import_numbers(self
):
421 """Registers a function that adds numbers and number types
422 collections to a calling module.
424 frame
= sys
._getframe
(1)
425 module_name
= frame
.f_locals
['__name__']
427 def _import_numbers(module
):
428 from sympycore
.arithmetic
import numbers
429 from sympycore
.arithmetic
import number_theory
430 module
.numbertypes
= numbers
.numbertypes
431 module
.numbertypes_set
= numbers
.numbertypes_set
432 module
.inttypes
= numbers
.inttypes
433 module
.inttypes_set
= numbers
.inttypes_set
434 module
.rationaltypes
= numbers
.rationaltypes
435 module
.realtypes
= numbers
.realtypes
436 module
.complextypes
= numbers
.complextypes
437 module
.Infinity
= numbers
.Infinity
438 module
.number_div
= numbers
.number_div
439 module
.mpq
= numbers
.mpq
440 module
.try_power
= numbers
.try_power
441 module
.gcd
= number_theory
.gcd
443 _import_numbers
.__module
__ = module_name
445 self
.register(_import_numbers
)
447 init_module
= InitModule()
448 init_module
.register(expr_module
.init_module
)
450 init_module
.import_heads()
452 class IntegerList(Expr
):
453 """ IntegerList holds a list of integers and supports element-wise
454 arithmetic operations.
458 def convert(cls
, arg
, typeerror
=True):
460 if t
is int or t
is long:
461 return cls(INTEGER_LIST
, [arg
])
463 return cls(INTEGER_LIST
, arg
)
465 return cls(INTEGER_LIST
, list(arg
))
469 raise TypeError('failed to convert %r to IntegerList' % (arg
))
470 return NotImplemented
473 return '%s(%s)' % (type(self
).__name
__, self
.data
)
475 def __len__(self
): return len(self
.data
)
478 return type(self
)(self
.data
[:])
480 def __getitem__(self
, index
):
481 return self
.data
[index
]
483 def __setitem__(self
, index
, value
):
485 self
.data
[index
] = value
487 raise TypeError('this IntegerList instance is not writable')
493 return IntegerList(INTEGER_LIST
, [-i
for i
in self
.data
])
495 def __add__(self
, other
):
496 lhead
, ldata
= self
.pair
498 if t
is int or t
is long:
501 return IntegerList(INTEGER_LIST
, [i
+ other
for i
in ldata
])
504 elif t
is list or t
is tuple:
507 return NotImplemented
508 if len(ldata
)!=len(rdata
):
509 raise TypeError('IntegerList.__add__ operands must have the same size')
510 return IntegerList(INTEGER_LIST
, [i
+ j
for i
,j
in zip(ldata
, rdata
)])
514 def __sub__(self
, other
):
516 if t
is int or t
is long:
519 return IntegerList(INTEGER_LIST
, [i
- other
for i
in self
.data
])
523 elif t
is list or t
is tuple:
526 return NotImplemented
527 if len(ldata
)!=len(rdata
):
528 raise TypeError('IntegerList.__sub__ operands must have the same size')
529 return IntegerList(INTEGER_LIST
, [i
- j
for i
,j
in zip(ldata
, rdata
)])
531 def __rsub__(self
, other
):
532 return (-self
) + other
534 def __mul__(self
, other
):
536 if t
is int or t
is long:
539 return IntegerList(INTEGER_LIST
, [i
* other
for i
in self
.data
])
543 elif t
is list or t
is tuple:
546 return NotImplemented
547 if len(ldata
)!=len(rdata
):
548 raise TypeError('IntegerList.__mul__ operands must have the same size')
549 return IntegerList(INTEGER_LIST
, [i
* j
for i
,j
in zip(ldata
, rdata
)])