Repository: symengine/symengine.py (language: python)

Issue:
Build error of symengine.py when SymEngine's LLVMDoubleVisitor is enabled.
I experienced this error first locally, and I have now reproduced it in our CI:
<details>
<summary>Relevant part of log https://github.com/bjodah/symengine.py/actions/runs/9315200175/job/25640872589</summary>

```
running build
running build_ext
CMake Deprecation Warning at CMakeLists.txt:1 (cmake_minimum_required):
  Compatibility with CMake < 3.5 will be removed from a future version of
  CMake.

  Update the VERSION argument <min> value or use a ...<max> suffix to tell
  CMake that the project does not need compatibility with older versions.


-- The C compiler identification is GNU 11.4.0
-- The CXX compiler identification is GNU 11.4.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/gcc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/g++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
CMake Deprecation Warning at /home/runner/our_usr/lib/cmake/symengine/SymEngineConfig.cmake:34 (cmake_minimum_required):
  Compatibility with CMake < 3.5 will be removed from a future version of
  CMake.

  Update the VERSION argument <min> value or use a ...<max> suffix to tell
  CMake that the project does not need compatibility with older versions.
Call Stack (most recent call first):
  CMakeLists.txt:16 (find_package)


-- Performing Test HAVE_FFI_CALL
-- Performing Test HAVE_FFI_CALL - Success
-- Found FFI: /home/runner/our_usr/lib/libffi.so
-- Performing Test Terminfo_LINKABLE
-- Performing Test Terminfo_LINKABLE - Success
                 from /home/runner/our_usr/include/boost/multiprecision/number.hpp:12,
                 from /home/runner/our_usr/include/boost/multiprecision/cpp_int.hpp:19,
                 from /home/runner/our_usr/include/symengine/mp_class.h:12,
                 from /home/runner/work/symengine.py/symengine.py/dist-extract/symengine-0.11.0/symengine/lib/symengine_wrapper.cpp:1275:
/home/runner/our_usr/include/boost/math/tools/config.hpp:23:6: warning: #warning "The minimum language standard to use Boost.Math will be C++14 starting in July 2023 (Boost 1.82 release)" [-Wcpp]
   23 | #    warning "The minimum language standard to use Boost.Math will be C++14 starting in July 2023 (Boost 1.82 release)"
      |      ^~~~~~~
In file included from /usr/include/c++/11/vector:66,
                 from /home/runner/work/symengine.py/symengine.py/dist-extract/symengine-0.11.0/symengine/lib/symengine_wrapper.cpp:1271:
/usr/include/c++/11/bits/stl_uninitialized.h: In instantiation of ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<SymEngine::LLVMDoubleVisitor*>; _ForwardIterator = SymEngine::LLVMDoubleVisitor*]’:
/usr/include/c++/11/bits/stl_uninitialized.h:333:37:   required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = std::move_iterator<SymEngine::LLVMDoubleVisitor*>; _ForwardIterator = SymEngine::LLVMDoubleVisitor*; _Tp = SymEngine::LLVMDoubleVisitor]’
/usr/include/c++/11/bits/stl_uninitialized.h:355:2:   required from ‘_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = SymEngine::LLVMDoubleVisitor*; _ForwardIterator = SymEngine::LLVMDoubleVisitor*; _Allocator = std::allocator<SymEngine::LLVMDoubleVisitor>]’
/usr/include/c++/11/bits/vector.tcc:659:48:   required from ‘void std::vector<_Tp, _Alloc>::_M_default_append(std::vector<_Tp, _Alloc>::size_type) [with _Tp = SymEngine::LLVMDoubleVisitor; _Alloc = std::allocator<SymEngine::LLVMDoubleVisitor>; std::vector<_Tp, _Alloc>::size_type = long unsigned int]’
/usr/include/c++/11/bits/stl_vector.h:940:4:   required from ‘void std::vector<_Tp, _Alloc>::resize(std::vector<_Tp, _Alloc>::size_type) [with _Tp = SymEngine::LLVMDoubleVisitor; _Alloc = std::allocator<SymEngine::LLVMDoubleVisitor>; std::vector<_Tp, _Alloc>::size_type = long unsigned int]’
/home/runner/work/symengine.py/symengine.py/dist-extract/symengine-0.11.0/symengine/lib/symengine_wrapper.cpp:185448:39:   required from here
/usr/include/c++/11/bits/stl_uninitialized.h:138:72: error: static assertion failed: result type must be constructible from value type of input range
  138 |       static_assert(is_constructible<_ValueType2, decltype(*__first)>::value,
      |                                                                        ^~~~~
/usr/include/c++/11/bits/stl_uninitialized.h:138:72: note: ‘std::integral_constant<bool, false>::value’ evaluates to false
/usr/include/c++/11/bits/stl_uninitialized.h: In instantiation of ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<SymEngine::LLVMFloatVisitor*>; _ForwardIterator = SymEngine::LLVMFloatVisitor*]’:
/usr/include/c++/11/bits/stl_uninitialized.h:333:37:   required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = std::move_iterator<SymEngine::LLVMFloatVisitor*>; _ForwardIterator = SymEngine::LLVMFloatVisitor*; _Tp = SymEngine::LLVMFloatVisitor]’
/usr/include/c++/11/bits/stl_uninitialized.h:355:2:   required from ‘_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = SymEngine::LLVMFloatVisitor*; _ForwardIterator = SymEngine::LLVMFloatVisitor*; _Allocator = std::allocator<SymEngine::LLVMFloatVisitor>]’
/usr/include/c++/11/bits/vector.tcc:659:48:   required from ‘void std::vector<_Tp, _Alloc>::_M_default_append(std::vector<_Tp, _Alloc>::size_type) [with _Tp = SymEngine::LLVMFloatVisitor; _Alloc = std::allocator<SymEngine::LLVMFloatVisitor>; std::vector<_Tp, _Alloc>::size_type = long unsigned int]’
/usr/include/c++/11/bits/stl_vector.h:940:4:   required from ‘void std::vector<_Tp, _Alloc>::resize(std::vector<_Tp, _Alloc>::size_type) [with _Tp = SymEngine::LLVMFloatVisitor; _Alloc = std::allocator<SymEngine::LLVMFloatVisitor>; std::vector<_Tp, _Alloc>::size_type = long unsigned int]’
/home/runner/work/symengine.py/symengine.py/dist-extract/symengine-0.11.0/symengine/lib/symengine_wrapper.cpp:187586:39:   required from here
/usr/include/c++/11/bits/stl_uninitialized.h:138:72: error: static assertion failed: result type must be constructible from value type of input range
/usr/include/c++/11/bits/stl_uninitialized.h:138:72: note: ‘std::integral_constant<bool, false>::value’ evaluates to false
/usr/include/c++/11/bits/stl_uninitialized.h: In instantiation of ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<SymEngine::LLVMLongDoubleVisitor*>; _ForwardIterator = SymEngine::LLVMLongDoubleVisitor*]’:
/usr/include/c++/11/bits/stl_uninitialized.h:333:37:   required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = std::move_iterator<SymEngine::LLVMLongDoubleVisitor*>; _ForwardIterator = SymEngine::LLVMLongDoubleVisitor*; _Tp = SymEngine::LLVMLongDoubleVisitor]’
/usr/include/c++/11/bits/stl_uninitialized.h:355:2:   required from ‘_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = SymEngine::LLVMLongDoubleVisitor*; _ForwardIterator = SymEngine::LLVMLongDoubleVisitor*; _Allocator = std::allocator<SymEngine::LLVMLongDoubleVisitor>]’
/usr/include/c++/11/bits/vector.tcc:659:48:   required from ‘void std::vector<_Tp, _Alloc>::_M_default_append(std::vector<_Tp, _Alloc>::size_type) [with _Tp = SymEngine::LLVMLongDoubleVisitor; _Alloc = std::allocator<SymEngine::LLVMLongDoubleVisitor>; std::vector<_Tp, _Alloc>::size_type = long unsigned int]’
/usr/include/c++/11/bits/stl_vector.h:940:4:   required from ‘void std::vector<_Tp, _Alloc>::resize(std::vector<_Tp, _Alloc>::size_type) [with _Tp = SymEngine::LLVMLongDoubleVisitor; _Alloc = std::allocator<SymEngine::LLVMLongDoubleVisitor>; std::vector<_Tp, _Alloc>::size_type = long unsigned int]’
/home/runner/work/symengine.py/symengine.py/dist-extract/symengine-0.11.0/symengine/lib/symengine_wrapper.cpp:188783:39:   required from here
/usr/include/c++/11/bits/stl_uninitialized.h:138:72: error: static assertion failed: result type must be constructible from value type of input range
/usr/include/c++/11/bits/stl_uninitialized.h:138:72: note: ‘std::integral_constant<bool, false>::value’ evaluates to false
gmake[2]: *** [symengine/lib/CMakeFiles/symengine_wrapper.dir/build.make:94: symengine/lib/CMakeFiles/symengine_wrapper.dir/symengine_wrapper.cpp.o] Error 1
gmake[2]: *** Waiting for unfinished jobs....
gmake[1]: *** [CMakeFiles/Makefile2:194: symengine/lib/CMakeFiles/symengine_wrapper.dir/all] Error 2
gmake: *** [Makefile:136: all] Error 2
error: error building project
```

