1 """Base class for all objects in sympy"""
6 from basic_methods
import BasicMeths
, cache_it
, cache_it_immutable
, BasicType
12 def __init__(self
, allowed_types
, converter
= None, name
= None):
13 self
._allowed
_types
= allowed_types
14 self
.converter
= converter
17 def fix_allowed_types(self
, have_been_here
={}):
19 if have_been_here
.get(i
): return
20 allowed_types
= self
._allowed
_types
21 if isinstance(allowed_types
, str):
22 self
.allowed_types
= getattr(Basic
, allowed_types
)
23 elif isinstance(allowed_types
, (tuple, list)):
24 new_allowed_types
= []
25 for t
in allowed_types
:
26 if isinstance(t
, str):
28 new_allowed_types
.append(t
)
29 self
.allowed_types
= tuple(new_allowed_types
)
31 self
.allowed_types
= allowed_types
32 have_been_here
[i
] = True
35 def process(self
, obj
, func
, index
= None):
36 if isinstance(obj
, self
.allowed_types
):
37 if self
.converter
is not None:
38 obj
= self
.converter(obj
)
40 func_src
= '%s:%s:function %s' % (func
.func_code
.co_filename
, func
.func_code
.co_firstlineno
, func
.func_name
)
42 raise ValueError('%s return value must be of type %r but got %r' % (func_src
, self
.allowed_types
, obj
))
43 if isinstance(index
, (int,long)):
44 raise ValueError('%s %s-th argument must be of type %r but got %r' % (func_src
, index
, self
.allowed_types
, obj
))
45 if isinstance(index
, str):
46 raise ValueError('%s %r keyword argument must be of type %r but got %r' % (func_src
, index
, self
.allowed_types
, obj
))
47 raise NotImplementedError(`index
,type(index
)`
)
50 """ Memoizer function decorator generator.
53 - checks that function arguments have allowed types
54 - optionally apply converters to arguments
55 - cache the results of function calls
56 - optionally apply converter to function values
60 @Memoizer(<allowed types for argument 0>,
61 MemoizerArg(<allowed types for argument 1>),
62 MemoizerArg(<allowed types for argument 2>, <convert argument before function call>),
63 MemoizerArg(<allowed types for argument 3>, <convert argument before function call>, name=<kw argument name>),
65 return_value_converter = <None or converter function, usually makes a copy>
67 def function(<arguments>, <kw_argumnets>):
71 - if allowed type is string object then there Basic must have attribute
72 with the string name that is used as the allowed type --- this is needed
73 for applying Memoizer decorator to Basic methods when Basic definition
77 - arguments must be immutable
78 - when function values are mutable then one must use return_value_converter to
79 deep copy the returned values
81 Ref: http://en.wikipedia.org/wiki/Memoization
84 def __init__(self
, *arg_templates
, **kw_arg_templates
):
85 new_arg_templates
= []
86 for t
in arg_templates
:
87 if not isinstance(t
, MemoizerArg
):
89 new_arg_templates
.append(t
)
90 self
.arg_templates
= tuple(new_arg_templates
)
91 return_value_converter
= kw_arg_templates
.pop('return_value_converter', None)
92 self
.kw_arg_templates
= kw_arg_templates
.copy()
93 for template
in self
.arg_templates
:
94 if template
.name
is not None:
95 self
.kw_arg_templates
[template
.name
] = template
96 if return_value_converter
is None:
97 self
.return_value_converter
= lambda obj
: obj
99 self
.return_value_converter
= return_value_converter
101 def fix_allowed_types(self
, have_been_here
={}):
103 if have_been_here
.get(i
): return
104 for t
in self
.arg_templates
:
105 t
.fix_allowed_types()
106 for k
,t
in self
.kw_arg_templates
.items():
107 t
.fix_allowed_types()
108 have_been_here
[i
] = True
110 def __call__(self
, func
):
113 def wrapper(*args
, **kw_args
):
114 kw_items
= tuple(kw_args
.items())
116 return self
.return_value_converter(cache
[args
,kw_items
])
119 self
.fix_allowed_types()
120 new_args
= tuple([template
.process(a
,func
,i
) for (a
, template
, i
) in zip(args
, self
.arg_templates
, range(len(args
)))])
121 assert len(args
)==len(new_args
)
123 for k
, v
in kw_items
:
124 template
= self
.kw_arg_templates
[k
]
125 v
= template
.process(v
, func
, k
)
127 new_kw_items
= tuple(new_kw_args
.items())
129 return self
.return_value_converter(cache
[new_args
, new_kw_items
])
131 r
= func(*new_args
, **new_kw_args
)
139 cache
[new_args
, new_kw_items
] = cache
[args
, kw_items
] = r
140 return self
.return_value_converter(r
)
145 class Basic(BasicMeths
):
147 Base class for all objects in sympy.
153 When you want to access parameters of some instance, always use [].
169 2) Never use internal methods or variables (the ones prefixed with "_").
172 In [6]: cot(x)._args #don't use this, use cot(x)[:] instead
178 def __new__(cls
, *args
, **assumptions
):
179 obj
= object.__new
__(cls
)
180 obj
.assume(**assumptions
)
181 obj
._mhash
= None # will be set by BasicMeths.__hash__ method.
182 obj
._args
= args
# all items in args must be Basic objects
186 def sympify(a
, sympify_lists
=False):
187 """Converts an arbitrary expression to a type that can be used
188 inside sympy. For example, it will convert python int's into
189 instance of sympy.Rational, floats into intances of sympy.Real,
190 etc. It is also able to coerce symbolic expressions which does
191 inherit after Basic. This can be useful in cooperation with SAGE.
193 It currently accepts as arguments:
194 - any object defined in sympy (except maybe matrices [TODO])
195 - standard numeric python types: int, long, float, Decimal
196 - strings (like "0.09" or "2e-19")
198 If sympify_lists is set to True then sympify will also accept
199 lists, tuples and sets. It will return the same type but with
200 all of the entries sympified.
202 If the argument is already a type that sympy understands, it will do
203 nothing but return that value. This can be used at the begining of a
204 function to ensure you are working with the correct type.
206 >>> from sympy import *
208 >>> sympify(2).is_integer
210 >>> sympify(2).is_real
213 >>> sympify(2.0).is_real
215 >>> sympify("2.0").is_real
217 >>> sympify("2e-45").is_real
221 if isinstance(a
, BasicType
):
223 if isinstance(a
, Basic
):
225 elif isinstance(a
, bool):
226 raise NotImplementedError("bool support")
227 elif isinstance(a
, (int, long)):
228 return Basic
.Integer(a
)
229 elif isinstance(a
, (float, decimal
.Decimal
)):
231 elif isinstance(a
, complex):
232 real
, imag
= map(Basic
.sympify
, (a
.real
, a
.imag
))
233 ireal
, iimag
= int(real
), int(imag
)
235 if ireal
+ iimag
*1j
== a
:
236 return ireal
+ iimag
*Basic
.ImaginaryUnit()
237 return real
+ Basic
.ImaginaryUnit() * imag
238 elif isinstance(a
, (list,tuple)) and len(a
) == 2:
239 return Basic
.Interval(*a
)
240 elif isinstance(a
, (list,tuple,set)) and sympify_lists
:
241 return type(a
)([Basic
.sympify(x
, True) for x
in a
])
243 # XXX this is here because of cyclic-import issues
244 from sympy
.matrices
import Matrix
246 if isinstance(a
, Matrix
):
247 raise NotImplementedError('matrix support')
249 if not isinstance(a
, str):
250 # At this point we were given an arbitrary expression
251 # which does not inherit after Basic. This may be
252 # SAGE's expression (or something alike) so take
253 # its normal form via str() and try to parse it.
257 return parser
.Expr(a
).tosymbolic()
260 raise ValueError("%r is NOT a valid SymPy expression" % a
)
262 @Memoizer('Basic', MemoizerArg((type, type(None), tuple), name
='type'), return_value_converter
= lambda obj
: obj
.copy())
263 def atoms(self
, type=None):
264 """Returns the atoms that form current object.
267 >>> from sympy import *
270 >>> (x+y**2+ 2*x*y).atoms()
273 You can also filter the results by a given type(s) of object
274 >>> (x+y+2+y**2*sin(x)).atoms(type=Symbol)
277 >>> (x+y+2+y**2*sin(x)).atoms(type=Number)
280 >>> (x+y+2+y**2*sin(x)).atoms(type=(Symbol, Number))
284 if type is not None and not isinstance(type, (type_class
, tuple)):
285 type = Basic
.sympify(type).__class
__
286 if isinstance(self
, Atom
):
287 if type is None or isinstance(self
, type):
291 result
= result
.union(obj
.atoms(type=type))
294 def is_hypergeometric(self
, arg
):
295 from sympy
.simplify
import hypersimp
296 return hypersimp(self
, arg
, simplify
=False) is not None
298 def is_fraction(self
, syms
):
299 p
, q
= self
.as_numer_denom()
301 if p
.is_polynomial(*syms
):
302 if q
.is_polynomial(*syms
):
307 def _eval_is_polynomial(self
, syms
):
310 def is_polynomial(self
, *syms
):
312 syms
= map(Basic
.sympify
, syms
)
314 syms
= list(self
.atoms(type=Basic
.Symbol
))
316 if not syms
: # constant polynomial
319 return self
._eval
_is
_polynomial
(syms
)
321 def as_polynomial(self
, *syms
, **kwargs
):
322 return Basic
.Polynomial(self
, var
=(syms
or None), **kwargs
)
324 def _eval_subs(self
, old
, new
):
330 def subs(self
, old
, new
):
331 """Substitutes an expression old -> new."""
332 old
= Basic
.sympify(old
)
333 new
= Basic
.sympify(new
)
335 # TODO This code is a start for issue 264. Currently, uncommenting
336 # this code will break A LOT of tests!
338 #if not old.is_dummy:
339 # exclude = ['dummy', 'comparable']
340 # for x in self._assume_defined:
341 # if x in exclude: continue
342 # old_val = getattr(old, 'is_' + x)
343 # if old_val is not None and old_val != getattr(new, 'is_' + x):
344 # raise ValueError("Cannot substitute '%s' for '%s' because assumptions do not match" % (str(new), str(old)))
346 return self
._eval
_subs
(old
, new
)
348 def _seq_subs(self
, old
, new
):
351 return self
.__class
__(*[s
.subs(old
, new
) for s
in self
._args
])
353 def has(self
, *patterns
):
355 Return True if self has any of the patterns.
363 raise TypeError("has() requires at least 1 argument (got none)")
364 p
= Basic
.sympify(patterns
[0])
365 if isinstance(p
, Basic
.Symbol
) and not isinstance(p
, Basic
.Wild
): # speeds up
366 return p
in self
.atoms(p
.__class
__)
367 if isinstance(p
, BasicType
):
368 #XXX hack, this is very fragile:
369 if str(self
).find(str(p
.__name
__)) == -1:
370 #didn't find p in self
374 if p
.matches(self
) is not None:
381 def _eval_derivative(self
, s
):
384 def _eval_integral(self
, s
):
387 def _eval_defined_integral(self
, s
, a
, b
):
390 def _eval_apply(self
, *args
, **assumptions
):
393 def _eval_fapply(self
, *args
, **assumptions
):
396 def _eval_fpower(b
, e
):
399 def _eval_apply_power(self
,b
,e
):
402 def _eval_apply_evalf(self
,*args
):
405 def _eval_eq_nonzero(self
, other
):
408 def _eval_apply_subs(self
, *args
):
411 def _calc_apply_positive(self
, *args
):
414 def _calc_apply_real(self
, *args
):
417 def _eval_conjugate(self
):
422 return S
.Conjugate(self
)
424 def subs_dict(self
, old_new_dict
):
426 for old
,new
in old_new_dict
.items():
431 def matches(pattern
, expr
, repl_dict
={}, evaluate
=False):
433 Helper method for match() - switches the pattern and expr.
435 Can be used to solve linear equations:
436 >>> from sympy import Symbol, Wild
437 >>> a,b = map(Symbol, 'ab')
439 >>> (a+b*x).matches(0)
443 from sympy
.core
.mul
import Mul
444 from sympy
.core
.power
import Pow
446 # weed out negative one prefixes
448 if isinstance(pattern
,Mul
) and pattern
[0] == -1:
449 pattern
= -pattern
; sign
= -sign
450 if isinstance(expr
, Mul
) and expr
[0] == -1:
451 expr
= -expr
; sign
= -sign
455 for old
,new
in repl_dict
.items():
456 pat
= pat
.subs(old
, new
)
458 return pat
.matches(expr
, repl_dict
)
459 expr
= Basic
.sympify(expr
)
460 if not isinstance(expr
, pattern
.__class
__):
461 from sympy
.core
.numbers
import Rational
462 # if we can omit the first factor, we can match it to sign * one
463 if isinstance(pattern
, Mul
) and Mul(*pattern
[1:]) == expr
:
464 return pattern
[0].matches(Rational(sign
), repl_dict
, evaluate
)
465 # two-factor product: if the 2nd factor matches, the first part must be sign * one
466 if isinstance(pattern
, Mul
) and len(pattern
[:]) == 2:
467 dd
= pattern
[1].matches(expr
, repl_dict
, evaluate
)
468 if dd
== None: return None
469 dd
= pattern
[0].matches(Rational(sign
), dd
, evaluate
)
473 if len(pattern
._args
[:])==0:
479 # weed out identical terms
480 pp
= list(pattern
._args
[:])
481 ee
= list(expr
._args
[:])
485 if e
in ee
: ee
.remove(e
)
486 if p
in pp
: pp
.remove(p
)
488 # only one symbol left in pattern -> match the remaining expression
489 from sympy
.core
.symbol
import Wild
490 if len(pp
) == 1 and isinstance(pp
[0], Wild
):
491 if len(ee
) == 1: d
[pp
[0]] = sign
* ee
[0]
492 else: d
[pp
[0]] = sign
* (type(expr
)(*ee
))
495 if len(ee
) != len(pp
):
499 for p
,e
in zip(pp
, ee
):
500 if i
== 0 and sign
!= 1:
502 except TypeError: return None
503 d
= p
.matches(e
, d
, evaluate
=not i
)
509 def match(self
, pattern
):
513 Wild symbols match all.
515 Return None when expression (self) does not match
516 with pattern. Otherwise return a dictionary such that
518 pattern.subs_dict(self.match(pattern)) == self
521 pattern
= Basic
.sympify(pattern
)
522 return pattern
.matches(self
, {})
524 def solve4linearsymbol(eqn
, rhs
, symbols
= None):
527 with respect to some linear symbol in eqn.
528 Returns (symbol, solution). If eqn is nonlinear
529 with respect to all symbols, then return
530 trivial solution (eqn, rhs).
532 if isinstance(eqn
, Basic
.Symbol
):
535 symbols
= eqn
.atoms(type=Basic
.Symbol
)
540 if isinstance(deqn
.diff(s
), Basic
.Zero
):
541 # eqn = a + b*c, a=eqn(c=0),b=deqn(c=0)
542 return s
, (rhs
- eqn
.subs(s
,0))/deqn
.subs(s
,0)
543 # no linear symbol, return trivial solution
546 def _calc_splitter(self
, d
):
549 r
= self
.__class
__(*[t
._calc
_splitter
(d
) for t
in self
])
552 s
= d
[r
] = Basic
.Temporary()
557 r
= self
._calc
_splitter
(d
)
558 l
= [(s
.dummy_index
,s
,e
) for e
,s
in d
.items()]
560 return [(s
,e
) for i
,s
,e
in l
]
563 def count_ops(self
, symbolic
=True):
564 """ Return the number of operations in expressions.
567 >>> (1+a+b**2).count_ops()
569 >>> (sin(x)*x+sin(x)**2).count_ops()
570 ADD + MUL + POW + 2 * SIN
572 return Basic
.Integer(len(self
[:])-1) + sum([t
.count_ops(symbolic
=symbolic
) for t
in self
])
574 def doit(self
, **hints
):
575 """Evaluate objects that are not evaluated by default like limits,
576 integrals, sums and products. All objects of this kind will be
577 evaluated unless some species were excluded via 'hints'.
579 >>> from sympy import *
580 >>> x, y = symbols('xy')
585 >>> (2*Integral(x, x)).doit()
589 terms
= [ term
.doit(**hints
) for term
in self
]
590 return self
.__class
__(*terms
, **self
._assumptions
)
592 ###########################################################################
593 ################# EXPRESSION REPRESENTATION METHODS #######################
594 ###########################################################################
596 def _eval_expand_basic(self
, *args
):
597 if isinstance(self
, Atom
):
599 terms
= [ term
._eval
_expand
_basic
(*args
) for term
in self
._args
]
600 return self
.__class
__(*terms
, **self
._assumptions
)
602 def _eval_expand_power(self
, *args
):
603 if isinstance(self
, Atom
):
605 terms
= [ term
._eval
_expand
_power
(*args
) for term
in self
._args
]
606 return self
.__class
__(*terms
, **self
._assumptions
)
608 def _eval_expand_complex(self
, *args
):
609 if isinstance(self
, Atom
):
611 terms
= [ term
._eval
_expand
_complex
(*args
) for term
in self
._args
]
612 return self
.__class
__(*terms
, **self
._assumptions
)
614 def _eval_expand_trig(self
, *args
):
615 if isinstance(self
, Atom
):
617 terms
= [ term
._eval
_expand
_trig
(*args
) for term
in self
._args
]
618 return self
.__class
__(*terms
, **self
._assumptions
)
620 def _eval_expand_func(self
, *args
):
621 if isinstance(self
, Atom
):
623 terms
= [ term
._eval
_expand
_func
(*args
) for term
in self
._args
]
624 return self
.__class
__(*terms
, **self
._assumptions
)
626 def expand(self
, *args
, **hints
):
627 """Expand an expression based on different hints. Currently
628 supported hints are basic, power, complex, trig and func.
633 if hints
[hint
] == True:
634 func
= getattr(obj
, '_eval_expand_'+hint
, None)
639 if hints
.get('basic', True):
640 obj
= obj
._eval
_expand
_basic
()
644 def _eval_rewrite(self
, pattern
, rule
, **hints
):
645 if isinstance(self
, Atom
):
647 terms
= [ t
._eval
_rewrite
(pattern
, rule
, **hints
) for t
in self
._args
]
648 return self
.__class
__(*terms
, **self
._assumptions
)
650 def rewrite(self
, *args
, **hints
):
651 """Rewrites expression containing applications of functions
652 of one kind in terms of functions of different kind. For
653 example you can rewrite trigonometric functions as complex
654 exponentials or combinatorial functions as gamma function.
656 As a pattern this function accepts a list of functions to
657 to rewrite (instances of DefinedFunction class). As rule
658 you can use string or a destinaton function instance (in
659 this cas rewrite() will use tostr() method).
661 There is also possibility to pass hints on how to rewrite
662 the given expressions. For now there is only one such hint
663 defined called 'deep'. When 'deep' is set to False it will
664 forbid functions to rewrite their contents.
666 >>> from sympy import *
667 >>> x, y = symbols('xy')
669 >>> sin(x).rewrite(sin, exp)
670 -1/2*I*(-exp(-I*x) + exp(I*x))
673 if isinstance(self
, Atom
) or not args
:
676 pattern
, rule
= args
[:-1], args
[-1]
678 if not isinstance(rule
, str):
681 rule
= '_eval_rewrite_as_' + rule
684 return self
._eval
_rewrite
(None, rule
, **hints
)
686 if isinstance(pattern
[0], (tuple, list)):
689 pattern
= [ p
.__class
__ for p
in pattern
if self
.has(p
) ]
692 return self
._eval
_rewrite
(tuple(pattern
), rule
, **hints
)
696 def as_coefficient(self
, expr
):
697 """Extracts symbolic coefficient at the given expression. In
698 other words, this functions separates 'self' into product
699 of 'expr' and 'expr'-free coefficient. If such separation
700 is not possible it will return None.
702 >>> from sympy import *
703 >>> x, y = symbols('xy')
705 >>> E.as_coefficient(E)
707 >>> (2*E).as_coefficient(E)
710 >>> (2*E + x).as_coefficient(E)
711 >>> (2*sin(E)*E).as_coefficient(E)
713 >>> (2*pi*I).as_coefficient(pi*I)
716 >>> (2*I).as_coefficient(pi*I)
719 if isinstance(expr
, Basic
.Add
):
724 coeff
= self
.match(w
* expr
)
726 if coeff
is not None:
727 if isinstance(expr
, Basic
.Mul
):
732 if coeff
[w
].has(*expr
):
739 def as_independent(self
, *deps
):
740 """Returns a pair with separated parts of a given expression
741 independent of specified symbols in the first place and
742 dependend on them in the other. Both parts are valid
745 >>> from sympy import *
746 >>> x, y = symbols('xy')
748 >>> (x*sin(x)*cos(y)).as_independent(x)
752 indeps
, depend
= [], []
754 if isinstance(self
, (Basic
.Add
, Basic
.Mul
)):
765 return Basic
.Mul(*indeps
), Basic
.Mul(*depend
)
767 def as_real_imag(self
):
768 """Performs complex expansion on 'self' and returns a tuple
769 containing collected both real and imaginary parts. This
770 method can't be confused with re() and im() functions,
771 which does not perform complex expansion at evaluation.
773 However it is possible to expand both re() and im()
774 functions and get exactly the same results as with
775 a single call to this function.
777 >>> from sympy import *
779 >>> x, y = symbols('xy', real=True)
781 >>> (x + y*I).as_real_imag()
784 >>> z, w = symbols('zw')
786 >>> (z + w*I).as_real_imag()
787 (-im(w) + re(z), re(w) + im(z))
790 expr
= self
.expand(complex=True)
792 if not isinstance(expr
, Basic
.Add
):
795 re_part
, im_part
= [], []
798 coeff
= term
.as_coefficient(S
.ImaginaryUnit
)
803 im_part
.append(coeff
)
805 return (Basic
.Add(*re_part
), Basic
.Add(*im_part
))
807 def as_powers_dict(self
):
808 return { self
: S
.One
}
810 def as_base_exp(self
):
812 return self
, Basic
.One()
814 def as_coeff_terms(self
, x
=None):
819 return Basic
.One(), [self
]
821 def as_indep_terms(self
, x
):
822 coeff
, terms
= self
.as_coeff_terms()
830 return Basic
.Mul(*indeps
), Basic
.Mul(*new_terms
)
832 def as_coeff_factors(self
, x
=None):
837 return Basic
.Zero(), [self
]
839 def as_numer_denom(self
):
841 base
, exp
= self
.as_base_exp()
842 coeff
, terms
= exp
.as_coeff_terms()
843 if coeff
.is_negative
:
845 return Basic
.One(), base
** (-exp
)
846 return self
, Basic
.One()
848 def as_expr_orders(self
):
849 """ Split expr + Order(..) to (expr, Order(..)).
853 if isinstance(self
, Basic
.Add
):
855 if isinstance(f
, Basic
.Order
):
859 elif isinstance(self
, Basic
.Order
):
863 return Basic
.Add(*l1
), Basic
.Add(*l2
)
866 n
, d
= self
.as_numer_denom()
867 if isinstance(d
, Basic
.One
):
871 ###################################################################################
872 ##################### DERIVATIVE, INTEGRAL, FUNCTIONAL METHODS ####################
873 ###################################################################################
875 def diff(self
, *symbols
, **assumptions
):
879 if isinstance(s
, Basic
.Integer
) and new_symbols
:
880 last_s
= new_symbols
.pop()
882 new_symbols
+= [last_s
] * i
883 elif isinstance(s
, Basic
.Symbol
):
884 new_symbols
.append(s
)
886 raise TypeError(".diff() argument must be Symbol|Integer instance (got %s)" % (s
.__class
__.__name
__))
887 ret
= Basic
.Derivative(self
, *new_symbols
, **assumptions
)
890 def fdiff(self
, *indices
):
891 return Basic
.FApply(Basic
.FDerivative(*indices
), self
)
893 def integral(self
, *symbols
, **assumptions
):
897 if isinstance(s
, Basic
.Integer
) and new_symbols
:
898 last_s
= new_symbols
[-1]
900 new_symbols
+= [last_s
] * (i
-1)
901 elif isinstance(s
, (Basic
.Symbol
, Basic
.Equality
)):
902 new_symbols
.append(s
)
904 raise TypeError(".integral() argument must be Symbol|Integer|Equality instance (got %s)" % (s
.__class
__.__name
__))
905 return Basic
.Integral(self
, *new_symbols
, **assumptions
)
907 def __call__(self
, *args
):
908 return Basic
.Apply(self
, *args
)
910 def _eval_evalf(self
):
913 def _seq_eval_evalf(self
):
914 return self
.__class
__(*[s
.evalf() for s
in self
])
917 result
= self
.evalf(precision
=16)
919 if isinstance(result
, Basic
.Number
):
922 raise ValueError("Symbolic value, can't compute")
924 def evalf(self
, precision
=None):
925 if precision
is None:
926 r
= self
._eval
_evalf
()
928 old_precision
= Basic
.set_precision(precision
)
929 r
= self
._eval
_evalf
()
930 Basic
.set_precision(old_precision
)
935 ###################################################################################
936 ##################### SERIES, LEADING TERM, LIMIT, ORDER METHODS ##################
937 ###################################################################################
939 def series(self
, x
, n
= 6):
943 Return the Taylor series around 0 of self with respect to x until
944 the n-th term (default n is 6).
948 For computing power series, use oseries() method.
951 o
= Basic
.Order(x
**n
,x
)
958 def oseries(self
, order
, _cache
={}):
960 Return the series of an expression upto given Order symbol.
962 if _cache
.has_key((self
, order
)):
963 raise RuntimeError('Detected recursion while computing oseries(%s, %s)' % (self
, order
))
964 order
= Basic
.Order(order
)
965 _cache
[(self
, order
)] = 1
966 if isinstance(order
, Basic
.Zero
):
967 del _cache
[(self
, order
)]
971 if o
.contains(order
):
972 del _cache
[(self
, order
)]
974 if order
.contains(self
):
975 del _cache
[(self
, order
)]
977 if len(order
.symbols
)>1:
979 for s
in order
.symbols
:
980 o
= Basic
.Order(order
.expr
, s
)
982 del _cache
[(self
, order
)]
986 del _cache
[(self
, order
)]
988 obj
= self
._eval
_oseries
(order
)
990 obj2
= obj
.expand(trig
=True)
992 r
= obj2
.oseries(order
)
993 del _cache
[(self
, order
)]
995 del _cache
[(self
, order
)]
997 del _cache
[(self
, order
)]
998 raise NotImplementedError('(%s).oseries(%s)' % (self
, order
))
1000 def _eval_oseries(self
, order
):
1003 def _compute_oseries(self
, arg
, order
, taylor_term
, unevaluated_func
, correction
= 0):
1005 compute series sum(taylor_term(i, arg), i=0..n-1) such
1006 that order.contains(taylor_term(n, arg)). Assumes that arg->0 as x->0.
1008 x
= order
.symbols
[0]
1010 o
= Basic
.Order(arg
, x
)
1011 if isinstance(o
, Basic
.Zero
):
1012 return unevaluated_func(arg
)
1014 e
= ln(order
.expr
*x
)/ln(x
)
1016 e
= ln(order
.expr
)/ln(o
.expr
)
1017 n
= e
.limit(x
,0) + 1 + correction
1019 # requested accuracy gives infinite series,
1020 # order is probably nonpolynomial e.g. O(exp(-1/x), x).
1021 return unevaluated_func(arg
)
1026 for i
in xrange(n
+2):
1027 g
= taylor_term(i
, arg
, g
)
1028 g
= g
.oseries(order
)
1030 return Basic
.Add(*l
)
1032 def limit(self
, x
, xlim
, direction
='<'):
1033 """ Compute limit x->xlim.
1035 return Basic
.Limit(self
, x
, xlim
, direction
)
1037 def inflimit(self
, x
): # inflimit has its own cache
1038 x
= Basic
.sympify(x
)
1039 return Basic
.InfLimit(self
, x
)
1042 def as_leading_term(self
, *symbols
):
1046 c
= c
.as_leading_term(x
)
1050 x
= Basic
.sympify(symbols
[0])
1051 assert isinstance(x
, Basic
.Symbol
),`x`
1054 expr
= self
.expand(trig
=True)
1055 obj
= expr
._eval
_as
_leading
_term
(x
)
1058 raise NotImplementedError('as_leading_term(%s, %s)' % (self
, x
))
1060 def as_coeff_exponent(self
, x
):
1061 """ c*x**e -> c,e where x can be any symbolic expression.
1063 x
= Basic
.sympify(x
)
1066 c
, terms
= self
.as_coeff_terms()
1071 return self
, Basic
.Zero()
1073 def ldegree(self
, x
):
1074 x
= Basic
.sympify(x
)
1075 c
,e
= self
.as_leading_term(x
).as_coeff_exponent(x
)
1078 raise ValueError("cannot compute ldegree(%s, %s), got c=%s" % (self
, x
, c
))
1080 def leadterm(self
, x
):
1081 x
= Basic
.sympify(x
)
1082 c
,e
= self
.as_leading_term(x
).as_coeff_exponent(x
)
1085 raise ValueError("cannot compute ldegree(%s, %s), got c=%s" % (self
, x
, c
))
1087 ##########################################################################
1088 ##################### END OF BASIC CLASS #################################
1089 ##########################################################################
1093 precedence
= Basic
.Atom_precedence
1095 def _eval_derivative(self
, s
):
1096 if self
==s
: return Basic
.One()
1099 def pattern_match(pattern
, expr
, repl_dict
):
1104 def as_numer_denom(self
):
1105 return self
, Basic
.One()
1107 def _calc_splitter(self
, d
):
1110 def count_ops(self
, symbolic
=True):
1113 def doit(self
, **hints
):
1116 def _eval_integral(self
, s
):
1121 def _eval_defined_integral(self
, s
, a
, b
):
1123 return (b
**2-a
**2)/2
1126 def _eval_is_polynomial(self
, syms
):
1129 def _eval_oseries(self
, order
):
1130 # .oseries() method checks for order.contains(self)
1133 def _eval_as_leading_term(self
, x
):
1137 class Singleton(Basic
):
1138 """ Singleton object.
1141 def __new__(cls
, *args
, **assumptions
):
1142 # if you need to overload __new__, then
1143 # use the same code as below to ensure
1144 # that only one instance of Singleton
1146 obj
= Singleton
.__dict
__.get(cls
.__name
__)
1148 obj
= Basic
.__new
__(cls
,*args
,**assumptions
)
1149 setattr(Singleton
, cls
.__name
__, obj
)
1152 class SingletonFactory
:
1154 A map between singleton classes and the corresponding instances.
1155 E.g. S.Exp == Basic.Exp()
1158 def __getattr__(self
, clsname
):
1159 if clsname
== "__repr__":
1161 obj
= Singleton
.__dict
__.get(clsname
)
1163 cls
= getattr(Basic
, clsname
)
1164 assert issubclass(cls
, Singleton
),`cls`
1166 setattr(self
, clsname
, obj
)
1169 S
= SingletonFactory()