diff --git a/.travis.yml b/.travis.yml index 2f81bb2ee..0fe382d3d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ os: - linux - osx sudo: false +osx_image: xcode6.4 addons: apt: sources: @@ -52,7 +53,7 @@ matrix: packages: - binutils-dev - g++-4.8 - - env: BUILD_TYPE="Debug" WITH_BFD="yes" PYTHON_VERSION="3.5" WITH_LLVM="yes" WITH_SCIPY="yes" + - env: BUILD_TYPE="Debug" WITH_BFD="yes" PYTHON_VERSION="3.5" WITH_LLVM="3.8" WITH_SCIPY="yes" compiler: clang os: linux addons: @@ -85,6 +86,13 @@ matrix: compiler: gcc os: linux +before_install: +- | + if [ "${TRAVIS_OS_NAME}" == "osx" ]; then + command curl -sSL https://rvm.io/mpapis.asc | gpg --import -; + rvm get head || true + fi + install: - export PYTHON_SOURCE_DIR=`pwd` - export TEST_CPP="no" diff --git a/symengine/lib/symengine.pxd b/symengine/lib/symengine.pxd index 5b717d296..adccf6c3a 100644 --- a/symengine/lib/symengine.pxd +++ b/symengine/lib/symengine.pxd @@ -972,6 +972,8 @@ cdef extern from "" namespace "SymEngine": LLVMDoubleVisitor() nogil void init(const vec_basic &x, const vec_basic &b, bool cse) nogil except + void call(double *r, const double *x) nogil + const string& dumps() nogil + void loads(const string&) nogil cdef extern from "" namespace "SymEngine": cdef cppclass SeriesCoeffInterface: diff --git a/symengine/lib/symengine_wrapper.pyx b/symengine/lib/symengine_wrapper.pyx index de0a622f9..685bb6bd8 100644 --- a/symengine/lib/symengine_wrapper.pyx +++ b/symengine/lib/symengine_wrapper.pyx @@ -4369,7 +4369,7 @@ cdef class _Lambdify(object): cdef vector[int] accum_out_sizes cdef object numpy_dtype - def __init__(self, args, *exprs, cppbool real=True, order='C', cppbool cse=False): + def __init__(self, args, *exprs, cppbool real=True, order='C', cppbool cse=False, cppbool _load=False): cdef: Basic e_ size_t ri, ci, nr, nc @@ -4378,6 +4378,13 @@ cdef class _Lambdify(object): symengine.vec_basic args_, outs_ vector[int] out_sizes + if _load: + self.args_size, self.tot_out_size, self.out_shapes, self.real, \ + self.n_exprs, self.order, self.accum_out_sizes, self.numpy_dtype, \ + llvm_function = args + self._load(llvm_function) + return + args = np.asanyarray(args) self.args_size = args.size exprs = tuple(np.asanyarray(expr) for expr in exprs) @@ -4414,6 +4421,9 @@ cdef class _Lambdify(object): cdef _init(self, symengine.vec_basic& args_, symengine.vec_basic& outs_, cppbool cse): raise ValueError("Not supported") + cdef _load(self, const string &s): + raise ValueError("Not supported") + cpdef unsafe_real(self, double[::1] inp, double[::1] out, int inp_offset=0, int out_offset=0): @@ -4625,6 +4635,18 @@ IF HAVE_SYMENGINE_LLVM: self.lambda_double.resize(1) self.lambda_double[0].init(args_, outs_, cse) + cdef _load(self, const string &s): + self.lambda_double.resize(1) + self.lambda_double[0].loads(s) + + def __reduce__(self): + """ + Interface for pickle. Note that the resulting object is platform dependent. + """ + cdef bytes s = self.lambda_double[0].dumps() + return llvm_loading_func, (self.args_size, self.tot_out_size, self.out_shapes, self.real, \ + self.n_exprs, self.order, self.accum_out_sizes, self.numpy_dtype, s) + cpdef unsafe_real(self, double[::1] inp, double[::1] out, int inp_offset=0, int out_offset=0): self.lambda_double[0].call(&out[out_offset], &inp[inp_offset]) @@ -4639,6 +4661,8 @@ IF HAVE_SYMENGINE_LLVM: addr2 = cast(&self.lambda_double[0], c_void_p) return create_low_level_callable(self, addr1, addr2) + def llvm_loading_func(*args): + return LLVMDouble(args, _load=True) def Lambdify(args, *exprs, cppbool real=True, backend=None, order='C', as_scipy=False, cse=False): """ diff --git a/symengine/tests/test_pickling.py b/symengine/tests/test_pickling.py new file mode 100644 index 000000000..b7f14a181 --- /dev/null +++ b/symengine/tests/test_pickling.py @@ -0,0 +1,17 @@ +from symengine import symbols, sin, sinh, have_numpy, have_llvm +import pickle +import unittest + +@unittest.skipUnless(have_llvm, "No LLVM support") +@unittest.skipUnless(have_numpy, "Numpy not installed") +def test_llvm_double(): + import numpy as np + from symengine import Lambdify + args = x, y, z = symbols('x y z') + expr = sin(sinh(x+y) + z) + l = Lambdify(args, expr, cse=True, backend='llvm') + ss = pickle.dumps(l) + ll = pickle.loads(ss) + inp = [1, 2, 3] + assert np.allclose(l(inp), ll(inp)) + diff --git a/symengine/tests/test_printing.py b/symengine/tests/test_printing.py index 6d4628cb4..d4314425a 100644 --- a/symengine/tests/test_printing.py +++ b/symengine/tests/test_printing.py @@ -9,7 +9,7 @@ def test_ccode(): assert ccode(x**3) == "pow(x, 3)" assert ccode(x**(y**3)) == "pow(x, pow(y, 3))" assert ccode(x**-1.0) == "pow(x, -1.0)" - assert ccode(Max(x, x*x)) == "max(x, pow(x, 2))" + assert ccode(Max(x, x*x)) == "fmax(x, pow(x, 2))" assert ccode(sin(x)) == "sin(x)" assert ccode(Integer(67)) == "67" assert ccode(Integer(-1)) == "-1" @@ -24,4 +24,4 @@ def test_CCodePrinter(): assert myprinter.doprint(MutableDenseMatrix(1, 2, [x, y]), "larry") == "larry[0] = x;\nlarry[1] = y;" raises(TypeError, lambda: myprinter.doprint(sin(x), Integer)) raises(RuntimeError, lambda: myprinter.doprint(MutableDenseMatrix(1, 2, [x, y]))) - \ No newline at end of file + diff --git a/symengine_version.txt b/symengine_version.txt index ac91982c7..781d7e63b 100644 --- a/symengine_version.txt +++ b/symengine_version.txt @@ -1 +1 @@ -2f5ff9db9ff511ee243438a85ea8e2da2d05af39 +fff6755331226a08f0b14571bfbce2b23001d911