</details>

I'm trying to narrow down what might have changed, I'm leaning towards cython generating a bad symengine_wrapper.cpp (the above attached full log shows that it uses cython-3.0.10):

[log.txt](https://github.com/user-attachments/files/15511000/log.txt)

I'll report back when I've tried different versions of cython.


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 6993dd9e..2763750c 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -111,32 +111,33 @@ jobs:
             PYTHON_VERSION: '3.8'
             WITH_SCIPY: yes
             WITH_LLVM: 5.0
-            OS: macos-latest
+            OS: macos-13
             CC: clang
 
           - BUILD_TYPE: Release
             PYTHON_VERSION: '3.9'
             WITH_NUMPY: no
-            OS: macos-latest
+            OS: macos-13
             CC: clang
 
           - BUILD_TYPE: Debug
             PYTHON_VERSION: '3.8'
             WITH_NUMPY: no
-            OS: macos-latest
+            OS: macos-13
             CC: gcc
 
           - BUILD_TYPE: Release
             PYTHON_VERSION: '3.8'
-            OS: macos-latest
+            OS: macos-13
             CC: gcc
 
           - BUILD_TYPE: Release
-            PYTHON_VERSION: '3.8'
+            PYTHON_VERSION: '3.11'
             OS: ubuntu-20.04
             WITH_MPC: yes
             WITH_MPFR: yes
             WITH_FLINT: yes
+            WITH_FLINT_PY: yes
             WITH_SCIPY: yes
             WITH_DOCS: yes
             INTEGER_CLASS: flint
diff --git a/appveyor.yml b/appveyor.yml
index 05e6b6eb..f21df0ae 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -7,30 +7,37 @@ environment:
     PLATFORMTOOLSET: "v140"
 
   matrix:
+    - BUILD_TYPE: "Release"
+      COMPILER: MSVC15
+      PLATFORM: "Win32"
+      PYTHON_VERSION: 39
+      CONDA_INSTALL_LOCN: C:\\Miniconda38-x64
+      WITH_MPFR: yes
+      WITH_MPC: yes
     - BUILD_TYPE: "Release"
       COMPILER: MSVC15
       PLATFORM: "x64"
       PYTHON_VERSION: 310-x64
-      CONDA_INSTALL_LOCN: C:\\Miniconda36-x64
+      CONDA_INSTALL_LOCN: C:\\Miniconda38-x64
       WITH_MPFR: yes
       WITH_MPC: yes
     - BUILD_TYPE: "Release"
       COMPILER: MSVC15
       PLATFORM: "x64"
       PYTHON_VERSION: 38-x64
-      CONDA_INSTALL_LOCN: C:\\Miniconda36-x64
+      CONDA_INSTALL_LOCN: C:\\Miniconda38-x64
     - BUILD_TYPE: "Release"
       COMPILER: MSVC15
       PLATFORM: "x64"
       PYTHON_VERSION: 39-x64
       WITH_SYMPY: no
-      CONDA_INSTALL_LOCN: C:\\Miniconda36-x64
+      CONDA_INSTALL_LOCN: C:\\Miniconda38-x64
     - BUILD_TYPE: "Release"
       COMPILER: MSVC15
       PLATFORM: "x64"
       PYTHON_VERSION: 311-x64
       WITH_NUMPY: no
-      CONDA_INSTALL_LOCN: C:\\Miniconda36-x64
+      CONDA_INSTALL_LOCN: C:\\Miniconda38-x64
     #- BUILD_TYPE: "Debug"
     #  COMPILER: MinGW-w64
     #  PYTHON_VERSION: 39-x64
@@ -42,18 +49,11 @@ environment:
     #  COMPILER: MinGW-w64
     #  PYTHON_VERSION: 39-x64
     #  WITH_SYMPY: no
-    - BUILD_TYPE: "Release"
-      COMPILER: MSVC15
-      PLATFORM: "Win32"
-      PYTHON_VERSION: 39
-      CONDA_INSTALL_LOCN: C:\\Miniconda36
-      WITH_MPFR: yes
-      WITH_MPC: yes
     - BUILD_TYPE: "Release"
       COMPILER: MSVC15
       PLATFORM: "x64"
       PYTHON_VERSION: 310-x64
-      CONDA_INSTALL_LOCN: C:\\Miniconda36-x64
+      CONDA_INSTALL_LOCN: C:\\Miniconda38-x64
       WITH_MPFR: yes
       WITH_MPC: yes
       WITH_LLVM: yes
@@ -61,19 +61,21 @@ environment:
 install:
 - set PYTHON_SOURCE_DIR=%CD%
 - git clone https://github.com/sympy/symengine symengine-cpp
+- if [%PLATFORM%]==[Win32] set "CONDA_SUBDIR=win-32"
 
 - if [%COMPILER%]==[MSVC15] call %CONDA_INSTALL_LOCN%\Scripts\activate.bat
-- if [%COMPILER%]==[MSVC15] conda install --yes --quiet conda python=3.6
-- if [%COMPILER%]==[MSVC15] conda config --add channels conda-forge
-- if [%COMPILER%]==[MSVC15] if [%BUILD_TYPE%]==[Debug] conda config --add channels symengine/label/debug
-- if [%COMPILER%]==[MSVC15] conda install --yes mpir=3.0.0 vc=14
+- if [%COMPILER%]==[MSVC15] set "CONDA_DEPS=mpir=3.0.0 vc=14"
+- if [%COMPILER%]==[MSVC15] if [%WITH_MPFR%]==[yes] set "CONDA_DEPS=%CONDA_DEPS% mpfr=3.1.5"
+- if [%COMPILER%]==[MSVC15] if [%WITH_MPC%]==[yes] set "CONDA_DEPS=%CONDA_DEPS% mpc=1.0.3"
+- if [%COMPILER%]==[MSVC15] if [%WITH_LLVM%]==[yes] set "CONDA_DEPS=%CONDA_DEPS% llvmdev=4.0"
+- if [%COMPILER%]==[MSVC15] set "CONDA_DEPS=%CONDA_DEPS% -c conda-forge"
+- if [%COMPILER%]==[MSVC15] if [%BUILD_TYPE%]==[Debug] set "CONDA_DEPS=%CONDA_DEPS% -c symengine/label/debug"
+- if [%COMPILER%]==[MSVC15] conda create -n deps --yes %CONDA_DEPS%
+- if [%COMPILER%]==[MSVC15] call conda activate deps
 - if [%COMPILER%]==[MSVC15] echo %CONDA_PREFIX%
 - if [%COMPILER%]==[MSVC15] echo %PATH%
 - if [%COMPILER%]==[MSVC15] set "PATH=%PATH%;%CONDA_PREFIX%\\Library\\bin;%CONDA_PREFIX%"
 - if [%COMPILER%]==[MSVC15] echo %PATH%
-- if [%COMPILER%]==[MSVC15] if [%WITH_MPFR%]==[yes] conda install --yes mpfr=3.1.5
-- if [%COMPILER%]==[MSVC15] if [%WITH_MPC%]==[yes] conda install --yes mpc=1.0.3
-- if [%COMPILER%]==[MSVC15] if [%WITH_LLVM%]==[yes] conda install --yes llvmdev=4.0
 
 - if [%COMPILER%]==[MinGW] set "PATH=C:\MinGW\bin;%PATH%"
 - if [%COMPILER%]==[MinGW] mingw-get update
diff --git a/bin/install_travis.sh b/bin/install_travis.sh
index 581354a0..8176202d 100644
--- a/bin/install_travis.sh
+++ b/bin/install_travis.sh
@@ -16,6 +16,10 @@ if [[ "${WITH_DOCS}" == "yes" ]]; then
     export conda_pkgs="${conda_pkgs} sphinx recommonmark";
 fi
 
+if [[ "${WITH_FLINT_PY}" == "yes" ]]; then
+    export conda_pkgs="${conda_pkgs} python-flint";  # python-flint affects sympy, see e.g. sympy/sympy#26645
+fi
+
 if [[ "${WITH_SAGE}" == "yes" ]]; then
     # This is split to avoid the 10 minute limit
     conda install -q sagelib=8.1
diff --git a/symengine/lib/symengine_wrapper.in.pxd b/symengine/lib/symengine_wrapper.in.pxd
index 3712e17c..03dbf1f0 100644
--- a/symengine/lib/symengine_wrapper.in.pxd
+++ b/symengine/lib/symengine_wrapper.in.pxd
@@ -2,6 +2,7 @@
 
 cimport symengine
 from symengine cimport RCP, map_basic_basic, rcp_const_basic
+from libcpp.memory cimport unique_ptr
 from libcpp.vector cimport vector
 from libcpp.string cimport string
 from libcpp cimport bool as cppbool
@@ -44,7 +45,7 @@ cdef class _Lambdify(object):
     cpdef unsafe_eval(sef, inp, out, unsigned nbroadcast=*)
 
 cdef class LambdaDouble(_Lambdify):
-    cdef vector[symengine.LambdaRealDoubleVisitor] lambda_double
+    cdef unique_ptr[symengine.LambdaRealDoubleVisitor] lambda_visitor
     cdef _init(self, symengine.vec_basic& args_, symengine.vec_basic& outs_, cppbool cse)
     cpdef unsafe_real(self, double[::1] inp, double[::1] out, int inp_offset=*, int out_offset=*)
     cpdef as_scipy_low_level_callable(self)
@@ -54,7 +55,7 @@ cdef class LambdaDouble(_Lambdify):
                       int inp_offset=*, int out_offset=*)
 
 cdef class LambdaComplexDouble(_Lambdify):
