-
-
Notifications
You must be signed in to change notification settings - Fork 60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for hypergeometric functions #1383
base: master
Are you sure you want to change the base?
Changes from all commits
53c91aa
bbecd08
43d30fa
2d369c7
6eb4e20
52d43fd
235cb2f
31116cb
96405f1
bbb4c2f
7cb353a
f89b80c
8c66f2d
1780e70
e55d74f
bece7d9
18fe6fd
ea22016
2e90531
4a91ca1
2c563eb
3eb4d18
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,225 @@ | ||||||
""" | ||||||
Hypergeometric functions | ||||||
|
||||||
See also <url> | ||||||
:Chapter 15 Hypergeometric Functions in the Digital Library of Mathematical Functions: | ||||||
https://dlmf.nist.gov/15</url>. | ||||||
""" | ||||||
|
||||||
import mpmath | ||||||
import sympy | ||||||
|
||||||
import mathics.eval.tracing as tracing | ||||||
from mathics.core.attributes import ( | ||||||
A_LISTABLE, | ||||||
A_N_HOLD_FIRST, | ||||||
A_NUMERIC_FUNCTION, | ||||||
A_PROTECTED, | ||||||
A_READ_PROTECTED, | ||||||
) | ||||||
from mathics.core.builtin import MPMathFunction | ||||||
from mathics.core.convert.mpmath import from_mpmath | ||||||
aravindh-krishnamoorthy marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
from mathics.core.convert.sympy import from_sympy | ||||||
aravindh-krishnamoorthy marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
from mathics.core.evaluation import Evaluation | ||||||
from mathics.core.number import FP_MANTISA_BINARY_DIGITS | ||||||
from mathics.core.systemsymbols import SymbolMachinePrecision | ||||||
|
||||||
|
||||||
class HypergeometricPFQ(MPMathFunction): | ||||||
""" | ||||||
<url> | ||||||
:Generalized hypergeometric function: https://en.wikipedia.org/wiki/Generalized_hypergeometric_function</url> (<url> | ||||||
:mpmath: https://mpmath.org/doc/current/functions/hypergeometric.html#hyper</url>, <url> | ||||||
:sympy: https://docs.sympy.org/latest/modules/functions/special.html#sympy.functions.special.hyper.hyper</url>, <url> | ||||||
:WMA: https://reference.wolfram.com/language/ref/HypergeometricPFQ.html</url>) | ||||||
<dl> | ||||||
<dt>'HypergeometricPFQ'[${a_1, ..., a_p}, {b_1, ..., b_q}, z$] | ||||||
<dd>returns ${}_p F_q({a_1, ..., a_p}; {b_1, ..., b_q}; z)$. | ||||||
</dl> | ||||||
>> HypergeometricPFQ[{2}, {2}, 1] | ||||||
= E | ||||||
|
||||||
Result is symbollicaly simplified by default: | ||||||
>> HypergeometricPFQ[{3}, {2}, 1] | ||||||
= HypergeometricPFQ[{3}, {2}, 1] | ||||||
unless a numerical evaluation is explicitly requested: | ||||||
>> HypergeometricPFQ[{3}, {2}, 1] // N | ||||||
= 4.07742 | ||||||
>> HypergeometricPFQ[{3}, {2}, 1.] | ||||||
= 4.07742 | ||||||
|
||||||
The following special cases are handled: | ||||||
>> HypergeometricPFQ[{}, {}, z] | ||||||
= 1 | ||||||
>> HypergeometricPFQ[{0}, {b}, z] | ||||||
= 1 | ||||||
>> HypergeometricPFQ[{b}, {b}, z] | ||||||
= E ^ z | ||||||
""" | ||||||
|
||||||
attributes = A_NUMERIC_FUNCTION | A_PROTECTED | A_READ_PROTECTED | ||||||
mpmath_name = "hyper" | ||||||
nargs = {3} | ||||||
rules = { | ||||||
"HypergeometricPFQ[{}, {}, z_]": "1", | ||||||
"HypergeometricPFQ[{0}, b_, z_]": "1", | ||||||
"HypergeometricPFQ[b_, b_, z_]": "Exp[z]", | ||||||
} | ||||||
summary_text = "compute the generalized hypergeometric function" | ||||||
sympy_name = "hyper" | ||||||
|
||||||
def eval(self, a, b, z, evaluation: Evaluation): | ||||||
"HypergeometricPFQ[a_, b_, z_]" | ||||||
try: | ||||||
a_sympy = [e.to_sympy() for e in a] | ||||||
b_sympy = [e.to_sympy() for e in b] | ||||||
result_sympy = tracing.run_sympy( | ||||||
sympy.hyper, a_sympy, b_sympy, z.to_sympy() | ||||||
) | ||||||
return from_sympy(result_sympy) | ||||||
except Exception: | ||||||
pass | ||||||
|
||||||
def eval_N(self, a, b, z, prec, evaluation: Evaluation): | ||||||
"N[HypergeometricPFQ[a_, b_, z_], prec_]" | ||||||
try: | ||||||
result_mpmath = tracing.run_mpmath( | ||||||
mpmath.hyper, a.to_python(), b.to_python(), z.to_python() | ||||||
) | ||||||
return from_mpmath(result_mpmath) | ||||||
except Exception: | ||||||
pass | ||||||
|
||||||
def eval_numeric(self, a, b, z, evaluation: Evaluation): | ||||||
"HypergeometricPFQ[a:{__?NumericQ}, b:{__?NumericQ}, z_?MachineNumberQ]" | ||||||
return self.eval_N(a, b, z, SymbolMachinePrecision, evaluation) | ||||||
|
||||||
|
||||||
class Hypergeometric1F1(MPMathFunction): | ||||||
""" | ||||||
<url> | ||||||
:Kummer confluent hypergeometric function: https://en.wikipedia.org/wiki/Confluent_hypergeometric_function</url> (<url> | ||||||
:mpmath: https://mpmath.org/doc/current/functions/hypergeometric.html#hyper</url>, <url> | ||||||
:WMA: https://reference.wolfram.com/language/ref/Hypergeometric1F1.html</url>) | ||||||
aravindh-krishnamoorthy marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
<dl> | ||||||
<dt>'Hypergeometric1F1'[$a$, $b$, $z$] | ||||||
<dd>returns ${}_1 F_1(a; b; z)$. | ||||||
</dl> | ||||||
|
||||||
Result is symbollicaly simplified by default: | ||||||
>> Hypergeometric1F1[3, 2, 1] | ||||||
= HypergeometricPFQ[{3}, {2}, 1] | ||||||
unless a numerical evaluation is explicitly requested: | ||||||
>> Hypergeometric1F1[3, 2, 1] // N | ||||||
= 4.07742 | ||||||
>> Hypergeometric1F1[3, 2, 1.] | ||||||
= 4.07742 | ||||||
|
||||||
Plot 'M'[3, 2, x] from 0 to 2 in steps of 0.5: | ||||||
>> Plot[Hypergeometric1F1[3, 2, x], {x, 0.5, 2}] | ||||||
= -Graphics- | ||||||
Here, plot explicitly requests a numerical evaluation. | ||||||
""" | ||||||
|
||||||
attributes = A_LISTABLE | A_NUMERIC_FUNCTION | A_PROTECTED | A_READ_PROTECTED | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
In contrast to HypergeometricPFQ, WMA does not list this as being ReadProtected. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @rocky I've these changes on my radar. Kindly wait until I've marked this PR for review. Before that, I'm just focusing on the important functional aspects. But, I'll fix the documentation and the attributes before completion. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For now, I'll limit myself to these four functions, which I will also be needing at work right now. But, eventually, other hypergeometric functions can be implemented just via rules. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll do that later in another PR. |
||||||
mpmath_name = "" | ||||||
nargs = {3} | ||||||
rules = { | ||||||
"Hypergeometric1F1[a_, b_, z_]": "HypergeometricPFQ[{a},{b},z]", | ||||||
} | ||||||
summary_text = "compute Kummer confluent hypergeometric function" | ||||||
sympy_name = "" | ||||||
|
||||||
|
||||||
class MeijerG(MPMathFunction): | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please do not start more functions until we have mastered the ones in progress. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rocky, please kindly wait with the reviews. I'll let you know once I'm done with this PR and put it out of draft mode. Otherwise, my development flow may be confusing to you. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is already too large. Please reduce the scope. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you don't want folks to see what's up. People get notifications even when working in draft mode. Instead, fork the code and work in your private fork. Thanks. |
||||||
""" | ||||||
<url> | ||||||
:Meijer G-function: https://en.wikipedia.org/wiki/Meijer_G-function</url> (<url> | ||||||
:mpmath: https://mpmath.org/doc/current/functions/hypergeometric.html#meijerg</url>, <url> | ||||||
:sympy: https://docs.sympy.org/latest/modules/functions/special.html#sympy.functions.special.hyper.meijerg</url>, <url> | ||||||
:WMA: https://reference.wolfram.com/language/ref/MeijerG.html</url>) | ||||||
<dl> | ||||||
<dt>'MeijerG'[${{a_1, ..., a_n}, {a_{n+1}, ..., a_p}}, {{b_1, ..., b_m}, {b_{m+1}, ..., a_q}}, z$] | ||||||
<dd>returns $G^{m,n}_{p,q}(z | {a_1, ..., a_p}; {b_1, ..., b_q})$. | ||||||
</dl> | ||||||
Result is symbollicaly simplified by default: | ||||||
>> MeijerG[{{1, 2}, {}}, {{3}, {}}, 1] | ||||||
= MeijerG[{{1, 2}, {}}, {{3}, {}}, 1] | ||||||
unless a numerical evaluation is explicitly requested: | ||||||
>> MeijerG[{{1, 2},{}}, {{3},{}}, 1] // N | ||||||
= 0.210958 | ||||||
>> MeijerG[{{1, 2},{}}, {{3},{}}, 1.] | ||||||
= 0.210958 | ||||||
""" | ||||||
|
||||||
attributes = A_NUMERIC_FUNCTION | A_PROTECTED | A_READ_PROTECTED | ||||||
mpmath_name = "meijerg" | ||||||
nargs = {3} | ||||||
rules = {} | ||||||
summary_text = "compute the Meijer G-function" | ||||||
sympy_name = "meijerg" | ||||||
|
||||||
def eval(self, a, b, z, evaluation: Evaluation): | ||||||
"MeijerG[a_, b_, z_]" | ||||||
try: | ||||||
a_sympy = [[e2.to_sympy() for e2 in e1] for e1 in a] | ||||||
b_sympy = [[e2.to_sympy() for e2 in e1] for e1 in b] | ||||||
result_sympy = tracing.run_sympy( | ||||||
sympy.meijerg, a_sympy, b_sympy, z.to_sympy() | ||||||
) | ||||||
return from_sympy(result_sympy) | ||||||
except Exception: | ||||||
pass | ||||||
|
||||||
def eval_N(self, a, b, z, prec, evaluation: Evaluation): | ||||||
"N[MeijerG[a_, b_, z_], prec_]" | ||||||
try: | ||||||
result_mpmath = tracing.run_mpmath( | ||||||
mpmath.meijerg, a.to_python(), b.to_python(), z.to_python() | ||||||
) | ||||||
return from_mpmath(result_mpmath) | ||||||
except Exception: | ||||||
pass | ||||||
|
||||||
def eval_numeric(self, a, b, z, evaluation: Evaluation): | ||||||
"MeijerG[a:{___List?(AllTrue[#, NumericQ, Infinity]&)}, b:{___List?(AllTrue[#, NumericQ, Infinity]&)}, z_?MachineNumberQ]" | ||||||
return self.eval_N(a, b, z, SymbolMachinePrecision, evaluation) | ||||||
|
||||||
|
||||||
class HypergeometricU(MPMathFunction): | ||||||
""" | ||||||
<url> | ||||||
:Confluent hypergeometric function: https://en.wikipedia.org/wiki/Confluent_hypergeometric_function</url> (<url> | ||||||
:mpmath: https://mpmath.org/doc/current/functions/bessel.html#mpmath.hyperu</url>, <url> | ||||||
:WMA: https://reference.wolfram.com/language/ref/HypergeometricU.html</url>) | ||||||
<dl> | ||||||
<dt>'HypergeometricU'[$a$, $b$, $z$] | ||||||
<dd>returns $U(a, b, z)$. | ||||||
</dl> | ||||||
Result is symbollicaly simplified by default: | ||||||
>> HypergeometricU[3, 2, 1] | ||||||
= MeijerG[{{1, 2}, {}}, {{3}, {}}, 1] | ||||||
unless a numerical evaluation is explicitly requested: | ||||||
>> HypergeometricU[3, 2, 1] // N | ||||||
= 0.105479 | ||||||
>> HypergeometricU[3, 2, 1.] | ||||||
= 0.105479 | ||||||
|
||||||
Plot 'U'[3, 2, x] from 0 to 10 in steps of 0.5: | ||||||
>> Plot[HypergeometricU[3, 2, x], {x, 0.5, 10}] | ||||||
= -Graphics- | ||||||
|
||||||
We handle this special case: | ||||||
>> HypergeometricU[0, b, z] | ||||||
= 1 | ||||||
""" | ||||||
|
||||||
attributes = A_LISTABLE | A_NUMERIC_FUNCTION | A_PROTECTED | A_READ_PROTECTED | ||||||
mpmath_name = "" | ||||||
nargs = {3} | ||||||
rules = { | ||||||
"HypergeometricU[0, c_, z_]": "1", | ||||||
"HypergeometricU[a_, b_, z_]": "MeijerG[{{1-a},{}},{{0,1-b},{}},z]/Gamma[a]/Gamma[a-b+1]", | ||||||
} | ||||||
summary_text = "compute the Tricomi confluent hypergeometric function" | ||||||
sympy_name = "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't revise functions until we've mastered the existing ones.