# HG changeset patch
# User Burcin Erocal <burcin@erocal.org>
# Date 1371691887 7200
# Thu Jun 20 03:31:27 2013 +0200
# Node ID 99ce058338cb7f20044271c32f2a64a2816bfda9
# Parent 56b284a7bf444ed1b7fa302f5209ff1f5fa8e638
trac 12455: fix bugs in symbolic airy functions
 airy_{a,b}i_general should evaluate to airy_{a,b}i_simple,
airy_{a,b}i_prime, etc. depending on the first parameter
 differentiating airy_{a,b}i_general in the first parameter is not allowed
 _evalf_ should not raise errors for unrecognized algorithm argument
diff git a/sage/functions/airy.py b/sage/functions/airy.py
a

b


36  36  from sage.symbolic.function import BuiltinFunction 
37  37  from sage.symbolic.expression import Expression 
38  38  from sage.symbolic.function import is_inexact 
 39  from sage.symbolic.ring import SR 
39  40  from sage.structure.coerce import parent as sage_structure_coerce_parent 
40  41  from sage.functions.other import gamma 
41  42  from sage.rings.integer_ring import ZZ 
42  43  from sage.rings.real_double import RDF 
43  44  from sage.rings.rational import Rational as R 
44  45  from sage.functions.special import meval 
45   from sage.calculus.var import var 
46  46  from sage.calculus.functional import derivative 
47  47  
48  48  
… 
… 

90  90  BuiltinFunction.__init__(self, "airy_ai", nargs=2, 
91  91  latex_name=r"\operatorname{Ai}") 
92  92  
93   def _derivative_(self, alpha, *args, **kwds): 
 93  def _derivative_(self, alpha, x, diff_param=None): 
94  94  """ 
95  95  EXAMPLES:: 
96  96  
97  97  sage: x, n = var('x n') 
98  98  sage: derivative(airy_ai(n, x), x) # indirect doctest 
99  99  airy_ai(n + 1, x) 
 100  sage: derivative(airy_ai(n, x), n) # indirect doctest 
 101  Traceback (most recent call last): 
 102  ... 
 103  ValueError: cannot differentiate airy_ai in the first parameter 
100  104  """ 
101   x = args[0] 
 105  if diff_param == 0: 
 106  raise ValueError("cannot differentiate airy_ai in the first parameter") 
102  107  return airy_ai_general(alpha + 1, x) 
103  108  
104   def _eval_(self, alpha, *args): 
 109  def _eval_(self, alpha, x): 
105  110  """ 
106  111  EXAMPLES:: 
107  112  
… 
… 

111  116  sage: airy_ai(n, 1.0) # indirect doctest 
112  117  airy_ai(n, 1.00000000000000) 
113  118  """ 
114   x = args[0] 
115   
116   if not isinstance(x, Expression) and not isinstance(alpha, Expression): 
 119  if not isinstance(x, Expression) and \ 
 120  not isinstance(alpha, Expression): 
117  121  if is_inexact(x): 
118  122  return self._evalf_(alpha, x) 
 123  if alpha == 0: 
 124  return airy_ai_simple(x) 
 125  if alpha == 1: 
 126  return airy_ai_prime(x) 
 127  if alpha == 2: 
 128  return x*airy_ai_simple(x) 
119  129  else: 
120  130  return None 
121  131  
122   def _evalf_(self, alpha, x, **kwargs): 
 132  def _evalf_(self, alpha, x, parent=None, algorithm=None): 
123  133  """ 
124  134  EXAMPLES:: 
125  135  
126  136  sage: airy_ai(2, 1.0) # indirect doctest 
127  137  0.136645379421096 
128  138  """ 
129   algorithm = kwargs.get('algorithm', None) or 'mpmath' 
130   parent = sage_structure_coerce_parent(x) 
131   if algorithm == 'mpmath': 
132   import mpmath 
133   from sage.libs.mpmath import utils as mpmath_utils 
134   return mpmath_utils.call(mpmath.airyai, x, derivative=alpha, 
135   parent=parent) 
136   elif algorithm == 'maxima': 
137   raise NotImplementedError("general case not available in Maxima") 
138   else: 
139   raise ValueError("unknown algorithm") 
 139  import mpmath 
 140  from sage.libs.mpmath import utils as mpmath_utils 
 141  return mpmath_utils.call(mpmath.airyai, x, derivative=alpha, 
 142  parent=parent) 