-    cdef vector[symengine.LambdaComplexDoubleVisitor] lambda_double
+    cdef unique_ptr[symengine.LambdaComplexDoubleVisitor] lambda_visitor
     cdef _init(self, symengine.vec_basic& args_, symengine.vec_basic& outs_, cppbool cse)
     cpdef unsafe_complex(self, double complex[::1] inp, double complex[::1] out, int inp_offset=*, int out_offset=*)
 
@@ -63,7 +64,7 @@ IF HAVE_SYMENGINE_LLVM:
         cdef int opt_level
 
     cdef class LLVMDouble(_LLVMLambdify):
-        cdef vector[symengine.LLVMDoubleVisitor] lambda_double
+        cdef unique_ptr[symengine.LLVMDoubleVisitor] lambda_visitor
         cdef _init(self, symengine.vec_basic& args_, symengine.vec_basic& outs_, cppbool cse)
         cdef _load(self, const string &s)
         cpdef unsafe_real(self, double[::1] inp, double[::1] out, int inp_offset=*, int out_offset=*)
@@ -71,14 +72,14 @@ IF HAVE_SYMENGINE_LLVM:
         cpdef as_ctypes(self)
 
     cdef class LLVMFloat(_LLVMLambdify):
-        cdef vector[symengine.LLVMFloatVisitor] lambda_double
+        cdef unique_ptr[symengine.LLVMFloatVisitor] lambda_visitor
         cdef _init(self, symengine.vec_basic& args_, symengine.vec_basic& outs_, cppbool cse)
         cdef _load(self, const string &s)
         cpdef unsafe_real(self, float[::1] inp, float[::1] out, int inp_offset=*, int out_offset=*)
 
     IF HAVE_SYMENGINE_LLVM_LONG_DOUBLE:
         cdef class LLVMLongDouble(_LLVMLambdify):
