Navigation

Source code for sympy.functions.elementary.exponential

fromsympy.coreimportC,sympifyfromsympy.core.addimportAddfromsympy.core.functionimportLambda,Function,ArgumentIndexErrorfromsympy.core.cacheimportcacheitfromsympy.core.singletonimportSfromsympy.core.symbolimportWild,Dummyfromsympy.core.mulimportMulfromsympy.functions.elementary.miscellaneousimportsqrtfromsympy.ntheoryimportmultiplicity,perfect_power# NOTE IMPORTANT# The series expansion code in this file is an important part of the gruntz# algorithm for determining limits. _eval_nseries has to return a generalized# power series with coefficients in C(log(x), log).# In more detail, the result of _eval_nseries(self, x, n) must be# c_0*x**e_0 + ... (finitely many terms)# where e_i are numbers (not necessarily integers) and c_i involve only# numbers, the function log, and log(x). [This also means it must not contain# log(x(1+p)), this *has* to be expanded to log(x)+log(1+p) if x.is_positive and# p.is_positive.]classExpBase(Function):nargs=1unbranched=Truedefinverse(self,argindex=1):""" Returns the inverse function of ``exp(x)``. """returnlogdefas_numer_denom(self):""" Returns this with a positive exponent as a 2-tuple (a fraction). Examples ======== >>> from sympy.functions import exp >>> from sympy.abc import x >>> exp(-x).as_numer_denom() (1, exp(x)) >>> exp(x).as_numer_denom() (exp(x), 1) """# this should be the same as Pow.as_numer_denom wrt# exponent handlingexp=self.expneg_exp=exp.is_negativeifnotneg_expandnotexp.is_real:neg_exp=_coeff_isneg(exp)ifneg_exp:returnS.One,self.func(-exp)returnself,S.One@propertydefexp(self):""" Returns the exponent of the function. """returnself.args[0]defas_base_exp(self):""" Returns the 2-tuple (base, exponent). """returnself.func(1),Mul(*self.args)def_eval_conjugate(self):returnself.func(self.args[0].conjugate())def_eval_is_bounded(self):arg=self.args[0]ifarg.is_unbounded:ifarg.is_negative:returnTrueifarg.is_positive:returnFalseifarg.is_bounded:returnTruedef_eval_is_rational(self):s=self.func(*self.args)ifs.func==self.func:ifs.args[0].is_rational:returnFalseelse:returns.is_rationaldef_eval_is_zero(self):return(self.args[0]isS.NegativeInfinity)def_eval_power(b,e):"""exp(arg)**e -> exp(arg*e) if assumptions allow it. """f=b.funcbe=b.exprv=f(be*e)ife.is_integer:returnrvifbe.is_real:returnrv# "is True" needed below; exp.is_polar returns <property object ...>iff.is_polarisTrue:returnrvife.is_polar:returnrvifbe.is_polar:returnrvbesmall=abs(be)<=S.Piifbesmall:returnrvelifbesmallisFalseande.is_Rationalande.q==2:return-rvdef_eval_expand_power_exp(self,**hints):arg=self.args[0]ifarg.is_Addandarg.is_commutative:expr=1forxinarg.args:expr*=self.func(x)returnexprreturnself.func(arg)classexp_polar(ExpBase):r""" Represent a 'polar number' (see g-function Sphinx documentation). ``exp_polar`` represents the function `Exp: \mathbb{C} \rightarrow \mathcal{S}`, sending the complex number `z = a + bi` to the polar number `r = exp(a), \theta = b`. It is one of the main functions to construct polar numbers. >>> from sympy import exp_polar, pi, I, exp The main difference is that polar numbers don't "wrap around" at `2 \pi`: >>> exp(2*pi*I) 1 >>> exp_polar(2*pi*I) exp_polar(2*I*pi) apart from that they behave mostly like classical complex numbers: >>> exp_polar(2)*exp_polar(3) exp_polar(5) See also ======== sympy.simplify.simplify.powsimp sympy.functions.elementary.complexes.polar_lift sympy.functions.elementary.complexes.periodic_argument sympy.functions.elementary.complexes.principal_branch """is_polar=Trueis_comparable=False# cannot be evalf'ddef_eval_Abs(self):fromsympyimportexpand_mulreturnsqrt(expand_mul(self*self.conjugate()))def_eval_evalf(self,prec):""" Careful! any evalf of polar numbers is flaky """fromsympyimportim,pi,rei=im(self.args[0])ifi<=-piori>pi:returnself# cannot evalf for this argumentres=exp(self.args[0])._eval_evalf(prec)ifi>0andim(res)<0:# i ~ pi, but exp(I*i) evaluated to argument slightly bigger than pireturnre(res)returnresdef_eval_is_real(self):ifself.args[0].is_real:returnTruedefas_base_exp(self):# XXX exp_polar(0) is special!ifself.args[0]==0:returnself,S(1)returnExpBase.as_base_exp(self)

[docs]classexp(ExpBase):""" The exponential function, :math:`e^x`. See Also ======== log """

[docs]deffdiff(self,argindex=1):""" Returns the first derivative of this function. """ifargindex==1:returnselfelse:raiseArgumentIndexError(self,argindex)

