Skip to content

Commit 10b20ed

Browse files
committed
Add support for converting to python float types
1 parent df48df0 commit 10b20ed

File tree

3 files changed

+115
-42
lines changed

3 files changed

+115
-42
lines changed

symengine/lib/symengine.pxd

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ cdef extern from "<symengine/basic.h>" namespace "SymEngine":
214214
RCP[const Subs] rcp_static_cast_Subs "SymEngine::rcp_static_cast<const SymEngine::Subs>"(rcp_const_basic &b) nogil
215215
RCP[const RealDouble] rcp_static_cast_RealDouble "SymEngine::rcp_static_cast<const SymEngine::RealDouble>"(rcp_const_basic &b) nogil
216216
RCP[const ComplexDouble] rcp_static_cast_ComplexDouble "SymEngine::rcp_static_cast<const SymEngine::ComplexDouble>"(rcp_const_basic &b) nogil
217+
RCP[const ComplexBase] rcp_static_cast_ComplexBase "SymEngine::rcp_static_cast<const SymEngine::ComplexBase>"(rcp_const_basic &b) nogil
217218
RCP[const RealMPFR] rcp_static_cast_RealMPFR "SymEngine::rcp_static_cast<const SymEngine::RealMPFR>"(rcp_const_basic &b) nogil
218219
RCP[const ComplexMPC] rcp_static_cast_ComplexMPC "SymEngine::rcp_static_cast<const SymEngine::ComplexMPC>"(rcp_const_basic &b) nogil
219220
RCP[const Log] rcp_static_cast_Log "SymEngine::rcp_static_cast<const SymEngine::Log>"(rcp_const_basic &b) nogil
@@ -363,7 +364,9 @@ cdef extern from "<symengine/integer.h>" namespace "SymEngine":
363364
Integer(int i) nogil
364365
Integer(integer_class i) nogil
365366
int compare(const Basic &o) nogil
366-
integer_class as_mpz() nogil
367+
integer_class as_integer_class() nogil
368+
cdef long mp_get_si(integer_class &i) nogil
369+
cdef double mp_get_d(integer_class &i) nogil
367370
cdef RCP[const Integer] integer(int i) nogil
368371
cdef RCP[const Integer] integer(integer_class i) nogil
369372
int i_nth_root(const Ptr[RCP[Integer]] &r, const Integer &a, unsigned long int n) nogil
@@ -372,16 +375,19 @@ cdef extern from "<symengine/integer.h>" namespace "SymEngine":
372375

373376
cdef extern from "<symengine/rational.h>" namespace "SymEngine":
374377
cdef cppclass Rational(Number):
375-
rational_class as_mpq() nogil
378+
rational_class as_rational_class() nogil
379+
cdef double mp_get_d(rational_class &i) nogil
376380
cdef RCP[const Number] from_mpq "SymEngine::Rational::from_mpq"(rational_class r) nogil
377381
cdef void get_num_den(const Rational &rat, const Ptr[RCP[Integer]] &num,
378382
const Ptr[RCP[Integer]] &den) nogil
379383
cdef RCP[const Number] rational(long n, long d) nogil
380384

381385
cdef extern from "<symengine/complex.h>" namespace "SymEngine":
382-
cdef cppclass Complex(Number):
386+
cdef cppclass ComplexBase(Number):
383387
RCP[const Number] real_part() nogil
384388
RCP[const Number] imaginary_part() nogil
389+
cdef cppclass Complex(ComplexBase):
390+
pass
385391

386392
cdef extern from "<symengine/real_double.h>" namespace "SymEngine":
387393
cdef cppclass RealDouble(Number):
@@ -390,10 +396,8 @@ cdef extern from "<symengine/real_double.h>" namespace "SymEngine":
390396
RCP[const RealDouble] real_double(double d) nogil
391397

392398
cdef extern from "<symengine/complex_double.h>" namespace "SymEngine":
393-
cdef cppclass ComplexDouble(Number):
399+
cdef cppclass ComplexDouble(ComplexBase):
394400
ComplexDouble(double complex x) nogil
395-
RCP[const Number] real_part() nogil
396-
RCP[const Number] imaginary_part() nogil
397401
double complex as_complex_double() nogil
398402
RCP[const ComplexDouble] complex_double(double complex d) nogil
399403

@@ -751,12 +755,10 @@ IF HAVE_SYMENGINE_MPC:
751755
mpc_ptr get_mpc_t() nogil
752756
mpc_class(string s, mpfr_prec_t prec, unsigned base) nogil
753757

754-
cdef cppclass ComplexMPC(Number):
758+
cdef cppclass ComplexMPC(ComplexBase):
755759
ComplexMPC(mpc_class) nogil
756760
mpc_class as_mpc() nogil
757761
mpfr_prec_t get_prec() nogil
758-
RCP[const Number] real_part() nogil
759-
RCP[const Number] imaginary_part() nogil
760762