-            cdef vector[symengine.LLVMLongDoubleVisitor] lambda_double
+            cdef unique_ptr[symengine.LLVMLongDoubleVisitor] lambda_visitor
             cdef _init(self, symengine.vec_basic& args_, symengine.vec_basic& outs_, cppbool cse)
             cdef _load(self, const string &s)
             cpdef unsafe_real(self, long double[::1] inp, long double[::1] out, int inp_offset=*, int out_offset=*)
diff --git a/symengine/lib/symengine_wrapper.in.pyx b/symengine/lib/symengine_wrapper.in.pyx
index e10d1476..44688fbe 100644
--- a/symengine/lib/symengine_wrapper.in.pyx
+++ b/symengine/lib/symengine_wrapper.in.pyx
@@ -1211,7 +1211,7 @@ cdef class Basic(object):
         return int(float(self))
 
     def __long__(self):
-        return long(float(self))
+        return int(float(self))
 
     def __complex__(self):
         f = self.n(real=False)
@@ -1627,7 +1627,9 @@ class Equality(Relational):
     def is_Equality(self):
         return True
 
-    func = __class__
+    @property
+    def func(self):
+        return self.__class__
 
 
 Eq = Equality
@@ -1648,7 +1650,9 @@ class Unequality(Relational):
         s = self.args_as_sage()
         return sage.ne(*s)
 
