diff --git a/symengine/lib/symengine.pxd b/symengine/lib/symengine.pxd index ad44992ec..2e29e5501 100644 --- a/symengine/lib/symengine.pxd +++ b/symengine/lib/symengine.pxd @@ -214,6 +214,7 @@ cdef extern from "" namespace "SymEngine": RCP[const Subs] rcp_static_cast_Subs "SymEngine::rcp_static_cast"(rcp_const_basic &b) nogil RCP[const RealDouble] rcp_static_cast_RealDouble "SymEngine::rcp_static_cast"(rcp_const_basic &b) nogil RCP[const ComplexDouble] rcp_static_cast_ComplexDouble "SymEngine::rcp_static_cast"(rcp_const_basic &b) nogil + RCP[const ComplexBase] rcp_static_cast_ComplexBase "SymEngine::rcp_static_cast"(rcp_const_basic &b) nogil RCP[const RealMPFR] rcp_static_cast_RealMPFR "SymEngine::rcp_static_cast"(rcp_const_basic &b) nogil RCP[const ComplexMPC] rcp_static_cast_ComplexMPC "SymEngine::rcp_static_cast"(rcp_const_basic &b) nogil RCP[const Log] rcp_static_cast_Log "SymEngine::rcp_static_cast"(rcp_const_basic &b) nogil @@ -363,7 +364,9 @@ cdef extern from "" namespace "SymEngine": Integer(int i) nogil Integer(integer_class i) nogil int compare(const Basic &o) nogil - integer_class as_mpz() nogil + integer_class as_integer_class() nogil + cdef long mp_get_si(integer_class &i) nogil + cdef double mp_get_d(integer_class &i) nogil cdef RCP[const Integer] integer(int i) nogil cdef RCP[const Integer] integer(integer_class i) nogil int i_nth_root(const Ptr[RCP[Integer]] &r, const Integer &a, unsigned long int n) nogil @@ -372,16 +375,19 @@ cdef extern from "" namespace "SymEngine": cdef extern from "" namespace "SymEngine": cdef cppclass Rational(Number): - rational_class as_mpq() nogil + rational_class as_rational_class() nogil + cdef double mp_get_d(rational_class &i) nogil cdef RCP[const Number] from_mpq "SymEngine::Rational::from_mpq"(rational_class r) nogil cdef void get_num_den(const Rational &rat, const Ptr[RCP[Integer]] &num, const Ptr[RCP[Integer]] &den) nogil cdef RCP[const Number] rational(long n, long d) nogil cdef extern from "" namespace "SymEngine": - cdef cppclass Complex(Number): + cdef cppclass ComplexBase(Number): RCP[const Number] real_part() nogil RCP[const Number] imaginary_part() nogil + cdef cppclass Complex(ComplexBase): + pass cdef extern from "" namespace "SymEngine": cdef cppclass RealDouble(Number): @@ -390,10 +396,8 @@ cdef extern from "" namespace "SymEngine": RCP[const RealDouble] real_double(double d) nogil cdef extern from "" namespace "SymEngine": - cdef cppclass ComplexDouble(Number): + cdef cppclass ComplexDouble(ComplexBase): ComplexDouble(double complex x) nogil - RCP[const Number] real_part() nogil - RCP[const Number] imaginary_part() nogil double complex as_complex_double() nogil RCP[const ComplexDouble] complex_double(double complex d) nogil @@ -751,12 +755,10 @@ IF HAVE_SYMENGINE_MPC: mpc_ptr get_mpc_t() nogil mpc_class(string s, mpfr_prec_t prec, unsigned base) nogil - cdef cppclass ComplexMPC(Number): + cdef cppclass ComplexMPC(ComplexBase): ComplexMPC(mpc_class) nogil mpc_class as_mpc() nogil mpfr_prec_t get_prec() nogil - RCP[const Number] real_part() nogil - RCP[const Number] imaginary_part() nogil RCP[const ComplexMPC] complex_mpc(mpc_class t) nogil ELSE: diff --git a/symengine/lib/symengine_wrapper.pyx b/symengine/lib/symengine_wrapper.pyx index dc5da333c..a8e8c5927 100644 --- a/symengine/lib/symengine_wrapper.pyx +++ b/symengine/lib/symengine_wrapper.pyx @@ -1066,6 +1066,25 @@ cdef class Basic(object): s.append(c2py((Y[i]))._sympy_()) return s + def __float__(self): + f = self.n(real=True) + if not isinstance(f, RealDouble): + raise TypeError("Can't convert expression to float") + return float(f) + + def __int__(self): + return int(float(self)) + + def __long__(self): + return long(float(self)) + + def __complex__(self): + f = self.n(real=False) + if not isinstance(f, (ComplexDouble, RealDouble)): + raise TypeError("Can't convert expression to float") + return complex(f) + + def series(ex, x=None, x0=0, n=6, as_deg_coef_pair=False): # TODO: check for x0 an infinity, see sympy/core/expr.py # TODO: nonzero x0 @@ -1546,6 +1565,14 @@ cdef class Number(Expr): def is_complex(Basic self): return deref(symengine.rcp_static_cast_Number(self.thisptr)).is_complex() + @property + def real(self): + return self + + @property + def imag(self): + return S.Zero + class Rational(Number): @@ -1602,6 +1629,7 @@ class Rational(Number): def func(self): return self.__class__ + class Integer(Rational): def __new__(cls, i): @@ -1687,14 +1715,8 @@ class Integer(Rational): import sage.all as sage return sage.Integer(str(self)) - def __int__(self): - return int(str(self)) - - def __long__(self): - return long(str(self)) - - def __float__(self): - return float(str(self)) + def __int__(Basic self): + return symengine.mp_get_si(deref(symengine.rcp_static_cast_Integer(self.thisptr)).as_integer_class()) @property def p(self): @@ -1779,14 +1801,33 @@ class RealDouble(Float): def _sage_(Basic self): import sage.all as sage - cdef double i = deref(symengine.rcp_static_cast_RealDouble(self.thisptr)).as_double() - return sage.RealDoubleField()(i) + return sage.RealDoubleField()(float(self)) - def __float__(self): - return float(str(self)) + def __float__(Basic self): + return deref(symengine.rcp_static_cast_RealDouble(self.thisptr)).as_double() + + def __complex__(self): + return complex(float(self)) -cdef class ComplexDouble(Number): +cdef class ComplexBase(Number): + + def real_part(Basic self): + return c2py(deref(symengine.rcp_static_cast_ComplexBase(self.thisptr)).real_part()) + + def imaginary_part(Basic self): + return c2py(deref(symengine.rcp_static_cast_ComplexBase(self.thisptr)).imaginary_part()) + + @property + def real(self): + return self.real_part() + + @property + def imag(self): + return self.imaginary_part() + + +cdef class ComplexDouble(ComplexBase): def __cinit__(self, i = None): if i is None: @@ -1794,12 +1835,6 @@ cdef class ComplexDouble(Number): cdef double complex i_ = i self.thisptr = symengine.make_rcp_ComplexDouble(i_) - def real_part(Basic self): - return c2py(deref(symengine.rcp_static_cast_ComplexDouble(self.thisptr)).real_part()) - - def imaginary_part(Basic self): - return c2py(deref(symengine.rcp_static_cast_ComplexDouble(self.thisptr)).imaginary_part()) - def _sympy_(self): import sympy return self.real_part()._sympy_() + sympy.I * self.imaginary_part()._sympy_() @@ -1808,6 +1843,9 @@ cdef class ComplexDouble(Number): import sage.all as sage return self.real_part()._sage_() + sage.I * self.imaginary_part()._sage_() + def __complex__(Basic self): + return deref(symengine.rcp_static_cast_ComplexDouble(self.thisptr)).as_complex_double() + class RealMPFR(Float): @@ -1836,14 +1874,11 @@ class RealMPFR(Float): except ImportError: import sage.all as sage return sage.RealField(int(self.get_prec()))(str(self)) - - def __float__(self): - return float(str(self)) ELSE: pass -cdef class ComplexMPC(Number): +cdef class ComplexMPC(ComplexBase): IF HAVE_SYMENGINE_MPC: def __cinit__(self, i = None, j = 0, long prec = 53, unsigned base = 10): if i is None: @@ -1852,12 +1887,6 @@ cdef class ComplexMPC(Number): cdef symengine.mpc_class m = symengine.mpc_class(i_, prec, base) self.thisptr = symengine.complex_mpc(symengine.std_move_mpc(m)) - def real_part(self): - return c2py(deref(symengine.rcp_static_cast_ComplexMPC(self.thisptr)).real_part()) - - def imaginary_part(self): - return c2py(deref(symengine.rcp_static_cast_ComplexMPC(self.thisptr)).imaginary_part()) - def _sympy_(self): import sympy return self.real_part()._sympy_() + sympy.I * self.imaginary_part()._sympy_() @@ -1873,13 +1902,7 @@ cdef class ComplexMPC(Number): pass -cdef class Complex(Number): - - def real_part(self): - return c2py(deref(symengine.rcp_static_cast_Complex(self.thisptr)).real_part()) - - def imaginary_part(self): - return c2py(deref(symengine.rcp_static_cast_Complex(self.thisptr)).imaginary_part()) +cdef class Complex(ComplexBase): def _sympy_(self): import sympy diff --git a/symengine/tests/test_number.py b/symengine/tests/test_number.py index 30de1173c..a189027c2 100644 --- a/symengine/tests/test_number.py +++ b/symengine/tests/test_number.py @@ -1,12 +1,17 @@ from symengine.utilities import raises -from symengine import Integer, I +from symengine import Integer, I, S from symengine.lib.symengine_wrapper import (perfect_power, is_square, integer_nthroot) def test_integer(): i = Integer(5) assert str(i) == "5" + assert int(i) == 5 + assert float(i) == 5.0 + assert complex(i) == 5.0 + 0j + assert i.real == i + assert i.imag == S.Zero def test_integer_long(): @@ -18,6 +23,30 @@ def test_integer_string(): assert Integer("133") == 133 +def test_rational(): + i = Integer(5)/10 + assert str(i) == "1/2" + assert int(i) == 0 + assert float(i) == 0.5 + assert complex(i) == 0.5 + 0j + assert i.real == i + assert i.imag == S.Zero + + +def test_complex(): + i = Integer(5)/10 + I + assert str(i) == "1/2 + I" + assert complex(i) == 0.5 + 1j + assert i.real == Integer(1)/2 + assert i.imag == 1 + + i = 0.5 + I + assert str(i) == "0.5 + 1.0*I" + assert complex(i) == 0.5 + 1j + assert i.real == 0.5 + assert i.imag == 1.0 + + def test_smallfloat_valid(): i = Integer(7.5) assert str(i) == "7"