Skip to content

Commit 494565a

Browse files
authored
Merge pull request #1160 from mathics/nintegrate
basic implementation of NIntegrate
2 parents e8a5440 + 910bdec commit 494565a

7 files changed

Lines changed: 610 additions & 86 deletions

File tree

CHANGES.rst

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,45 @@ CHANGES
44
2.1.0
55
-----
66

7-
New builtins
8-
++++++++++++++
7+
New builtins
8+
++++++++++++
99

10+
* ``ArcTanh``
1011
* ``ByteArray``
11-
* ``FileNames``
1212
* ``CreateFile``
1313
* ``CreateTemporary``
14-
14+
* ``FileNames``
15+
* ``NIntegrate``
1516

1617
Enhancements
1718
++++++++++++
1819

20+
* the Mathics version is checked for builtin modules at load time. A message is given when a builtin doesn't load.
21+
* Automatic detection for the best strategy to numeric evaluation of constants.
1922
* ``FileNameJoin`` - implement ``OperatingSystem`` option
2023
* Mathics functions are accepted by ``Compile[]``. The return value or type will be
21-
``CompiledFunction``
24+
``Compiled[] and CompiledFunction[]`` every expression can have a compiled form,
25+
as a Python function.
2226
* ``EqualQ[]`` now compares complex against other numbers properly.
2327

28+
29+
Bug fixes
30+
+++++++++
31+
32+
* TeXForm for integrals are now properly formatted.
33+
34+
35+
Pymathics Modules
36+
+++++++++++++++++
37+
38+
* Pymathics modules now can run initialization code when are loaded.
39+
* The ``builtins`` list is not hardliked to the library anymore. This simplifies
40+
the loading and reloading of pymathics modules.
41+
* Decoupling of BoxConstructors from the library. Now are defined at the
42+
level of the definition objects. This is useful for customizing the
43+
Graphics output if it is available.
44+
45+
2446
Miscellanea
2547
+++++++++++
2648

mathics/builtin/compilation.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import ctypes
22

3+
from mathics.version import __version__ # noqa used in loading to check consistency.
34
from mathics.builtin.base import Builtin, BoxConstruct
45
from mathics.core.evaluation import Evaluation
56
from mathics.core.expression import (
@@ -10,7 +11,7 @@
1011
from_python,
1112
Integer,
1213
)
13-
from mathics.version import __version__ # noqa used in loading to check consistency.
14+
from types import FunctionType
1415

1516

1617
class Compile(Builtin):
@@ -42,7 +43,7 @@ class Compile(Builtin):
4243
: Duplicate parameter x found in {{x, _Real}, {x, _Integer}}.
4344
= Compile[{{x, _Real}, {x, _Integer}}, Sin[x + y]]
4445
#> cf = Compile[{{x, _Real}, {y, _Integer}}, Sin[x + z]]
45-
= CompiledFunction[{x, y}, Sin[x + z], -CompiledCode-]
46+
= CompiledFunction[{x, y}, Sin[x + z], -PythonizedCode-]
4647
#> cf = Compile[{{x, _Real}, {y, _Integer}}, Sin[x + y]]
4748
= CompiledFunction[{x, y}, Sin[x + y], -CompiledCode-]
4849
#> cf[1, 2]
@@ -61,7 +62,7 @@ class Compile(Builtin):
6162
Loops and variable assignments are supported as python (not llvmlite)
6263
functions
6364
>> Compile[{{a, _Integer}, {b, _Integer}}, While[b != 0, {a, b} = {b, Mod[a, b]}]; a] (* GCD of a, b *)
64-
= CompiledFunction[{a, b}, a, -CompiledCode-]
65+
= CompiledFunction[{a, b}, a, -PythonizedCode-]
6566
"""
6667

6768
requires = ("llvmlite",)
@@ -138,7 +139,7 @@ def _pythonized_mathics_expr(*x):
138139

139140
# TODO: check if we can use numba to compile this...
140141
cfunc = _pythonized_mathics_expr
141-
except Exception as e:
142+
except Exception:
142143
cfunc = None
143144

144145
if cfunc is None:
@@ -158,6 +159,8 @@ def __init__(self, cfunc, args, **kwargs):
158159
self.args = args
159160

160161
def __str__(self):
162+
if type(self.cfunc) is FunctionType:
163+
return "-PythonizedCode-"
161164
return "-CompiledCode-"
162165

163166
def do_copy(self):
@@ -182,7 +185,7 @@ def __hash__(self):
182185
return hash(("CompiledCode", ctypes.addressof(self.cfunc))) # XXX hack
183186

184187
def atom_to_boxes(self, f, evaluation):
185-
return CompiledCodeBox(String("Nocode"), evaluation=evaluation)
188+
return CompiledCodeBox(String(self.__str__()), evaluation=evaluation)
186189

187190

188191
class CompiledCodeBox(BoxConstruct):
@@ -191,19 +194,19 @@ class CompiledCodeBox(BoxConstruct):
191194
"""
192195