-    func = __class__
+    @property
+    def func(self):
+        return self.__class__
 
 
 Ne = Unequality
@@ -5152,11 +5156,11 @@ cdef class LambdaDouble(_Lambdify):
         pass
 
     cdef _init(self, symengine.vec_basic& args_, symengine.vec_basic& outs_, cppbool cse):
-        self.lambda_double.resize(1)
-        self.lambda_double[0].init(args_, outs_, cse)
+        self.lambda_visitor.reset(new symengine.LambdaRealDoubleVisitor())
+        deref(self.lambda_visitor).init(args_, outs_, cse)
 
     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])
+        deref(self.lambda_visitor).call(&out[out_offset], &inp[inp_offset])
 
     cpdef unsafe_eval(self, inp, out, unsigned nbroadcast=1):
         cdef double[::1] c_inp, c_out
@@ -5164,7 +5168,7 @@ cdef class LambdaDouble(_Lambdify):
         c_inp = np.ascontiguousarray(inp.ravel(order=self.order), dtype=self.numpy_dtype)
         c_out = out
         for idx in range(nbroadcast):
-            self.lambda_double[0].call(&c_out[idx*self.tot_out_size], &c_inp[idx*self.args_size])
+            deref(self.lambda_visitor).call(&c_out[idx*self.tot_out_size], &c_inp[idx*self.args_size])
 
     cpdef as_scipy_low_level_callable(self):
         from ctypes import c_double, c_void_p, c_int, cast, POINTER, CFUNCTYPE
