Skip to content

Commit 8aff3c8

Browse files
authored
Merge pull request #112 from bjodah/heterogeneous-Lambdify
Heterogeneous output in Lambdify
2 parents 308403b + 0154f9c commit 8aff3c8

17 files changed

+800
-544
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,4 @@ symengine.egg-info/
3434

3535
# Temp files
3636
*~
37+
.eggs/

.travis.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ env:
3131

3232
# Release builds:
3333
- PYTHON_VERSION="2.7" BUILD_SHARED_LIBS="yes"
34-
- PYTHON_VERSION="2.7" WITH_MPFR="yes" INTEGER_CLASS="gmpxx"
34+
- PYTHON_VERSION="2.7" WITH_MPFR="yes" INTEGER_CLASS="gmpxx" WITH_NUMPY="no"
3535
- PYTHON_VERSION="3.3" WITH_MPC="yes"
36-
- PYTHON_VERSION="3.4" WITH_MPFR="yes" WITH_NUMPY="yes"
37-
- PYTHON_VERSION="3.5" WITH_MPC="yes" WITH_NUMPY="yes"
38-
- PYTHON_VERSION="3.6" WITH_MPC="yes" WITH_NUMPY="yes"
36+
- PYTHON_VERSION="3.4" WITH_MPFR="yes"
37+
- PYTHON_VERSION="3.5" WITH_MPC="yes"
38+
- PYTHON_VERSION="3.6" WITH_MPC="yes"
3939

4040
matrix:
4141
exclude:
@@ -63,16 +63,16 @@ matrix:
6363
- clang
6464
- libstdc++-4.8-dev
6565
- binutils-dev
66-
- env: BUILD_TYPE="Release" PYTHON_VERSION="2.7"
66+
- env: BUILD_TYPE="Release" PYTHON_VERSION="2.7" WITH_NUMPY="no"
6767
compiler: clang
6868
os: linux
6969
- env: BUILD_TYPE="Debug" PYTHON_VERSION="2.7"
7070
compiler: clang
7171
os: osx
72-
- env: BUILD_TYPE="Release" PYTHON_VERSION="3.5"
72+
- env: BUILD_TYPE="Release" PYTHON_VERSION="3.5" WITH_NUMPY="no"
7373
compiler: clang
7474
os: osx
75-
- env: BUILD_TYPE="Debug" PYTHON_VERSION="2.7" WITH_NUMPY="yes"
75+
- env: BUILD_TYPE="Debug" PYTHON_VERSION="2.7" WITH_NUMPY="no"
7676
compiler: gcc
7777
os: osx
7878
- env: BUILD_TYPE="Release" PYTHON_VERSION="3.5"

CMakeLists.txt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ include_directories(${SYMENGINE_INCLUDE_DIRS})
1313
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
1414
find_package(Python REQUIRED)
1515
find_package(Cython REQUIRED)
16-
1716
include_directories(${PYTHON_INCLUDE_PATH})
1817

