(calphadpy3) [rotis@kaufman pycalphad]$ python -c 'import symengine ; import pycalphad'
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/home/rotis/git/pycalphad/pycalphad/__init__.py", line 37, in <module>
from pycalphad.core.calculate import calculate
File "/home/rotis/git/pycalphad/pycalphad/core/calculate.py", line 7, in <module>
from pycalphad.codegen.callables import build_phase_records
File "/home/rotis/git/pycalphad/pycalphad/codegen/callables.py", line 5, in <module>
from pycalphad.core.phase_rec import PhaseRecord
ImportError: /home/rotis/git/pycalphad/pycalphad/core/phase_rec.cpython-37m-x86_64-linux-gnu.so: undefined symbol: _ZN9SymEngine17LLVMDoubleVisitor5loadsERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
(calphadpy3) [rotis@kaufman pycalphad]$ ldd /home/rotis/anaconda3/envs/calphadpy3/lib/python3.7/site-packages/symengine/lib/symengine_wrapper.cpython-37m-x86_64-linux-gnu.so
linux-vdso.so.1 => (0x00007ffc20ffa000)
libsymengine.so.0.4 => /home/rotis/anaconda3/envs/calphadpy3/lib/python3.7/site-packages/symengine/lib/../../../../libsymengine.so.0.4 (0x00007f1867949000)
libflint.so.13 => /home/rotis/anaconda3/envs/calphadpy3/lib/python3.7/site-packages/symengine/lib/../../../../libflint.so.13 (0x00007f18672fd000)
libmpc.so.3 => /home/rotis/anaconda3/envs/calphadpy3/lib/python3.7/site-packages/symengine/lib/../../../../libmpc.so.3 (0x00007f18672e2000)
libmpfr.so.6 => /home/rotis/anaconda3/envs/calphadpy3/lib/python3.7/site-packages/symengine/lib/../../../../libmpfr.so.6 (0x00007f1867263000)
libstdc++.so.6 => /home/rotis/anaconda3/envs/calphadpy3/lib/python3.7/site-packages/symengine/lib/../../../../libstdc++.so.6 (0x00007f1867121000)
libm.so.6 => /lib64/libm.so.6 (0x00007f1866df6000)
libgcc_s.so.1 => /home/rotis/anaconda3/envs/calphadpy3/lib/python3.7/site-packages/symengine/lib/../../../../libgcc_s.so.1 (0x00007f1866de1000)
libc.so.6 => /lib64/libc.so.6 (0x00007f1866a1d000)
libgmp.so.10 => /home/rotis/anaconda3/envs/calphadpy3/lib/python3.7/site-packages/symengine/lib/../../../.././libgmp.so.10 (0x00007f1866789000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f1866584000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f1866368000)
/lib64/ld-linux-x86-64.so.2 (0x00007f18696ba000)
libntl.so.33 => /home/rotis/anaconda3/envs/calphadpy3/lib/python3.7/site-packages/symengine/lib/../../../.././libntl.so.33 (0x00007f1865f3a000)
libgf2x.so.1 => /home/rotis/anaconda3/envs/calphadpy3/lib/python3.7/site-packages/symengine/lib/../../../../././libgf2x.so.1 (0x00007f1865d2d000)
(calphadpy3) [rotis@kaufman pycalphad]$ nm -g /home/rotis/anaconda3/envs/calphadpy3/lib/python3.7/site-packages/symengine/lib/../../../../libsymengine.so.0.4 | grep _ZN9SymEngine17LLVMDoubleVisitor5loadsERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE00000000003e0e80 T _ZN9SymEngine17LLVMDoubleVisitor5loadsERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
00000000003e0e80 T _ZN9SymEngine17LLVMDoubleVisitor5loadsERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Any idea what some use cases of symengine would be where you need guarantees of compatibility as mentioned in the last comment?
Their 2 main downsides are that 1) they serialize into some custom format, which is not much usable as a data exchange format with other libraries/programs 2) they offer few guarantees of forward compatibility (e.g., if you serialize an object with Boost 1.66 it's not guaranteed to be deserializable with Boost 1.65).
Pickling and unpickling the LLVMDouble
does not correctly reset the LLVMDoubleVisitor
that is supposed to be in llvm_double[0]
.
from symengine import symbols
x, y, z = symbols('x y z')
ex = x**2 + y**2 + z**2
from symengine import lambdify
l = lambdify([x, y, z], [ex], backend='llvm')
import pickle
print('pickle.loads(pickle.dumps(l)) == l :: ', pickle.loads(pickle.dumps(l)) == l)
print(l.__reduce__())
print(pickle.loads(pickle.dumps(l)).__reduce__())
gives
pickle.loads(pickle.dumps(l)) == l :: False
(<built-in function llvm_loading_func>, (3, 1, [()], True, 1, 'C', [0, 1], <class 'numpy.float64'>, b"\xcf\xfa\xed\xfe\x07\x00\x00\x01\x03\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00`\x01\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x19\x00\x00\x00\xe8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00\x00\x00\x00`\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x07\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00__eh_frame\x00\x00\x00\x00\x00\x00__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00(\x00\x00\x00\x00\x00\x00\x008\x00\x00\x00\x00\x00\x00\x00\xa8\x01\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00h\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$\x00\x00\x00\x10\x00\x00\x00\x00\x0e\n\x00\x00\x00\x00\x00\x02\x00\x00\x00\x18\x00\x00\x00\xe0\x01\x00\x00\x01\x00\x00\x00\xf0\x01\x00\x00\x10\x00\x00\x00\x0b\x00\x00\x00P\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf2\x0f\x10\x07\xf2\x0f\x10O\x08\xf2\x0f\x10W\x10\xf2\x0fY\xd2\xf2\x0fY\xc0\xf2\x0fX\xc2\xf2\x0fY\xc9\xf2\x0fX\xc8\xf2\x0f\x11\x0e\xc3\x00\x14\x00\x00\x00\x00\x00\x00\x00\x01zR\x00\x01x\x10\x01\x10\x0c\x07\x08\x90\x01\x00\x00\x1c\x00\x00\x00\x1c\x00\x00\x00\xb8\xff\xff\xff\xff\xff\xff\xff'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x0e\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00___unnamed_1\x00\x00\x00"))
(<built-in function llvm_loading_func>, (3, 1, [()], True, 1, 'C', [0, 1], <class 'numpy.float64'>, b''))
You can see that the pickled/unpickled version gives an empty byte string for the dumped LLVMDoubleVisitor bytes. @richardotis and I were tracking this down and the issue looks to be that the membuffer
is not correctly reset in LLVMDoubleVisitor.loads
here when called in self.llvm_double[0].loads
as part of the LLVMDouble._load
method here. In that case, the root fix would be to set the membuffer
in LLVMDoubleVisitor.loads
in the same way as LLVMDoubleVisitor.__init__
.
A test for this might be to do pickle.loads(pickle.dumps(pickle.loads(pickle.dumps(l))))
, which currently will kill the kernel with a LLVM ERROR: The file was not recognized as a valid object file
membuffer = s
at the beginning of loads
should fix it