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
])
242 elif hasattr(a
, "_sympy_"):
243 # the "a" implements _sympy_() method, that returns a SymPy
244 # expression (by definition), so we just use it
247 # XXX this is here because of cyclic-import issues
248 from sympy
.matrices
import Matrix
250 if isinstance(a
, Matrix
):
251 raise NotImplementedError('matrix support')
253 if not isinstance(a
, str):
254 # At this point we were given an arbitrary expression
255 # which does not inherit from Basic and doesn't implement
256 # _sympy_ (which is a canonical and robust way to convert
257 # anything to SymPy expression).
259 # As a last chance, we try to take "a"'s normal form via str()
260 # and try to parse it. If it fails, then we have no luck and
261 # return an exception
265 return parser
.Expr(a
).tosymbolic()
269 return Basic
.sympify(a
.strip())
270 raise ValueError("%r is NOT a valid SymPy expression" % a
)
272 @Memoizer('Basic', MemoizerArg((type, type(None), tuple), name
='type'), return_value_converter
= lambda obj
: obj
.copy())
273 def atoms(self
, type=None):
274 """Returns the atoms that form current object.
277 >>> from sympy import *
280 >>> (x+y**2+ 2*x*y).atoms()
283 You can also filter the results by a given type(s) of object
284 >>> (x+y+2+y**2*sin(x)).atoms(type=Symbol)
287 >>> (x+y+2+y**2*sin(x)).atoms(type=Number)
290 >>> (x+y+2+y**2*sin(x)).atoms(type=(Symbol, Number))
294 if type is not None and not isinstance(type, (type_class
, tuple)):
295 type = Basic
.sympify(type).__class
__
296 if isinstance(self
, Atom
):
297 if type is None or isinstance(self
, type):
301 result
= result
.union(obj
.atoms(type=type))
304 def is_hypergeometric(self
, arg
):
305 from sympy
.simplify
import hypersimp
306 return hypersimp(self
, arg
, simplify
=False) is not None
310 """Returns True if self is a number (like 1, or 1+log(2)), and False
311 otherwise (e.g. 1+x)."""
312 return len(self
.atoms(Basic
.Symbol
)) == 0
314 def is_fraction(self
, syms
):
315 p
, q
= self
.as_numer_denom()
317 if p
.is_polynomial(*syms
):
318 if q
.is_polynomial(*syms
):
323 def _eval_is_polynomial(self
, syms
):
326 def is_polynomial(self
, *syms
):
328 syms
= map(Basic
.sympify
, syms
)
330 syms
= list(self
.atoms(type=Basic
.Symbol
))
332 if not syms
: # constant polynomial
335 return self
._eval
_is
_polynomial
(syms
)
337 def as_polynomial(self
, *syms
, **kwargs
):
338 return Basic
.Polynomial(self
, var
=(syms
or None), **kwargs
)
340 def _eval_subs(self
, old
, new
):
346 def subs(self
, old
, new
):
347 """Substitutes an expression old -> new."""
348 old
= Basic
.sympify(old
)
349 new
= Basic
.sympify(new
)
351 # TODO This code is a start for issue 264. Currently, uncommenting
352 # this code will break A LOT of tests!
354 #if not old.is_dummy:
355 # exclude = ['dummy', 'comparable']
356 # for x in self._assume_defined:
357 # if x in exclude: continue
358 # old_val = getattr(old, 'is_' + x)
359 # if old_val is not None and old_val != getattr(new, 'is_' + x):
360 # raise ValueError("Cannot substitute '%s' for '%s' because assumptions do not match" % (str(new), str(old)))
362 #print self, old, new
363 return self
._eval
_subs
(old
, new
)
365 def _seq_subs(self
, old
, new
):
368 #new functions are initialized differently, than old functions
369 from sympy
.core
.function
import FunctionClass
370 if isinstance(self
.func
, FunctionClass
):
373 args
= (self
.func
,)+self
[:]
374 return self
.__class
__(*[s
.subs(old
, new
) for s
in args
])
376 def has(self
, *patterns
):
378 Return True if self has any of the patterns.
386 raise TypeError("has() requires at least 1 argument (got none)")
387 p
= Basic
.sympify(patterns
[0])
388 if isinstance(p
, Basic
.Symbol
) and not isinstance(p
, Basic
.Wild
): # speeds up
389 return p
in self
.atoms(p
.__class
__)
390 if isinstance(p
, BasicType
):
391 #XXX hack, this is very fragile:
392 if str(self
).find(str(p
.__name
__)) == -1:
393 #didn't find p in self
397 if p
.matches(self
) is not None:
402 args
= (self
.func
,)+self
[:]
408 def _eval_derivative(self
, s
):
411 def _eval_integral(self
, s
):
414 def _eval_defined_integral(self
, s
, a
, b
):
417 def _eval_fapply(self
, *args
, **assumptions
):
420 def _eval_fpower(b
, e
):
423 def _eval_apply_power(self
,b
,e
):
426 def _eval_apply_evalf(self
,*args
):
429 def _eval_eq_nonzero(self
, other
):
433 def _eval_apply_subs(cls
, *args
):
436 def _calc_apply_positive(self
, *args
):
439 def _calc_apply_real(self
, *args
):
442 def _eval_conjugate(self
):
447 from sympy
.functions
.elementary
.complexes
import conjugate
as c
450 def subs_dict(self
, old_new_dict
):
452 for old
,new
in old_new_dict
.items():
457 def matches(pattern
, expr
, repl_dict
={}, evaluate
=False):
459 Helper method for match() - switches the pattern and expr.
461 Can be used to solve linear equations:
462 >>> from sympy import Symbol, Wild
463 >>> a,b = map(Symbol, 'ab')
465 >>> (a+b*x).matches(0)
469 from sympy
.core
.mul
import Mul
470 from sympy
.core
.power
import Pow
472 # weed out negative one prefixes
474 if isinstance(pattern
,Mul
) and pattern
[0] == -1:
475 pattern
= -pattern
; sign
= -sign
476 if isinstance(expr
, Mul
) and expr
[0] == -1:
477 expr
= -expr
; sign
= -sign
481 for old
,new
in repl_dict
.items():
482 pat
= pat
.subs(old
, new
)
484 return pat
.matches(expr
, repl_dict
)
485 expr
= Basic
.sympify(expr
)
486 if not isinstance(expr
, pattern
.__class
__):
487 from sympy
.core
.numbers
import Rational
488 # if we can omit the first factor, we can match it to sign * one
489 if isinstance(pattern
, Mul
) and Mul(*pattern
[1:]) == expr
:
490 return pattern
[0].matches(Rational(sign
), repl_dict
, evaluate
)
491 # two-factor product: if the 2nd factor matches, the first part must be sign * one
492 if isinstance(pattern
, Mul
) and len(pattern
[:]) == 2:
493 dd
= pattern
[1].matches(expr
, repl_dict
, evaluate
)
494 if dd
== None: return None
495 dd
= pattern
[0].matches(Rational(sign
), dd
, evaluate
)
499 if len(pattern
[:])==0:
505 # weed out identical terms
511 if e
in ee
: ee
.remove(e
)
512 if p
in pp
: pp
.remove(p
)
514 # only one symbol left in pattern -> match the remaining expression
515 from sympy
.core
.symbol
import Wild
516 if len(pp
) == 1 and isinstance(pp
[0], Wild
):
517 if len(ee
) == 1: d
[pp
[0]] = sign
* ee
[0]
518 else: d
[pp
[0]] = sign
* (type(expr
)(*ee
))
521 if len(ee
) != len(pp
):
525 for p
,e
in zip(pp
, ee
):
526 if i
== 0 and sign
!= 1:
528 except TypeError: return None
529 d
= p
.matches(e
, d
, evaluate
=not i
)
535 def match(self
, pattern
):
539 Wild symbols match all.
541 Return None when expression (self) does not match
542 with pattern. Otherwise return a dictionary such that
544 pattern.subs_dict(self.match(pattern)) == self
547 pattern
= Basic
.sympify(pattern
)
548 return pattern
.matches(self
, {})
550 def solve4linearsymbol(eqn
, rhs
, symbols
= None):
553 with respect to some linear symbol in eqn.
554 Returns (symbol, solution). If eqn is nonlinear
555 with respect to all symbols, then return
556 trivial solution (eqn, rhs).
558 if isinstance(eqn
, Basic
.Symbol
):
561 symbols
= eqn
.atoms(type=Basic
.Symbol
)
566 if isinstance(deqn
.diff(s
), Basic
.Zero
):
567 # eqn = a + b*c, a=eqn(c=0),b=deqn(c=0)
568 return s
, (rhs
- eqn
.subs(s
,0))/deqn
.subs(s
,0)
569 # no linear symbol, return trivial solution
572 def _calc_splitter(self
, d
):
575 r
= self
.__class
__(*[t
._calc
_splitter
(d
) for t
in self
])
578 s
= d
[r
] = Basic
.Temporary()
583 r
= self
._calc
_splitter
(d
)
584 l
= [(s
.dummy_index
,s
,e
) for e
,s
in d
.items()]
586 return [(s
,e
) for i
,s
,e
in l
]
589 def count_ops(self
, symbolic
=True):
590 """ Return the number of operations in expressions.
593 >>> (1+a+b**2).count_ops()
595 >>> (sin(x)*x+sin(x)**2).count_ops()
596 ADD + MUL + POW + 2 * SIN
598 return Basic
.Integer(len(self
[:])-1) + sum([t
.count_ops(symbolic
=symbolic
) for t
in self
])
600 def doit(self
, **hints
):
601 """Evaluate objects that are not evaluated by default like limits,
602 integrals, sums and products. All objects of this kind will be
603 evaluated unless some species were excluded via 'hints'.
605 >>> from sympy import *
606 >>> x, y = symbols('xy')
611 >>> (2*Integral(x, x)).doit()
615 terms
= [ term
.doit(**hints
) for term
in self
]
616 return self
.__class
__(*terms
, **self
._assumptions
)
618 ###########################################################################
619 ################# EXPRESSION REPRESENTATION METHODS #######################
620 ###########################################################################
622 def _eval_expand_basic(self
, *args
):
623 if isinstance(self
, Atom
):
626 terms
= [ term
._eval
_expand
_basic
(*args
) for term
in sargs
]
627 return self
.__class
__(*terms
, **self
._assumptions
)
629 def _eval_expand_power(self
, *args
):
630 if isinstance(self
, Atom
):
632 if not isinstance(self
, Basic
.Apply
):
635 sargs
= (self
.func
,)+self
[:]
636 terms
= [ term
._eval
_expand
_power
(*args
) for term
in sargs
]
637 return self
.__class
__(*terms
, **self
._assumptions
)
639 def _eval_expand_complex(self
, *args
):
640 if isinstance(self
, Atom
):
643 terms
= [ term
._eval
_expand
_complex
(*args
) for term
in sargs
]
644 return self
.__class
__(*terms
, **self
._assumptions
)
646 def _eval_expand_trig(self
, *args
):
647 if isinstance(self
, Atom
):
650 terms
= [ term
._eval
_expand
_trig
(*args
) for term
in sargs
]
651 return self
.__class
__(*terms
, **self
._assumptions
)
653 def _eval_expand_func(self
, *args
):
654 if isinstance(self
, Atom
):
657 terms
= [ term
._eval
_expand
_func
(*args
) for term
in sargs
]
658 return self
.__class
__(*terms
, **self
._assumptions
)
660 def expand(self
, *args
, **hints
):
661 """Expand an expression based on different hints. Currently
662 supported hints are basic, power, complex, trig and func.
667 if hints
[hint
] == True:
668 func
= getattr(obj
, '_eval_expand_'+hint
, None)
673 if hints
.get('basic', True):
674 obj
= obj
._eval
_expand
_basic
()
678 def _eval_rewrite(self
, pattern
, rule
, **hints
):
679 if isinstance(self
, Atom
):
682 terms
= [ t
._eval
_rewrite
(pattern
, rule
, **hints
) for t
in sargs
]
683 return self
.__class
__(*terms
, **self
._assumptions
)
685 def rewrite(self
, *args
, **hints
):
686 """Rewrites expression containing applications of functions
687 of one kind in terms of functions of different kind. For
688 example you can rewrite trigonometric functions as complex
689 exponentials or combinatorial functions as gamma function.
691 As a pattern this function accepts a list of functions to
692 to rewrite (instances of DefinedFunction class). As rule
693 you can use string or a destinaton function instance (in
694 this cas rewrite() will use tostr() method).
696 There is also possibility to pass hints on how to rewrite
697 the given expressions. For now there is only one such hint
698 defined called 'deep'. When 'deep' is set to False it will
699 forbid functions to rewrite their contents.
701 >>> from sympy import *
702 >>> x, y = symbols('xy')
704 >>> sin(x).rewrite(sin, exp)
705 -1/2*I*(-exp(-I*x) + exp(I*x))
708 if isinstance(self
, Atom
) or not args
:
711 pattern
, rule
= args
[:-1], args
[-1]
713 if not isinstance(rule
, str):
714 # XXX move me out of here (cyclic imports)
715 from function
import FunctionClass
717 if rule
== Basic
.tan
:
719 elif rule
== Basic
.exp
:
721 elif isinstance(rule
, FunctionClass
): # new-style functions
723 rule
= rule
.__name
__ # XXX proper attribute for name?
728 rule
= '_eval_rewrite_as_' + rule
731 return self
._eval
_rewrite
(None, rule
, **hints
)
733 if isinstance(pattern
[0], (tuple, list)):
736 pattern
= [ p
.__class
__ for p
in pattern
if self
.has(p
) ]
739 return self
._eval
_rewrite
(tuple(pattern
), rule
, **hints
)
743 def as_coefficient(self
, expr
):
744 """Extracts symbolic coefficient at the given expression. In
745 other words, this functions separates 'self' into product
746 of 'expr' and 'expr'-free coefficient. If such separation
747 is not possible it will return None.
749 >>> from sympy import *
750 >>> x, y = symbols('xy')
752 >>> E.as_coefficient(E)
754 >>> (2*E).as_coefficient(E)
757 >>> (2*E + x).as_coefficient(E)
758 >>> (2*sin(E)*E).as_coefficient(E)
760 >>> (2*pi*I).as_coefficient(pi*I)
763 >>> (2*I).as_coefficient(pi*I)
766 if isinstance(expr
, Basic
.Add
):
771 coeff
= self
.match(w
* expr
)
773 if coeff
is not None:
774 if isinstance(expr
, Basic
.Mul
):
779 if coeff
[w
].has(*expr
):
786 def as_independent(self
, *deps
):
787 """Returns a pair with separated parts of a given expression
788 independent of specified symbols in the first place and
789 dependend on them in the other. Both parts are valid
792 >>> from sympy import *
793 >>> x, y = symbols('xy')
795 >>> (x*sin(x)*cos(y)).as_independent(x)
799 indeps
, depend
= [], []
801 if isinstance(self
, (Basic
.Add
, Basic
.Mul
)):
812 return Basic
.Mul(*indeps
), Basic
.Mul(*depend
)
814 def as_real_imag(self
):
815 """Performs complex expansion on 'self' and returns a tuple
816 containing collected both real and imaginary parts. This
817 method can't be confused with re() and im() functions,
818 which does not perform complex expansion at evaluation.
820 However it is possible to expand both re() and im()
821 functions and get exactly the same results as with
822 a single call to this function.
824 >>> from sympy import *
826 >>> x, y = symbols('xy', real=True)
828 >>> (x + y*I).as_real_imag()
831 >>> z, w = symbols('zw')
833 >>> (z + w*I).as_real_imag()
834 (-im(w) + re(z), im(z) + re(w))
837 expr
= self
.expand(complex=True)
839 if not isinstance(expr
, Basic
.Add
):
842 re_part
, im_part
= [], []
845 coeff
= term
.as_coefficient(S
.ImaginaryUnit
)
850 im_part
.append(coeff
)
852 return (Basic
.Add(*re_part
), Basic
.Add(*im_part
))
854 def as_powers_dict(self
):
855 return { self
: S
.One
}
857 def as_base_exp(self
):
859 return self
, Basic
.One()
861 def as_coeff_terms(self
, x
=None):
866 return Basic
.One(), [self
]
868 def as_indep_terms(self
, x
):
869 coeff
, terms
= self
.as_coeff_terms()
877 return Basic
.Mul(*indeps
), Basic
.Mul(*new_terms
)
879 def as_coeff_factors(self
, x
=None):
884 return Basic
.Zero(), [self
]
886 def as_numer_denom(self
):
888 base
, exp
= self
.as_base_exp()
889 coeff
, terms
= exp
.as_coeff_terms()
890 if coeff
.is_negative
:
892 return Basic
.One(), base
** (-exp
)
893 return self
, Basic
.One()
895 def as_expr_orders(self
):
896 """ Split expr + Order(..) to (expr, Order(..)).
900 if isinstance(self
, Basic
.Add
):
902 if isinstance(f
, Basic
.Order
):
906 elif isinstance(self
, Basic
.Order
):
910 return Basic
.Add(*l1
), Basic
.Add(*l2
)
913 n
, d
= self
.as_numer_denom()
914 if isinstance(d
, Basic
.One
):
918 ###################################################################################
919 ##################### DERIVATIVE, INTEGRAL, FUNCTIONAL METHODS ####################
920 ###################################################################################
922 def diff(self
, *symbols
, **assumptions
):
926 if isinstance(s
, Basic
.Integer
) and new_symbols
:
927 last_s
= new_symbols
.pop()
929 new_symbols
+= [last_s
] * i
930 elif isinstance(s
, Basic
.Symbol
):
931 new_symbols
.append(s
)
933 raise TypeError(".diff() argument must be Symbol|Integer instance (got %s)" % (s
.__class
__.__name
__))
934 ret
= Basic
.Derivative(self
, *new_symbols
, **assumptions
)
937 def fdiff(self
, *indices
):
938 return Basic
.FApply(Basic
.FDerivative(*indices
), self
)
940 def integral(self
, *symbols
, **assumptions
):
944 if isinstance(s
, Basic
.Integer
) and new_symbols
:
945 last_s
= new_symbols
[-1]
947 new_symbols
+= [last_s
] * (i
-1)
948 elif isinstance(s
, (Basic
.Symbol
, Basic
.Equality
)):
949 new_symbols
.append(s
)
951 raise TypeError(".integral() argument must be Symbol|Integer|Equality instance (got %s)" % (s
.__class
__.__name
__))
952 return Basic
.Integral(self
, *new_symbols
, **assumptions
)
954 #XXX fix the removeme
955 def __call__(self
, *args
, **removeme
):
956 return Basic
.SingleValuedFunction(self
[0])(*args
)
958 return Basic
.Apply(self
, *args
)
960 def _eval_evalf(self
):
963 def _seq_eval_evalf(self
):
964 return self
.__class
__(*[s
.evalf() for s
in self
])
967 result
= self
.evalf(precision
=16)
969 if isinstance(result
, Basic
.Number
):
972 raise ValueError("Symbolic value, can't compute")
974 def evalf(self
, precision
=None):
975 if precision
is None:
976 r
= self
._eval
_evalf
()
978 old_precision
= Basic
.set_precision(precision
)
979 r
= self
._eval
_evalf
()
980 Basic
.set_precision(old_precision
)
985 ###################################################################################
986 ##################### SERIES, LEADING TERM, LIMIT, ORDER METHODS ##################
987 ###################################################################################
989 def series(self
, x
, n
= 6):
993 Return the Taylor series around 0 of self with respect to x until
994 the n-th term (default n is 6).
998 This method is the most high level method and it returns the
999 series including the O(x**n) term.
1001 Internally, it executes a method oseries(), which takes an
1002 O instance as the only parameter and it is responsible for
1003 returning a series (without the O term) up to the given order.
1005 x
= Basic
.sympify(x
)
1006 o
= Basic
.Order(x
**n
,x
)
1013 def oseries(self
, order
, _cache
={}):
1015 Return the series of an expression upto given Order symbol (without the
1018 The general philosophy is this: simply start with the most simple
1019 taylor (laurent) term and calculate one be one and use
1020 order.contains(term) method to determine if your term is still
1021 significant and should be added to the series, or we should stop.
1023 The _cache parameter is not meant to be used by a user. It is here only
1024 to detect an infinite recursion.
1026 #is the _cache mechanism really necessary? I think it could be removed
1027 #completely, it's only slowing things down (well, probably negligibly).
1028 #python can also detect an infinite recursion, so I am for removing
1030 if _cache
.has_key((self
, order
)):
1031 raise RuntimeError('Detected recursion while computing oseries(%s, %s)' % (self
, order
))
1032 order
= Basic
.Order(order
)
1033 _cache
[(self
, order
)] = 1
1034 if isinstance(order
, Basic
.Zero
):
1035 del _cache
[(self
, order
)]
1037 if order
.contains(self
):
1038 del _cache
[(self
, order
)]
1040 if len(order
.symbols
)>1:
1042 for s
in order
.symbols
:
1043 o
= Basic
.Order(order
.expr
, s
)
1045 del _cache
[(self
, order
)]
1047 x
= order
.symbols
[0]
1049 del _cache
[(self
, order
)]
1051 obj
= self
._eval
_oseries
(order
)
1053 #obj2 = obj.expand(trig=True)
1056 r
= obj2
.oseries(order
)
1057 del _cache
[(self
, order
)]
1059 del _cache
[(self
, order
)]
1061 del _cache
[(self
, order
)]
1062 raise NotImplementedError('(%s).oseries(%s)' % (self
, order
))
1064 def _eval_oseries(self
, order
):
1067 def _compute_oseries(self
, arg
, order
, taylor_term
, unevaluated_func
, correction
= 0):
1069 compute series sum(taylor_term(i, arg), i=0..n-1) such
1070 that order.contains(taylor_term(n, arg)). Assumes that arg->0 as x->0.
1072 x
= order
.symbols
[0]
1074 o
= Basic
.Order(arg
, x
)
1075 if isinstance(o
, Basic
.Zero
):
1076 return unevaluated_func(arg
)
1078 e
= ln(order
.expr
*x
)/ln(x
)
1080 e
= ln(order
.expr
)/ln(o
.expr
)
1081 n
= e
.limit(x
,0) + 1 + correction
1083 # requested accuracy gives infinite series,
1084 # order is probably nonpolynomial e.g. O(exp(-1/x), x).
1085 return unevaluated_func(arg
)
1089 #well, the n is something more complicated (like 1+log(2))
1090 n
= int(n
.evalf()) + 1
1094 for i
in xrange(n
+2):
1095 g
= taylor_term(i
, arg
, g
)
1096 g
= g
.oseries(order
)
1098 return Basic
.Add(*l
)
1100 def limit(self
, x
, xlim
, direction
='<'):
1101 """ Compute limit x->xlim.
1103 from sympy
.series
.limits_series
import Limit
1104 return Limit(self
, x
, xlim
, direction
)
1106 def inflimit(self
, x
): # inflimit has its own cache
1107 x
= Basic
.sympify(x
)
1108 from sympy
.series
.limits_series
import InfLimit
1109 return InfLimit(self
, x
)
1112 def as_leading_term(self
, *symbols
):
1116 c
= c
.as_leading_term(x
)
1120 x
= Basic
.sympify(symbols
[0])
1121 assert isinstance(x
, Basic
.Symbol
),`x`
1124 expr
= self
.expand(trig
=True)
1125 obj
= expr
._eval
_as
_leading
_term
(x
)
1128 raise NotImplementedError('as_leading_term(%s, %s)' % (self
, x
))
1130 def as_coeff_exponent(self
, x
):
1131 """ c*x**e -> c,e where x can be any symbolic expression.
1133 x
= Basic
.sympify(x
)
1136 c
, terms
= self
.as_coeff_terms()
1141 return self
, Basic
.Zero()
1143 def ldegree(self
, x
):
1144 x
= Basic
.sympify(x
)
1145 c
,e
= self
.as_leading_term(x
).as_coeff_exponent(x
)
1148 raise ValueError("cannot compute ldegree(%s, %s), got c=%s" % (self
, x
, c
))
1150 def leadterm(self
, x
):
1151 x
= Basic
.sympify(x
)
1152 c
,e
= self
.as_leading_term(x
).as_coeff_exponent(x
)
1155 raise ValueError("cannot compute ldegree(%s, %s), got c=%s" % (self
, x
, c
))
1157 ##########################################################################
1158 ##################### END OF BASIC CLASS #################################
1159 ##########################################################################
1163 precedence
= Basic
.Atom_precedence
1165 def _eval_derivative(self
, s
):
1166 if self
==s
: return Basic
.One()
1169 def pattern_match(pattern
, expr
, repl_dict
):
1174 def as_numer_denom(self
):
1175 return self
, Basic
.One()
1177 def _calc_splitter(self
, d
):
1180 def count_ops(self
, symbolic
=True):
1183 def doit(self
, **hints
):
1186 def _eval_integral(self
, s
):
1191 def _eval_defined_integral(self
, s
, a
, b
):
1193 return (b
**2-a
**2)/2
1196 def _eval_is_polynomial(self
, syms
):
1199 def _eval_oseries(self
, order
):
1200 # .oseries() method checks for order.contains(self)
1203 def _eval_as_leading_term(self
, x
):
1207 class Singleton(Basic
):
1208 """ Singleton object.
1211 def __new__(cls
, *args
, **assumptions
):
1212 # if you need to overload __new__, then
1213 # use the same code as below to ensure
1214 # that only one instance of Singleton
1216 obj
= Singleton
.__dict
__.get(cls
.__name
__)
1218 obj
= Basic
.__new
__(cls
,*args
,**assumptions
)
1219 setattr(Singleton
, cls
.__name
__, obj
)
1222 class SingletonFactory
:
1224 A map between singleton classes and the corresponding instances.
1225 E.g. S.Exp == Basic.Exp()
1228 def __getattr__(self
, clsname
):
1229 if clsname
== "__repr__":
1231 obj
= Singleton
.__dict
__.get(clsname
)
1233 cls
= getattr(Basic
, clsname
)
1234 assert issubclass(cls
, Singleton
),`cls`
1236 setattr(self
, clsname
, obj
)
1239 S
= SingletonFactory()