Skip to content

GSoC 2015 Application Abinash Meher: Ruby bindings for CSymPy

Abinash Meher edited this page Apr 11, 2015 · 16 revisions
  1. Contact information.
    Name : Abinash Meher
    Email : [email protected]
    GitHub user ID : @abinashmeher999
    Location : IIT Kharagpur, India

  2. Why do you like Ruby, and why do you want to work on SciRuby?
    Ruby is so close to the natural language, that it becomes very easy to express my logic with a few lines of code. I was amazed when I saw a few samples of code, that one cannot tell if it's a simple english sentence or a piece of ruby code. Thanks to 'why's (poignant) guide to Ruby' for making learning the language just like reading a comic. If it weren't for it, I won't be as attached to ruby as I am today.

I have used scientific libraries for python, and I know how easy they make working on a difficult project, where writing optimized code can divert your attention from the main problem statement. A library for these things comes to be of great help. One can use existing research without having to be a scientist for it! SciRuby does the same for ruby. Knowing how easy it is to code your logic in ruby, one can say that it's going to be very much used in the coming years.

This is a very good opportunity to be involved in such an endeavour at its early stages. Getting an opportunity to write some code, that you know is going to be used by many engineers and scientists, is very exciting. Ruby and a scientific library for it like SciRuby make a great combination. SciRuby will also help Ruby gain popularity in the scientific community. Not only SciRuby, but I also get to work with CSymPy too. Very few get the chance to work with two organisations in a single GSoC.

  1. What do you like about science and why? What area do you like best?
    Science in itself is an attempt to explain the things in the universe. It has provided us with reason and logic, very powerful tools in an order to make sense out of things, that would have otherwise appeared chaotic and baffled our minds. I have a tendency to like things that make sense. Science has allowed us to progress and evolve by giving us something to exercise our grey cells. I like how it uses a systematic approach to understand and discover pattern from something that seems random on the surface, backed by reason and logic at every point.

I am very much fascinated by theoretical physics, which can very much be accredited to 'A Brief History of Time'.

  1. Describe your experience with the following: Ruby, C, C++, other languages.
    Ruby : Started coding one month back. Comfortable in using the language, but not as much as in C++.
    C/C++ : Have been coding in these languages for past 2 years, and have been exposed to most of the features. I am very much comfortable working in C or C++.
    Java : 6 months experience. I am fairly comfortable with Java. I have used this for completing assignments that also involve designing GUI.
    Python : Little experience. I can very well read python code, but can't write it as fluently as Ruby.

  2. Describe your educational background (school, degree plan, major, past degrees, research area, publications, etc.).
    I am a second year undergraduate student in Department of Computer Science and Engineering. I am also a member of the software team of Autonomous Ground Vehicle (AGV) Research Group, IIT Kharagpur where I have worked on Motion Planning and Machine Learning.
    I have taken courses like Programming and Data Structures, Discrete Structures, Introduction to Algorithms, Software Engineering in Computer Science, and Mathematics-I and II, Probability and Statistics in Mathematics.

  3. Have you offered any pull requests for SciRuby or contributed in other ways? Please provide links, if possible. Past contributions are not essential, but are highly recommended.
    I started working on SciRuby pretty late. However, after I chose the project Ruby bindings to the CSymPy C++ symbolic library I tried to get started as soon as I can. I learnt ruby from scratch, which I think I needed, to get a good foundation. Apart from that because of some prior commitment, I couldn't give sufficient time to the project.

  1. What other commitments do you have this summer aside from GSoC? What obstacles do you foresee this summer as far as contributing the full forty hours per week during the GSoC period?

I am going to stay here at the college for the whole summer (except for a few days). I don't have any commitments at my home too. Although my college starts from 10th of July, I will still be able to contribute full time since there won't be any exams or tests. Apart from that I don't see any other obstacles. These, in a sense, are not obstacles but some engagements.

  1. Are you planning any fun vacations this summer?
    The only fun I will have this summer is by coding and by the company of friends who will be staying back at college for some projects. Apart from that I don't have any fun vacations planned.

  2. How many classes are you taking this summer?
    I am not taking any classes this summer.

  3. Do you have any other employment this summer?
    I am not doing any summer project or going for an internship(if that is what you mean). The only engagements I have are the commitments that I have mentioned above.

  4. Please talk a bit about any past GSoC projects in which you have participated. If you've done GSoC before, how could we reach your mentor(s)?
    I haven't done GSoC before. This is my first attempt at GSoC.

  5. Please propose a project you would like to work on.


