@@ -46,6 +46,7 @@ cpdef void assign_to_capsule(object capsule, object value):
4646
4747cdef object c2py(rcp_const_basic o):
4848 cdef Basic r
49+ cdef PyObject * obj
4950 if (symengine.is_a_Add(deref(o))):
5051 r = Expr.__new__ (Add)
5152 elif (symengine.is_a_Mul(deref(o))):
@@ -74,7 +75,10 @@ cdef object c2py(rcp_const_basic o):
7475 r = Dummy.__new__ (Dummy)
7576 elif (symengine.is_a_Symbol(deref(o))):
7677 if (symengine.is_a_PySymbol(deref(o))):
77- return < object > (deref(symengine.rcp_static_cast_PySymbol(o)).get_py_object())
78+ obj = deref(symengine.rcp_static_cast_PySymbol(o)).get_py_object()
79+ result = < object > (obj)
80+ Py_XDECREF(obj);
81+ return result
7882 r = Symbol.__new__ (Symbol)
7983 elif (symengine.is_a_Constant(deref(o))):
8084 r = S.Pi
@@ -1216,16 +1220,26 @@ cdef class Expr(Basic):
12161220
12171221
12181222cdef class Symbol(Expr):
1219-
12201223 """
12211224 Symbol is a class to store a symbolic variable with a given name.
1225+ Subclassing Symbol leads to a memory leak due to a cycle in reference counting.
1226+ To avoid this with a performance penalty, set the kwarg store_pickle=True
1227+ in the constructor and support the pickle protocol in the subclass by
1228+ implmenting __reduce__.
12221229 """
12231230
12241231 def __init__ (Basic self , name , *args , **kwargs ):
1232+ cdef cppbool store_pickle;
12251233 if type (self ) == Symbol:
12261234 self .thisptr = symengine.make_rcp_Symbol(name.encode(" utf-8" ))
12271235 else :
1228- self .thisptr = symengine.make_rcp_PySymbol(name.encode(" utf-8" ), < PyObject* > self )
1236+ store_pickle = kwargs.pop(" store_pickle" , False )
1237+ if store_pickle:
1238+ # First set the pointer to a regular symbol so that when pickle.dumps
1239+ # is called when the PySymbol is created, methods like name works.
1240+ self .thisptr = symengine.make_rcp_Symbol(name.encode(" utf-8" ))
1241+ self .thisptr = symengine.make_rcp_PySymbol(name.encode(" utf-8" ), < PyObject* > self ,
1242+ store_pickle)
12291243
12301244 def _sympy_ (self ):
12311245 import sympy
@@ -2635,6 +2649,14 @@ class atan2(Function):
26352649 cdef Basic Y = sympify(y)
26362650 return c2py(symengine.atan2(X.thisptr, Y.thisptr))
26372651
2652+ def _sympy_ (self ):
2653+ import sympy
2654+ return sympy.atan2(* self .args_as_sympy())
2655+
2656+ def _sage_ (self ):
2657+ import sage.all as sage
2658+ return sage.atan2(* self .args_as_sage())
2659+
26382660# For backwards compatibility
26392661
26402662Sin = sin
@@ -3895,7 +3917,7 @@ cdef class DenseMatrixBase(MatrixBase):
38953917 l.append(c2py(A.get(i, j))._sympy_())
38963918 s.append(l)
38973919 import sympy
3898- return sympy.Matrix (s)
3920+ return sympy.ImmutableMatrix (s)
38993921
39003922 def _sage_ (self ):
39013923 s = []
@@ -3906,7 +3928,7 @@ cdef class DenseMatrixBase(MatrixBase):
39063928 l.append(c2py(A.get(i, j))._sage_())
39073929 s.append(l)
39083930 import sage.all as sage
3909- return sage.Matrix(s)
3931+ return sage.Matrix(s, immutable = True )
39103932
39113933 def dump_real (self , double[::1] out ):
39123934 cdef size_t ri, ci, nr, nc
@@ -4046,6 +4068,12 @@ cdef class ImmutableDenseMatrix(DenseMatrixBase):
40464068 def __setitem__ (self , key , value ):
40474069 raise TypeError (" Cannot set values of {}" .format(self .__class__))
40484070
4071+ def _applyfunc (self , f ):
4072+ res = DenseMatrix(self )
4073+ res._applyfunc(f)
4074+ return ImmutableDenseMatrix(res)
4075+
4076+
40494077ImmutableMatrix = ImmutableDenseMatrix
40504078
40514079
@@ -5203,7 +5231,7 @@ def Lambdify(args, *exprs, cppbool real=True, backend=None, order='C',
52035231 Whether datatype is ``double`` (``double complex`` otherwise).
52045232 backend : str
52055233 'llvm' or 'lambda'. When ``None`` the environment variable
5206- 'SYMENGINE_LAMBDIFY_BACKEND' is used (taken as 'lambda ' if unset ).
5234+ 'SYMENGINE_LAMBDIFY_BACKEND' is used (taken as 'llvm ' if available, otherwise 'lambda' ).
52075235 order : 'C' or 'F'
52085236 C- or Fortran-contiguous memory layout. Note that this affects
52095237 broadcasting: e.g. a (m, n) matrix taking 3 arguments and given a
@@ -5235,7 +5263,11 @@ def Lambdify(args, *exprs, cppbool real=True, backend=None, order='C',
52355263
52365264 """
52375265 if backend is None :
5238- backend = os.getenv(' SYMENGINE_LAMBDIFY_BACKEND' , " lambda" )
5266+ IF HAVE_SYMENGINE_LLVM:
5267+ backend_default = ' llvm' if real else ' lambda'
5268+ ELSE :
5269+ backend_default = ' lambda'
5270+ backend = os.getenv(' SYMENGINE_LAMBDIFY_BACKEND' , backend_default)
52395271 if backend == " llvm" :
52405272 IF HAVE_SYMENGINE_LLVM:
52415273 if dtype == None :
0 commit comments