1918
if (MINGW AND ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8"))
@@ -59,6 +58,16 @@ else()
5958
set(HAVE_SYMENGINE_LLVM False)
6059
endif()
6160

61+
if(WITH_NUMPY)
62+
set(WITH_NUMPY True CACHE BOOL INTERNAL)
63+
find_package(NumPy REQUIRED)
64+
include_directories(${NUMPY_INCLUDE_PATH})
65+
set(HAVE_NUMPY True)
66+
else()
67+
set(WITH_NUMPY False CACHE BOOL INTERNAL)
68+
set(HAVE_NUMPY False)
69+
endif()
70+
6271

6372
message("CMAKE_BUILD_TYPE : ${CMAKE_BUILD_TYPE}")
6473
message("CMAKE_CXX_FLAGS_RELEASE : ${CMAKE_CXX_FLAGS_RELEASE}")
@@ -68,6 +77,7 @@ message("HAVE_SYMENGINE_MPC : ${HAVE_SYMENGINE_MPC}")
6877
message("HAVE_SYMENGINE_PIRANHA : ${HAVE_SYMENGINE_PIRANHA}")
6978
message("HAVE_SYMENGINE_FLINT : ${HAVE_SYMENGINE_FLINT}")
7079
message("HAVE_SYMENGINE_LLVM : ${HAVE_SYMENGINE_LLVM}")
80+
message("HAVE_NUMPY : ${HAVE_NUMPY}")
7181

7282
message("Copying source of python wrappers into: ${CMAKE_CURRENT_BINARY_DIR}")
7383
file(COPY symengine/ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/symengine)

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,10 @@ Additional options to setup.py are
4343
--define="var1=value1;var2=value2" # Give options to CMake
4444
--inplace # Build the extension in source tree
4545

46-
Standard options to setup.py like `--user`, `--prefix` can be used to configure install location
46+
Standard options to setup.py like `--user`, `--prefix` can be used to
47+
configure install location. NumPy is used if found by default, if you wish
48+
to make your choice of NumPy use explicit: then add
49+
e.g. ``WITH_NUMPY=False`` to ``--define``.
4750

4851
Use SymEngine from Python as follows:
4952

appveyor.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ environment:
2929
- BUILD_TYPE: "Debug"
3030
COMPILER: MinGW-w64
3131
PYTHON_VERSION: 35-x64
32+
WITH_NUMPY: no
3233

3334
install:
3435
- set PYTHON_SOURCE_DIR=%CD%
@@ -63,6 +64,7 @@ install:
6364
- set PATH=C:\Python%PYTHON_VERSION%;C:\Python%PYTHON_VERSION%\Scripts;%PATH%
6465
- pip install nose pytest sympy
6566
- pip install --install-option="--no-cython-compile" cython
67+
- if NOT [%WITH_NUMPY%]==[no] pip install numpy
6668

6769
- set /p commit=<symengine_version.txt
6870
- cd symengine-cpp

benchmarks/6_links_rhs.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[y0, y1, y2, y3, y4, y5, y6, l0*m1*y1**2*cos(x1) + l0*m2*y1**2*cos(x1) + l0*m3*y1**2*cos(x1) + l0*m4*y1**2*cos(x1) + l0*m5*y1**2*cos(x1) + l0*m6*y1**2*cos(x1) + l1*m2*y2**2*cos(x2) + l1*m3*y2**2*cos(x2) + l1*m4*y2**2*cos(x2) + l1*m5*y2**2*cos(x2) + l1*m6*y2**2*cos(x2) + l2*m3*y3**2*cos(x3) + l2*m4*y3**2*cos(x3) + l2*m5*y3**2*cos(x3) + l2*m6*y3**2*cos(x3) + l3*m4*y4**2*cos(x4) + l3*m5*y4**2*cos(x4) + l3*m6*y4**2*cos(x4) + l4*m5*y5**2*cos(x5) + l4*m6*y5**2*cos(x5) + l5*m6*y6**2*cos(x6), -g*l0*m1*cos(x1) - g*l0*m2*cos(x1) - g*l0*m3*cos(x1) - g*l0*m4*cos(x1) - g*l0*m5*cos(x1) - g*l0*m6*cos(x1) + l0*l1*m2*y2**2*(-sin(x1)*cos(x2) + sin(x2)*cos(x1)) + l0*l1*m3*y2**2*(-sin(x1)*cos(x2) + sin(x2)*cos(x1)) + l0*l1*m4*y2**2*(-sin(x1)*cos(x2) + sin(x2)*cos(x1)) + l0*l1*m5*y2**2*(-sin(x1)*cos(x2) + sin(x2)*cos(x1)) + l0*l1*m6*y2**2*(-sin(x1)*cos(x2) + sin(x2)*cos(x1)) + l0*l2*m3*y3**2*(-sin(x1)*cos(x3) + sin(x3)*cos(x1)) + l0*l2*m4*y3**2*(-sin(x1)*cos(x3) + sin(x3)*cos(x1)) + l0*l2*m5*y3**2*(-sin(x1)*cos(x3) + sin(x3)*cos(x1)) + l0*l2*m6*y3**2*(-sin(x1)*cos(x3) + sin(x3)*cos(x1)) + l0*l3*m4*y4**2*(-sin(x1)*cos(x4) + sin(x4)*cos(x1)) + l0*l3*m5*y4**2*(-sin(x1)*cos(x4) + sin(x4)*cos(x1)) + l0*l3*m6*y4**2*(-sin(x1)*cos(x4) + sin(x4)*cos(x1)) + l0*l4*m5*y5**2*(-sin(x1)*cos(x5) + sin(x5)*cos(x1)) + l0*l4*m6*y5**2*(-sin(x1)*cos(x5) + sin(x5)*cos(x1)) + l0*l5*m6*y6**2*(-sin(x1)*cos(x6) + sin(x6)*cos(x1)), -g*l1*m2*cos(x2) - g*l1*m3*cos(x2) - g*l1*m4*cos(x2) - g*l1*m5*cos(x2) - g*l1*m6*cos(x2) + l0*l1*m2*y1**2*(sin(x1)*cos(x2) - sin(x2)*cos(x1)) + l0*l1*m3*y1**2*(sin(x1)*cos(x2) - sin(x2)*cos(x1)) + l0*l1*m4*y1**2*(sin(x1)*cos(x2) - sin(x2)*cos(x1)) + l0*l1*m5*y1**2*(sin(x1)*cos(x2) - sin(x2)*cos(x1)) + l0*l1*m6*y1**2*(sin(x1)*cos(x2) - sin(x2)*cos(x1)) + l1*l2*m3*y3**2*(-sin(x2)*cos(x3) + sin(x3)*cos(x2)) + l1*l2*m4*y3**2*(-sin(x2)*cos(x3) + sin(x3)*cos(x2)) + l1*l2*m5*y3**2*(-sin(x2)*cos(x3) + sin(x3)*cos(x2)) + l1*l2*m6*y3**2*(-sin(x2)*cos(x3) + sin(x3)*cos(x2)) + l1*l3*m4*y4**2*(-sin(x2)*cos(x4) + sin(x4)*cos(x2)) + l1*l3*m5*y4**2*(-sin(x2)*cos(x4) + sin(x4)*cos(x2)) + l1*l3*m6*y4**2*(-sin(x2)*cos(x4) + sin(x4)*cos(x2)) + l1*l4*m5*y5**2*(-sin(x2)*cos(x5) + sin(x5)*cos(x2)) + l1*l4*m6*y5**2*(-sin(x2)*cos(x5) + sin(x5)*cos(x2)) + l1*l5*m6*y6**2*(-sin(x2)*cos(x6) + sin(x6)*cos(x2)), -g*l2*m3*cos(x3) - g*l2*m4*cos(x3) - g*l2*m5*cos(x3) - g*l2*m6*cos(x3) + l0*l2*m3*y1**2*(sin(x1)*cos(x3) - sin(x3)*cos(x1)) + l0*l2*m4*y1**2*(sin(x1)*cos(x3) - sin(x3)*cos(x1)) + l0*l2*m5*y1**2*(sin(x1)*cos(x3) - sin(x3)*cos(x1)) + l0*l2*m6*y1**2*(sin(x1)*cos(x3) - sin(x3)*cos(x1)) + l1*l2*m3*y2**2*(sin(x2)*cos(x3) - sin(x3)*cos(x2)) + l1*l2*m4*y2**2*(sin(x2)*cos(x3) - sin(x3)*cos(x2)) + l1*l2*m5*y2**2*(sin(x2)*cos(x3) - sin(x3)*cos(x2)) + l1*l2*m6*y2**2*(sin(x2)*cos(x3) - sin(x3)*cos(x2)) + l2*l3*m4*y4**2*(-sin(x3)*cos(x4) + sin(x4)*cos(x3)) + l2*l3*m5*y4**2*(-sin(x3)*cos(x4) + sin(x4)*cos(x3)) + l2*l3*m6*y4**2*(-sin(x3)*cos(x4) + sin(x4)*cos(x3)) + l2*l4*m5*y5**2*(-sin(x3)*cos(x5) + sin(x5)*cos(x3)) + l2*l4*m6*y5**2*(-sin(x3)*cos(x5) + sin(x5)*cos(x3)) + l2*l5*m6*y6**2*(-sin(x3)*cos(x6) + sin(x6)*cos(x3)), -g*l3*m4*cos(x4) - g*l3*m5*cos(x4) - g*l3*m6*cos(x4) + l0*l3*m4*y1**2*(sin(x1)*cos(x4) - sin(x4)*cos(x1)) + l0*l3*m5*y1**2*(sin(x1)*cos(x4) - sin(x4)*cos(x1)) + l0*l3*m6*y1**2*(sin(x1)*cos(x4) - sin(x4)*cos(x1)) + l1*l3*m4*y2**2*(sin(x2)*cos(x4) - sin(x4)*cos(x2)) + l1*l3*m5*y2**2*(sin(x2)*cos(x4) - sin(x4)*cos(x2)) + l1*l3*m6*y2**2*(sin(x2)*cos(x4) - sin(x4)*cos(x2)) + l2*l3*m4*y3**2*(sin(x3)*cos(x4) - sin(x4)*cos(x3)) + l2*l3*m5*y3**2*(sin(x3)*cos(x4) - sin(x4)*cos(x3)) + l2*l3*m6*y3**2*(sin(x3)*cos(x4) - sin(x4)*cos(x3)) + l3*l4*m5*y5**2*(-sin(x4)*cos(x5) + sin(x5)*cos(x4)) + l3*l4*m6*y5**2*(-sin(x4)*cos(x5) + sin(x5)*cos(x4)) + l3*l5*m6*y6**2*(-sin(x4)*cos(x6) + sin(x6)*cos(x4)), -g*l4*m5*cos(x5) - g*l4*m6*cos(x5) + l0*l4*m5*y1**2*(sin(x1)*cos(x5) - sin(x5)*cos(x1)) + l0*l4*m6*y1**2*(sin(x1)*cos(x5) - sin(x5)*cos(x1)) + l1*l4*m5*y2**2*(sin(x2)*cos(x5) - sin(x5)*cos(x2)) + l1*l4*m6*y2**2*(sin(x2)*cos(x5) - sin(x5)*cos(x2)) + l2*l4*m5*y3**2*(sin(x3)*cos(x5) - sin(x5)*cos(x3)) + l2*l4*m6*y3**2*(sin(x3)*cos(x5) - sin(x5)*cos(x3)) + l3*l4*m5*y4**2*(sin(x4)*cos(x5) - sin(x5)*cos(x4)) + l3*l4*m6*y4**2*(sin(x4)*cos(x5) - sin(x5)*cos(x4)) + l4*l5*m6*y6**2*(-sin(x5)*cos(x6) + sin(x6)*cos(x5)), -g*l5*m6*cos(x6) + l0*l5*m6*y1**2*(sin(x1)*cos(x6) - sin(x6)*cos(x1)) + l1*l5*m6*y2**2*(sin(x2)*cos(x6) - sin(x6)*cos(x2)) + l2*l5*m6*y3**2*(sin(x3)*cos(x6) - sin(x6)*cos(x3)) + l3*l5*m6*y4**2*(sin(x4)*cos(x6) - sin(x6)*cos(x4)) + l4*l5*m6*y5**2*(sin(x5)*cos(x6) - sin(x6)*cos(x5))]

benchmarks/Lambdify.py

Lines changed: 84 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,92 @@
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)
1515