140  143  
141  144  
142  145  class FunctionAiryAiSimple(BuiltinFunction): 
… 
… 

187  190  else: 
188  191  return None 
189  192  
190   def _evalf_(self, x, **kwargs): 
 193  def _evalf_(self, x, parent=None, algorithm=None): 
191  194  """ 
192  195  EXAMPLES:: 
193  196  
… 
… 

210  213  sage: airy_ai(3).n(algorithm='maxima', prec=70) 
211  214  Traceback (most recent call last): 
212  215  ... 
213   ValueError: for the Maxima algorithm the precision must be 53 
 216  ValueError: precision must be 53 for algorithm=maxima 
 217  """ 
 218  if algorithm == 'maxima': 
 219  try: 
 220  prec = parent.prec() 
 221  except AttributeError: 
 222  prec = 53 
 223  if prec != 53: 
 224  raise ValueError("precision must be 53 " 
 225  "for algorithm=maxima") 
 226  return RDF(meval("airy_ai({})".format(RDF(x)))) 
214  227  
215   """ 
216   algorithm = kwargs.get('algorithm', None) or 'mpmath' 
217   parent = sage_structure_coerce_parent(x) 
218   prec = parent.prec() if hasattr(parent, 'prec') else 53 
219   if algorithm == 'mpmath': 
220   import mpmath 
221   from sage.libs.mpmath import utils as mpmath_utils 
222   return mpmath_utils.call(mpmath.airyai, x, parent=parent) 
223   elif algorithm == 'maxima': 
224   if prec != 53: 
225   raise ValueError("for the Maxima algorithm the precision must " 
226   "be 53") 
227   return RDF(meval("airy_ai({})".format(RDF(x)))) 
228   else: 
229   raise ValueError("unknown algorithm") 
 228  import mpmath 
 229  from sage.libs.mpmath import utils as mpmath_utils 
 230  return mpmath_utils.call(mpmath.airyai, x, parent=parent) 
230  231  
231  232  
232  233  class FunctionAiryAiPrime(BuiltinFunction): 
… 
… 

275  276  else: 
276  277  return None 
277  278  
278   def _evalf_(self, x, **kwargs): 
 279  def _evalf_(self, x, parent=None, algorithm=None): 
279  280  """ 
280  281  EXAMPLES:: 
281  282  
… 
… 

296  297  sage: airy_ai(1, 4).n(algorithm='maxima', prec=70) 
297  298  Traceback (most recent call last): 
298  299  ... 
299   ValueError: for the Maxima algorithm the precision must be 53 
 300  ValueError: precision must be 53 for algorithm=maxima 
