@@ -46,6 +46,7 @@ cpdef void assign_to_capsule(object capsule, object value):
46
46
47
47
cdef object c2py(rcp_const_basic o):
48
48
cdef Basic r
49
+ cdef PyObject * obj
49
50
if (symengine.is_a_Add(deref(o))):
50
51
r = Expr.__new__ (Add)
51
52
elif (symengine.is_a_Mul(deref(o))):
@@ -74,7 +75,10 @@ cdef object c2py(rcp_const_basic o):
74
75
r = Dummy.__new__ (Dummy)
75
76
elif (symengine.is_a_Symbol(deref(o))):
76
77
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
78
82
r = Symbol.__new__ (Symbol)
79
83
elif (symengine.is_a_Constant(deref(o))):
80
84
r = S.Pi
@@ -1216,16 +1220,26 @@ cdef class Expr(Basic):
1216
1220
1217
1221
1218
1222
cdef class Symbol(Expr):
1219
-
1220
1223
"""
1221
1224
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__.
1222
1229
"""
1223
1230
1224
1231
def __init__ (Basic self , name , *args , **kwargs ):
1232
+ cdef cppbool store_pickle;
1225
1233
if type (self ) == Symbol:
1226
1234
self .thisptr = symengine.make_rcp_Symbol(name.encode(" utf-8" ))
1227
1235
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)
1229
1243
1230
1244
def _sympy_ (self ):
1231
1245
import sympy
@@ -2635,6 +2649,14 @@ class atan2(Function):
2635
2649
cdef Basic Y = sympify(y)
2636
2650
return c2py(symengine.atan2(X.thisptr, Y.thisptr))
2637
2651
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
+
2638
2660
# For backwards compatibility
2639
2661
2640
2662
Sin = sin
@@ -3895,7 +3917,7 @@ cdef class DenseMatrixBase(MatrixBase):
3895
3917
l.append(c2py(A.get(i, j))._sympy_())
3896
3918
s.append(l)
3897
3919
import sympy
3898
- return sympy.Matrix (s)
3920
+ return sympy.ImmutableMatrix (s)
3899
3921
3900
3922
def _sage_ (self ):
3901
3923
s = []
@@ -3906,7 +3928,7 @@ cdef class DenseMatrixBase(MatrixBase):
3906
3928
l.append(c2py(A.get(i, j))._sage_())
3907
3929
s.append(l)
3908
3930
import sage.all as sage
3909
- return sage.Matrix(s)
3931
+ return sage.Matrix(s, immutable = True )
3910
3932
3911
3933
def dump_real (self , double[::1] out ):
3912
3934
cdef size_t ri, ci, nr, nc
@@ -4046,6 +4068,12 @@ cdef class ImmutableDenseMatrix(DenseMatrixBase):
4046
4068
def __setitem__ (self , key , value ):
4047
4069
raise TypeError (" Cannot set values of {}" .format(self .__class__))
4048
4070
4071
+ def _applyfunc (self , f ):
4072
+ res = DenseMatrix(self )
4073
+ res._applyfunc(f)
4074
+ return ImmutableDenseMatrix(res)
4075
+
4076
+
4049
4077
ImmutableMatrix = ImmutableDenseMatrix
4050
4078
4051
4079
@@ -5203,7 +5231,7 @@ def Lambdify(args, *exprs, cppbool real=True, backend=None, order='C',
5203
5231
Whether datatype is ``double`` (``double complex`` otherwise).
5204
5232
backend : str
5205
5233
'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' ).
5207
5235
order : 'C' or 'F'
5208
5236
C- or Fortran-contiguous memory layout. Note that this affects
5209
5237
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',
5235
5263
5236
5264
"""
5237
5265
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)
5239
5271
if backend == " llvm" :
5240
5272
IF HAVE_SYMENGINE_LLVM:
5241
5273
if dtype == None :
0 commit comments