Skip to content

Commit 2678c20

Browse files
authored
Go over mathics.builtin.intfns (#1698)
* Add argument checking * Go through sympy tracking in GCD, LCM, SterlingS1, and SterlingS2 * expand tracing to handle keyword arguments * Move BernoulliB to "Recurrence and Sum" section * Go over docstrings and sort builtin class attributes * Create some eval routines for `mathics.builtin.intfns.divlike`
1 parent a5f085e commit 2678c20

File tree

7 files changed

+161
-127
lines changed

7 files changed

+161
-127
lines changed

mathics/builtin/intfns/divlike.py

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"""
66

77
import sys
8-
from typing import List
8+
from typing import List, Optional
99

1010
import sympy
1111
from sympy import Q, ask
@@ -30,6 +30,7 @@
3030
SymbolQuotient,
3131
SymbolQuotientRemainder,
3232
)
33+
from mathics.eval.intfns.divlike import eval_GCD, eval_LCM, eval_ModularInverse
3334

3435

3536
class CompositeQ(Builtin):
@@ -121,17 +122,10 @@ class GCD(Builtin):
121122
attributes = A_FLAT | A_LISTABLE | A_ONE_IDENTITY | A_ORDERLESS | A_PROTECTED
122123
summary_text = "greatest common divisor"
123124

124-
def eval(self, ns, evaluation: Evaluation):
125+
def eval(self, ns, evaluation: Evaluation) -> Optional[Integer]:
125126
"GCD[ns___Integer]"
126127

127-
ns = ns.get_sequence()
128-
result = 0
129-
for n in ns:
130-
value = n.value
131-
if value is None:
132-
return
133-
result = sympy.gcd(result, value)
134-
return Integer(result)
128+
return eval_GCD(ns.get_sequence())
135129

136130

137131
class LCM(Builtin):
@@ -157,20 +151,14 @@ class LCM(Builtin):
157151
}
158152
summary_text = "least common multiple"
159153

160-
def eval(self, ns: List[Integer], evaluation: Evaluation):
154+
def eval(self, ns: List[Integer], evaluation: Evaluation) -> Optional[Integer]:
161155
"LCM[ns___Integer]"
162156

163-
ns = ns.get_sequence()
164-
if len(ns) == 0:
157+
ns_tuple = ns.get_sequence()
158+
if len(ns_tuple) == 0:
165159
evaluation.message("LCM", "argm")
166160
return
167-
result = 1
168-
for n in ns:
169-
value = n.value
170-
if value is None:
171-
return
172-
result = sympy.lcm(result, value)
173-
return Integer(result)
161+
return eval_LCM(ns_tuple)
174162

175163

176164
class Mod(SympyFunction):
@@ -247,13 +235,9 @@ class ModularInverse(SympyFunction):
247235
summary_text = "returns the modular inverse $k^(-1)$ mod $n$"
248236
sympy_name = "mod_inverse"
249237

250-
def eval_k_n(self, k: Integer, n: Integer, evaluation: Evaluation):
238+
def eval(self, k: Integer, n: Integer, evaluation: Evaluation) -> Optional[Integer]:
251239
"ModularInverse[k_Integer, n_Integer]"
252-
try:
253-
r = sympy.mod_inverse(k.value, n.value)
254-
except ValueError:
255-
return
256-
return Integer(r)
240+
return eval_ModularInverse(k.value, n.value)
257241

258242

259243
class PowerMod(Builtin):

mathics/builtin/intfns/misc.py

Lines changed: 0 additions & 48 deletions
This file was deleted.

mathics/builtin/intfns/recurrence.py

Lines changed: 95 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
as a function of the preceding terms.
99
"""
1010

11-
1211
from sympy.functions.combinatorial.numbers import stirling
1312

13+
import mathics.eval.tracing as tracing
1414
from mathics.core.atoms import Integer
1515
from mathics.core.attributes import (
1616
A_LISTABLE,
@@ -22,46 +22,91 @@
2222
from mathics.core.evaluation import Evaluation
2323

2424

25-
class Fibonacci(MPMathFunction):
25+
class BernoulliB(MPMathFunction):
2626
"""
27-
<url>
28-
:Fibonacci Sequence:
29-
https://en.wikipedia.org/wiki/Fibonacci_sequence</url>, <url>(
30-
:WMA link:https://reference.wolfram.com/language/ref/Fibonacci.html</url>)
27+
<url>:Bernoulli number:
28+
https://en.wikipedia.org/wiki/Bernoulli_number</url> (<url>:WMA link:https://reference.wolfram.com/language/ref/BernoulliB.html</url>)
3129
32-
<dl>
33-
<dt>'Fibonacci'[$n$]
34-
<dd>computes the $n$-th Fibonacci number.
35-
<dt>'Fibonacci'[$n$, $x$]
36-
<dd>computes the Fibonacci polynomial $F_n(x)$.
37-
</dl>
30+
<dl>
31+
<dt>'BernoulliB'[$n$]
32+
<dd>represents the Bernoulli number $B_n$.
3833
39-
>> Fibonacci[0]
40-
= 0
41-
>> Fibonacci[1]
42-
= 1
43-
>> Fibonacci[10]
44-
= 55
45-
>> Fibonacci[200]
46-
= 280571172992510140037611932413038677189525
47-
>> Fibonacci[7, x]
48-
= 1 + 6 x ^ 2 + 5 x ^ 4 + x ^ 6
34+
<dt>'BernouilliB'[$n$, $x$]
35+
<dd>represents the Bernoulli polynomial $B_n(x)$.
36+
</dl>
4937
50-
See also <url>
51-
:LinearRecurrence:
52-
/doc/reference-of-built-in-symbols/integer-functions/recurrence-and-sum-functions/linearrecurrence</url>.
38+
>> BernoulliB[42]
39+
= 1520097643918070802691 / 1806
40+
41+
First five Bernoulli numbers:
42+
43+
>> Table[BernoulliB[k], {k, 0, 5}]
44+
= ...
45+
46+
## This must be (according to WMA)
47+
## = {1, -1 / 2, 1 / 6, 0, -1 / 30, 0}
48+
## but for some reason, in the CI the previous test produces
49+
## the output:
50+
## {1, 1 / 2, 1 / 6, 0, -1 / 30, 0}
51+
52+
First five Bernoulli polynomials:
53+
54+
>> Table[BernoulliB[k, z], {k, 0, 3}]
55+
= {1, -1 / 2 + z, 1 / 6 - z + z ^ 2, z / 2 - 3 z ^ 2 / 2 + z ^ 3}
56+
"""
57+
58+
attributes = A_LISTABLE | A_PROTECTED
59+
eval_error = Builtin.generic_argument_error
60+
expected_args = (1, 2)
61+
mpmath_name = "bernoulli"
62+
nargs = {1, 2}
63+
summary_text = "Bernoulli numbers and polynomials"
64+
sympy_name = "bernoulli"
65+
66+
67+
class Fibonacci(MPMathFunction):
68+
"""
69+
<url>
70+
:Fibonacci Sequence:
71+
https://en.wikipedia.org/wiki/Fibonacci_sequence</url> and <url>
72+
:Fibonacci polynomials:
73+
https://en.wikipedia.org/wiki/Fibonacci_polynomials</url> (<url>
74+
:WMA link:https://reference.wolfram.com/language/ref/Fibonacci.html</url>)
75+
76+
<dl>
77+
<dt>'Fibonacci'[$n$]
78+
<dd>computes the $n$-th Fibonacci number.
79+
<dt>'Fibonacci'[$n$, $x$]
80+
<dd>computes the Fibonacci polynomial $F_n(x)$.
81+
</dl>
82+
83+
>> Fibonacci[0]
84+
= 0
85+
>> Fibonacci[1]
86+
= 1
87+
>> Fibonacci[10]
88+
= 55
89+
>> Fibonacci[200]
90+
= 280571172992510140037611932413038677189525
91+
>> Fibonacci[7, x]
92+
= 1 + 6 x ^ 2 + 5 x ^ 4 + x ^ 6
93+
94+
See also <url>
95+
:LinearRecurrence:
96+
/doc/reference-of-built-in-symbols/integer-functions/recurrence-and-sum-functions/linearrecurrence</url>.
5397
"""
5498

55-
nargs = {1}
5699
attributes = A_LISTABLE | A_NUMERIC_FUNCTION | A_PROTECTED | A_READ_PROTECTED
57-
sympy_name = "fibonacci"
100+
eval_error = Builtin.generic_argument_error
101+
expected_args = (1, 2)
58102
mpmath_name = "fibonacci"
59-
summary_text = "Fibonacci's numbers"
60-
103+
nargs = {1}
61104
rules = {
62105
"Fibonacci[0, x_]": "0",
63106
"Fibonacci[n_Integer?Negative, x_]": "Fibonacci[-n, x]",
64107
}
108+
summary_text = "Fibonacci sequences and polynomials"
109+
sympy_name = "fibonacci"
65110

66111

67112
class HarmonicNumber(MPMathFunction):
@@ -81,19 +126,22 @@ class HarmonicNumber(MPMathFunction):
81126
= 2.03806
82127
"""
83128

129+
attributes = A_LISTABLE | A_NUMERIC_FUNCTION | A_READ_PROTECTED | A_PROTECTED
130+
eval_error = Builtin.generic_argument_error
131+
expected_args = (1, 2)
132+
mpmath_name = "harmonic"
84133
rules = {
85134
"HarmonicNumber[-1]": "ComplexInfinity",
86135
}
87136
summary_text = "Harmonic numbers"
88-
mpmath_name = "harmonic"
89137
sympy_name = "harmonic"
90138

91139

92140
class LinearRecurrence(Builtin):
93141
"""
94142
<url>:Linear recurrence with constant coefficients:
95-
https://en.wikipedia.org/wiki/Linear_recurrence_with_constant_coefficients</url>, <url>
96-
:WMA link:https://reference.wolfram.com/language/ref/LinearRecurrence.html</url>
143+
https://en.wikipedia.org/wiki/Linear_recurrence_with_constant_coefficients</url> (<url>
144+
:WMA link:https://reference.wolfram.com/language/ref/LinearRecurrence.html</url>)
97145
98146
<dl>
99147
<dt>'LinearRecurrence'[$ker$, $init$, $n$]
@@ -124,13 +172,15 @@ class LinearRecurrence(Builtin):
124172
"""
125173

126174
attributes = A_PROTECTED | A_READ_PROTECTED
127-
summary_text = "linear recurrence"
175+
eval_error = Builtin.generic_argument_error
176+
expected_args = 3
128177

129178
rules = {
130179
"LinearRecurrence[ker_List, init_List, n_Integer]": "Nest[Append[#, Reverse[ker] . Take[#, -Length[ker]]] &, init, n - Length[init]]",
131180
"LinearRecurrence[ker_List, init_List, {n_Integer?Positive}]": "LinearRecurrence[ker, init, n][[n]]",
132181
"LinearRecurrence[ker_List, init_List, {nmin_Integer?Positive, nmax_Integer?Positive}]": "LinearRecurrence[ker, init, nmax][[nmin;;nmax]]",
133182
}
183+
summary_text = "linear recurrence"
134184

135185

136186
# Note: WL allows StirlingS1[{2, 4, 6}, 2], but we don't (yet).
@@ -155,17 +205,18 @@ class StirlingS1(Builtin):
155205
"""
156206

157207
attributes = A_LISTABLE | A_PROTECTED
158-
208+
eval_error = Builtin.generic_argument_error
209+
expected_args = 2
210+
mpmath_name = "stirling1"
159211
nargs = {2}
160212
summary_text = "Stirling numbers of the first kind"
161213
sympy_name = "functions.combinatorial.stirling"
162-
mpmath_name = "stirling1"
163214

164215
def eval(self, n: Integer, m: Integer, evaluation: Evaluation):
165-
"%(name)s[n_Integer, m_Integer]"
166-
n_value = n.value
167-
m_value = m.value
168-
return Integer(stirling(n_value, m_value, kind=1, signed=True))
216+
"StirlingS1[n_Integer, m_Integer]"
217+
return Integer(
218+
tracing.run_sympy(stirling, n.value, m.value, kind=1, signed=True)
219+
)
169220

170221

171222
class StirlingS2(Builtin):
@@ -188,13 +239,13 @@ class StirlingS2(Builtin):
188239
"""
189240

190241
attributes = A_LISTABLE | A_PROTECTED
191-
nargs = {2}
242+
eval_error = Builtin.generic_argument_error
243+
expected_args = 2
192244
sympy_name = "functions.combinatorial.numbers.stirling"
193245
mpmath_name = "stirling2"
246+
nargs = {2}
194247
summary_text = "Stirling numbers of the second kind"
195248

196249
def eval(self, m: Integer, n: Integer, evaluation: Evaluation):
197-
"%(name)s[n_Integer, m_Integer]"
198-
n_value = n.value
199-
m_value = m.value
200-
return Integer(stirling(n_value, m_value, kind=2))
250+
"StirlingS2[n_Integer, m_Integer]"
251+
return Integer(tracing.run_sympy(stirling, n.value, m.value, kind=2))

mathics/eval/hyperbolic.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
Mathics3 builtins from mathics.core.numbers.hyperbolic
2+
Mathics3 builtins from mathics.builtin.numbers.hyperbolic
33
"""
44

55
from sympy import Symbol as SympySymbol

mathics/eval/intfns/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"""
2+
Evaluation functions associated with mathics.builtin.intfns.
3+
"""

0 commit comments

Comments
 (0)