-
Notifications
You must be signed in to change notification settings - Fork 0
GSoC 2015 Application Abinash Meher: Ruby bindings for CSymPy
-
Contact information.
Name : Abinash Meher
Email : [email protected]
GitHub user ID : @abinashmeher999
Location : IIT Kharagpur, India -
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.
- 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'.
-
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. -
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. -
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.
- [Merged] in csympy(Sympy) - Added eval_double1 to .gitignore addressing issue #411
- [Unmerged] in csympy(Sympy) - Ruby wrappers initial file structure addressing issue #413
- [Merged] in mdarray(SciRuby) - Added test for method
det
fromMDMatrix
addressing issue #11
- 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?
- 7 Days for The 23rd Annual Intelligent Ground Vehicle Competition from June 5 - 8. (3 Days for travel making it from 3 to 9)
-
5 Days for IISc Undergraduate Summer School on Computer Science most probably from June 24 - 28. Might not be held this time. No announcements so far.Seems I am ineligible.
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.
-
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. -
How many classes are you taking this summer?
I am not taking any classes this summer. -
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. -
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. -
Please propose a project you would like to work on.
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
-
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. -
File structure
Currently all the python wrappers are in a foldercsympy
under the root folder. The idea is to keep all the wrapper code at a single place, i.e. inside thesrc
in separate folders likesrc/c
,src/python
andsrc/ruby
. The same logic can be applied to other languages later likesrc/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. -
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 throughextern
. 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.
-
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.
-
mkmf
andextconf.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. Itrequire
s themkmf
or the MakeMakefile module for that matter. Theextconf.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)
-
Data structures in CSymPy
CSymPy uses some STL data types likestd::vector
andstd::map
. These map cleanly to theArray
andHash
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 Array
s and Hash
s.
-
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 withrb_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 functionTest::test_func()
throws an exception. This is how we will be changing theTestWrapper.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.
-
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 theT_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 useT_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 VALUE
s 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.
-
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.). -
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.
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.
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.
-
Phase 1 :
Symbol
, its dependent classes and Parsing
Estimated time: 2 Weeks
-
After this, the gem will support
Symbol
class and classes likeInteger
,Rational
andComplex
. -
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
andtest_sympify.py
.-
Phase 2 :
arit
andsubs
Estimated time: 2 Weeks
-
Phase 2 :
-
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
andtest_subs.py
.-
Phase 3 :
eval
andfunctions
Estimated time: 2 Weeks
-
Phase 3 :
-
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
andtest_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.-
Phase 4 :
matrices
Estimated time: 2 Weeks
-
Phase 4 :
-
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
.-
Phase 5 :
ntheory
Estimated time: 2 Weeks
-
Phase 5 :
-
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.
- 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 invokingrake
fromcmake
. So that the building of extensions can be checked by travis. Travis is already integrated with csympy.
- 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.
- This week I will write tests and interface
Symbol
class and other dependent classes likeInteger
,Complex
andRational
.
- This week I will be working to achieve Parsing to symbols from text. Tests will precede this.
- Also start working on the arithmetic operations.
- This week will be devoted towards supporting arithmetic operations with symbols and testing them.
- Start writing the tests for
subs
.
- 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.
- Writing target tests and interfacing
eval
that will make evaluation of expressions possible. If this finishes early I can start onfunction_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.
- 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.
- 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.
- 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.
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
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.
- 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.
The project will consist of four phases.
-
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 fromcmake
, -
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.
- 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.
- 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.
- 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 withextern "C"
, with C++ code in them. The interface between C and C++. - Also I will prefer to document the functions.
- 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.
- 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.
- 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.
- 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.
- I will devote this week to configure the
extconf.rb
usingFLANN
'sextconf.rb
as a model, and extensively cover all therake
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 invokingrake
fromcmake
. So that the building of extensions can be checked by travis.
- 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.
- 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.
- 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.
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
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.
- 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.
[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
-
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. -
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.
-
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! -
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.