Skip to content

Commit 3f4b0df

Browse files
authored
Merge pull request #1161 from mathics/fixes4Compile
Implementing Compile for non compilable llvmlite functions as python functions
2 parents e452038 + 974e332 commit 3f4b0df

4 files changed

Lines changed: 769 additions & 543 deletions

File tree

CHANGES.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,13 @@ Enhancements
2121
Miscellanea
2222
+++++++++++
2323

24-
A pass was made to improve Microsoft Windows compatability and testing
24+
* A pass was made to improve Microsoft Windows compatability and testing
2525
Windows under MSYS.
2626

27+
* Mathics functions are accepted by ``Compile[]``. The return value or type will be
28+
``CompiledFunction``
29+
30+
2731
2.0.0
2832
-----
2933

mathics/builtin/compilation.py

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

33
from mathics.builtin.base import Builtin, BoxConstruct
4+
from mathics.core.evaluation import Evaluation
45
from mathics.core.expression import (
56
Atom,
67
Expression,
@@ -41,8 +42,7 @@ class Compile(Builtin):
4142
: Duplicate parameter x found in {{x, _Real}, {x, _Integer}}.
4243
= Compile[{{x, _Real}, {x, _Integer}}, Sin[x + y]]
4344
#> cf = Compile[{{x, _Real}, {y, _Integer}}, Sin[x + z]]
44-
: Expression Sin[x + z] could not be compiled.
45-
= Function[{Global`x, Global`y}, Sin[x + z]]
45+
= CompiledFunction[{x, y}, Sin[x + z], -CompiledCode-]
4646
#> cf = Compile[{{x, _Real}, {y, _Integer}}, Sin[x + y]]
4747
= CompiledFunction[{x, y}, Sin[x + y], -CompiledCode-]
4848
#> cf[1, 2]
@@ -58,10 +58,10 @@ class Compile(Builtin):
5858
#> cf[0, -2]
5959
= 0.5
6060
61-
Loops and variable assignments are not yet supported
61+
Loops and variable assignments are supported as python (not llvmlite)
62+
functions
6263
>> Compile[{{a, _Integer}, {b, _Integer}}, While[b != 0, {a, b} = {b, Mod[a, b]}]; a] (* GCD of a, b *)
63-
: Expression While[b != 0, {a, b} = {b, Mod[a, b]}] ; a could not be compiled.
64-
= Function[{Global`a, Global`b}, While[b != 0, {a, b} = {b, Mod[a, b]}] ; a]
64+
= CompiledFunction[{a, b}, a, -CompiledCode-]
6565
"""
6666

6767
requires = ("llvmlite",)
@@ -123,9 +123,29 @@ def apply(self, vars, expr, evaluation):
123123
try:
124124
cfunc = _compile(expr, args)
125125
except CompileError:
126+
cfunc = None
127+
128+
if cfunc is None:
129+
try:
130+
131+
def _pythonized_mathics_expr(*x):
132+
inner_evaluation = Evaluation(definitions=evaluation.definitions)
133+
vars = dict(list(zip(names, x[: len(names)])))
134+
pyexpr = expr.replace_vars(vars)
135+
pyexpr = Expression("N", pyexpr).evaluate(inner_evaluation)
136+
res = pyexpr.to_python(n_evaluation=inner_evaluation)
137+
return res
138+
139+
# TODO: check if we can use numba to compile this...
140+
cfunc = _pythonized_mathics_expr
141+
except Exception as e:
142+
cfunc = None
143+
144+
if cfunc is None:
126145
evaluation.message("Compile", "comperr", expr)
127146
args = Expression("List", *names)
128147
return Expression("Function", args, expr)
148+
129149
code = CompiledCode(cfunc, args)
130150
arg_names = Expression("List", *(Symbol(arg.name) for arg in args))
131151
return Expression("CompiledFunction", arg_names, expr, code)

mathics/builtin/functional.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,14 @@ def apply_named(self, vars, body, args, evaluation):
8383

8484
args = args.get_sequence()
8585
if len(vars) > len(args):
86-
evaluation.message('Function', 'fpct', )
86+
evaluation.message('Function', 'fpct')
8787
else:
8888
vars = dict(list(zip((
8989
var.get_name() for var in vars), args[:len(vars)])))
90-
return body.replace_vars(vars)
90+
try:
91+
return body.replace_vars(vars)
92+
except:
93+
return
9194

9295
# Not sure if DRY is possible here...
9396
def apply_named_attr(self, vars, body, attr, args, evaluation):
@@ -99,12 +102,14 @@ def apply_named_attr(self, vars, body, attr, args, evaluation):
99102

100103
args = args.get_sequence()
101104
if len(vars) > len(args):
102-
evaluation.message('Function', 'fpct', )
105+
evaluation.message('Function', 'fpct')
103106
else:
104107
vars = dict(list(zip((
105108
var.get_name() for var in vars), args[:len(vars)])))
106-
return body.replace_vars(vars)
107-
109+
try:
110+
return body.replace_vars(vars)
111+
except:
112+
return
108113

109114
class Slot(Builtin):
110115
"""

0 commit comments

Comments
 (0)