193196
def boxes_to_text(self, leaves=None, **options):
194-
if not leaves:
197+
if leaves is None:
195198
leaves = self._leaves
196-
return "-CompiledCode-"
199+
return leaves[0].value
197200

198201
def boxes_to_xml(self, leaves=None, **options):
199-
if not leaves:
202+
if leaves is None:
200203
leaves = self._leaves
201-
return "-CompiledCode-"
204+
return leaves[0].value
202205

203206
def boxes_to_tex(self, leaves=None, **options):
204-
if not leaves:
207+
if leaves is None:
205208
leaves = self._leaves
206-
return "-CompiledCode-"
209+
return leaves[0].value
207210

208211

209212
class CompiledFunction(Builtin):

mathics/builtin/exptrig.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,7 @@ class ArcTanh(_MPMathFunction):
545545

546546
sympy_name = "atanh"
547547
mpmath_name = "atanh"
548+
numpy_name = "arctanh"
548549

549550
rules = {
550551
"Derivative[1][ArcTanh]": "1/(1-#^2)&",

mathics/builtin/functional.py

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -56,61 +56,68 @@ class Function(PostfixOperator):
5656
= 3
5757
"""
5858

59-
operator = '&'
59+
operator = "&"
6060
precedence = 90
61-
attributes = ('HoldAll',)
61+
attributes = ("HoldAll",)
6262

6363
messages = {
64-
'slot': "`1` should contain a positive integer.",
65-
'slotn': "Slot number `1` cannot be filled.",
66-
'fpct': "Too many parameters to be filled.",
67-
'iassoc': "Invalid association item `1`"
64+
"slot": "`1` should contain a positive integer.",
65+
"slotn": "Slot number `1` cannot be filled.",
66+
"fpct": "Too many parameters to be filled.",
67+
"iassoc": "Invalid association item `1`",
6868
}
6969

7070
def apply_slots(self, body, args, evaluation):
71-
'Function[body_][args___]'
71+
"Function[body_][args___]"
7272

73-
args = list(chain([Expression('Function', body)], args.get_sequence()))
73+
args = list(chain([Expression("Function", body)], args.get_sequence()))
7474
return body.replace_slots(args, evaluation)
7575

7676
def apply_named(self, vars, body, args, evaluation):
77-
'Function[vars_, body_][args___]'
77+
"Function[vars_, body_][args___]"
7878

79-
if vars.has_form('List', None):
79+
if vars.has_form("List", None):
8080
vars = vars.leaves
8181
else:
8282
vars = [vars]
8383

84+
# print([v.get_head_name()=="System`Pattern" or v.is_symbol() for v in vars])
8485
args = args.get_sequence()
8586
if len(vars) > len(args):
86-
evaluation.message('Function', 'fpct')
87+
evaluation.message("Function", "fpct")
8788
else:
88-
vars = dict(list(zip((
89-
var.get_name() for var in vars), args[:len(vars)])))
89+
# Allows to use both symbols or Blank patterns (z_Complex) to state the symbol.
90+
# this is not included in WL, and here does not have any impact, but it is needed for
91+
# translating the function to a compiled version.
92+
var_names = (
93+
var.get_name() if var.is_symbol() else var.leaves[0].get_name()
94+
for var in vars
95+
)
96+
vars = dict(list(zip(var_names, args[: len(vars)])))
9097
try:
9198
return body.replace_vars(vars)
9299
except:
93100
return
94101

95102
# Not sure if DRY is possible here...
96103
def apply_named_attr(self, vars, body, attr, args, evaluation):
97-
'Function[vars_, body_, attr_][args___]'
98-
if vars.has_form('List', None):
104+
"Function[vars_, body_, attr_][args___]"
105+
if vars.has_form("List", None):
99106
vars = vars.leaves
100107
else:
101108
vars = [vars]
102109

103110
args = args.get_sequence()
104111
if len(vars) > len(args):
105-
evaluation.message('Function', 'fpct')
112+
evaluation.message("Function", "fpct")
106113
else:
107-
vars = dict(list(zip((
108-
var.get_name() for var in vars), args[:len(vars)])))
114+
vars = dict(list(zip((var.get_name() for var in vars), args[: len(vars)])))
109115
try:
110116
return body.replace_vars(vars)
111117
except:
112118
return
113119

120+
114121
class Slot(Builtin):
115122
"""
116123
<dl>
@@ -140,13 +147,14 @@ class Slot(Builtin):
140147
= #0
141148
"""
142149

143-
attributes = ('NHoldAll',)
150+
attributes = ("NHoldAll",)
144151

145152
rules = {
146-
'Slot[]': 'Slot[1]',
147-
'MakeBoxes[Slot[n_Integer?NonNegative],'
148-
' f:StandardForm|TraditionalForm|InputForm|OutputForm]': (
149-
'"#" <> ToString[n]'),
153+
"Slot[]": "Slot[1]",
154+
"MakeBoxes[Slot[n_Integer?NonNegative],"
155+
" f:StandardForm|TraditionalForm|InputForm|OutputForm]": (
156+
'"#" <> ToString[n]'
157+
),
150158
}
151159

152160

@@ -171,13 +179,12 @@ class SlotSequence(Builtin):
171179
= ##1
172180
"""
173181

174-
attributes = ('NHoldAll',)
182+
attributes = ("NHoldAll",)
175183

176184
rules = {
177-
'SlotSequence[]': 'SlotSequence[1]',
178-
'MakeBoxes[SlotSequence[n_Integer?Positive],'
179-
'f:StandardForm|TraditionalForm|InputForm|OutputForm]': (
180-
'"##" <> ToString[n]'),
185+
"SlotSequence[]": "SlotSequence[1]",
186+
"MakeBoxes[SlotSequence[n_Integer?Positive],"
187+
"f:StandardForm|TraditionalForm|InputForm|OutputForm]": ('"##" <> ToString[n]'),
181188
}
182189

183190

@@ -202,14 +209,14 @@ class Composition(Builtin):
202209
= Composition[f, g, h]
203210
"""
204211

205-
attributes = ('Flat', 'OneIdentity')
212+
attributes = ("Flat", "OneIdentity")
206213

207214
rules = {
208-
'Composition[]': 'Identity',
215+
"Composition[]": "Identity",
209216
}
210217

211218
def apply(self, functions, args, evaluation):
212-
'Composition[functions__][args___]'
219+
"Composition[functions__][args___]"
213220

214221
functions = functions.get_sequence()
215222
args = args.get_sequence()
@@ -232,5 +239,5 @@ class Identity(Builtin):
232239
"""
233240

234241
rules = {
235-
'Identity[x_]': 'x',
242+
"Identity[x_]": "x",
236243
}

0 commit comments

Comments
 (0)