Friday, June 26, 2015

GSoC Week 5

This week, I looked into installing SymEngine in Sage and wrappers. One issue was that we have a header named `complex.h` and some libraries look inside `$SAGE_LOCAL/include` for the C header `complex` and this leads to errors. It was decided to install symengine headers inside a folder called `symengine` so that a header could be accessed by `symengine/basic.h` form and it avoids clashes.

I looked at other libraries for how this is done. Some libraries have the installing headers in a separate folder like `include/project_name`, but `.cpp`s under `src`. Some libraries have headers and source files in the same folder and they are included in `project_name` folder. Since SymEngine has headers and sources in the same folder, we decided to rename `src` to `symengine`. This lead to another problem. Python wrappers folder was named `symengine`. So I moved them to `symengine/python/symengine` to enable using symengine python wrappers inside the build directory (although you have to change directory into `symengine/python` to use it).

Some other work involved, making sure `make install` installed all the python tests and installing dependencies in Travis-ci without using sudo.

That's all the updates for this week. Mid evaluations are coming this week, so I hope to get a SymEngine spkg done this week.

Saturday, June 20, 2015

GSoC 2015 - Week 4

This week I got access to OS X, so I decided to do all the work related to OS X this week while I had access. First of all, I worked on getting CMake to build on Sage in OS X 10.10. CMake is supported to be built using clang on OS X and is not supporting gcc. Since sage uses gcc for building packages, I tried building CMake on Sage. (Thanks to +Rajith for giving me the chance to work on his Mac).

Main problem with CMake in OSX 10.10 was that it uses an Apple header <CoreFoundation/CoreFoundation.h> which is a collection of headers including <CoreFoundation/CFStream.h> which in turn includes a faulty Apple header '/usr/local/include/dispatch/dispatch.h'. After going through CMake code, it seemed that although the header 'CoreFoundation.h' was included 'CFStream.h' was not needed. So I used the specific headers needed (<CoreFoundation/CFBundle.h> etc.) and CMake was successfully built on Sage. Testing the CMake installation resulted in 6 out of 387 tests failing.

Another good news was that we got access to test SymEngine on TravisCI with OSX. We are testing clang and gcc both to make sure, symengine builds on both. Building with clang was successful, but with gcc there were couple of problems and was hard to check on TravisCI as there were huge queuing times for builds on OSX.

One issue is that on OSX, gmp library we are linking to is installed by homebrew. g++ was using a different C++ standard library than what gmp was compiled with and hence linking errors occur. A CMake check was added to try to compile a simple program with gmpxx and if it fails, give an error message at configuration time.

Another issue was that `uint` was used in some places instead of `unsigned int`. On Linux and OSX clang `unsigned int` was typedef as `uint`, so there was no problem detected in automated tests in Travis-CI. Since `uint` is not a C++ standard type, it was changed to `unsigned int`.

Next week, I will try to figure out why 6 tests in CMake test suite fails and try to fix those and get CMake into optional packages. Also I will work on the wrappers for sage for SymEngine.

Sunday, June 14, 2015

GSoC 2015 : Week 3

This week, I continued my work from the previous two weeks to complete the floating point support for SymEngine.

RealDouble was the wrapper for double used in SymEngine and it used to return NaN for numerical evaluations that resulted in a complex number. Checks were added to ensure that if the result was complex, a ComplexDouble was returned. So now, `asin` for RealDouble looks like this

    virtual RCP<const Basic> asin(const Basic &x) const {
        SYMENGINE_ASSERT(is_a<RealDouble>(x))
        double d = static_cast<const RealDouble &>(x).i;
        if (d <= 1.0 && d >= -1.0) {
            return number(std::asin(d));
        } else {
            return number(std::asin(std::complex<double>(d)));
        }
    }

Here, when the result is a double, a RealMPFR is returned, while when it is complex, RealDouble is converted to std::complex<double>, evaluated and then a ComplexDouble is returned.

Implementing RealMPFR took more time than I thought, because of several design decisions that were needed to be taken.

Basic classes in SymEngine are immutable classes. So, when constructing a RealMPFR class, the mpfr_t value has to be passed into the RealMPFR's constructor. Which means when working with RealMPFR, we would first construct a mpfr_t, initialize it, set a value to the mpfr_t and then construct the RealMPFR. Therefore when exceptions are raised and caught, memory leaks happen, because the mpfr_t is not managed. This is also in EvalMPFR class where if we had an expression like 3 + x that we want to evaluate numerically, but when trying to evaluate x numerically, an exception is raised and a memory leak happens. Solution was to implement a managed mpfr_class that acts like mpz_class. 

To avoid adding a new dependency, I implemented a simple mpfr_class that would manage the mpfr_t inside it. 