Ruby bindings to the CSymPy C++ symbolic library

Motivation

The motivation was to have a computer algebra system for Ruby. At the beginning, the idea was to use ruby wrapper for sage which uses Pynac for its symbolic manipulation (Pynac is a Python interfact to GiNaC and CLN), because it is much faster.
However, from the benchmarks, CSymPy is much faster than Pynac. The reason Pynac is slower is probably because it uses Sage's GMP functionality. In case of CSymPy there is no Python being called from the C++ code. The code is entirely in C++. It was for this reason that there's no need to worry about any potential Python overhead. It also allows us to use it from other languages, with the help of wrappers.
Another option was to wrap GiNaC directly, but CSymPy also seems to be a bit faster than GiNaC itself by now. The code has been designed in such a way so that one can play with various data structures and really make sure the code is fast.
There is one small limitation however. Compared to GiNaC, CSymPy is missing specialized polynomial manipulation and series expansion and pattern matching, all of which are being worked on and will get the functionality soon. Most part of it might get completed during this summer as part of GSoC projects. Execution

  1. Tool to generate the wrappers
    There were many choices like Ruby inline, Rice, FFI, SWIG and manually using Ruby C API . From the first 3 FFI seems to be the fastest as benchmarked in this link. However, with the FFI method, we get a segfault at runtime while running Ruby tests (which we will be adding whatever tool we use). Here manual method is advantageous since it is compiled, so we immediately get a compile error on Travis if we change an interface in CSymPy, so we know we have to fix it, while merging the patch. It will be a huge comfort. Also, the manual method is preferred while dealing with a lot of pointers in the C++ code. Because either way we would end up doing as much work. Also the code is clearer in the manual method. With SWIG, C++ references are supported, but SWIG transforms them back into pointers, as mentioned here. It's a feature that we might be needing some time later. So, going with the manual method seems the wisest.

  2. File structure
    Currently all the python wrappers are in a folder csympy under the root folder. The idea is to keep all the wrapper code at a single place, i.e. inside the src in separate folders like src/c, src/python and src/ruby. The same logic can be applied to other languages later like src/julia, etc.
    Each folder can then be configured to a ready to install package like the python wrappers as a pip-package and the ruby wrappers as a gem.

  3. Exposing the C++ functions to C with extern "C"
    Ruby provides interfacing to only C functions. For that we need to expose the C++ code through extern. The functions can now be called from C. Let's take an example C++ class, using one header file (Test.hpp) for demonstration

//File: Test.hpp
class Test {
    public:
        int testfunc();
        Test();

    private:
        int testint;
};

and one implementation file (Test.cpp)

//File: Test.cpp
#include <iostream>
#include "Test.hpp"

using namespace std;

Test::Test() {
    this->testint = rand()%1000 ;
}

int Test::testfunc() {
    return this->testint;
}

This is how csympy is structured, C++ code that does the actual job.

