cfunctions.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. """
  2. This module contains SymPy functions mathcin corresponding to special math functions in the
  3. C standard library (since C99, also available in C++11).
  4. The functions defined in this module allows the user to express functions such as ``expm1``
  5. as a SymPy function for symbolic manipulation.
  6. """
  7. from sympy.core.function import ArgumentIndexError, Function
  8. from sympy.core.numbers import Rational
  9. from sympy.core.power import Pow
  10. from sympy.core.singleton import S
  11. from sympy.functions.elementary.exponential import exp, log
  12. from sympy.functions.elementary.miscellaneous import sqrt
  13. from sympy.logic.boolalg import BooleanFunction, true, false
  14. def _expm1(x):
  15. return exp(x) - S.One
  16. class expm1(Function):
  17. """
  18. Represents the exponential function minus one.
  19. Explanation
  20. ===========
  21. The benefit of using ``expm1(x)`` over ``exp(x) - 1``
  22. is that the latter is prone to cancellation under finite precision
  23. arithmetic when x is close to zero.
  24. Examples
  25. ========
  26. >>> from sympy.abc import x
  27. >>> from sympy.codegen.cfunctions import expm1
  28. >>> '%.0e' % expm1(1e-99).evalf()
  29. '1e-99'
  30. >>> from math import exp
  31. >>> exp(1e-99) - 1
  32. 0.0
  33. >>> expm1(x).diff(x)
  34. exp(x)
  35. See Also
  36. ========
  37. log1p
  38. """
  39. nargs = 1
  40. def fdiff(self, argindex=1):
  41. """
  42. Returns the first derivative of this function.
  43. """
  44. if argindex == 1:
  45. return exp(*self.args)
  46. else:
  47. raise ArgumentIndexError(self, argindex)
  48. def _eval_expand_func(self, **hints):
  49. return _expm1(*self.args)
  50. def _eval_rewrite_as_exp(self, arg, **kwargs):
  51. return exp(arg) - S.One
  52. _eval_rewrite_as_tractable = _eval_rewrite_as_exp
  53. @classmethod
  54. def eval(cls, arg):
  55. exp_arg = exp.eval(arg)
  56. if exp_arg is not None:
  57. return exp_arg - S.One
  58. def _eval_is_real(self):
  59. return self.args[0].is_real
  60. def _eval_is_finite(self):
  61. return self.args[0].is_finite
  62. def _log1p(x):
  63. return log(x + S.One)
  64. class log1p(Function):
  65. """
  66. Represents the natural logarithm of a number plus one.
  67. Explanation
  68. ===========
  69. The benefit of using ``log1p(x)`` over ``log(x + 1)``
  70. is that the latter is prone to cancellation under finite precision
  71. arithmetic when x is close to zero.
  72. Examples
  73. ========
  74. >>> from sympy.abc import x
  75. >>> from sympy.codegen.cfunctions import log1p
  76. >>> from sympy import expand_log
  77. >>> '%.0e' % expand_log(log1p(1e-99)).evalf()
  78. '1e-99'
  79. >>> from math import log
  80. >>> log(1 + 1e-99)
  81. 0.0
  82. >>> log1p(x).diff(x)
  83. 1/(x + 1)
  84. See Also
  85. ========
  86. expm1
  87. """
  88. nargs = 1
  89. def fdiff(self, argindex=1):
  90. """
  91. Returns the first derivative of this function.
  92. """
  93. if argindex == 1:
  94. return S.One/(self.args[0] + S.One)
  95. else:
  96. raise ArgumentIndexError(self, argindex)
  97. def _eval_expand_func(self, **hints):
  98. return _log1p(*self.args)
  99. def _eval_rewrite_as_log(self, arg, **kwargs):
  100. return _log1p(arg)
  101. _eval_rewrite_as_tractable = _eval_rewrite_as_log
  102. @classmethod
  103. def eval(cls, arg):
  104. if arg.is_Rational:
  105. return log(arg + S.One)
  106. elif not arg.is_Float: # not safe to add 1 to Float
  107. return log.eval(arg + S.One)
  108. elif arg.is_number:
  109. return log(Rational(arg) + S.One)
  110. def _eval_is_real(self):
  111. return (self.args[0] + S.One).is_nonnegative
  112. def _eval_is_finite(self):
  113. if (self.args[0] + S.One).is_zero:
  114. return False
  115. return self.args[0].is_finite
  116. def _eval_is_positive(self):
  117. return self.args[0].is_positive
  118. def _eval_is_zero(self):
  119. return self.args[0].is_zero
  120. def _eval_is_nonnegative(self):
  121. return self.args[0].is_nonnegative
  122. _Two = S(2)
  123. def _exp2(x):
  124. return Pow(_Two, x)
  125. class exp2(Function):
  126. """
  127. Represents the exponential function with base two.
  128. Explanation
  129. ===========
  130. The benefit of using ``exp2(x)`` over ``2**x``
  131. is that the latter is not as efficient under finite precision
  132. arithmetic.
  133. Examples
  134. ========
  135. >>> from sympy.abc import x
  136. >>> from sympy.codegen.cfunctions import exp2
  137. >>> exp2(2).evalf() == 4.0
  138. True
  139. >>> exp2(x).diff(x)
  140. log(2)*exp2(x)
  141. See Also
  142. ========
  143. log2
  144. """
  145. nargs = 1
  146. def fdiff(self, argindex=1):
  147. """
  148. Returns the first derivative of this function.
  149. """
  150. if argindex == 1:
  151. return self*log(_Two)
  152. else:
  153. raise ArgumentIndexError(self, argindex)
  154. def _eval_rewrite_as_Pow(self, arg, **kwargs):
  155. return _exp2(arg)
  156. _eval_rewrite_as_tractable = _eval_rewrite_as_Pow
  157. def _eval_expand_func(self, **hints):
  158. return _exp2(*self.args)
  159. @classmethod
  160. def eval(cls, arg):
  161. if arg.is_number:
  162. return _exp2(arg)
  163. def _log2(x):
  164. return log(x)/log(_Two)
  165. class log2(Function):
  166. """
  167. Represents the logarithm function with base two.
  168. Explanation
  169. ===========
  170. The benefit of using ``log2(x)`` over ``log(x)/log(2)``
  171. is that the latter is not as efficient under finite precision
  172. arithmetic.
  173. Examples
  174. ========
  175. >>> from sympy.abc import x
  176. >>> from sympy.codegen.cfunctions import log2
  177. >>> log2(4).evalf() == 2.0
  178. True
  179. >>> log2(x).diff(x)
  180. 1/(x*log(2))
  181. See Also
  182. ========
  183. exp2
  184. log10
  185. """
  186. nargs = 1
  187. def fdiff(self, argindex=1):
  188. """
  189. Returns the first derivative of this function.
  190. """
  191. if argindex == 1:
  192. return S.One/(log(_Two)*self.args[0])
  193. else:
  194. raise ArgumentIndexError(self, argindex)
  195. @classmethod
  196. def eval(cls, arg):
  197. if arg.is_number:
  198. result = log.eval(arg, base=_Two)
  199. if result.is_Atom:
  200. return result
  201. elif arg.is_Pow and arg.base == _Two:
  202. return arg.exp
  203. def _eval_evalf(self, *args, **kwargs):
  204. return self.rewrite(log).evalf(*args, **kwargs)
  205. def _eval_expand_func(self, **hints):
  206. return _log2(*self.args)
  207. def _eval_rewrite_as_log(self, arg, **kwargs):
  208. return _log2(arg)
  209. _eval_rewrite_as_tractable = _eval_rewrite_as_log
  210. def _fma(x, y, z):
  211. return x*y + z
  212. class fma(Function):
  213. """
  214. Represents "fused multiply add".
  215. Explanation
  216. ===========
  217. The benefit of using ``fma(x, y, z)`` over ``x*y + z``
  218. is that, under finite precision arithmetic, the former is
  219. supported by special instructions on some CPUs.
  220. Examples
  221. ========
  222. >>> from sympy.abc import x, y, z
  223. >>> from sympy.codegen.cfunctions import fma
  224. >>> fma(x, y, z).diff(x)
  225. y
  226. """
  227. nargs = 3
  228. def fdiff(self, argindex=1):
  229. """
  230. Returns the first derivative of this function.
  231. """
  232. if argindex in (1, 2):
  233. return self.args[2 - argindex]
  234. elif argindex == 3:
  235. return S.One
  236. else:
  237. raise ArgumentIndexError(self, argindex)
  238. def _eval_expand_func(self, **hints):
  239. return _fma(*self.args)
  240. def _eval_rewrite_as_tractable(self, arg, limitvar=None, **kwargs):
  241. return _fma(arg)
  242. _Ten = S(10)
  243. def _log10(x):
  244. return log(x)/log(_Ten)
  245. class log10(Function):
  246. """
  247. Represents the logarithm function with base ten.
  248. Examples
  249. ========
  250. >>> from sympy.abc import x
  251. >>> from sympy.codegen.cfunctions import log10
  252. >>> log10(100).evalf() == 2.0
  253. True
  254. >>> log10(x).diff(x)
  255. 1/(x*log(10))
  256. See Also
  257. ========
  258. log2
  259. """
  260. nargs = 1
  261. def fdiff(self, argindex=1):
  262. """
  263. Returns the first derivative of this function.
  264. """
  265. if argindex == 1:
  266. return S.One/(log(_Ten)*self.args[0])
  267. else:
  268. raise ArgumentIndexError(self, argindex)
  269. @classmethod
  270. def eval(cls, arg):
  271. if arg.is_number:
  272. result = log.eval(arg, base=_Ten)
  273. if result.is_Atom:
  274. return result
  275. elif arg.is_Pow and arg.base == _Ten:
  276. return arg.exp
  277. def _eval_expand_func(self, **hints):
  278. return _log10(*self.args)
  279. def _eval_rewrite_as_log(self, arg, **kwargs):
  280. return _log10(arg)
  281. _eval_rewrite_as_tractable = _eval_rewrite_as_log
  282. def _Sqrt(x):
  283. return Pow(x, S.Half)
  284. class Sqrt(Function): # 'sqrt' already defined in sympy.functions.elementary.miscellaneous
  285. """
  286. Represents the square root function.
  287. Explanation
  288. ===========
  289. The reason why one would use ``Sqrt(x)`` over ``sqrt(x)``
  290. is that the latter is internally represented as ``Pow(x, S.Half)`` which
  291. may not be what one wants when doing code-generation.
  292. Examples
  293. ========
  294. >>> from sympy.abc import x
  295. >>> from sympy.codegen.cfunctions import Sqrt
  296. >>> Sqrt(x)
  297. Sqrt(x)
  298. >>> Sqrt(x).diff(x)
  299. 1/(2*sqrt(x))
  300. See Also
  301. ========
  302. Cbrt
  303. """
  304. nargs = 1
  305. def fdiff(self, argindex=1):
  306. """
  307. Returns the first derivative of this function.
  308. """
  309. if argindex == 1:
  310. return Pow(self.args[0], Rational(-1, 2))/_Two
  311. else:
  312. raise ArgumentIndexError(self, argindex)
  313. def _eval_expand_func(self, **hints):
  314. return _Sqrt(*self.args)
  315. def _eval_rewrite_as_Pow(self, arg, **kwargs):
  316. return _Sqrt(arg)
  317. _eval_rewrite_as_tractable = _eval_rewrite_as_Pow
  318. def _Cbrt(x):
  319. return Pow(x, Rational(1, 3))
  320. class Cbrt(Function): # 'cbrt' already defined in sympy.functions.elementary.miscellaneous
  321. """
  322. Represents the cube root function.
  323. Explanation
  324. ===========
  325. The reason why one would use ``Cbrt(x)`` over ``cbrt(x)``
  326. is that the latter is internally represented as ``Pow(x, Rational(1, 3))`` which
  327. may not be what one wants when doing code-generation.
  328. Examples
  329. ========
  330. >>> from sympy.abc import x
  331. >>> from sympy.codegen.cfunctions import Cbrt
  332. >>> Cbrt(x)
  333. Cbrt(x)
  334. >>> Cbrt(x).diff(x)
  335. 1/(3*x**(2/3))
  336. See Also
  337. ========
  338. Sqrt
  339. """
  340. nargs = 1
  341. def fdiff(self, argindex=1):
  342. """
  343. Returns the first derivative of this function.
  344. """
  345. if argindex == 1:
  346. return Pow(self.args[0], Rational(-_Two/3))/3
  347. else:
  348. raise ArgumentIndexError(self, argindex)
  349. def _eval_expand_func(self, **hints):
  350. return _Cbrt(*self.args)
  351. def _eval_rewrite_as_Pow(self, arg, **kwargs):
  352. return _Cbrt(arg)
  353. _eval_rewrite_as_tractable = _eval_rewrite_as_Pow
  354. def _hypot(x, y):
  355. return sqrt(Pow(x, 2) + Pow(y, 2))
  356. class hypot(Function):
  357. """
  358. Represents the hypotenuse function.
  359. Explanation
  360. ===========
  361. The hypotenuse function is provided by e.g. the math library
  362. in the C99 standard, hence one may want to represent the function
  363. symbolically when doing code-generation.
  364. Examples
  365. ========
  366. >>> from sympy.abc import x, y
  367. >>> from sympy.codegen.cfunctions import hypot
  368. >>> hypot(3, 4).evalf() == 5.0
  369. True
  370. >>> hypot(x, y)
  371. hypot(x, y)
  372. >>> hypot(x, y).diff(x)
  373. x/hypot(x, y)
  374. """
  375. nargs = 2
  376. def fdiff(self, argindex=1):
  377. """
  378. Returns the first derivative of this function.
  379. """
  380. if argindex in (1, 2):
  381. return 2*self.args[argindex-1]/(_Two*self.func(*self.args))
  382. else:
  383. raise ArgumentIndexError(self, argindex)
  384. def _eval_expand_func(self, **hints):
  385. return _hypot(*self.args)
  386. def _eval_rewrite_as_Pow(self, arg, **kwargs):
  387. return _hypot(arg)
  388. _eval_rewrite_as_tractable = _eval_rewrite_as_Pow
  389. class isnan(BooleanFunction):
  390. nargs = 1
  391. @classmethod
  392. def eval(cls, arg):
  393. if arg is S.NaN:
  394. return true
  395. elif arg.is_number:
  396. return false
  397. else:
  398. return None
  399. class isinf(BooleanFunction):
  400. nargs = 1
  401. @classmethod
  402. def eval(cls, arg):
  403. if arg.is_infinite:
  404. return true
  405. elif arg.is_finite:
  406. return false
  407. else:
  408. return None