@@ -5172,7 +5176,7 @@ cdef class LambdaDouble(_Lambdify):
             raise RuntimeError("SciPy LowLevelCallable supports only functions with 1 output")
         addr1 = cast(<size_t>&_scipy_callback_lambda_real,
                         CFUNCTYPE(c_double, c_int, POINTER(c_double), c_void_p))
-        addr2 = cast(<size_t>&self.lambda_double[0], c_void_p)
+        addr2 = cast(<size_t>self.lambda_visitor.get(), c_void_p)
         return create_low_level_callable(self, addr1, addr2)
 
     cpdef as_ctypes(self):
@@ -5187,7 +5191,7 @@ cdef class LambdaDouble(_Lambdify):
         from ctypes import c_double, c_void_p, c_int, cast, POINTER, CFUNCTYPE
         addr1 = cast(<size_t>&_ctypes_callback_lambda_real,
                         CFUNCTYPE(c_void_p, POINTER(c_double), POINTER(c_double), c_void_p))
-        addr2 = cast(<size_t>&self.lambda_double[0], c_void_p)
+        addr2 = cast(<size_t>self.lambda_visitor.get(), c_void_p)
         return addr1, addr2
 
 
@@ -5197,11 +5201,11 @@ cdef class LambdaComplexDouble(_Lambdify):
         pass
 
     cdef _init(self, symengine.vec_basic& args_, symengine.vec_basic& outs_, cppbool cse):
-        self.lambda_double.resize(1)
-        self.lambda_double[0].init(args_, outs_, cse)
+        self.lambda_visitor.reset(new symengine.LambdaComplexDoubleVisitor())
+        deref(self.lambda_visitor).init(args_, outs_, cse)
 
     cpdef unsafe_complex(self, double complex[::1] inp, double complex[::1] out, int inp_offset=0, int out_offset=0):
-        self.lambda_double[0].call(&out[out_offset], &inp[inp_offset])
+        deref(self.lambda_visitor).call(&out[out_offset], &inp[inp_offset])
 
     cpdef unsafe_eval(self, inp, out, unsigned nbroadcast=1):
         cdef double complex[::1] c_inp, c_out
@@ -5209,7 +5213,7 @@ cdef class LambdaComplexDouble(_Lambdify):
         c_inp = np.ascontiguousarray(inp.ravel(order=self.order), dtype=self.numpy_dtype)
         c_out = out
         for idx in range(nbroadcast):