class mpfr_class {
private:
    mpfr_t mp;
public:
    mpfr_ptr get_mpfr_t() { return mp; }
    mpfr_srcptr get_mpfr_t() const { return mp; }
    mpfr_class(mpfr_t m) {
        mpfr_init2(mp, mpfr_get_prec(m));
        mpfr_set(mp, m, MPFR_RNDN);
    }
    mpfr_class(mpfr_prec_t prec = 53) {
        mpfr_init2(mp, prec);
    }
mpfr_class(const mpfr_class& other) { mpfr_init2(mp, mpfr_get_prec(other.get_mpfr_t())); mpfr_set(mp, other.get_mpfr_t(), MPFR_RNDN); } mpfr_class(mpfr_class&& other) { mp->_mpfr_d = nullptr; mpfr_swap(mp, other.get_mpfr_t()); } mpfr_class& operator=(const mpfr_class& other) { mpfr_set_prec(mp, mpfr_get_prec(other.get_mpfr_t())); mpfr_set(mp, other.get_mpfr_t(), MPFR_RNDN); return *this; } mpfr_class& operator=(mpfr_class&& other) { mpfr_swap(mp, other.get_mpfr_t()); return *this; } ~mpfr_class() { if (mp->_mpfr_d != nullptr) { mpfr_clear(mp); } } };

To add the move constructors and destructors, it was needed to know if a mpfr_class has been initialized or not. This was achieved by setting _mpfr_d pointer to null when move constructor is called to avoid adding a data member to mpfr_class. Thanks to +Ondřej Čertík  and +Francesco Biscani  for the ideas and comments. 

Similarly an mpc_class was introduced to manage a mpc_t object. Another decision taken was to use a default rounding mode for rounding when operations on RealMPFR's and ComplexMPC's are done.

When adding two RealMPFR's of different precisions, it was decided to promote the RealMPFR with low precision to higher precision. An example of this is given below.

RCP<const Number> RealMPFR::addreal(const RealMPFR &other) const {
    mpfr_class t(std::max(get_prec(), other.get_prec()));
    mpfr_add(t.get_mpfr_t(), i.get_mpfr_t(), other.i.get_mpfr_t(), MPFR_RNDN);
    return rcp(new RealMPFR(std::move(t)));
}
To add SymEngine into Sage, I had to add CMake into Sage as well, since CMake is a dependency of SymEngine. Problem with including CMake was that it fails to build with OS X 10.10 due to a bug in a header installed in OS X 10.10 (/usr/include/dispatch/object.h). This header does not give a fault when compiling with clang but with gcc which is included in Sage this gives an error. This seemed to be a problem in building bundled curl in cmake, but realized that it was not so afterwards. After building curl and linking with it in cmake, I got the same error on OS X. I got access to OS X 10.10 only this week, but will try next week as time permits.

For next week, I am going to implement the wrappers for SymEngine for Sage. (i.e. conversions to and from Sage).

Sunday, June 7, 2015

GSoC 2015 : Weeks 1 & 2

These two weeks, I worked on finishing up the floating point support for SymEngine.

First ComplexDouble class was introduced to keep a std::complex<double>. With automatic simplification interface completed, implementing this class did not touch any of the other classes except for RealDouble which used the ComplexDouble classes when an operation on RealDouble resulted in a complex.

SymEngine had eval_arb and eval_double for numerical evaluations, but eval_double is double precision only and since arb is not a standard package with sage, SymEngine needed to use another library already in Sage for that. eval_mpfr method was introduced to use MPFR to get arbitrary precision numerical approximations for symbolic expressions. MPFR library is a C library for multiple-precision floating-point computations with correct rounding. MPFR is also a dependency of arb and therefore SymEngine already had support for linking against it in cmake. See PR.

Next step is to interface a library for arbitrary precision complex floating point computations and MPC which is a Sage standard package is used. MPC extends the functionality of MPFR to complex numbers. eval_mpc was written to evaluate the expressions using MPC.

This weekend, I hope to finish eval_mpc, add a RealMPFR and a ComplexMPC classes to store mpfr_t and mpc_t respectively and then write a eval function that would combine all 4 methods, eval_double, eval_complex_double, eval_mpfr, eval_mpc and finally wrap it into python so that a user can call it with expression.n(number_of_bits)

3rd and 4th week, I am going to concentrate on getting the wrappers for Sage done. CSymPy (Python wrappers of SymEngine) to Sage and Sage to CSymPy conversion support is going to be added to sage via Cython. This PR has some work on this for CSymPy to Sage conversions, but then it was decided to implement this in the sage symbolic directory to avoid a cyclic dependency.