Skip to content

Commit e5c5e83

Browse files
committed
Benchmark llvm backend
1 parent dc1877e commit e5c5e83

File tree

2 files changed

+64
-20
lines changed

2 files changed

+64
-20
lines changed

benchmarks/Lambdify.py

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
#!/usr/bin/env python
12
from time import clock
23
import numpy as np
34
import sympy as sp
45
import symengine as se
6+
import warnings
57

68
# Real-life example (ion speciation problem in water chemistry)
79

@@ -10,22 +12,63 @@
1012
args = np.concatenate((x, p))
1113
exp = sp.exp
1214
exprs = [x[0] + x[1] - x[4] + 36.252574322669, x[0] - x[2] + x[3] + 21.3219379611249, x[3] + x[5] - x[6] + 9.9011158998744, 2*x[3] + x[5] - x[7] + 18.190422234653, 3*x[3] + x[5] - x[8] + 24.8679190043357, 4*x[3] + x[5] - x[9] + 29.9336062089226, -x[10] + 5*x[3] + x[5] + 28.5520551531262, 2*x[0] + x[11] - 2*x[4] - 2*x[5] + 32.4401680272417, 3*x[1] - x[12] + x[5] + 34.9992934135095, 4*x[1] - x[13] + x[5] + 37.0716199972041, p[0] - p[1] + 2*p[10] + 2*p[11] - p[12] - 2*p[13] + p[2] + 2*p[5] + 2*p[6] + 2*p[7] + 2*p[8] + 2*p[9] - exp(x[0]) + exp(x[1]) - 2*exp(x[10]) - 2*exp(x[11]) + exp(x[12]) + 2*exp(x[13]) - exp(x[2]) - 2*exp(x[5]) - 2*exp(x[6]) - 2*exp(x[7]) - 2*exp(x[8]) - 2*exp(x[9]), -p[0] - p[1] - 15*p[10] - 2*p[11] - 3*p[12] - 4*p[13] - 4*p[2] - 3*p[3] - 2*p[4] - 3*p[6] - 6*p[7] - 9*p[8] - 12*p[9] + exp(x[0]) + exp(x[1]) + 15*exp(x[10]) + 2*exp(x[11]) + 3*exp(x[12]) + 4*exp(x[13]) + 4*exp(x[2]) + 3*exp(x[3]) + 2*exp(x[4]) + 3*exp(x[6]) + 6*exp(x[7]) + 9*exp(x[8]) + 12*exp(x[9]), -5*p[10] - p[2] - p[3] - p[6] - 2*p[7] - 3*p[8] - 4*p[9] + 5*exp(x[10]) + exp(x[2]) + exp(x[3]) + exp(x[6]) + 2*exp(x[7]) + 3*exp(x[8]) + 4*exp(x[9]), -p[1] - 2*p[11] - 3*p[12] - 4*p[13] - p[4] + exp(x[1]) + 2*exp(x[11]) + 3*exp(x[12]) + 4*exp(x[13]) + exp(x[4]), -p[10] - 2*p[11] - p[12] - p[13] - p[5] - p[6] - p[7] - p[8] - p[9] + exp(x[10]) + 2*exp(x[11]) + exp(x[12]) + exp(x[13]) + exp(x[5]) + exp(x[6]) + exp(x[7]) + exp(x[8]) + exp(x[9])]
13-
lmb_symengine = se.Lambdify(args, exprs)
14-
lmb_sympy = sp.lambdify(args, exprs)
15+
lmb_sp = sp.lambdify(args, exprs)
16+
lbm_se = se.Lambdify(args, exprs)
17+
lbm_se_llvm = se.Lambdify(args, exprs, backend='llvm')
1518

1619
inp = np.ones(28)
1720

18-
tim_symengine = clock()
19-
res_symengine = np.empty(len(exprs))
20-
for i in range(500):
21-
res_symengine = lmb_symengine(inp)
22-
#lmb_symengine.unsafe_real_real(inp, res_symengine)
23-
tim_symengine = clock() - tim_symengine
24-
2521
tim_sympy = clock()
2622
for i in range(500):
27-
res_sympy = lmb_sympy(*inp)
23+
res_sympy = lmb_sp(*inp)
2824
tim_sympy = clock() - tim_sympy
2925