-            self.lambda_double[0].call(&c_out[idx*self.tot_out_size], &c_inp[idx*self.args_size])
+            deref(self.lambda_visitor).call(&c_out[idx*self.tot_out_size], &c_inp[idx*self.args_size])
 
 
 IF HAVE_SYMENGINE_LLVM:
@@ -5218,23 +5222,23 @@ IF HAVE_SYMENGINE_LLVM:
             self.opt_level = opt_level
 
         cdef _init(self, symengine.vec_basic& args_, symengine.vec_basic& outs_, cppbool cse):
-            self.lambda_double.resize(1)
-            self.lambda_double[0].init(args_, outs_, cse, self.opt_level)
+            self.lambda_visitor.reset(new symengine.LLVMDoubleVisitor())
+            deref(self.lambda_visitor).init(args_, outs_, cse, self.opt_level)
 
         cdef _load(self, const string &s):
-            self.lambda_double.resize(1)
-            self.lambda_double[0].loads(s)
+            self.lambda_visitor.reset(new symengine.LLVMDoubleVisitor())
+            deref(self.lambda_visitor).loads(s)
 
         def __reduce__(self):
             """
             Interface for pickle. Note that the resulting object is platform dependent.
             """
-            cdef bytes s = self.lambda_double[0].dumps()
+            cdef bytes s = deref(self.lambda_visitor).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])
+            deref(self.lambda_visitor).call(&out[out_offset], &inp[inp_offset])
 
         cpdef unsafe_eval(self, inp, out, unsigned nbroadcast=1):
             cdef double[::1] c_inp, c_out
@@ -5242,7 +5246,7 @@ IF HAVE_SYMENGINE_LLVM:
             c_inp = np.ascontiguousarray(inp.ravel(order=self.order), dtype=self.numpy_dtype)
             c_out = out
             for idx in range(nbroadcast):
-                self.lambda_double[0].call(&c_out[idx*self.tot_out_size], &c_inp[idx*self.args_size])
+                deref(self.lambda_visitor).call(&c_out[idx*self.tot_out_size], &c_inp[idx*self.args_size])
 
         cpdef as_scipy_low_level_callable(self):
             from ctypes import c_double, c_void_p, c_int, cast, POINTER, CFUNCTYPE
@@ -5252,7 +5256,7 @@ IF HAVE_SYMENGINE_LLVM:
                 raise RuntimeError("SciPy LowLevelCallable supports only functions with 1 output")
             addr1 = cast(<size_t>&_scipy_callback_llvm_real,
                             CFUNCTYPE(c_double, c_int, POINTER(c_double), c_void_p))
-            addr2 = cast(<size_t>&self.lambda_double[0], c_void_p)
+            addr2 = cast(<size_t>self.lambda_visitor.get(), c_void_p)
             return create_low_level_callable(self, addr1, addr2)
 
         cpdef as_ctypes(self):
@@ -5269,7 +5273,7 @@ IF HAVE_SYMENGINE_LLVM:
                 raise RuntimeError("Lambda function has to be real")
             addr1 = cast(<size_t>&_ctypes_callback_llvm_real,
                             CFUNCTYPE(c_void_p, POINTER(c_double), POINTER(c_double), c_void_p))
-            addr2 = cast(<size_t>&self.lambda_double[0], c_void_p)
+            addr2 = cast(<size_t>self.lambda_visitor.get(), c_void_p)
             return addr1, addr2
 
     cdef class LLVMFloat(_LLVMLambdify):
@@ -5277,23 +5281,23 @@ IF HAVE_SYMENGINE_LLVM:
             self.opt_level = opt_level
 
         cdef _init(self, symengine.vec_basic& args_, symengine.vec_basic& outs_, cppbool cse):
-            self.lambda_double.resize(1)
-            self.lambda_double[0].init(args_, outs_, cse, self.opt_level)
+            self.lambda_visitor.reset(new symengine.LLVMFloatVisitor())
+            deref(self.lambda_visitor).init(args_, outs_, cse, self.opt_level)
 
         cdef _load(self, const string &s):
-            self.lambda_double.resize(1)
-            self.lambda_double[0].loads(s)
+            self.lambda_visitor.reset(new symengine.LLVMFloatVisitor())
+            deref(self.lambda_visitor).loads(s)
 
         def __reduce__(self):
             """
             Interface for pickle. Note that the resulting object is platform dependent.
             """