@classmethoddefeval(cls,arg):ifarg.is_Number:ifargisS.NaN:returnS.NaNelifargisS.Zero:returnS.OneelifargisS.One:returnS.Exp1elifargisS.Infinity:returnS.InfinityelifargisS.NegativeInfinity:returnS.Zeroelifarg.funcislog:returnarg.args[0]elifarg.is_Mul:Ioo=S.ImaginaryUnit*S.Infinityifargin[Ioo,-Ioo]:returnS.NaNcoeff=arg.coeff(S.Pi*S.ImaginaryUnit)ifcoeff:if(2*coeff).is_integer:ifcoeff.is_even:returnS.Oneelifcoeff.is_odd:returnS.NegativeOneelif(coeff+S.Half).is_even:return-S.ImaginaryUnitelif(coeff+S.Half).is_odd:returnS.ImaginaryUnit# look for a single log factorcoeff,terms=arg.as_coeff_Mul()# but it can't be multiplied by ooifcoeffin[S.NegativeInfinity,S.Infinity]:returnNonecoeffs,log_term=[coeff],NoneforterminMul.make_args(terms):ifterm.funcislog:iflog_termisNone:log_term=term.args[0]else:returnNoneelifterm.is_comparable:coeffs.append(term)else:returnNonereturnlog_term**Mul(*coeffs)iflog_termelseNoneelifarg.is_Add:out=[]add=[]forainarg.args:ifaisS.One:add.append(a)continuenewa=cls(a)ifnewa.funciscls:add.append(a)else:out.append(newa)ifout:returnMul(*out)*cls(Add(*add),evaluate=False)@property

[docs]defbase(self):""" Returns the base of the exponential function. """returnS.Exp1

@staticmethod@cacheit

[docs]deftaylor_term(n,x,*previous_terms):""" Calculates the next term in the Taylor series expansion. """ifn<0:returnS.Zeroifn==0:returnS.Onex=sympify(x)ifprevious_terms:p=previous_terms[-1]ifpisnotNone:returnp*x/nreturnx**n/C.factorial()(n)

[docs]defas_base_exp(self):""" Returns this function in the form (base, exponent). """returnself,S.One

@staticmethod@cacheit

[docs]deftaylor_term(n,x,*previous_terms):# of log(1+x)""" Returns the next term in the Taylor series expansion of log(1+x). """fromsympyimportpowsimpifn<0:returnS.Zerox=sympify(x)ifn==0:returnxifprevious_terms:p=previous_terms[-1]ifpisnotNone:returnpowsimp((-n)*p*x/(n+1),deep=True,combine='exp')return(1-2*(n%2))*x**(n+1)/(n+1)

def_eval_is_rational(self):s=self.func(*self.args)ifs.func==self.func:ifs.args[0].is_rational:returnFalseelse:returns.is_rationaldef_eval_is_real(self):returnself.args[0].is_positivedef_eval_is_bounded(self):arg=self.args[0]ifarg.is_infinitesimal:returnFalsereturnarg.is_boundeddef_eval_is_positive(self):arg=self.args[0]ifarg.is_positive:ifarg.is_unbounded:returnTrueifarg.is_infinitesimal:returnFalseifarg.is_Number:returnarg>1def_eval_is_zero(self):# XXX This is not quite useless. Try evaluating log(0.5).is_negative# without it. There's probably a nicer way though.ifself.args[0]isS.One:returnTrueelifself.args[0].is_number:returnself.args[0].expand()isS.Oneelifself.args[0].is_negative:returnFalsedef_eval_nseries(self,x,n,logx):# NOTE Please see the comment at the beginning of this file, labelled# IMPORTANT.fromsympyimportcancelifnotlogx:logx=log(x)ifself.args[0]==x:returnlogxarg=self.args[0]k,l=Wild("k"),Wild("l")r=arg.match(k*x**l)ifrisnotNone:#k = r.get(r, S.One)#l = r.get(l, S.Zero)k,l=r[k],r[l]ifl!=0andnotl.has(x)andnotk.has(x):r=log(k)+l*logx# XXX true regardless of assumptions?returnr# TODO new and probably slows=self.args[0].nseries(x,n=n,logx=logx)whiles.is_Order:n+=1s=self.args[0].nseries(x,n=n,logx=logx)a,b=s.leadterm(x)p=cancel(s/(a*x**b)-1)g=Nonel=[]foriinrange(n+2):g=log.taylor_term(i,p,g)g=g.nseries(x,n=n,logx=logx)l.append(g)returnlog(a)+b*logx+Add(*l)+C.Order(p**n,x)def_eval_as_leading_term(self,x):arg=self.args[0].as_leading_term(x)ifargisS.One:return(self.args[0]-1).as_leading_term(x)returnself.func(arg)def_sage_(self):importsage.allassagereturnsage.log(self.args[0]._sage_())

[docs]classLambertW(Function):"""Lambert W function, defined as the inverse function of x*exp(x). This function represents the principal branch of this inverse function, which like the natural logarithm is multivalued. For more information, see: http://en.wikipedia.org/wiki/Lambert_W_function """nargs=1@classmethoddefeval(cls,x):ifx==S.Zero:returnS.Zeroifx==S.Exp1:returnS.Oneifx==-1/S.Exp1:returnS.NegativeOneifx==-log(2)/2:return-log(2)ifx==S.Infinity:returnS.Infinity

[docs]deffdiff(self,argindex=1):""" Return the first derivative of this function. """ifargindex==1:x=self.args[0]returnLambertW(x)/(x*(1+LambertW(x)))else:raiseArgumentIndexError(self,argindex)