16-
inp = np.ones(28)
16+
lmb_sp = sp.lambdify(args, exprs, modules='math')
17+
lmb_se = se.Lambdify(args, exprs)
18+
lmb_se_cse = se.LambdifyCSE(args, exprs)
19+
lmb_se_llvm = se.Lambdify(args, exprs, backend='llvm')
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
21+
inp = np.ones(28)
2422

23+
lmb_sp(*inp)
2524
tim_sympy = clock()
2625
for i in range(500):
27-
res_sympy = lmb_sympy(*inp)
26+
res_sympy = lmb_sp(*inp)
2827
tim_sympy = clock() - tim_sympy
2928

30-
print('symengine speed-up factor (higher is better) vs sympy: %12.5g' %
31-
(tim_sympy/tim_symengine))
29+
lmb_se(inp)
30+
tim_se = clock()
31+
res_se = np.empty(len(exprs))
32+
for i in range(500):
33+
res_se = lmb_se(inp)
34+
tim_se = clock() - tim_se
35+
36+
lmb_se_cse(inp)
37+
tim_se_cse = clock()
38+
res_se_cse = np.empty(len(exprs))
39+
for i in range(500):
40+
res_se_cse = lmb_se_cse(inp)
41+
tim_se_cse = clock() - tim_se_cse
42+
43+
lmb_se_llvm(inp)
44+
tim_se_llvm = clock()
45+
res_se_llvm = np.empty(len(exprs))
46+
for i in range(500):
47+
res_se_llvm = lmb_se_llvm(inp)
48+
tim_se_llvm = clock() - tim_se_llvm
49+
50+
51+
print('SymEngine (lambda double) speed-up factor (higher is better) vs sympy: %12.5g' %
52+
(tim_sympy/tim_se))
53+
54+
print('symengine (lambda double + CSE) speed-up factor (higher is better) vs sympy: %12.5g' %
55+
(tim_sympy/tim_se_cse))
56+
57+
print('symengine (LLVM) speed-up factor (higher is better) vs sympy: %12.5g' %
58+
(tim_sympy/tim_se_llvm))
59+
60+
import itertools
61+
from functools import reduce
62+
from operator import mul
63+
64+
def ManualLLVM(inputs, *outputs):
65+
outputs_ravel = list(itertools.chain(*outputs))
66+
cb = se.Lambdify(inputs, outputs_ravel, backend="llvm")
67+
def func(*args):
68+
result = []
69+
n = np.empty(len(outputs_ravel))
70+
t = cb.unsafe_real(np.concatenate([arg.ravel() for arg in args]), n)
71+
start = 0
72+
for output in outputs:
73+
elems = reduce(mul, output.shape)
74+
result.append(n[start:start+elems].reshape(output.shape))
75+
start += elems
76+
return result
77+
return func
78+
79+
lmb_se_llvm_manual = ManualLLVM(args, np.array(exprs))
80+
lmb_se_llvm_manual(inp)
81+
tim_se_llvm_manual = clock()
82+
res_se_llvm_manual = np.empty(len(exprs))
83+
for i in range(500):
84+
res_se_llvm_manual = lmb_se_llvm_manual(inp)
85+
tim_se_llvm_manual = clock() - tim_se_llvm_manual
86+
print('symengine (ManualLLVM) speed-up factor (higher is better) vs sympy: %12.5g' %
87+
(tim_sympy/tim_se_llvm_manual))
88+
89+
if tim_se_llvm_manual < tim_se_llvm:
90+
warnings.warn("Cython code for Lambdify.__call__ is slow.")
91+
92+
import setuptools
93+
import pyximport
94+
pyximport.install()
95+
from Lambdify_reference import _benchmark_reference_for_Lambdify as lmb_ref
96+
97+
lmb_ref(inp)
98+
tim_ref = clock()
99+
for i in range(500):
100+
res_ref = lmb_ref(inp)
101+
tim_ref = clock() - tim_ref
102+
print('Hard-coded Cython code speed-up factor (higher is better) vs sympy: %12.5g' %
103+
(tim_sympy/tim_ref))