30-
print('symengine speed-up factor (higher is better) vs sympy: %12.5g' %
31-
(tim_sympy/tim_symengine))
26+
tim_se = clock()
27+
res_se = np.empty(len(exprs))
28+
for i in range(500):
29+
res_se = lbm_se(inp)
30+
tim_se = clock() - tim_se
31+
32+
tim_se_llvm = clock()
33+
res_se_llvm = np.empty(len(exprs))
34+
for i in range(500):
35+
res_se_llvm = lbm_se_llvm(inp)
36+
tim_se_llvm = clock() - tim_se_llvm
37+
38+
39+
print('SymEngine (lambda double) speed-up factor (higher is better) vs sympy: %12.5g' %
40+
(tim_sympy/tim_se))
41+
42+
print('symengine (LLVM) speed-up factor (higher is better) vs sympy: %12.5g' %
43+
(tim_sympy/tim_se_llvm))
44+
45+
import itertools
46+
from functools import reduce
47+
from operator import mul
48+
49+
def ManualLLVM(inputs, *outputs):
50+
outputs_ravel = list(itertools.chain(*outputs))
51+
cb = se.Lambdify(inputs, outputs_ravel, backend="llvm")
52+
def func(*args):
53+
result = []
54+
n = np.empty(len(outputs_ravel))
55+
t = cb.unsafe_real(np.concatenate([arg.ravel() for arg in args]), n)
56+
start = 0
57+
for output in outputs:
58+
elems = reduce(mul, output.shape)
59+
result.append(n[start:start+elems].reshape(output.shape))
60+
start += elems
61+
return result
62+
return func
63+
64+
lbm_se_llvm_manual = ManualLLVM(args, np.array(exprs))
65+
tim_se_llvm_manual = clock()
66+
res_se_llvm_manual = np.empty(len(exprs))
67+
for i in range(500):
68+
res_se_llvm_manual = lbm_se_llvm_manual(inp)
69+
tim_se_llvm_manual = clock() - tim_se_llvm_manual
70+
print('symengine (ManualLLVM) speed-up factor (higher is better) vs sympy: %12.5g' %
71+
(tim_sympy/tim_se_llvm_manual))
72+
73+
if tim_se_llvm_manual < tim_se_llvm:
74+
warnings.warn("Cython code for Lambdify.__call__ is slow.")

symengine/lib/symengine_wrapper.pyx

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3386,7 +3386,7 @@ def Lambdify(args, *exprs, bool real=True, backend="lambda"):
33863386
return LambdaDouble(args, *exprs, real=real)
33873387

33883388

3389-
def LambdifyCSE(args, *exprs, real=True, cse=None, concatenate=None):
3389+
def LambdifyCSE(args, *exprs, cse=None, concatenate=None, **kwargs):
33903390
"""
33913391
Analogous with Lambdify but performs common subexpression elimination
33923392
internally. See docstring of Lambdify.
@@ -3395,13 +3395,14 @@ def LambdifyCSE(args, *exprs, real=True, cse=None, concatenate=None):
33953395
----------
33963396
args: iterable of symbols
33973397
exprs: iterable of expressions (with symbols from args)
3398-
real: bool (default: True)
33993398
cse: callback (default: None)
34003399
defaults to sympy.cse (see SymPy documentation)
34013400
concatenate: callback (default: numpy.concatenate)
34023401
Examples when not using numpy:
34033402
``lambda tup: tup[0]+list(tup[1])``
34043403
``lambda tup: tup[0]+array.array('d', tup[1])``
3404+
\*\*kwargs: Keyword arguments passed onto Lambdify
3405+
34053406
"""
34063407
if cse is None:
34073408
from sympy import cse
@@ -3424,16 +3425,16 @@ def LambdifyCSE(args, *exprs, real=True, cse=None, concatenate=None):
34243425
else:
34253426
raise NotImplementedError("n-dimensional output not yet supported.")
34263427
n_taken += size
3427-
lmb = Lambdify(tuple(args) + cse_symbs, *new_exprs, real=real)
3428-
cse_lambda = Lambdify(args, cse_exprs, real=real)
3429-
def cb(inp, out=None, **kwargs):
3430-
cse_vals = cse_lambda(inp, **kwargs)
3428+
lmb = Lambdify(tuple(args) + cse_symbs, *new_exprs, **kwargs)
3429+
cse_lambda = Lambdify(args, cse_exprs, **kwargs)
3430+
def cb(inp, out=None, **kw):
3431+
cse_vals = cse_lambda(inp, **kw)
34313432
new_inp = concatenate((inp, cse_vals))
3432-
return lmb(new_inp, out, **kwargs)
3433+
return lmb(new_inp, out, **kw)
34333434

34343435
return cb
34353436
else:
3436-
return Lambdify(args, *exprs, real=real)
3437+
return Lambdify(args, *exprs, **kwargs)
34373438

34383439

34393440
def has_symbol(obj, symbol=None):

0 commit comments

Comments
 (0)