-            cdef bytes s = self.lambda_double[0].dumps()
+            cdef bytes s = deref(self.lambda_visitor).dumps()
             return llvm_float_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, float[::1] inp, float[::1] out, int inp_offset=0, int out_offset=0):
-            self.lambda_double[0].call(&out[out_offset], &inp[inp_offset])
+            deref(self.lambda_visitor).call(&out[out_offset], &inp[inp_offset])
 
         cpdef unsafe_eval(self, inp, out, unsigned nbroadcast=1):
             cdef float[::1] c_inp, c_out
@@ -5301,7 +5305,7 @@ IF HAVE_SYMENGINE_LLVM:
             c_inp = np.ascontiguousarray(inp.ravel(order=self.order), dtype=self.numpy_dtype)
             c_out = out
             for idx in range(nbroadcast):
-                self.lambda_double[0].call(&c_out[idx*self.tot_out_size], &c_inp[idx*self.args_size])
+                deref(self.lambda_visitor).call(&c_out[idx*self.tot_out_size], &c_inp[idx*self.args_size])
 
     IF HAVE_SYMENGINE_LLVM_LONG_DOUBLE:
         cdef class LLVMLongDouble(_LLVMLambdify):
@@ -5309,23 +5313,23 @@ IF HAVE_SYMENGINE_LLVM:
                 self.opt_level = opt_level
 
             cdef _init(self, symengine.vec_basic& args_, symengine.vec_basic& outs_, cppbool cse):
-                self.lambda_double.resize(1)
-                self.lambda_double[0].init(args_, outs_, cse, self.opt_level)
+                self.lambda_visitor.reset(new symengine.LLVMLongDoubleVisitor())
+                deref(self.lambda_visitor).init(args_, outs_, cse, self.opt_level)
 
             cdef _load(self, const string &s):
-                self.lambda_double.resize(1)
-                self.lambda_double[0].loads(s)
+                self.lambda_visitor.reset(new symengine.LLVMLongDoubleVisitor())
+                deref(self.lambda_visitor).loads(s)
 
             def __reduce__(self):
                 """
                 Interface for pickle. Note that the resulting object is platform dependent.
                 """
-                cdef bytes s = self.lambda_double[0].dumps()
+                cdef bytes s = deref(self.lambda_visitor).dumps()
                 return llvm_long_double_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, long double[::1] inp, long double[::1] out, int inp_offset=0, int out_offset=0):
-                self.lambda_double[0].call(&out[out_offset], &inp[inp_offset])
+                deref(self.lambda_visitor).call(&out[out_offset], &inp[inp_offset])
 
             cpdef unsafe_eval(self, inp, out, unsigned nbroadcast=1):
                 cdef long double[::1] c_inp, c_out
@@ -5333,7 +5337,7 @@ IF HAVE_SYMENGINE_LLVM:
                 c_inp = np.ascontiguousarray(inp.ravel(order=self.order), dtype=self.numpy_dtype)
                 c_out = out
                 for idx in range(nbroadcast):
-                    self.lambda_double[0].call(&c_out[idx*self.tot_out_size], &c_inp[idx*self.args_size])
+                    deref(self.lambda_visitor).call(&c_out[idx*self.tot_out_size], &c_inp[idx*self.args_size])
 
     def llvm_loading_func(*args):
         return LLVMDouble(args, _load=True)
diff --git a/symengine_version.txt b/symengine_version.txt
index 4f7638fd..87a1cf59 100644
--- a/symengine_version.txt
+++ b/symengine_version.txt
@@ -1,1 +1,1 @@
-v0.11.1
+v0.12.0


Test patch:
diff --git a/symengine/tests/test_logic.py b/symengine/tests/test_logic.py
index 7c01f8e9..3d0c3391 100644
--- a/symengine/tests/test_logic.py
+++ b/symengine/tests/test_logic.py
@@ -27,6 +27,10 @@ def test_relationals():
     assert Ge(1, 1) == true
     assert Eq(I, 2) == false
     assert Ne(I, 2) == true
+    eq = Eq(x, y)
+    assert eq.func(*eq.args) == eq
+    ne = Ne(x, y)
+    assert ne.func(*ne.args) == ne
 
 
 def test_rich_cmp():
@@ -118,4 +122,3 @@ def test_Contains():
     assert Contains(x, Interval(1, 1)) != false
     assert Contains(oo, Interval(-oo, oo)) == false
     assert Contains(-oo, Interval(-oo, oo)) == false
-