benchmarks/Lambdify_reference.pyx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Benchmark reference:
2+
cimport numpy as cnp
3+
import numpy as np
4+
from libc.math cimport exp as exp_
5+
6+
def _benchmark_reference_for_Lambdify(cnp.ndarray[cnp.float64_t] x):
7+
cdef cnp.ndarray[cnp.float64_t] out = np.empty(14)
8+
cdef double * data = <double *>out.data
9+
data[:] = [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, x[14+0] - x[14+1] + 2*x[14+10] + 2*x[14+11] - x[14+12] - 2*x[14+13] + x[14+2] + 2*x[14+5] + 2*x[14+6] + 2*x[14+7] + 2*x[14+8] + 2*x[14+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]), -x[14+0] - x[14+1] - 15*x[14+10] - 2*x[14+11] - 3*x[14+12] - 4*x[14+13] - 4*x[14+2] - 3*x[14+3] - 2*x[14+4] - 3*x[14+6] - 6*x[14+7] - 9*x[14+8] - 12*x[14+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*x[14+10] - x[14+2] - x[14+3] - x[14+6] - 2*x[14+7] - 3*x[14+8] - 4*x[14+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]), -x[14+1] - 2*x[14+11] - 3*x[14+12] - 4*x[14+13] - x[14+4] + exp_(x[1]) + 2*exp_(x[11]) + 3*exp_(x[12]) + 4*exp_(x[13]) + exp_(x[4]), -x[14+10] - 2*x[14+11] - x[14+12] - x[14+13] - x[14+5] - x[14+6] - x[14+7] - x[14+8] - x[14+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])]
10+
return out
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#!/usr/bin/env python
2+
import os
3+
from time import clock
4+
import numpy as np
5+
import sympy as sp
6+
from sympy.parsing.sympy_parser import parse_expr
7+
from sympy.parsing.sympy_parser import standard_transformations
8+
import symengine as se
9+
import warnings
10+
11+
src = os.path.join(os.path.dirname(__file__), '6_links_rhs.txt')
12+
serial = open(src, 'tr').read()
13+
parsed = parse_expr(serial, transformations=standard_transformations)
14+
vec = sp.Matrix(1, 14, parsed)
15+
args = tuple(sorted(vec.free_symbols, key=lambda arg: arg.name))
16+
exprs = vec, vec.jacobian(args[:-14])
17+
inp = np.ones(len(args))
18+
assert inp.size == 26
19+
20+
21+
lmb_sp = sp.lambdify(args, exprs, modules=['math', 'sympy'])
22+
lmb_se = se.Lambdify(args, *exprs)
23+
lmb_se_llvm = se.Lambdify(args, *exprs, backend='llvm')
24+
25+
26+
lmb_sp(*inp)
27+
tim_sympy = clock()
28+
for i in range(500):
29+
v, m = lmb_sp(*inp)
30+
tim_sympy = clock() - tim_sympy
31+
32+
lmb_se(inp)
33+
tim_se = clock()
34+
for i in range(500):
35+
v, m = lmb_se(inp)
36+
tim_se = clock() - tim_se
37+
38+
39+
lmb_se_llvm(inp)
40+
tim_se_llvm = clock()
41+
res_se_llvm = np.empty(len(exprs))
42+
for i in range(500):
43+
v, m = lmb_se_llvm(inp)
44+
tim_se_llvm = clock() - tim_se_llvm
45+
46+
47+
print('SymEngine (lambda double) speed-up factor (higher is better) vs sympy: %12.5g' %
48+
(tim_sympy/tim_se))
49+
50+
51+
print('symengine (LLVM) speed-up factor (higher is better) vs sympy: %12.5g' %
52+
(tim_sympy/tim_se_llvm))
53+
54+
import itertools
55+
from functools import reduce
56+
from operator import mul
57+
58+
def ManualLLVM(inputs, *outputs):
59+
outputs_ravel = list(itertools.chain(*outputs))
60+
cb = se.Lambdify(inputs, outputs_ravel, backend="llvm")
61+
def func(*args):
62+
result = []
63+
n = np.empty(len(outputs_ravel))
64+
t = cb.unsafe_real(np.concatenate([arg.ravel() for arg in args]), n)
65+
start = 0
66+
for output in outputs:
67+
elems = reduce(mul, output.shape)
68+
result.append(n[start:start+elems].reshape(output.shape))
69+
start += elems
70+
return result
71+
return func
72+
73+
lmb_se_llvm_manual = ManualLLVM(args, *exprs)
74+
lmb_se_llvm_manual(inp)
75+
tim_se_llvm_manual = clock()
76+
for i in range(500):
77+
v, m = lmb_se_llvm_manual(inp)
78+
tim_se_llvm_manual = clock() - tim_se_llvm_manual
79+
print('symengine (ManualLLVM) speed-up factor (higher is better) vs sympy: %12.5g' %
80+
(tim_sympy/tim_se_llvm_manual))
81+
82+
if tim_se_llvm_manual < tim_se_llvm:
83+
warnings.warn("Cython code for Lambdify.__call__ is slow.")

bin/install_travis.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# symengine's bin/install_travis.sh will install miniconda
44
export conda_pkgs="python=${PYTHON_VERSION} pip cython sympy nose pytest"
55

6-
if [[ "${WITH_NUMPY}" == "yes" ]]; then
6+
if [[ "${WITH_NUMPY}" != "no" ]]; then
77
export conda_pkgs="${conda_pkgs} numpy";
88
fi
99

0 commit comments

Comments
 (0)