761763
RCP[const ComplexMPC] complex_mpc(mpc_class t) nogil
762764
ELSE:

symengine/lib/symengine_wrapper.pyx

Lines changed: 74 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,6 +1546,14 @@ cdef class Number(Expr):
15461546
def is_complex(Basic self):
15471547
return deref(symengine.rcp_static_cast_Number(self.thisptr)).is_complex()
15481548

1549+
@property
1550+
def real(self):
1551+
return self
1552+
1553+
@property
1554+
def imag(self):
1555+
return S.Zero
1556+
15491557

15501558
class Rational(Number):
15511559

@@ -1602,6 +1610,18 @@ class Rational(Number):
16021610
def func(self):
16031611
return self.__class__
16041612

1613+
def __int__(Basic self):
1614+
return int(float(self))
1615+
1616+
def __long__(self):
1617+
return int(self)
1618+
1619+
def __float__(Basic self):
1620+
return symengine.mp_get_d(deref(symengine.rcp_static_cast_Rational(self.thisptr)).as_rational_class())
1621+
1622+
def __complex__(self):
1623+
return complex(float(self))
1624+
16051625
class Integer(Rational):
16061626

16071627
def __new__(cls, i):
@@ -1687,14 +1707,11 @@ class Integer(Rational):
16871707
import sage.all as sage
16881708
return sage.Integer(str(self))
16891709

1690-
def __int__(self):
1691-
return int(str(self))
1710+
def __int__(Basic self):
1711+
return symengine.mp_get_si(deref(symengine.rcp_static_cast_Integer(self.thisptr)).as_integer_class())
16921712

1693-
def __long__(self):
1694-
return long(str(self))
1695-
1696-
def __float__(self):
1697-
return float(str(self))
1713+
def __float__(Basic self):
1714+
return symengine.mp_get_d(deref(symengine.rcp_static_cast_Integer(self.thisptr)).as_integer_class())
16981715

16991716
@property
17001717
def p(self):
@@ -1779,27 +1796,55 @@ class RealDouble(Float):
17791796

17801797
def _sage_(Basic self):
17811798
import sage.all as sage
1782-
cdef double i = deref(symengine.rcp_static_cast_RealDouble(self.thisptr)).as_double()
1783-
return sage.RealDoubleField()(i)
1799+
return sage.RealDoubleField()(float(self))
1800+
1801+
def __float__(Basic self):
1802+
return deref(symengine.rcp_static_cast_RealDouble(self.thisptr)).as_double()
1803+
1804+
def __int__(self):
1805+
return int(float(self))
1806+
1807+
def __long__(self):
1808+
return long(float(self))
1809+
1810+
def __complex__(self):
1811+
return complex(float(self))
1812+
1813+
1814+
cdef class ComplexBase(Number):
1815+
1816+
def __int__(self):
1817+
return int(complex(self))
1818+
1819+
def __long__(self):
1820+
return long(complex(self))
17841821

17851822
def __float__(self):
1786-
return float(str(self))
1823+
return float(complex(self))
1824+
1825+
def real_part(Basic self):
1826+
return c2py(<rcp_const_basic>deref(symengine.rcp_static_cast_ComplexBase(self.thisptr)).real_part())
1827+
1828+
def imaginary_part(Basic self):
1829+
return c2py(<rcp_const_basic>deref(symengine.rcp_static_cast_ComplexBase(self.thisptr)).imaginary_part())
1830+
1831+
@property
1832+
def real(self):
1833+
return self.real_part()
1834+
1835+
@property
1836+
def imag(self):
1837+
return self.imaginary_part()
17871838

17881839

1789-
cdef class ComplexDouble(Number):
1840+
cdef class ComplexDouble(ComplexBase):
17901841

17911842
def __cinit__(self, i = None):
17921843
if i is None:
17931844
return
17941845
cdef double complex i_ = i
17951846
self.thisptr = symengine.make_rcp_ComplexDouble(i_)
17961847

1797-
def real_part(Basic self):
1798-
return c2py(<rcp_const_basic>deref(symengine.rcp_static_cast_ComplexDouble(self.thisptr)).real_part())
1799-
1800-
def imaginary_part(Basic self):
1801-
return c2py(<rcp_const_basic>deref(symengine.rcp_static_cast_ComplexDouble(self.thisptr)).imaginary_part())
1802-
18031848
def _sympy_(self):
18041849
import sympy
18051850
return self.real_part()._sympy_() + sympy.I * self.imaginary_part()._sympy_()
@@ -1808,6 +1853,9 @@ cdef class ComplexDouble(Number):
18081853
import sage.all as sage
18091854
return self.real_part()._sage_() + sage.I * self.imaginary_part()._sage_()
18101855