We will have some glue code. This code is something in-between C and C++. We will have one header file (TestWrapper.h, just .h as it doesn't contain any C++ code)

//File: TestWrapper.h
#include <ruby.h>
typedef void CTest;

#ifdef __cplusplus
extern "C" {
#endif

static VALUE test_alloc(VALUE self);
static VALUE test_initialize(VALUE self);
static VALUE test_testfunc(VALUE self);
void test_delete(CTest *t);

#ifdef __cplusplus
}
#endif

and the function implementations (TestWrapper.cpp, .cpp as it contains C++ code):

//File: TestWrapper.cpp
#include "TestWrapper.h"
#include "Test.hpp"

extern "C" {

    void test_delete(CTest *test) {
        Test *t = static_cast<Test *>(test);
        delete t;
    }

    static VALUE test_alloc(VALUE self) {
        Test *data = new Test();
        data = static_cast<CTest *>(data);
        return Data_Wrap_Struct(self, NULL, test_delete, data);
    }

    static VALUE test_testfunc(VALUE self) {
        Test * data;
        Data_Get_Struct(self,Test,data);
        return INT2NUM(data->testfunc());
    }

    static VALUE test_initialize(VALUE self) {
        //nothing to do in this case
        return self;
    }
}

These are the wrappers that expose the C++ functions to C.

  1. Writing the extensions with Ruby C API
    Since the Ruby interpreter is implemented in C, its API can be used. This is called the Ruby C API. It can be accessed with the inclusion of a single file #include <ruby.h>.

"Everything you can do in Ruby, you can also do using [the] C API"

ruby.h contains all the datatypes, C functions and MACRO definitions to be able to interface C/C++ with Ruby.
Every Ruby type/class is a VALUE C type. VALUE is a just a uintptr_t C type, or void* to simplify things. There is also another type representing Ruby symbols (like :my_symbol), this is the C type ID. Ruby C API also defines a bunch of handful C constants defining standard Ruby objects.
There are macros defined to convert the C types to the ruby types. Rest all are C functions that define modules, classes, and their instance and class methods. There are also functions to raise exceptions.
With some more effort, even threading can be implemented.
See The Definitive Guide to Ruby's C API for more details.
For example, doing this for the Test class we get.

//File: ruby_TestWrapper.c
#include <ruby.h>
#include "TestWrapper.h"

static VALUE m_testmodule;
static VALUE c_test;

void Init_testmodule() {  //this is called when we call require 'testmodule' in ruby
    m_testmodule = rb_define_module("TestModule");
    c_test = rb_define_class_under(m_testmodule,"Test",rb_cObject);

    rb_define_alloc_func(c_test, test_new);
    rb_define_method(c_test, "initialize", test_initialize, 0);
    rb_define_method(c_test, "testfunc", test_testfunc, 0);
}

Since everything is not covered, you can refer to the documentation for this from README.EXT. Also the Chris Lalancette's blog.

  1. mkmf and extconf.rb
    The extconf.rb configures a Makefile that will build our extension based. The extconf.rb must check for the necessary functions, macros and shared libraries your extension depends upon. The extconf.rb must exit with an error if any of these are missing. It requires the mkmf or the MakeMakefile module for that matter. The extconf.rb would look like
require 'mkmf'

#Gives the ability to easily use alternate compilers to build the extension
RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC']

extension_name = 'csympy'

#Check to see if the csympy library required to build this extension exists.
#Typically, we would want to use libcsympy installed, including the header files
unless pkg_config('libcsympy')
      raise "libcsympy not found"
end

have_func('useful_function', 'libcsympy/lib.h')#if found, will define a HAVE_USEFUL_FUNCTION in extconf.h
have_type('useful_type', 'libcsympy/lib.h')#if found, will define a HAVE_TYPE_USEFUL_TYPE in extconf.h

#creates the header file extconf.h, based on the results from all of the previous have_*() functions.
#The extconf.h file will be included by all of the C files in the project 
#to gain access to the HAVE_* macros that extconf defines.
create_header

create_makefile(extension_name)
  1. Data structures in CSymPy
    CSymPy uses some STL data types like std::vector and std::map. These map cleanly to the Array and Hash in Ruby.

We will only need to interface the data between both of them only in the case of when the underlying C++ functions return these data types, not when they are used as member variables. Because we are passing the objects as simple pointers of type void * and again casting them (either static_cast or reinterpret_cast) back to the object inside the C function call implementation. Assuming all the member variables of the class are private and interacts only with methods, there is no need to worry about having a similar internal structure as the C++ one in Ruby. We just have to worry about interfacing the member functions. Even if the corresponding implementation of the data types in Ruby turns out to be slow, we won't be affected by it, except when a new similar large data type is to be made to be returned.

So, we are not losing out on speed that CSymPy offers.

Please see Part-9 and Part-10 of this blog for more information about interfacing Arrays and Hashs.

  1. Exception Handling
    All the C++ code that is to be interfaced will have to be wrapped with a C function first, to be used with the Ruby C API. However in C, there doesn't seem to be a way to handle the exceptions that the underlying C++ code might throw. Therefore all the exceptions will have to be handled in the underlying C++ code itself. Since the ruby C API defined exceptions can also be called from C++ the idea is to catch the exceptions from the underlying C++ code and rethrow it with rb_raise after copying the required information from the exception passed. This is possible because they are compiled with a cpp compiler. For example, let's say that the member function Test::test_func() throws an exception. This is how we will be changing the TestWrapper.cc file
//the previous function definition of test_testfunc will be replaced by
static VALUE test_testfunc(VALUE self) {
    try{
        Test * data;
        Data_Get_Struct(self,Test,data);
        return INT2NUM(data->testfunc());
    }catch(ExceptionClass1 e1){
        VALUE exception;
        //Copy the required information from e1
        //to exception;
        exception=rb_exc_new2(rb_eException, "Error message");
        rb_iv_set(exception, "@additional_info",
                 rb_str_new2("information from e1"));
        rb_exc_raise(exception);
    }
}

This is not final, please refer here for an ongoing discussion.

  1. Garbage Collection
    Ruby 2.1 introduced a generational garbage collector (called RGenGC). RGenGC (mostly) keeps compatibility. Generally, the use of the technique called write barriers is required in extension libraries for generational GC. RGenGC works fine without write barriers in extension libraries. However, caring about write barrier can improve the performance of the GC.
    But we won't need to if we are using built-in types from Ruby C API. Most built-in types support write barrier. If we are using the T_DATA datatype from ruby, which doesn't have write barriers, we might have to write one. But that is strongly discouraged since writing write barriers are easy to introduce critical bugs and there is too much risk associated with it. We won't use T_DATA unless there's no other way.
    For this to work properly it's advised not to touch the pointers directly. Rather use the C-API's methods to acquire pointers to the internal data structures.

While using the C API, there won't be the need to 'mark' each data we define, if they are defined following the proper allocation framework(Given in the Ruby Hacking Guide) using Data_Wrap_Struct() and Data_Get_Struct(), or using the given ruby C functions for that purpose, like rb_class_new_instance(). The functions mark them internally, and is taken care of automatically by the GC.

Also, there will be issues because of the optimizing C compilers. Since they are not designed with conservative GC in mind, they might optimize away the original VALUE even when the code depends on it. Also sometimes a variable might get GC'ed when we don't want it to. To prevent such premature GC, we will use RB_GC_GUARD() macro which comes with Ruby C API and needs to be called after the last usage of the variable. There might be times when this doesn't work, like when the VALUEs are in the heap storage and we do not want them on the stack for the time they are not to be GC'ed, we can hack the functions in API to mark them for the time and develop our own functions to do this, like NM_GC_(UN)REGISTER functions in NMatrix.

Also, there might be times when we are sure that a particular object is not needed anymore and can be GC'ed rb_gc_force_recycle() can be invoked. It let's users mention explicitly to collect a particular object.

I don't think that the RCP(either the Teuchos or the csympy implementation) used in csympy will interfere with the wrappers, since they are used with the underlying C++ functions to be wrapped. We still cannot eliminate the possibility.

  1. Ruby Interface
    This is a crucial factor when it comes to writing a library for ruby. This project may not involve writing complete library but also it doesn't involve writing only the extensions. This also incorporates designing a proper interface that suits the style of coding in Ruby. Again, this can't be achieved at once, but will require feedback from people who use the wrappers. I sure would like to have the wrappers have a rubyish interface. However, This is a long term process. My first goal would be to clone the C++ wrappers as faithfully as I can, and then second would be to improve upon the base design, incorporating things like blocks, procs, mixins, named methods, etc. that are characteristic of ruby. The latter might require writing additional classes. For the time being, I will follow the ruby convention of naming the methods and variables (e.g. ending with ?, etc.).

  2. Making this a gem
    Making this available as a gem will make it very easy to install. The ease of installation can be very important factor when it comes to user engagement. User will have the choice if (s)he wants to install the wrappers along with csympy or only the wrappers(in case he has csympy already). A check can be included to automate this. We will also need a functionality to just compile the extensions separately than the library.

Tools I am going to use

I am using a system dual-booted with Ubuntu 14.04.2 LTS and Windows 8.1. Following are the configurations on my machine

abinashmeher999@JARVIS:~$ ruby --version
ruby 2.0.0p598 (2014-05-08 revision 45883) [x86_64-linux]
abinashmeher999@JARVIS:~$ gem --version
1.8.23
abinashmeher999@JARVIS:~$ rake --version
rake, version 10.0.4
abinashmeher999@JARVIS:~$ rspec --version
3.2.2
abinashmeher999@JARVIS:~$ bundle --version
Bundler version 1.3.5
abinashmeher999@JARVIS:~$ rdoc --version
rdoc 3.9.5
abinashmeher999@JARVIS:~$ rvm --version
rvm 1.26.10 (latest) by Wayne E. Seguin <[email protected]>, Michal Papis <[email protected]> [https://rvm.io/]
abinashmeher999@JARVIS:~$ valgrind --version
valgrind-3.10.0.SVN

I am using RVM to manage the ruby versions in my system. Besides that, I will be using vim as my primary text editor. Apart from that I will be using the following

  • Rake-compiler
    rake-compiler is a set of rake tasks for automating extension building. Rake eases the process of making extensions by its 'rake/extensiontask'. If a proper project structure is followed, generating extensions requires only a few lines of code.
  • RSpec
    RSpec tests it the way a developer would like it to, to make sure all works as (s)he intended them. More like the unit tests. Whereas, Cucumber tests it the way a client/consumer would expect from the software. Like the integration tests. Most of the places, people suggest that both go hand in hand. But since the underlying C++ code is tested elsewhere, integration testing won't be needed.
  • Bundler
    Bundler provides a consistent environment for Ruby projects by tracking and installing the exact gems and versions that are needed. It ensures that the gems you need are present in development, staging, and production.
  • RDoc
    For documentation of code and tests. I would also like to look into to generate ri(ruby interactive) documentation if time permits.
  • Valgrind
    Valgrind is a tool suite that automatically detects many memory and thread related problems with an application. It's composed of few tools, each designed to track different kind of problems like detect bad memory usage, detect memory leaks, profile heap usage, etc. This will prove to be a very useful to check for memory leaks from the extension code. I wil be using it to check for memory leaks in the C code.

Timeline (tentative)

New Proposed Timeline

The new timeline is inspired by Test-Driven Development that will break down the entire task of writing wrappers into modules that can be subsequently tested and deployed as they develop, into a minimal gem. This way we can get feedback early. This will involve writing the tests before writing the code. These tests will set short term goals for the wrappers. After the tests pass, they can be directly merged with the codebase and hence to the gem.

The whole task can be divided into 5 phases, each with their short-term goal/test to achieve. The phases consist of one or more units that can be introduced as a feature to the gem which we will build upon. And the tests that the code should pass, will be divided as one test file for each unit.

Before the phases begin, some preparations will also be done for setting up the basic framework of the wrappers and the units will be subsequently added after that.

Also each of the units will involve first writing the tests, then writing the function declaration for the pure C wrappers and their definition, then writing the C ruby wrappers declaration and definition, and finally writing them in the Init_csympy(). In short, I will be going through the cycle of my old timeline for each of these units.

I will use the test files for the python wrappers as a reference. They have given a vague idea on how to proceed.
Documenting them are an obvious task.

  1. Phase 1 : Symbol, its dependent classes and Parsing
    Estimated time: 2 Weeks
  • After this, the gem will support Symbol class and classes like Integer, Rational and Complex .

  • The gem will also support parsing of strings as expressions of symbols.

  • The corresponding test files will be the RSpec equivalent of test_symbol.py, test_integer.py and test_sympify.py.

    1. Phase 2 : arit and subs
      Estimated time: 2 Weeks
  • The gem will support all the arithmetic operations like addition, multiplication and exponentiation of symbols.

  • It will also support substitution of one symbol by other symbols. Might be useful for evaluation of expressions later.

  • The corresponding test files will be the RSpec equivalent of test_arit.py and test_subs.py.

    1. Phase 3 : eval and functions
      Estimated time: 2 Weeks
  • After this, the gem will support evaluation of expressions by substituting symbols with numbers.

  • It will also support function_symbols, and all the arithmetic operations on functions. It will also support derivative of them.

  • I will also add the trigonometric functions after the above. However, we may need a different test files for them.

  • The corresponding test files will be the RSpec equivalent of test_eval.py and test_functions.py.

    Till Mid-Term I would have covered upto eval/evaluation of expressions. That's the minimum target. If possible I would like to finish this early to concentrate on later parts.

    1. Phase 4 : matrices
      Estimated time: 2 Weeks
  • After this, it will support symbolic operations on the elements of matrices.

  • As well as arithmetic operations on matrices that have symbols.

  • The corresponding test files will be the RSpec equivalent of test_matrices.py.

    1. Phase 5 : ntheory
      Estimated time: 2 Weeks
  • This will add support for all the functions corresponding to number theory in csympy, like mod, quotient, quotient_mod, mod_inverse, etc.

  • These will also support operations like lcm, gcd, finding primes, etc.

  • The corresponding test files will be the RSpec equivalent of test_ntheory.py.

    I have kept 2 weeks at the beginning for Community bonding and learning the things that I am yet to learn, and 2 weeks at the end as a buffer time, to compensate for my 8 day absence and catching up.

Community Bonding period (27th April - 24th May) and Week 1

  • I don't know everybody yet, neither did I get enough time to know at least a few developers in the community before the application. This will be a great time to get to know everybody and the fellow students. My summer vacation will start from 29th of April.
  • The remaining time will be devoted to integrating making of ruby extensions from cmake, by invoking rake from cmake. So that the building of extensions can be checked by travis. Travis is already integrated with csympy.

Week 2

  • I can get up to speed by reading the documentation and getting to know the practices followed in the community. While I don't claim to know how to use the tools that I mentioned, this will be the time, I learn them.
  • I will also use this time to read the documentation for the tools I will be using, so that I know how to use them properly and am aware of the best way to achieve the result and make informed decisions.
  • I will also set a dummy gem with no functionality so that the functionalities are added as they are interfaced. The gem will be published after 2 weeks from now.

Week 3

  • This week I will write tests and interface Symbol class and other dependent classes like Integer, Complex and Rational.

Week 4

  • This week I will be working to achieve Parsing to symbols from text. Tests will precede this.
  • Also start working on the arithmetic operations.

Week 5

  • This week will be devoted towards supporting arithmetic operations with symbols and testing them.
  • Start writing the tests for subs.

Week 6

  • This week will be devoted to supporting substitution with symbols in expressions.
  • If time is left I will start working on function_symbols and evaluation of expressions.

Week 7

  • Writing target tests and interfacing eval that will make evaluation of expressions possible. If this finishes early I can start on function_symbols, because other trigonometric functions might will take more time.
  • By the end of this week, for the Mid-term the gem will have the functionality for all the above phases.

Week 8

  • I will write target tests for the trigonometric functions, substitution of function_symbols and many more. Then implement the all the C and Ruby wrapper for them just like the previous ones.

Week 9 and Week 10

  • This week will be dedicated to achieve arithmetic operations with matrices that have symbols as their elements.
  • The rest of the week will be devoted to implement the features tested in test_ntheory.py. They are a bunch of features and we might need to use a bit of our buffer week too.

Week 11

  • These two weeks will mainly focus on interfacing the number theory and like functions. However, I still aim to cover some part of this earlier. Because one week might not be enough as I have written in the phase description.
  • This will most probably be covered within this week. If not, I will extend it to the Buffer period.

Buffer Period and Week 12 and 13

This week is the buffer and a precaution for everything that might delay the completion. This will mostly involve

  • cleaning up the code and refactoring, fixing bugs and documentation
  • addition of more tests, examples and everything that's pending
  • Make sure the installation works on all systems

Note:

During the whole GSoC, I will be blogging weekly about my progress and experience at this blog. The timeline might seem sparse as at this moment I am not able to judge how much time each work is going to take. If something is finished before time, I will proceed to the next part. Also there is the buffer period in case a bug pushes things down the line.

Post GSoC

  • I will try to write some benchmarks for the ruby wrappers if the time permits and any of the buffer period in still left.
  • I will try to include the functionality that csympy currently lacks but will most likely get as a result of the GSoC. I will be able to contribute during my semester, but not as effectively as during the summer. This could be completed by end of winter(December) holidays.

Previous Timeline (for reference)

The project will consist of four phases.

  1. Phase 1 : Writing the C wrappers
    Estimated time: 2 Weeks
    The first step would be to write pure C wrappers for the C++ code, so that we create some reusable code since we are interfacing through C, that can be used for some other languages. This will involve
  • writing function declarations in header files,

  • their definitions in source files,

  • creating new structs maybe,

  • error handling (returning error codes) and

  • documentation. 2. Phase 2 : Writing the Ruby wrappers
    Estimated time: 3 Weeks
    This will be the code that will be in C and will use Ruby C API to interface the created pure C functions to Ruby. This will involve

  • writing function declarations in header files,

  • writing their definitions in source files,

  • exception handling (raising exceptions in Ruby),

  • managing garbage collection,

  • defining module, its classes and methods in Init_csympy and

  • configuring extconf.rb

  • documentation 3. Phase 3 : Writing the Tests (RSpec)
    Estimated time: 2.5 Weeks
    This the phase where we test that our code is working and not leaking memory. If anything is wrong, we make sure that the extension is working. This involves

  • Setting up the rake tasks,

  • Invoking rake commands from cmake,

  • Writing tests using RSpec

  • Checking for memory leaks using Valgrind

  • Fixing bugs 4. Phase 4 : Packaging and Wrap up
    Estimated time: 1.5 Weeks
    In this phase, we make the set of extensions readily available to be installed and used. The rest of the time is used to do cleanup of code, and fixing bugs. This involves

  • Clean up and refactoring, if needed

  • Fixing bugs

  • Packaging it as a gem

  • Making sure it works and installs for all platforms

  • Publishing the gem to rubygems.org

    I have kept 2 weeks at the beginning for Community bonding and learning the things that I am yet to learn, and 2 weeks at the end as a buffer time, to compensate for my 8 day absence and catching up.

Community Bonding period (27th April - 24th May) and Week 1

  • I don't know everybody yet, neither did I get enough time to know at least a few developers in the community before the application. This will be a great time to get to know everybody and the fellow students. My summer vacation will start from 29th of April.

Week 2

  • I can get up to speed by reading the documentation and getting to know the practices followed in the community. While I don't claim to know how to use the tools that I mentioned, this will be the time, I learn them.
  • I will also use this time to read the documentation for the tools I will be using, so that I know how to use them properly and am aware of the best way to achieve the result and make informed decisions.

Week 3

  • This week will be dedicated to make the header files in src/c(the place for pure C wrappers), that contain the C function prototypes with extern "C", with C++ code in them. The interface between C and C++.
  • Also I will prefer to document the functions.

Week 4

  • This week has, writing the function definition for the declarations in the header files for the pure C wrappers. Error handling will be done the standard way upon catching any exceptions. This part won't use Ruby C API.
  • Also documenting it on the go.

Week 5

  • This week's task will be to write the header files, that contain the C function prototypes for the Ruby wrappers. These will go to the folder src/ruby. These will not be the same as the earlier ones since these will use the Ruby C API.
  • Defining some additional MACROs for GC as discussed above. Also documenting the code.

Week 6

  • This week involves writing the implementations/function declarations for the ruby-wrapper C header files in src/ruby(the ones that use Ruby C API). This will also include having proper exception handling along with the guarantee they provide, and looking for places where GC might prematurely collect.
  • Some custom data types might need making custom classes and that would require writing write barriers.
  • This will also involve documenting the implementation.

Week 7

  • I will completely devote this week to writing the actual Ruby wrappers in the Init_csympy function, the function that will initialise the module. This function will contain calls to the Ruby C API functions to define the module, the classes and their methods.

Week 8

  • I will devote this week to configure the extconf.rb using FLANN's extconf.rb as a model, and extensively cover all the rake tasks that would be needed for the building of extensions and the tests.
  • The remaining time will be devoted to integrating making of ruby extensions from cmake, by invoking rake from cmake. So that the building of extensions can be checked by travis.

Testing and Week 9

  • This week will involve writing the unit tests and carrying them out using RSpec.
  • Special tests that involve writing the possible memory leaking piece of code and running it in a loop, and checking the memory usage during that period. More details here. Valgrind might be useful for this.
  • Also automating the above tests.

Testing and Week 10

  • After writing the tests, bugs and errors are sure to pop up. This week will be devoted to fix them. This includes finding and fixing memory leaks and making sure garbage collection works properly. I might have to delve deeper into garbage collection in order to fix the problem. This might involve using low level functions in API as a hack.
  • The rest of the time I will devote to make improvements in the interface, the way they will be called from Ruby code, trying to accommodate the ruby coding style with the function calls.

Packaging and Week 11

  • This week I will devote to making this project a gem, that will check if all the dependencies are met on the system to be installed. If not, it might provide the libraries of csympy that can be used to build the extensions or ask the user to resolve them.
  • Following the procedure I will publish this gem to the rubygems.org, so that it can be easily installed from command line.
  • I will also test the installation on all platforms using Travis.

Buffer Period and Week 12 and 13

This week is the buffer and a precaution for everything that might delay the completion. This will mostly involve

  • cleaning up the code and refactoring, fixing bugs and documentation
  • addition of more tests, examples and everything that's pending
  • Make sure the installation works on all systems

Note:

During the whole GSoC, I will be blogging weekly about my progress and experience at this blog. The timeline might seem sparse as at this moment I am not able to judge how much time each work is going to take. If something is finished before time, I will proceed to the next part. Also there is the buffer period in case a bug pushes things down the line.

Post GSoC

  • I will try to write some benchmarks for the ruby wrappers if the time permits and any of the buffer period in still left.
  • I will try to include the functionality that csympy currently lacks but will most likely get as a result of the GSoC. I will be able to contribute during my semester, but not as effectively as during the summer. This could be completed by end of winter(December) holidays.

Relevant Issues/ Discussions and References

[1] https://groups.google.com/forum/#!topic/sciruby-dev/vIgrXnI5eq8
[2] https://groups.google.com/forum/#!topic/sciruby-dev/iVRxZX4m7cU/discussion
[3] https://groups.google.com/forum/#!searchin/sciruby-dev/csympy/sciruby-dev/Cb59l2sFlhU/nqptwJFjRGgJ
[4] Calling C/C++ from Ruby
[5] SWIG and C++ - References and Pointers
[6] File structure for Ruby extension #413
[7] Calling C++ class method from C
[8] How to mix C and C++
[9] Wrapping C++ class API for C consumption
[10] README.EXT Documentation
[11] The Definitive Guide to Ruby's C API
[12] Chris Lalancette's blog - Writing Ruby extensions in C
[13] Gems with Extensions
[14] rake-compiler - Github
[15] Brian Guthre's blog - When to use RSpec, when to use Cucumber
[16] Bundler
[17] Garbage Collection | Ruby Hacking Guide
[18] GC Management Changes (also list/yale inject rank, slicing bugfixes) #160
[19] Figure out a way for exception handling with C wrappers #418


  1. What is one long-term vision for something you'd like scientific software to be able to do. Think big picture, not necessarily realistic in the short term.
    A time when the software is so intelligent that the programmer/user need not worry about anything other than the algorithm (s)he is going to use. Nothing like what platform will it run on, how large values can it handle, what are the data structures it is going to use, what libraries does it have, etc. The software just gets the job done with the least effort on the user side. All the low level implementations are taken care by the software.
    A very good measure would be that the code for the algorithm that the user came up with, occupies lesser number of lines than the number of lines (s)he would use in plain language to explain it to a colleague, and the code is just as understandable as the natural language.

  2. What are your hobbies, aside from coding? Tell us a little about yourself that isn't reflected in the rest of your application. What do you want to do with your life (if you have any idea)?
    I love tweaking, if that's a hobby. I have changed so many things with my Ubuntu system that a fresh install of Ubuntu feels like a completely different flavour of Linux. I love Linux and Ubuntu ❤️. I had dual-booted my system with Ubuntu and Windows(only for gaming 😜), but I feel more at home with Ubuntu. I also love playing badminton.

My thought process is usually different from my friends. Sometimes I think a lot, and can be lost in contemplation, if not brought back to the real world. I keep getting ideas, and my friends often come to me for some brainstorming. I bring new insight to the conversations. Incomplete knowledge fuels my curiosity.

I also have this crazy idea, a vision more appropriately, that I want to realise in the future. I also think of making a job for me out of this idea and work full time. More like a startup.

  1. What else do you think we should have asked but didn't? Propose a question of your own and answer it here.
    How do you think your project helps the organisation? How do you see your project in the future?
    This project will set up a strong foundation for any symbolic manipulation library or "SymRuby" for that matter, to be built for Ruby in the future. CSymPy is fast and is very apt to start the work with. I have also come across GlucSym, which is an unpublished Ruby-to-GiNaC bridge from 2008.
    But this interface(my project) might be the impulse the Ruby community needed to have a fully functional symbolic manipulation library. After all Ruby is a Very High Level Language! It will soon be needing such libraries.
    For me, I would be glad if someone uses the library for her/his project!

  2. Bonus question: One aim of the SciRuby foundation is to increase diversity in open source science software development. How do we get more women interested in open source software development and science?
    It is funny that there was a time when software design and programming were considered women's work and men were associated with hardware, engineers that built computers. But ironically, things have taken a huge turn and now there is a wider gender gap in the industry. But women did do good in software. The first computer programmer was a woman, Ada Lovelace! They sure are competent, and sometimes even better that the male counterparts. So, the question is what is keeping women away from open source software development?
    Much of it can be attributed to the expectations that our society has imposed on us. The stereotypes, and the way the kids are upbrought. Even the media, has played a huge role in partially categorising jobs. Even parents play a huge role in the career decision.
    Where making a difference seems difficult, what we can do is create an environment as welcoming as possible for everyone. A few things we can do are:

  • Using gender neutral language
    In our conversations, we avoid use of words that in any way imply that it's being addressed to a guy or a girl. Even if a situation arises, we can use words like '(s)he' or 'xe'( if we feel like being nerdy). This way if any of the new contributors is going through the conversations, (s)he doesn't feel out of place.

  • Encourage the current women developers share their experience informally in social media
    If one of my friends share's about a wonderful experience that (s)he had, on his/her facebook timeline or any other social media for that matter, I would definitely want to know more about it and want to try it out. Even I, myself came to know about GSoC from social media. This can prove very effective in neutralising the image today's media imposes. Because people ought to believe what their friend says more than the TV.

  • Programs like Summer of Code for Women
    Rails Girls Summer of Code is a similar endeavour to get more women interested in Open Source. RGSoC is a program that funds and supports women around the world to work full-time for three months on Open Source projects. Participants speak at conferences, attend developer events, and get in touch with the wider Open Source community.

Clone this wiki locally