300  301  """ 
301   algorithm = kwargs.get('algorithm', None) or 'mpmath' 
302   parent = sage_structure_coerce_parent(x) 
303   prec = parent.prec() if hasattr(parent, 'prec') else 53 
304   if algorithm == 'mpmath': 
305   import mpmath 
306   from sage.libs.mpmath import utils as mpmath_utils 
307   return mpmath_utils.call(mpmath.airyai, x, derivative=1, 
308   parent=parent) 
309   elif algorithm == 'maxima': 
 302  if algorithm == 'maxima': 
 303  try: 
 304  prec = parent.prec() 
 305  except AttributeError: 
 306  prec = 53 
310  307  if prec != 53: 
311   raise ValueError("for the Maxima algorithm the precision must " 
312   "be 53") 
 308  raise ValueError("precision must be 53 " 
 309  "for algorithm=maxima") 
313  310  return RDF(meval("airy_dai({})".format(RDF(x)))) 
314   else: 
315   raise ValueError("unknown algorithm") 
 311  
 312  import mpmath 
 313  from sage.libs.mpmath import utils as mpmath_utils 
 314  return mpmath_utils.call(mpmath.airyai, x, derivative=1, 
 315  parent=parent) 
316  316  
317  317  airy_ai_general = FunctionAiryAiGeneral() 
318  318  airy_ai_simple = FunctionAiryAiSimple() 
… 
… 

428  428  
429  429  # We take care of all other cases. 
430  430  if not alpha in ZZ and not isinstance(alpha, Expression): 
431   raise ValueError("alpha must be an integer") 
 431  return airy_ai_general(alpha, x, **kwds) 
432  432  if hold_derivative: 
433  433  return airy_ai_general(alpha, x, **kwds) 
434  434  elif alpha == 0: 
… 
… 

441  441  # which would return 0. What we want is the value of 
442  442  # the derivative at the value and not the derivative of 
443  443  # a particular value of the function. 
444   v = var('v') 
445   return derivative(airy_ai_simple(v, **kwds), v, alpha).subs(v=x) 
 444  v = SR.symbol() 
 445  return derivative(airy_ai_simple(v, **kwds), v, alpha).subs({v: x}) 
446  446  else: 
447  447  return airy_ai_general(alpha, x, **kwds) 
448  448  
… 
… 

494  494  BuiltinFunction.__init__(self, "airy_bi", nargs=2, 
495  495  latex_name=r"\operatorname{Bi}") 
496  496  
497   def _derivative_(self, alpha, *args, **kwds): 
 497  def _derivative_(self, alpha, x, diff_param=None): 
498  498  """ 
499  499  EXAMPLES:: 
500  500  
501  501  sage: x, n = var('x n') 
502  502  sage: derivative(airy_bi(n, x), x) # indirect doctest 
503  503  airy_bi(n + 1, x) 
 504  sage: derivative(airy_bi(n, x), n) # indirect doctest 
 505  Traceback (most recent call last): 
 506  ... 
 507  ValueError: cannot differentiate airy_bi in the first parameter 
504  508  """ 
505   x = args[0] 
 509  if diff_param == 0: 
 510  raise ValueError("cannot differentiate airy_bi in the first parameter") 
506  511  return airy_bi_general(alpha + 1, x) 
507  512  
508   def _eval_(self, alpha, *args): 
 513  def _eval_(self, alpha, x): 
509  514  """ 
510  515  EXAMPLES:: 
511  516  
… 
… 

515  520  sage: airy_bi(n, 1.0) # indirect doctest 
516  521  airy_bi(n, 1.00000000000000) 
517  522  """ 
518   x = args[0] 
519   if not isinstance(x, Expression) and not isinstance(alpha, Expression): 
 523  if not isinstance(x, Expression) and \ 
 524  not isinstance(alpha, Expression): 
520  525  if is_inexact(x): 
521  526  return self._evalf_(alpha, x) 
 527  if alpha == 0: 
 528  return airy_bi_simple(x) 
 529  if alpha == 1: 
 530  return airy_bi_prime(x) 
 531  if alpha == 2: 
 532  return x*airy_bi_simple(x) 
522  533  else: 
523  534  return None 
524  535  
… 
… 

530  541  0.388621540699059 
531  542  
532  543  """ 
533   algorithm = kwargs.get('algorithm', None) or 'mpmath' 
534   parent = sage_structure_coerce_parent(x) 
535   if algorithm == 'mpmath': 
536   import mpmath 
537   from sage.libs.mpmath import utils as mpmath_utils 
538   return mpmath_utils.call(mpmath.airybi, x, derivative=alpha, 
539   parent=parent) 
540   elif algorithm == 'maxima': 
541   raise NotImplementedError("general case not available in Maxima") 
542   else: 
543   raise ValueError("unknown algorithm") 
 544  parent = kwargs.get('parent') 
 545  import mpmath 
 546  from sage.libs.mpmath import utils as mpmath_utils 
 547  return mpmath_utils.call(mpmath.airybi, x, derivative=alpha, 
 548  parent=parent) 
544  549  
545  550  
546  551  class FunctionAiryBiSimple(BuiltinFunction): 
… 
… 