1856+
def __complex__(Basic self):
1857+
return deref(symengine.rcp_static_cast_ComplexDouble(self.thisptr)).as_complex_double()
1858+
18111859

18121860
class RealMPFR(Float):
18131861

@@ -1838,12 +1886,12 @@ class RealMPFR(Float):
18381886
return sage.RealField(int(self.get_prec()))(str(self))
18391887

18401888
def __float__(self):
1841-
return float(str(self))
1889+
return float(self.n(real=True))
18421890
ELSE:
18431891
pass
18441892

18451893

1846-
cdef class ComplexMPC(Number):
1894+
cdef class ComplexMPC(ComplexBase):
18471895
IF HAVE_SYMENGINE_MPC:
18481896
def __cinit__(self, i = None, j = 0, long prec = 53, unsigned base = 10):
18491897
if i is None:
@@ -1852,12 +1900,6 @@ cdef class ComplexMPC(Number):
18521900
cdef symengine.mpc_class m = symengine.mpc_class(i_, prec, base)
18531901
self.thisptr = <rcp_const_basic>symengine.complex_mpc(symengine.std_move_mpc(m))
18541902

1855-
def real_part(self):
1856-
return c2py(<rcp_const_basic>deref(symengine.rcp_static_cast_ComplexMPC(self.thisptr)).real_part())
1857-
1858-
def imaginary_part(self):
1859-
return c2py(<rcp_const_basic>deref(symengine.rcp_static_cast_ComplexMPC(self.thisptr)).imaginary_part())
1860-
18611903
def _sympy_(self):
18621904
import sympy
18631905
return self.real_part()._sympy_() + sympy.I * self.imaginary_part()._sympy_()
@@ -1869,17 +1911,14 @@ cdef class ComplexMPC(Number):
18691911
except ImportError:
18701912
import sage.all as sage
18711913
return sage.MPComplexField(int(self.get_prec()))(str(self.real_part()), str(self.imaginary_part()))
1914+
1915+
def __complex__(self):
1916+
return complex(self.n(real=False))
18721917
ELSE:
18731918
pass
18741919

18751920

1876-
cdef class Complex(Number):
1877-
1878-
def real_part(self):
1879-
return c2py(<rcp_const_basic>deref(symengine.rcp_static_cast_Complex(self.thisptr)).real_part())
1880-
1881-
def imaginary_part(self):
1882-
return c2py(<rcp_const_basic>deref(symengine.rcp_static_cast_Complex(self.thisptr)).imaginary_part())
1921+
cdef class Complex(ComplexBase):
18831922

18841923
def _sympy_(self):
18851924
import sympy
@@ -1889,6 +1928,9 @@ cdef class Complex(Number):
18891928
import sage.all as sage
18901929
return self.real_part()._sage_() + sage.I * self.imaginary_part()._sage_()
18911930

1931+
def __complex__(self):
1932+
return complex(self.n(real=False))
1933+
18921934

18931935
cdef class Infinity(Number):
18941936

symengine/tests/test_number.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
from symengine.utilities import raises
22

3-
from symengine import Integer, I
3+
from symengine import Integer, I, S
44
from symengine.lib.symengine_wrapper import (perfect_power, is_square, integer_nthroot)
55

66

77
def test_integer():
88
i = Integer(5)
99
assert str(i) == "5"
10+
assert int(i) == 5
11+
assert float(i) == 5.0
12+
assert complex(i) == 5.0 + 0j
13+
assert i.real == i
14+
assert i.imag == S.Zero
1015

1116

1217
def test_integer_long():
@@ -18,6 +23,30 @@ def test_integer_string():
1823
assert Integer("133") == 133
1924

2025

26+
def test_rational():
27+
i = Integer(5)/10
28+
assert str(i) == "1/2"
29+
assert int(i) == 0
30+
assert float(i) == 0.5
31+
assert complex(i) == 0.5 + 0j
32+
assert i.real == i
33+
assert i.imag == S.Zero
34+
35+
36+
def test_complex():
37+
i = Integer(5)/10 + I
38+
assert str(i) == "1/2 + I"
39+
assert complex(i) == 0.5 + 1j
40+
assert i.real == Integer(1)/2
41+
assert i.imag == 1
42+
43+
i = 0.5 + I
44+
assert str(i) == "0.5 + 1.0*I"
45+
assert complex(i) == 0.5 + 1j
46+
assert i.real == 0.5
47+
assert i.imag == 1.0
48+
49+
2150
def test_smallfloat_valid():
2251
i = Integer(7.5)
2352
assert str(i) == "7"

0 commit comments

Comments
 (0)