616  621  sage: airy_bi(3).n(algorithm='maxima', prec=100) 
617  622  Traceback (most recent call last): 
618  623  ... 
619   ValueError: for the Maxima algorithm the precision must be 53 
620   
 624  ValueError: precision must be 53 for algorithm=maxima 
621  625  """ 
622  626  algorithm = kwargs.get('algorithm', None) or 'mpmath' 
623   parent = sage_structure_coerce_parent(x) 
624   prec = parent.prec() if hasattr(parent, 'prec') else 53 
625   if algorithm == 'mpmath': 
626   import mpmath 
627   from sage.libs.mpmath import utils as mpmath_utils 
628   return mpmath_utils.call(mpmath.airybi, x, parent=parent) 
629   elif algorithm == 'maxima': 
 627  parent = kwargs.get('parent') 
 628  if algorithm == 'maxima': 
 629  try: 
 630  prec = parent.prec() 
 631  except AttributeError: 
 632  prec = 53 
630  633  if prec != 53: 
631   raise ValueError("for the Maxima algorithm the precision must " 
632   "be 53") 
 634  raise ValueError("precision must be 53 " 
 635  "for algorithm=maxima") 
633  636  return RDF(meval("airy_bi({})".format(RDF(x)))) 
634   else: 
635   raise ValueError("unknown algorithm") 
 637  
 638  import mpmath 
 639  from sage.libs.mpmath import utils as mpmath_utils 
 640  return mpmath_utils.call(mpmath.airybi, x, parent=parent) 
636  641  
637  642  
638  643  class FunctionAiryBiPrime(BuiltinFunction): 
… 
… 

702  707  sage: airy_bi(1, 4).n(algorithm='maxima', prec=70) 
703  708  Traceback (most recent call last): 
704  709  ... 
705   ValueError: for the Maxima algorithm the precision must be 53 
 710  ValueError: precision must be 53 for algorithm=maxima 
706  711  """ 
707  712  algorithm = kwargs.get('algorithm', None) or 'mpmath' 
708  713  parent = sage_structure_coerce_parent(x) 
709   prec = parent.prec() if hasattr(parent, 'prec') else 53 
710   if algorithm == 'mpmath': 
711   import mpmath 
712   from sage.libs.mpmath import utils as mpmath_utils 
713   return mpmath_utils.call(mpmath.airybi, x, derivative=1, 
714   parent=parent) 
715   elif algorithm == 'maxima': 
 714  if algorithm == 'maxima': 
 715  try: 
 716  prec = parent.prec() 
 717  except AttributeError: 
 718  prec = 53 
716  719  if prec != 53: 
717   raise ValueError("for the Maxima algorithm the precision must " 
718   "be 53") 
 720  raise ValueError("precision must be 53 " 
 721  "for algorithm=maxima") 
719  722  return RDF(meval("airy_dbi({})".format(RDF(x)))) 
720   else: 
721   raise ValueError("unknown algorithm") 
 723  
 724  import mpmath 
 725  from sage.libs.mpmath import utils as mpmath_utils 
 726  return mpmath_utils.call(mpmath.airybi, x, derivative=1, 
 727  parent=parent) 
722  728  
723  729  airy_bi_general = FunctionAiryBiGeneral() 
724  730  airy_bi_simple = FunctionAiryBiSimple() 
… 
… 

834  840  "({} given)").format(len(args) + 3)) 
835  841  
836  842  # We take care of all other cases. 
 843  if not alpha in ZZ and not isinstance(alpha, Expression): 
 844  return airy_bi_general(alpha, x, **kwds) 
837  845  if hold_derivative: 
838  846  return airy_bi_general(alpha, x, **kwds) 
839  847  elif alpha == 0: 
… 
… 

846  854  # which would return 0. What we want is the value of 
847  855  # the derivative at the value and not the derivative of 
848  856  # a particular value of the function. 
849   v = var('v') 
850   return derivative(airy_bi_simple(v, **kwds), v, alpha).subs(v=x) 
 857  v = SR.symbol() 
 858  return derivative(airy_bi_simple(v, **kwds), v, alpha).subs({v: x}) 
851  859  else: 
852  860  return airy_bi_general(alpha, x, **kwds) 