Lets talk about each of them in detail.
Categorical data is now readily recognized by Daru and Daru has all the necessary procedures for dealing with it.
To analyze categorical variable, simply turn the numerical vector to categorical and you are ready to go.
We will use, for demonstration purposes, animal shelter data taken
from the Kaggle Competition. It is
stored in shelter_data
.
1 2 3 4 5 6 7 8 9 

1 2 3 4 5 6 7 8 9 

Please refer to this blog post to know more.
With the help of Nyaplot, GnuplotRB and Gruff, Daru now provides ability to visualize categorical data as it does with numerical data.
To plot a vector with Nyaplot one needs to call the function #plot
.
1 2 3 4 5 6 7 

Given a dataframe, one can plot the scatter plot such that the points color, shape and size can be varied acording to a categorical variable.
1 2 3 4 5 6 7 8 9 10 11 12 

In a similar manner Gnuplot and Gruff also support plotting of categorical variables.
An additional work I did was to add Gruff with Daru. Now one can plot vectors and dataframes also using Gruff.
See more notebooks on visualizing categorical data with Daru here.
Now categorical data is supported in multiple linear regression and generalized linear models (GLM) in Statsample and StatsampleGLM.
A new formula language (like that used in R or Patsy) has been introduced to ease the task of specifying regressions.
Now there’s no need to manually create a dataframe for regression.
1 2 3 4 5 6 7 

Additionally, through the work of Alexej Grossmann, one can also predict on new data using the model.
1 2 3 

This, I believe, makes StatsampleGLM very convenient to use.
See this for a complete example.
In addition to the aforementioned, there are some other considerable changes:
CategoricalIndex
to handle the case when index column is a categorical data. More about it here.You can read about all my work in detail here.. Additionally, my project page can be found here.
I hope with these additions one will be able to see data more clearly with Daru.
]]>There are installation instructions in the readme and there are already some sample Kernel files in
the spec folder to try out various routines on. Apart from cloning the repository, one additional thing you will need to do is download the SPICE toolkit. You may want to keep the entire compressed file for later, but you’ll only need the cspice.a
file in the lib/
subdirectory. After this follow the instructions in the readme and you should be good to go. (Be sure to run bundle install
to install any dependencies that you don’t already have.)
After you’re done compiling and installing, run rake pry
in the gem root directory.
If you remember, almost any useful task involving the SPICE Toolkit is preceded by loading data through kernel files. The relevant routine to do this is called furnsh_c()
, and the most direct way to access it through Ruby is by calling the function SpiceRub::Native.furnsh
. (However, this is not recommended because SpiceRub has a specific Ruby class unifying all the kernel related methods, and also because SPICE maintains its own internal variables for both tracking loaded kernel files and unloading them.)
Below is a crude dependency sequence:
1 2 3 4 5 

That’s the basic design of the wrapper, so here are a few simple examples on using the Kernel API. =>
denotes the interpreted output of pry.
First of all, the main KernelPool class is a singleton class, that means it can only be instantiated with the #instance
method and the usual #new
is private.
Any subsequent calls to #instance
will produce the same object.
1 2 3 4 5 6 7 8 9 10 11 12 

This is to make sure there is only one KernelPool state being maintained at a time. Now we have a bunch of kernel files in the spec/data/kernels
folder which we’ll use for this example. There is an accessor attribute called @path
which can be used to point to a particular folder.
1


From here on it’s required that you’re running pry or irb from the gem root folder in order for the paths to match in these examples.
Now let’s load a couple of kernel files, you can type system("ls", kernel_pool.path)
into your console to get a list of all the test kernels available in that folder. The KernelPool object has a #load
method to load kernel files. If the variable path is set, then you only need to enter the file name, otherwise the entire path needs to be provided. An integer denoting the index of the kernel in the pool is returned if the load is successful.
1 2 

Note that this is the same as providing the full relative path of spec/data/kernels/naif0011.tls
when the path
variable is not set or nil.
Let’s load two more files:
1 2 3 4 5 6 7 8 9 10 11 12 13 

So now if you try to view the @pool
member of kernel_pool
, you’ll find three SpiceKernel objects with @loaded=true
and their respective file paths.
There isn’t much to do with a SpiceKernel
object except unload it, or check its state. Note that you can only load kernel files into a KernelPool
object and unload them via the SpiceKernel
object.
You can access the kernel pool by calling the #[]
operator and using the index that was returned on load:
1 2 3 4 5 6 7 8 9 10 11 

So here we unload the first kernel and note that the count drops to 2. If you look up kernel_pool[0]
, you’ll find that the kernel is still present — but its @loaded
variable has been set to false, which means that it has been removed from the CSPICE internal kernel pool.
1 2 

To unload all kernels simultaneously and delete the kernel pool, use #clear!
1 2 3 4 5 6 7 8 

And that about wraps up this blog post on basic kernel handling. Since we know how to load data but not use it yet, I’ll cover that and the various kernel types in the next blog post. Thank you for reading.
]]>Target
: The body of interestFrame
: A rotational frame of reference (Default is J2000 [Not to be confused with the J2000 epoch])Observer
: An observing body whose viewpoint is used to chart the vectorEpoch
: An epoch in Ephemeris TimeSPICE has an integerkey convention for the kind of bodies that it
has support for. Each body can be referenced via a string or an
integer id. While there isn’t an actual strict range for integer ID
classification, it is mentioned here and can be summed up
in the following if
and elsif
clauses. (In Ruby constant strings
are better off as symbols, so the constructor takes either an integer
ID of a string symbol)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 

It was very tempting to involve inheritance and extend a base Body
class onto these potential classes, but I simply did not see the need
for it at this point. The way it is at the moment, the Body
object
has a reader attribute type that stores some metadata about the body
for the user’s convenience. Perhaps as coverage of SPICE improves,
this minor thing can be changed later on.
To create a Body object, you instantiate with either a body name or a
body id. Certain bodies such as instruments will require additional
kernels to be loaded. To proceed seamlessly, load a leap seconds
kernel, a planetary constants kernel, and an ephemeris kernel. (All
avaialable in spec/data/kernels
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 

399
and :earth
map to the same body in SPICE data. The frame of
reference can also be specified as a named parameter during
instantiation to set a custom default frame for that particular
object.
1 2 3 4 5 6 

In SPICE, a state
is a 6 length column vector that stores position
and velocity in 3D cartesian coordinates
As a base case, let’s find out the the position of the Earth with respect to itself.
1 2 3 4 5 

The origin as seen from itself is still the origin, so this makes
sense. The methods #velocity_at
and #state_at
take an identical
set of parameters. While there is a bit of redundancy going on,
splitting them makes the API more elegant, but the basic relationship
between these three vectors is the following :
1 2 3 4 

One thing to note is that state/velocity/position vectors will always
be returned as an NMatrix
object, SciRuby’s numerical matrix core,
to allow for calculations via the NMatrix API.
As an example that is used in the code, one line can turn a position vector into distance from origin (here using Euclidean distance):
1 2 

As a simple imprecise experiment, let’s find out how the speed of light can be “estimated” up with this data.
1 2 3 4 5 6 7 8 

The unit of distance here is kilometers, so the speed of light by this measurement is about pretty close to the textbook figure of 3e+8 m/s.
There is also a function to check if a list of bodies are within a
radial proximity from an observing body. We already calculated the
distance of the moon to be about 367,000 km. The function
within_proximity
returns a list of all bodies that are within the
specified radial distance from the calling body object.
1 2 3 4 5 6 7 8 

Now that we’ve come to the end of the functionality, I would like to
mention that there is another named argument aberration_correction
which is basically an error reduction method to provide a more
accurate result than the default observation. The default :none
option for aberration correction basically provides the geometric
observations without any corrections for reception or transmission of
photons. For a list of various aberration correction methods
available, have a look at the documentation for spkpos_c to
find out if you need an aberration correction on SPICE data.
1 2 3 4 5 6 7 

If you want to look at it another way, no aberration correction would give you the textbook response of rigid geometry, while introducing an aberration correction would give you a somewhat more realistic output accounting for the errors that do happen when these observations are made.
Finally, if you need to generate a continuous time series for a body,
then SpiceRub::Time
has two functions to aid in that:
1 2 3 4 5 6 7 

In this case, I took a start time and an end time that was one day
after and requested 4 linearly spaced epochs. This is basically an
interface to NMatrix.linspace
.
The other function requires you to input a start time and an end time and a step size that keeps getting added to the start time till the end time is reached. As a contrived example, we’ll take two epochs, five days apart and ask for a step size of a day, expecting six elements.
1 2 3 4 5 6 7 8 9 

And that’s it for this blog post. I would appreciate any feedback
regarding this as I’ve been juggling the design back and forth very
frequently. There is large potential of expansion of the Body
class,
particularly creating new classes as when different Bobdy objects
would have a corresponding function. (For example, the function
getfov_c
which returns the field of view of an instrument could be
an instance function attached to the Instrument
subclass of Body
,
but this is just potential expansions in the future.)
00:00 A.M. UTC
is 5:30 A.M. IST
for me, and the world remains sane.
But what happens when you accept the fact that you’re just a speck of microdust adjusting time relatively for an only slightly bigger speck of dust floating in the universe? Twentyfour hours in a day and thus we reset after 2300, but consider: how would a resident of Venus know when teatime is on Venus if he had an Earth wristwatch that reset after twentyfour hours? Barely a tenth of Venus’ day is complete in that time! (If you know anybody intent on relocating to Mars, do not gift them a clock or watch.)
So a decimal floating point representation must be the answer for uniformity. Time zones can be dealt with; we’ll just pick a convenient point in time and count the seconds from there onwards so that the location on Earth doesn’t matter henceforth. It’ll drive humans insane with the arithmetic but machines will work just fine with this. This sort of a time system is called epoch time.
And so the internal time of most UNIX machines is the number of
seconds after midnight on Thursday, 1 January 1970 UTC
. (And this
very convention is going to open a can of worms by
2038 if there is even a small set of critical machines
that haven’t moved on from 32bit architectures.)
But we’re still not okay universally. Try going on an infinite journey to space and you’ll find that counting seconds leads to some inconsistencies with your local time when you try to synchronize with Earth. How can the number of seconds after January 1970 be different in any case? Well, your MacBook Pro has not been adjusted for … relativity! Gravity bends light and thus the perception of time. There’s a lot more mass, and thus a lot more gravitatonal fields in neighborhoods away from Earth. The exact details of how this works is beyond the scope of this blog post.
If the past few paragraphs were incessant and seemingly irrelevant, they were there to drive home the point that Earth time simply will not do when we step out of the ghetto to see what’s happening. But astronomy’s been around for way longer, and astrophysicists came forth with a time system adjusted for the relativity effects of the solar system, called Barycentric Dynamical Time, or TDB. Like our machines, it counts the seconds after a certain known reference time point, except that it adjusts for relativity and can become a standard for astronomical time.
There are many similar time scales like this, but SPICE has chosen to
use TDB as the standard for most of their design. Within the SPICE
API, TDB is the same as Ephemeris Time which is the main system used
to specify time points of astronomical bodies. Even though spacecrafts
have their clocks coordinated with UTC on Earth, you would require
that time in Ephemeris Time to be able to calculate their positions and
velocities using SPICE. SpiceRub::Time
is built for this very purpose,
to revolve around a main attribute @et
for Ephemeris Time and
provide many methods to convert to and from.
If you’d like to proceed with the examples, you’ll need a Leap Second
Kernel file to use SpiceRub::Time
. This is a generic kernel, so you
can easily use naif0011.tls
in spec/data/kernels
of the repository
folder.
So Ephemeris Time is the number of seconds elapsed after Noon, January 1, 2000, TDB
. This point in time is also known as the J2000
epoch. We find that out in an instant by using the Time.parse
function which is a wrapper function for SPICE’s str2et_c
that
converts many formats of strings to Ephemeris Time
. You can have a
look at the various string formats supported in its documentation
here
1 2 

So as a base case, using the reference epoch gives us 0 seconds as we would expect. Now would also be a good time to find out the discrepancy in UTC
as well.
1 2 

So right away we know that UTC was 64ish seconds off from TDB / ET at the time of the reference J2000 epoch. What would the difference be around right now?
1 2 3 4 5 

Well, here’s a surprise, it’s 68.18 now. Before I explain why that is, here is a brief overview of what the above code does:
Time.now
is a convenient way to specify your current UTC
timezone. It uses Ruby’s core Time.now
method so this method is only
good if you’re working in UTC or Earth like Timezones. For a similar
purpose, the function Time.from_time
let’s you create a SpiceRub
Time object from a Ruby Time object.
The +/
operators return a new Time object where the right operand
is added/subtracted to the left operand’s @et
when it is a float or
integer. If a Time object is supplied , then it does the same with the
right operand’s ephemeris time instead. (Note that there really isn’t
a significant meaning to having a Time object whose @et is the
difference/sum of two other epochs, however you can increase a certain
epoch or decrease it by a constant offset of seconds)
In our case we used #to_utc
to convert from ephemeris time to UTC,
and then the minus operator gave us a Time object that wasn’t really
an epoch, but a difference of two epochs, so using #to_f
got us
exactly that.
It appears that UTC has changed by 4 seconds since 2000 with respect to ephemeris time. This is actually the adjustment of “leap seconds” that gets added to UTC to prevent it from falling too far behind other time systems. (Humans really like to hack everything, don’t they?)
To verify this yourself, if you open up the kernel naif0011.tls
in your
text editor and search for DELTET/DELTA_AT
, you’ll find a list like
representation of the following sort :
1 2 3 4 5 6 7 

Here you can see that just before the year 2000, there were 32 leap seconds added to UTC, and in 2015 when the last leap second was added, there were 36. It’s an ongoing and indefinite process and so there really is no way to account for leap second errors far in the future for leap seconds that are yet to be added. As of now, the next scheduled addition is in December, 2016.
Coming back to our Time object, let’s look at its basic
construction. One tricky task in the API was the option to specify
different epochs of reference in different time scales, like
International Atomic Time. As of now, Time.new
requires that you
have kept your word of using the J2000 epoch and allows you to use a
named parameter seconds:
for specifying the time scale. The use of
scale
as a key was avoided as it sometimes is also used to refer to the
reference epoch used.
1 2 3 4 5 6 

:tai
here refers to International Atomic Time. For a list of more
parameters and their keyword abbreviations, have a look at
this SPICE documentation for the function that the
conversion is wrapped on top of.
But there is also a way to reference other epochs without doing the
manual conversions yourself, you can call the class method Time.at
to perform the same function as the constructor, with the option of a
different reference epoch. The resultant Time object will however have
its internal time referring to J2000.
A more readable way would involve step by step calculations, but that
would consume runtime resources everytime Time.at
is called, so I’ve
basically precalculated the ephemeris times of the reference epochs
and subtracted them from the epoch.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 

To quickly verify the last one with the #to_s
method:
1 2 

It’s exactly the UNIX epoch! Let’s try out 1 day (86400 seconds) after this epoch:
1 2 

Just a second short of heading into the next day, because we’ve added 86400 TDB seconds and converted the time into a UTC string.
There are some more functions provided to work in tandem with the
Body
class that I’ll explain more about in the next blog post, but
this more or less covers the core of SpiceRub:Time
. Till then,
thanks for reading.
I worked on “Port NMatrix to JRuby” in the context of the Google Summer of Code (GSoC) 2016 and I am pleased to announce that NMatrix can now be used in JRuby.
With JRuby NMatrix, a linear algebra library, wraps Apache Commons Math for its most basic functionalities. NMatrix supports dense matrices containing either doubles or Ruby objects as the data type. The performance of JRuby with Apache Commons Maths is quite satisfactory (see below for performance comparisons) even without making use of JRuby threading capabilities.
I have also ported the mixed_models gem, which uses NMatrix heavily at its core, to JRuby. This gem allowed us to test NMatrixJRuby with reallife data.
This blog post summarizes my work on the project with SciRuby, and reports the final status of the project.
The original GSoC proposal, plan and application can be found here. Until merging is complete, commits are available here.
I have benchmarked some of the NMatrix functionalities. The following plots compare the performance between NMatrixJRuby, NMatrixMRI, and NMatrixMRI using LAPACK/ATLAS libraries. (Note: MRI refers to the reference implementation of Ruby, for those who are new.)
Notes:
For twodimensional matrices, NMatrixJRuby is currently slower than NMatrixMRI for matrix multiplication and matrix decomposition functionalities (calculating determinant and factoring a matrix). NMatrixJRuby is faster than NMatrixMRI for other functionalities of a twodimensional matrix — like addition, subtraction, trigonometric operations, etc.
NMatrixJRuby is a clear winner when we are working with matrices of arbitrary dimensions.
The major components of an NMatrix
are shape, elements, dtype and
stype. When initialized, the dense type stores the elements as a onedimensional
array; in the JRuby port, the ArrayRealVector
class is used to store
the elements.
@s
stores elements, @shape
stores the shape of the matrix, while
@dtype
and @stype
store the data type and storage type
respectively. Currently, I have nmatrixjruby implemented only for
:float64
(double) and Ruby :object
data types.
NMatrixMRI uses struct
as a type
to store dim
, shape
, offset
, count
, src
of an NMatrix. ALLOC
and xfree
are used to wrap the NMatrix attributes to C structs
and release the unrequired memory.
Implementing slicing was the toughest part of NMatrixJRuby
implementation. NMatrix@s
stores the elements of a matrix as a
onedimensional array. The elements along any dimension are accessed with the
help of the stride. NMatrix#get_stride
calculates the stride with
the help of the dimension and shape and returns an Array.
1 2 3 4 5 6 7 8 9 10 

NMatrix#[]
and NMatrix#[]=
are thus able to read and write the
elements of a matrix. NMatrix#MRI uses the @s
object which stores
the stride when the nmatrix is initialized.
NMatrix#[]
calls the #xslice
operator which calls #get_slice
operator that use the stride to determine whether we are accessing a
single element or multiple elements. If there are multiple elements,
#dense_storage_get
returns an NMatrix object with the elements along
the dimension.
NMatrixMRI differs from NMatrixJRuby implementation as it makes sure that memory is properly utilized as the memory needs to be properly garbage collected.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 

NMatrix#[]=
calls the #dense_storage_set
operator which calls
#get_slice
operator that use the stride to find out whether we are
accessing a single element or multiple elements. If there are
multiple elements #set_slice
recursively sets the elements of the
matrix then returns an NMatrix object with the elements along the
dimension.
All the relevant code for slicing can be found here.
NMatrixMRI uses the C code for enumerating the elements of a matrix. Just as with slicing, the NMatrixJRuby uses pure Ruby code in place of the C code. Currently, all the enumerators for dense matrices with real datatype have been implemented and are properly functional. Enumerators for objects have not yet been implemented.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 

Linear algebra is mostly about twodimensional matrices. In NMatrix,
when performing calculations in a twodimensional matrix, a onedimensional array
is converted to a twodimensional matrix. A twodimensional matrix is
stored in the JRuby implementation as a BlockRealMatrix
or
Array2DRowRealMatrix
. Each has its own advantages.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 

Memory Usage and Garbage Collection: A scientific library is memory intensive and hence, every step counts. The JRuby interpreter doesn’t need to dynamically guess the data type and uses less memory, typically around onetenth of it. If the memory is properly utilized, when the GC kicks in, the GC has to clear less used memory space.
Speed: Using java method greatly improves the speed — by around 1000 times, when compared to using the Ruby method.
All the operators from NMatrixMRI have been implemented except modulus. The binary operators were easily implemented through Commons Math API and Java Math API.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 

Unary Operators (Trigonometric, Exponentiation and Log operators) have been implemented using #mapToSelf
method that takes a Univariate function
as an argument. #mapToSelf
maps every element of ArrayRealVector object to the Univariate function
, that is passed to it and returns self
object.
1 2 3 4 5 

NMatrix#method(arg) has been implemented using bivariate functions provided by Commons Math API and Java Math API.
1 2 3 4 5 

1 2 3 4 5 6 7 8 9 10 11 12 13 

NMatrixMRI relies on LAPACK and ATLAS for matrix decomposition and
solving functionalities. Apache Commons Math provides a different set
of API for decomposing a matrix and solving an equation. For example,
#potrf
and other LAPACK specific functions have not been implemented
as they are not required at all.
Calculating determinant in NMatrix is tricky where a matrix is reduced either to a lower or upper matrix and the diagonal elements of the matrix are multiplied to get the result. Also, the correct sign of the result (whether positive or negative) is taken into account while calculating the determinant. However, NMatrixJRuby uses Commons Math API to calculate the determinant.
1 2 3 4 5 6 7 

Given below is code that shows how Cholesky decomposition has been implemented by using Commons Math API.
1 2 3 4 5 6 7 8 9 10 11 12 13 

Similarly, LU Decomposition and QR factorization have been implemented.
NMatrix#solve
The solve method currently uses LU and Cholesky decomposition.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 

NMatrix#matrix_solve
Suppose we need to solve a system of linear equations:
AX = B
where A is an m×n matrix, B and X are n×p matrices, we need to solve this equation by iterating through B.
NMatrixMRI implements this functionality using NMatrix::BLAS::cblas_trsm
method. However, for NMatrixJRuby, NMatrix#matrix_solve
is the analogous method used.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 

Currently, Hessenberg transformation for NMatrixJRuby has not been implemented.
I have tried implementing float dtypes using FloatMatrix
class
provide by jblas. jblas was used instead of Commons Math as the
latter uses Field Elements
for Floats and it had some issues
with Reflection
and Type Erasure
.
However, using jblas resulted in errors due to precision.
To minimise conflict with the MRI codebase all the JRuby front end
code has been placed in the /lib/nmatrix/jruby
directory. lib/nmatrix/nmatrix.rb
decides whether to load
nmatrix.so
or nmatrix_jruby.rb
after detecting the Ruby platform.
The added advantage is that the Ruby interpreter must not decide which function to call at runtime. The impact on performance can be seen when programs which intensively use NMatrix for linear algebraic computations (e.g., mixed_models) are run.
After the port; this is the final report that summarizes the number of tests that successfully pass:
Spec file  Total Tests  Success  Failure  Pending  

00_nmatrix_spec  188  139  43  6  
01_enum_spec  17  8  09  0  
02_slice_spec  144  116  28  0  
03_nmatrix_monkeys_spec  12  11  01  0  
elementwise_spec  38  21  17  0  
homogeneous_spec.rb  07  06  01  0  
math_spec  737  541  196  0  
shortcuts_spec  81  57  24  0  
stat_spec  72  40  32  0  
slice_set_spec  6  2  04  0 
floor
, ceil
, and round
methods.Spec file  Total Test  Success  Failure  Pending  

Deviance_spec  04  04  0  0  
LMM_spec  195  195  0  0  
LMM_categorical_data_spec.rb  48  45  3  0  
LMMFormula_spec.rb  05  05  0  0  
LMM_interaction_effects_spec.rb  82  82  0  0  
LMM_nested_effects_spec.rb  40  40  0  0  
matrix_methods_spec.rb  52  52  0  0  
ModelSpecification_spec.rb  07  07  0  0  
NelderMeadWithConstraints_spec.rb  08  08  0  0 
NMatrix on JRuby offers comparable speeds to MRI. For specific computations it will be possible to leverage the threading support of JRuby and speed up things using multiple cores.
Adding new functionality to NMatrixJRuby will be easy from here. Personally, I am interested to add OpenCL support to leverage the GPU computational capacity available on most machines today.
The main goal of this project was to to gain from the performance JRuby offers, and bring a unified interface for linear algebra between MRI and JRuby.
By the end of GSoC, I have been able to successfully create a linear algebra library, NMatrix for JRuby users, which they can easily run on their machines — unless they want to use complex numbers, at least for now.
I have mixed_models gem simultaneously ported to JRuby. Even here, NMatrixJRuby is very close to NMatrixMRI, considering the performance .
I would like to express my sincere gratitude to my mentor Pjotr Prins for the continuous support through the summers, and for his patience, motivation, enthusiasm, and immense knowledge. I could not have imagined having a better advisor and mentor, for this project.
I am very grateful to Google and the Ruby Science Foundation for this golden opportunity.
I am very thankful to Charles Nutter, John Woods, Sameer Deshmukh, Kenta Murata and Alexej Gossmann, who mentored me through the project. It has been a great learning experience.
I thank my fellow GSoC participants Rajith, Lokesh and Gaurav who helped me with certain aspects of my project.
]]>There are installation instructions in the ReadMe and there are already some sample Kernel files in
the spec folder to try out various routines on. Apart from cloning the repository, one additional thing you will need to do is download the SPICE toolkit from here. You may want to keep the entire compressed file for later, but you’ll only need the cspice.a
file in the lib/ subdirectory. After this follow the instructions in the ReadMe and you should be good to go. Be sure to run bundle install
to install any dependencies that you don’t already have.
After you’re done compiling/installing, run rake pry
in the gem root directory. If you remember, almost any useful task involving the SPICE Toolkit is preceded by loading data through kernel files. The relevant routine to do this is called furnsh_c()
, and the most direct way to access it through Ruby is by calling the function SpiceRub::Native.furnsh
. This is not recommended because SpiceRub has a specific Ruby class unifying all the kernel related methods and also because SPICE maintains its own internal variables for tracking loaded kernel files / unloading them. Below is a crude dependency sequence :
1 2 3 4 5 

That’s the basic design of the wrapper, so here’s a few simple examples on using the Kernel API. =>
denotes the interpreted output of pry.
First of all, the main KernelPool class is a singleton class, that means it can only be instantiated with the #instance
method and the usual #new
is private.
Any subsequent calls to #instance
will produce the same object.
1 2 3 4 5 6 7 8 9 10 11 12 

This is to make sure there is only one KernelPool state being maintained at a time. Now we have a bunch of kernel files in the spec/data/kernels
folder which we’ll use for this example. There is an accessor attribute called @path
which can be used to point to a particular folder.
1


From here on it’s required that you’re running pry or irb from the gem root folder in order for the paths to match in these examples.
Now let’s load a couple of kernel files, you can type system("ls", kernel_pool.path)
into your console to get a list of all the test kernels available
in that folder. The KernelPool object has a #load
method to load kernel files. If the variable path is set, then you only need to enter the file name,
otherwise the entire path needs to be provided. An integer denoting the index of the kernel in the pool is returned if the load is successful.
1 2 

Note that this is the same as providing the full relative path of spec/data/kernels/naif0011.tls
when the path
variable is not set or nil.
Let’s load two more files:
1 2 3 4 5 6 7 8 9 10 11 12 13 

So now if you try to view the @pool
member of kernel_pool, you’ll find 3 SpiceKernel objects with @loaded=true
and their respective file paths.
There isn’t much to do with a SpiceKernel
object except unload it, or check its state. Note that you can only load kernel files into a KernelPool
object and unload
them via the SpiceKernel
object.
You can access the kernel pool by calling the #[]
operator and using the index that was returned on load :
1 2 3 4 5 6 7 8 9 10 11 

So here we unload the first kernel and note that the count drops to 2. If you look up kernel_pool[0]
, you’ll find that the kernel
is still present but it’s @loaded
variable has been set to false which means that it has been removed from the CSPICE internal kernel pool.
1 2 

To unload all kernels simultaneously and delete the kernel pool, use #clear!
1 2 3 4 5 6 7 8 

And that about wraps up this blog post on basic kernel handling. Since we know how to load data but not use it yet, I’ll cover that and the various kernel types in the next blog post. Thank you for reading :)
]]>My GSoC project is the Ruby gem mixed_models. Mixed models are statistical models which predict the value of a response variable as a result of fixed and random effects. The gem in its current version can be used to fit statistical linear mixed models and perform statistical inference on the model parameters as well as to predict future observations. A number of tutorials/examples in IRuby notebook format are accessible from the mixed_models
github repository.
Linear mixed models are implemented in the class LMM
. The constructor method LMM#initialize
provides a flexible model specification interface, where an arbitrary covariance structure of the random effects terms can be passed as a Proc
or a block.
A convenient userfriendly interface to the basic model fitting algorithm is LMM#from_formula
, which uses the formula language of the R mixed models package lme4
for model specification. With the #from_formula
method, the user can conveniently fit models with categorical predictor variables, interaction fixed or random effects, as well as multiple crossed or nested random effects, all with just one line of code.
Examples are given in the sections below.
The parameter estimation in LMM#initialize
is largely based on the approach developed by the authors of the R mixed models package lme4
, which is delineated in the lme4
vignette. I have tried to make the code of the model fitting algorithm in LMM#initialize
easy to read, especially compared to the corresponding implementation in lme4
.
The lme4
code is largely written in C++, which is integrated in R via the packages Rcpp
and RcppEigen
. It uses CHOLMOD code for various sparse matrix tricks, and it involves passing pointers to C++ object to R (and vice versa) many times, and passing different R environments from function to function. All this makes the lme4
code rather hard to read. Even Douglas Bates, the main developer of lme4
, admits that “The end result is confusing (my fault entirely) and fragile”, because of all the utilized performance improvements. I have analyzed the lme4
code in three blog posts (part 1, part 2 and part 3) before starting to work on my gem mixed_models
.
The method LMM#initialize
is written in a more functional style, which makes the code shorter and (I find) easier to follow. All matrix calculations are performed using the gem nmatrix
, which has a quite intuitive syntax and contributes to the overall code readability as well.
The Ruby gem loses with respect to memory consumption and speed in comparison to lme4
, because it is written in pure Ruby and does not utilize any sparse matrix tricks. However, for the same reasons the mixed_models
code is much shorter and easier to read than lme4
. Moreover, the linear mixed model formulation in mixed_models
is a little bit more general, because it does not assume that the random effects covariance matrix is sparse. More about the implementation of LMM#initialize
can be found in this blog post.
Popular existing software packages for mixed models include the R package lme4
(which is arguably the standard software for linear mixed models), the R package nlme
(an older package developed by the same author as lme4
, still widely used), Python’s statmodels
, and the Julia package MixedModels.jl
.
Below, I give a couple of examples illustrating some of the capabilities of mixed_models
and explore how it compares to the alternatives.
As an example, we use data from the UCI machine learning repository, which originate from blog posts from various sources in 20102012, in order to model (the logarithm of) the number of comments that a blog post receives. The linear predictors are the text length, the logtransform of the average number of comments at the hosting website, the average number of trackbacks at the hosting website, and the parent blog posts. We assume a random effect on the number of comments due to the day of the week on which the blog post was published. In mixed_models
this model can be fit with
1 2 

and we can display some information about the estimated fixed effects with
1


which produces the following output:
1 2 3 4 5 6 

We can also display the estimated random effects coefficients and the random effects standard deviation,
1 2 3 4 

which produces
1 2 3 4 5 6 7 

Interestingly, the estimates of the random effects coefficients and standard deviation are all zero! That is, we have a singular fit. Thus, our results imply that the day of the week on which a blog post is published has no effect on the number of comments that the blog post will receive.
It is worth pointing out that such a model fit with a singular covariance matrix is problematic with the current version of Python’s statmodels
(described as “numerically challenging” in the documentation) and the R package nlme
(“Singular covariance matrices correspond to infinite parameter values”, a mailing list reply by Douglas Bates, the author of nlme
). However, mixed_models
, lme4
and MixedModels.jl
can handle singular fits without problems.
In fact, like mixed_models
above, lme4
estimates the random effects coefficients and standard deviation to be zero, as we can see from the following R output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 

Unfortunately, mixed_models
is rather slow when applied to such a large data set (blog_data
is a data frame of size 22435×8), especially when compared to lme4
which uses many sparse matrix tricks and is mostly written in C++ (integrated in R via Rcpp
) to speed up computation. The difference in performance between mixed_models
and lme4
is on the order of hours for large data, and Julia’s MixedModels.jl
promises to be even faster than lme4
. However, there is no noticeable difference in performance speed for smaller data sets.
The full data analysis of the blog post data can be found in this IRuby notebook.
Often, the experimental design or the data suggests a linear mixed model whose random effects are associated with multiple grouping factors. A specification of multiple random effects terms which correspond to multiple grouping factors is often referred to as crossed random effect, or nested random effects if the corresponding grouping factors are nested in each other.
A good reference on such models is Chapter 2 of Douglas Bates’ lme4
book.
Like lme4
, mixed_models
is particularly well suited for models with crossed or nested random effects. The current release of statmodels
, however, does not support crossed or nested random effects (according to the documentation).
As an example we fit a linear mixed model with nested random effects to a data frame with 100 rows, of the form:
1 2 3 4 5 6 7 

We consider the following model:
y
to be the response and x
its predictor.b
to be nested within the factor a
.a
; that is, a different (random) intercept term for each level of a
.b
which is nested in a
; that is, different (random) intercept for each combination of levels of a
and b
.That is, mathematically the model can be expressed as
1


where gamma(a) ~ N(0, phi**2)
and delta(a,b) ~ N(0, psi**2)
are normally distributed random variables which assume different realizations for different values of a
and b
, and where epsilon
is a random Gaussian noise term with variance sigma**2
. The goal is to estimate the parameters beta_0
, beta_1
, phi
, psi
and sigma
.
We fit this model in mixed_models
, and display the estimated random effects correlation structure with
1 2 3 

which produces the output
1 2 3 

The correlation between the factor a
and the nested random effect a_and_b
is denoted as nil
, because the random effects in the model at hand are assumed to be independent.
An advantage of mixed_models
over some other tools is the simplicity with which pvalues and confidence intervals for the parameter estimates can be calculated using a multitude of available methods. Such methods include a likelihood ratio test implementation, multiple bootstrap based methods (which run in parallel by default), and methods based on the Wald Z statistic.
We can compute five types of 95% confidence intervals for the fixed effects coefficients with the following line of code:
1


which yields the result
1 2 3 4 5 6 

For example, we see here that the intercept term is likely not significantly different from zero. We could proceed now by performing hypotheses tests using #fix_ef_p
or #likelihood_ratio_test
, or by refitting a model without an intercept using #drop_fix_ef
.
We can also test the nested random effect for significance, in order to decide whether we should drop that term from the model to reduce model complexity. We can use a bootstrap based version of likelihood ratio test as follows.
1 2 

We get a pvalue of 9.99e4, suggesting that we probably should keep the term (1a:b)
in the model formula.
Another advantage of mixed_models
against comparable tools is the ease of fitting models with arbitrary covariance structures of the random effects, which are not covered by the formula interface of lme4
. This can be done in a userfriendly manner by providing a block or a Proc
to the LMM
constructor. This unique feature of the Ruby language makes the implementation and usage of the method incredibly convenient. A danger of allowing for arbitrary covariance structures is, of course, that such a flexibility gives the user the freedom to specify degenerate and computationally unstable models.
As an example we look at an application to genetics, namely to SNP data (singlenucleotide polymorphism) with known pedigree structures (family relationships of the subjects). The family information is prior knowledge that we can model in the random effects of a linear mixed effects model.
We model the quantitative trait y
(a vector of length 1200) as
1


where X
is a 1200 x 130
matrix containing the genotypes (i.e. 130 SNPs for each of the 1200 subjects); epsilon
is a vector of independent random noise terms with variances equal to sigma**2
; beta
is a vector of unknown fixed effects coefficients measuring the contribution of each SNP to the quantitative trait y
; and b
is a vector of random effects.
If we denote the kinship matrix by K
, then we can express the probability distribution of b
as b ~ N(0, delta**2 * 2 * K)
, where we multiply K
by 2
because the diagonal of K
is constant 0.5
, and where delta**2
is a unknown scaling factor.
The goal is to estimate the unknown parameters beta
, sigma
, and delta
, and to determine which of the fixed effects coefficients are significantly different from 0 (i.e. which SNPs are possibly causing the variability in the trait y
).
In order to specify the covariance structure of the random effects, we need to pass a block or Proc
that produces the upper triangular Cholesky factor of the covariance matrix of the random effects from an input Array. In this example, that would be the multiplication of the prior known Cholesky factor of the kinship matrix with a scaling factor.
Having all the model matrices and vectors, we compute the Cholesky factor of the kinship matrix and fit the model with
1 2 3 4 5 6 7 8 

Then we can use the available hypotheses test and confidence interval methods to determine which SNPs are significant predictors of the quantitative trait. Out of the 130 SNPs in the model, we find 24 to be significant as linear predictors.
See this blog post for a full analysis of this data with mixed_models
.
Writing the formula language interpretation code used by LMM#from_formula
from scratch was not easy. Much of the code can be reorganized to be easier to read and to use in other projects. Possibly, the formula interface should be separated out, similar to how it is done with the Python package patsy. Also, some shortcut symbols (namely *
, /
, and 
) in the model specification formula language are currently not implemented.
I plan to add linear mixed models for highdimensional data (i.e. more predictors than observations) to mixed_models
, because that work would be in line with my current PhD research.
I plan to add generalized linear mixed models capabilities to mixed_models
, which can be used to fit mixed models to discrete data (such as binary or count data).
I want to thank Google and the Ruby Science Foundation for giving me this excellent opportunity! I especially want to thank Pjotr Prins who was my mentor for the project for much helpful advice and suggestions as well as his prompt responses to any of my concerns. I also want to thank my fellow GSoC participants Will, Ivan, and Sameer for their help with certain aspects of my project.
]]>nmatrix
gem to optional plugin gems. NMatrix is a Ruby library for linear algebra,
used by many other projects.
In addition to the code that was part of
NMatrix proper, NMatrix previously required the ATLAS library, which
implemented fast versions of common matrix operations like multiplication
and inversion, as well as more advanced operations like eigenvalue
decomposition and Cholesky decomposition.
There were two separate but related motivations for my project. The first was to simplify the NMatrix installation process. ATLAS can be difficult to install, so the installation process for NMatrix was complicated, especially on OS X, and may have discouraged people from using NMatrix. The second motivation was that by separating out the ATLAS code from the main NMatrix code, it would be easier to add new linear algebra backends which provide similar features. Indeed, I implemented a second backend this summer.
The end result of my summer’s work:
nmatrix
gem does not depend on any external linear matrix
libraries. It provides nonoptimized implementations of common matrix
operations.nmatrixatlas
gem, so that
those who are only interested in the core functionality are not required to
install ATLAS. nmatrixatlas
provides optimized implementations of common matrix
operations, as well as advanced functions not available in nmatrix
.
I wrote a blog post describing the setup for releasing multiple gems from the same repository, which this required.nmatrixlapacke
, which provides the same features as
nmatrixatlas
, but instead of depending specifically on the ATLAS
library, requires any generic LAPACK and
BLAS
implementation. This should be easier to use for many users as they may
already have LAPACK installed (it comes preinstalled with OS X and is
commonly used in Linux systems), but not ATLAS.nmatrix
gem. Compare the new installation instructions
to the old ones.The one deviation from my original proposal was that I originally intended to remove
all the ATLAS code and release only the nmatrixlapacke
plugin, so that we
would only have one interface to the advanced linear algebra functions, but I
decided to keep the ATLAS code, since the nmatrixlapacke
code is new and
has not had a chance to be thoroughly tested.
1 2 3 4 5 

1 2 3 4 5 6 

For advanced functions not provided by the core nmatrix
gem, for example
gesvd
, nmatrixatlas
and nmatrixlapacke
provide a common interface:
1 2 3 4 5 

1 2 3 4 5 6 

If the developer wants to use an advanced feature, but does not care
whether the user is using nmatrixatlas
or nmatrixlapacke
, they can require nmatrix/lapack_plugin
, which will
require whichever of the two is available, instead of being forced to
choose between the two.
As a fun test of the new gems, I did a very simple benchmark, just
testing how long it took to invert a
1500by1500 matrix in place using NMatix#invert!
:
nmatrix
(no external libraries): 3.67snmatrixatlas
: 0.96snmatrixlapacke
with ATLAS: 0.99snmatrixlapacke
with OpenBLAS (multithreading enabled): 0.39snmatrixlapacke
with reference implementations of LAPACK and BLAS: 3.72sThis is not supposed to be a thorough or realistic benchmark (performance will depend on your system, on how you built the libraries, and on the exact functions that you use), but there are still a few interesting conclusions we can draw from it:
nmatrixatlas
and nmatrixlapacke
(this means we could consider deprecating
the nmatixatlas
gem).Overall, my summer has been productive. I implemented everything that I proposed and feedback from testers so far has been positive. I plan to stay involved with NMatrix, especially to follow up on any issues related to my changes. Although I won’t be a student next summer, I would certainly consider participating in Google Summer of Code in the future as a mentor. I’d like to thank my mentor John Woods and the rest of the SciRuby community for support and feedback throughout the summer.
]]>This summer I’ve been participating in Google Summer of Code with GnuplotRB project (plotting tool for Ruby users based on Gnuplot) for SciRuby. GSoC is almost over and I’m releasing v0.3.1 of GnuplotRB as a gem. In this blog post I want to introduce the gem and highlight some of its capabilities.
There are several existing plotting tools for Ruby such as Nyaplot, Plotrb, Rubyvis and Gnuplot gem. However they are not designed for large datasets and have fewer plotting styles and options than Gnuplot. Gnuplot gem was developed long ago and nowadays consists mostly of hacks and does not support modern Gnuplot features such as multiplot.
Therefore my goal was to develop new gem for Gnuplot which would allow full use of its features in Ruby. I was inspired to build an easytouse interface for the most commonly used features of Gnuplot and allow users to customize their plots with Gnuplot options as easily as possible in Rubyesque way.
The main feature of every plotting tool is its ability to plot graphs. GnuplotRB allows you
to plot both mathematical formula and (huge) sets of data. GnuplotRB supports plotting
2D graphs (GnuplotRB::Plot
class) in Cartesian/parametric/polar coordinates and 3D
graphs (GnuplotRB::Splot
class) — in Cartesian/cylindrical/spherical coordinates.
There are vast of plotting styles supported by GnuplotRB:
points
lines
histograms
boxerrorbars
circles
boxes
filledcurves
vectors
heatmap
Plot examples:
For code examples please see the repository README, notebooks and the examples folder.
GnuplotRB::Multiplot
allows users to place several plots on a single layout and output
them at once (e.g., to a PNG file).
Multiplot notebook.
Here is a multiplot example (taken from Sameer’s notebook):
GnuplotRB may output any plot to gif file but GnuplotRB::Animation
allows
to make this gif animated. It takes several Plot
or Splot
objects just as
multiplot does and outputs them onebyone as frames of gif animation.
Animation notebook.
Although the main GnuplotRB’s purpose is to provide you with swift, robust and
easytouse plotting tool, it also offers a Fit
module that contains several
methods for fitting given data with a function. See examples in Fit notebook.
GnuplotRB plots may be embedded into iRuby notebooks as JPEG/PNG/SVG
images, as ASCII art or GIF animations (Animation
class). This functionality
explained in a special iRuby notebook.
To link GnuplotRB with other SciRuby tools I implemented plot
creation from data given in Daru containers (Daru::Dataframe
and Daru::Vector
).
One can use daru
gem in order to work with statistical SciRuby gems
and plotting with GnuplotRB. Notebooks with examples: 1, 2.
You can pass to Plot (or Splot or Dataset) constructor data in the following forms:
'sin(x)'
)'points.data'
)#to_gnuplot_points
Array
Daru::Dataframe
Daru::Vector
See examples in notebooks.
My project was to write the Ruby extensions for the library SymEngine and come up with a Rubyish interface, after which we can use the features of SymEngine from Ruby.
SymEngine is a library for symbolic computation in C++. You may ask, why SymEngine? There are other CASs that I know of. This question was indeed asked. At the beginning, the idea was to use ruby wrappers for sage (a mathematics software system) which uses Pynac, an interface to GiNaC (another CAS). As it turns out from the benchmarks, SymEngine is much faster than Pynac. What about directly wrapping GiNaC? SymEngine is also a bit faster than GiNaC.
The motivation for SymEngine itself is to develop it once in C++ and then use it from other languages rather than doing the same thing all over again for each language that it is required in. In particular, a long term goal is to make Sage as well as SymPy use it by default, thus unifying the Python CAS communities. The goal of implementing the Ruby wrappers is to provide a CAS for the Ruby community.
There are times when we might need a symbolic computation library. Here is an incomplete list of some of the situations:
With that said, a symbolic manipulation library is indispensable for scientists and students. Ruby has gained a great deal of popularity over the years, and a symbolic manipulation library gem like this project in Ruby might prove to be the foundation for a computer algebra system in Ruby. With many efforts like these, Ruby might become the first choice for academicians given how easy it is to code your logic in Ruby.
To install, please follow the compile instructions given in the README. After you are done, I would suggest to test the extensions. To run the test suite execute rspec spec
on the command line, from the symengine/ruby
dir.
The gem is still in alpha release. Please help us out by reporting any issues in the repo issue tracker.
Currently, the following features are available in the gem:
 Construct expressions out of variables (mathematical).
 Simplify the expressions.
 Carry out arithmetic operations like +
, 
, *
, /
, **
with the variables and expressions.
 Extract arguments or variables from an expression.
 Differentiate an expression with respect to another.
 Substitute variables with other expressions.
Features that will soon be ported to the SymEngine gem  Functions, including trigonometric, hyperbolic and some special functions.  Matrices, and their operations.  Basic numbertheoretic functions.
I have developed a few IRuby notebooks that demonstrate the use of the new SymEngine module in ruby.
Below is an example taken from the notebooks.
SymEngine is a module in the extensions, and the classes are a part of it. So first you fire up the interpreter or an IRuby notebook and load the file:
1 2 

Go ahead and try a function:
1 2 3 4 5 6 

or create a variable:
1 2 

This shows that we have successfully loaded the module.
Just like there are variables like x, y, and z in a mathematical expression or equation, we have SymEngine::Symbol
in SymEngine to represent them. To use a variable, first we need to make a SymEngine::Symbol
object with the string we are going to represent the variable with.:
1 2 3 4 5 6 7 

Then we can construct expressions out of them:
1 2 3 

In SymEngine, every object is an instance of Basic or its subclasses. So, even an instance of SymEngine::Symbol
is a Basic object.:
1 2 3 4 5 

Now that we have an expression, we would like to see it’s expanded form using #expand
:
1 2 3 

Or check if two expressions are same:
1 2 

But e
and f
are not equal since they are only mathematically equal, not structurally:
1 2 

Let us suppose you want to know what variables/symbols your expression has. You can do that with the #free_symbols
method, which returns a set of the symbols that are in the expression.:
1 2 

Let us use #map
method to see the elements of the Set
.:
1 2 

#args
returns the terms of the expression,:
1 2 

or if it is a single term it breaks down the elements:
1 2 

You can make objects of class SymEngine::Integer
. It’s like regular Integer
in ruby kernel, except it can do all the operations a Basic
object can — such as arithmetic operations, etc.:
1 2 3 4 5 

Additionally, it can support numbers of arbitrarily large length.
1 2 

You can also make objects of class SymEngine::Rational
which is the SymEngine counterpart for Rationals
in Ruby.:
1 2 3 4 

Like any other Basic
object arithmetic operations can be done on this rational type too.:
1 2 

You need not create an instance of SymEngine::Integer
or SymEngine::Rational
, every time you want to use them in an expression that uses many Integer
s. Let us say you already have Integer
/Rational
object. Even then you can use them without having to create a new SymEngine
object.:
1 2 3 

As you can see, ruby kernel Integer
s and Rational
s interoperate seamlessly with the SymEngine
objects.
1 2 

In the rest of the post, I would like to summarise my work and what I learned as a participant of Google Summer of Code 2015.
I am a newbie when it comes to Ruby, and it took me a while to setup the gem and configure files for the building of extensions.
I faced a lot of problem in the early stages, when I was trying to build the extensions. Ondrej, my mentor, and Isuru, a fellow GSoC student, helped me a lot. There were many C flags that were being reported as missing. Some flags cmake
added by default but extconf.rb
didn’t, the same one that was required to be added to build it as a shared library. I am still confused about the details, some of which are explored in greater detail in my personal blog. Finally, the library had to be built as a dynamic one. The problem of missing C flags was resolved later by hooking the process to cmake
rather than mkmf
.
Many LoadError
s popped up, but were eventually solved. Ivan helped a lot in debugging the errors. In the end, it turned out to be a simple file missing in the gemspec, that was not being installed.
One of our aims during developing this was to get rid of unessential dependencies. The ones we already had the tools for. Like later the file extconf.rb
, that is used to generate Makefile for the extension was removed, because that could also be done by cmake
. Flags were added to cmake
for building the Ruby extensions, like the flag DWITH_RUBY=yes
. The Makefile
then generates the library symengine.so
in the directory lib/symengine
.Along with extconf.rb
, the file extconf.h
was also gone. Along these lines, the dependency on rake
was also removed, and with that the Rakefile
. Any task automation will most probably be done in python. So, the Rake::ExtensionTask
was done by cmake
and the Rake::GemPackageTask
was replaced by the manual method of gem build symengine.gemspec
and gem install symengine0.0.0.gem
Not many projects have travisci setup for multiple languages. Not even the tutorials had clearly mentioned about setting up for multiple languages. But I did know about one of them, which is Shogun, the machinelearning toolbox. I referred to their .travis.yml
and setup it up. If something like this wouldn’t have worked the plan was to manually install the required version of ruby and then execute the shell commands.
Finally, I was able to successfully build the extensions, link the extensions with the SymEngine library, load the rubyextension library in the interpreter and successfully instantiate an object of type Basic
.
At this time, the way inheritance works(like the sequence of formation and destruction of objects of a class that had a superclass) with the Ruby C API, was confusing for all of us. I designed an experiment
to check what was actually happening. That cleared things out, and made the it easier to wrap things from now on. I also wrapped the Symbol
class during the course.
We had to design an ugly function to wrap vector in C. That led us to redesign the C interface. This approach had no reinterpret casting that was being done earlier. Each data structure had a type that was determined at compile time. For C, it was an opaque structure, while for C++ the opaque structure declared in the shared header file was implemented in the source file that had C++ data types. This blog post explains it further.
While trying to port the SymEngine classes, Integer
and Rational
, I had to port many methods in Basic
before that. I also replicated the rake
tasks in NMatrix, for detection of memory leaks, in form of bash scripts.
Since all objects in the Ruby C API are of the type CBasic
, we needed a function that would give us the typename during the runtime for the corresponding objects to be wrapped in ruby, as an object of the correct Class
in ruby. Since, this was achieved with enum
in C++, the same thing could be done in C too, with all the classes written manually again. But there was no guarantee for this to be consistent, if ever the features required to be wrapped for a new language, and also manually adding the class in all the enum list everytime a new class is added was prone to errors. So, to make this DRY, we automated this by sharing the list of enums. More details for the implementation can be found here.
To support interoperability with the builtin ruby types, I had to overload the methods in builtin classes earlier(this was not continued). Overriding all the existing binary operations for a ruby class to support SymEngine types, violated the open/closed principle. There was indeed another way, which is ‘Class Coercion’. It was suggested by Isuru. After that, SymEngine types could seamlessly interoperate between the ruby types.
After this, all the arithmetic operations had been successfully ported. Each Basic
object can now perform arithmetic operations with other Basic
object(sometimes even ruby objects like Integer
). The test file in python, that had all the corresponding test cases was ported to its RSpec counterpart.
Recently I completed porting the substitutions module to the extensions(#subs
). This feature has added a lot of convenience as now you can substitute a SymEngine::Symbol
with some other value in an expression and then #expand
to get the result.
Currently, I am working on porting the trigonometric functions in SymEngine to the extensions. This would first require to wrap the Function
class and then the TrigFunction
class in SymEngine.
I also have plans to integrate the ruby bindings for gmp
, mpfr
and mpc
libraries, that are already available as gems, with ruby bindings for our library. I have created an issue here. Feel free to drop any suggestions.
There is much scope for improvement in both the projects. For SymEngine, to support more features like polynomials and seriesexpansion in the near future, and improving the user interface and the exception handling for the extensions. In short, making the extensions more rubyish.
I am grateful to my mentor, Mr. Ondřej Čertík, the Ruby Science Foundation and the SymPy Organisation for the opportunity that they gave me and guiding me through the project, and my teammates for helping me with the issues. I hope more people will contribute to the project and together we will give a nice symbolic manipulation gem to the Ruby community.
]]>The new features led to the inclusion of daru in many of SciRuby’s gems, which use daru’s data storage, access and indexing features for storing and carrying around data. Statsample, statsampleglm, statsampletimeseries, statsamplebivariateextensions are all now compatible with daru and use Daru::Vector
and Daru::DataFrame
as their primary data structures. I also overhauled Daru’s plotting functionality, that interfaced with nyaplot for creating interactive plots directly from the data.
Also, new gems developed by other GSOC students, notably Ivan’s GnuplotRB gem and Alexej’s mixed_models gem both now accept data from daru data structures. Do see their repo pages for seeing interesting ways of using daru.
The work on daru is also proving to be quite useful for other people, which led to a talk/presentation at DeccanRubyConf 2015, which is one of the three major Ruby conferences in India. You can see the slides and notebooks presented at the talk here. Given the current interest in data analysis and the need for a viable solution in Ruby, I plan to take daru much further. Keep watching the repo for interesting updates :)
In the rest of this post I’ll elaborate on all the work done this summer.
Daru as a gem before GSOC was not exactly user friendly. There were many cases, particularly the iterators, that required some thinking before anybody used them. This is against the design philosophy of daru, or even Ruby general, where surprising programmers with ubiqtuos constructs is usually frowned down upon by the community. So the first thing that I did mainly concerned overhauling the daru’s many iterators for both Vector
and DataFrame
.
For example, the #map
iterator from Enumerable
returns an Array
no matter object you call it on. This was not the case before, where #map
would a Daru::Vector
or Daru::DataFrame
. This behaviour was changed, and now #map
returns an Array
. If you want a Vector
or a DataFrame
of the modified values, you should call #recode
on Vector
or DataFrame
.
Each of these iterators also accepts an optional argument, :row
or :vector
, which will define the axis over which iteration is supposed to be carried out. So now there are the #each
, #map
, #map!
, #recode
, #recode!
, #collect
, #collect_matrix
, #all?
, #any?
, #keep_vector_if
and #keep_row_if
. To iterate over elements along with their respective indexes (or labels), you can likewise use #each_row_with_index
, #each_vector_with_index
, #map_rows_with_index
, #map_vector_with_index
, #collect_rows_with_index
, #collect_vector_with_index
or #each_index
. I urge you to go over the docs of each of these methods to utilize the full power of daru.
Apart from the improvements to iterators there was also quite a bit of refactoring involved for many methods (courtesy Alexej). The refactoring of certain core methods has made daru much faster than previous versions.
The next (major) thing to do was making daru compatible with Statsample. This was very essential since statsample is very important tool for statistics in Ruby and it was using its own Vector
and Dataset
classes, which weren’t very robust as computation tools and very difficult to use when it came to cleaning or munging data. So I replaced statsample’s Vector and Dataset clases with Daru::Vector
and Daru::DataFrame
. It involved a significant amount of work on both statsample and daru — Statsample because many constructs had to be changed to make them compatible with daru, and daru because there was a lot of essential functionality in these classes that had to be ported to daru.
Porting code from statsample to daru improved daru significantly. There were a whole of statistics methods in statsample that were imported into daru and you can now use all them from daru. Statsample also works well with rubyvis, a great tool for visualization. You can now do that with daru as well.
Many new methods for reading and writing data to and from files were also added to daru. You can now read and write data to and from CSV, Excel, plain text files or even SQL databases.
In effect, daru is now completely compatible with Statsample (and all the other Statsample extensions). You can use daru data structures for storing data and pass them to statsample for performing computations. The biggest advantage of this approach is that the analysed data can be passed around to other scientific Ruby libraries (some of which listed above) that use daru as well. Since daru offers inbuilt functions to better ‘see’ your data, better visualization is possible.
See these blogs and notebooks for a complete overview of daru’s new features.
Also see the notebooks in the statsample README for using daru with statsample.
Most of time post the mid term submissions was spent in implementing the time series functions for daru.
I implemented a new index, the DateTimeIndex, which can used for indexing data on time stamps. It enables users to query data based on time stamps. Time stamps can either be specified with precise Ruby DateTime objects or can be specified as strings, which will lead to retrival of all the data falling under that time. For example specifying ‘2012’ returns all data that falls in the year 2012. See detailed usage of DateTimeIndex
and DateTime
in conjunction with other daru constructs in the daru README.
An essential utility in implementing DateTimeIndex
was DateOffset
, which is a new set of classes that offsets dates based on certain rules or business logic. It can advance or lag a Ruby DateTime
to the nearest day, or any day of the week, or the end or beginning of the month, etc. DateOffset
is an essential part of DateTimeIndex
and can also be used as a standalone utility for advancing/lagging DateTime
objects. This blog post elaborates more on the nuances of DateOffset
and its usage.
The last thing done during the post mid term was complete compatibility with Ankur Goel’s statsampletimeseries, which was created by during GSOC 2013. Statsampletimeseries is a comprehensive suite offering various functions for statistical analysis of time sries data. It now works with daru containers and can be used for statistical analysis of data indexed on Daru::DateTimeIndex
. See some use cases in the README.
I’d like to conclude by thanking all the people directly and indirectly involved in making this project a success  My mentor Carlos for his help and support throughout the summer, Ivan, Alexej and Will for their support and feedback in various stages of developing daru. Also a big thank you to all the SciRuby maintainers for making this happen!
]]>Rather than discussing what NMatrix has (which you can find in the readme), I want to take this opportunity to discuss where we’d like it to go in the future. Think of this as our roadmap to 1.0.
NMatrix currently has an extremely limited set of Ruby gem dependencies — essentially only packable, which is needed for some of the I/O functionality — but as with other linear algebra libraries, its native library requirements can be problematic.
Specifically, NMatrix requires ATLAS — which is virtually impossible to install on many Macs, and is no longer readily available with Yosemite — and also likes to have LAPACK around. Moreover, some would prefer to use other math libraries with NMatrix.
There are several partial solutions. The clearest is that any components of NMatrix which require external nonstandard libraries need to be abstracted into separate gems — such as nmatrixatlas and nmatrixio — and that these components should be interchangeable with others. NMatrix then needs to be able to fall back on either native C/C++ or Ruby implementations of certain functionalities.
To this end, a number of simple LAPACK and CBLAS functions have been implemented in NMatrix, with volunteers working on a few others (the list is available in the README). One of our proposed Google Summer of Code 2015 project ideas involves breaking up NMatrix into several gems.
The end result will be a much simpler installation process, and more freedom of choice.
We thought it would be quite clever to include rational number support in NMatrix, including three types (32bit, 64bit, and 128bit). Unfortunately, these types increase compilation time by about 30% (backoftheenvelope calculation), and aren’t particularly useful since most matrix operations with rationals as inputs give irrationalvalued matrices as their outputs. The inclusion of rational types also complicates the codebase.
Additionally, rationals are computationally problematic; what happens if there is overflow? Ruby handles overflow gracefully in its own rational type, which NMatrix users would still be able to utilize via the :object dtype.
The biggest change going forward is that NMatrix development needs to support actual usecases. In the past, we’ve aimed to flesh out support for sparse storage formats, as well as math operations for the dense storagetype. It is folly to develop features no one wants to use. Future core development, then, will aim to make NMatrix’s current feature set more usable.
That means that future noncore development depends on you. What would you like to see in NMatrix? What would make it more useful for you?
If you want to become involved, now is a good time. We’re getting ready to submit a Google Summer of Code application (our third, I believe), and we’re in need of students — and especially mentors. Please consider joining our mailing list and adding yourself as a mentor on the ideas page.
Thanks so much for your support!
]]>Three months of GSoC 2014 term was over this week and finally I released my product Nyaplot as a gem. This blog post was written to introduce Nyaplot version 0.1.1.
There are various plotting libraries in the world as ggplot2 from R community and Plotrb and Rubyvis from Ruby. The features of Nyaplot compared with those libraries are interactivity, simplicity, and extensibility.
Interactivity is the main theme of my D3 project in GSoC 2014. You can soon find the aforementioned interactivity by clicking plots with your mouse or trackpad. This feature is also available on browsers bundled with Android or iOS thanks to technologies like SVG and WebGL.
However, the word ‘interactivity’ is not limited to situations like the above. You can explore that for yourself by using Nyaplot in IRuby notebook. Various modules prepared by Nyaplot help you to create plots interactively in the notebook. You can also publish the result quickly by uploading the notebook to your Dropbox storage, a gist or pastebin, or somewhere else. Here is an example which Mauricio Giraldo created and published on gist.
Simplicity is also an important element. Many plotting libraries has MATLABlike functionbased API but Nyaplot does not. Nyaplot is designed in a more Rubylike objectoriented style, and its plots consist of various objects created from different classes. But Nyaplot has simple shortcut methods and users may avoid the more complex API.
Nyaplot can be easily and dramatically extended with some JavaScript code. It bundles 3 extension libraries in its gem package: Nyaplot3D for 3D plots, Mapnya for map visualization, and Bionya for circular plots inspired by circos. Their structure is very simple and you can write the extension easily if you have a little experience in JavaScript and Ruby. For example, the Ruby part of Bionya has only about a hundred lines, even though the graphic’s style is far from that of standard plots.
You can install Nyaplot by simply running gem install nyaplot
.
After that, find example code from
path_to_gems/nyaplot0.1.1/examples/rb
and run some of them using
ruby
command. These scripts will generate some plots with Nyaplot
and export them as html files to current directory.
In addition, I strongly recommend you to install IRuby notebook at the same time. IRuby is a webbased, interactive Ruby environment and is useful for quickly creating plots with Nyaplot. The introduction video embedded at the top of this post was also created on IRuby.
IRuby depends on some software outside of Rubyecosystem, so its installation method is a bit complicated. Please read the description in the readme to learn more.
I already wrote tutorials, so I’d like to limit the role of this paragraph to the introduction of the basic usage. You can skip reading this paragraph and find details in the nbviewer tutorial and documentation.
The minimum code to create a scatter plot is as shown below:
1 2 

Nyaplot::Plot
is the base class to create plots and
Nyaplot::Plot#add
is the method to add diagram to its instance. The
first argument is to specify the type of diagram, and the second and
third are for data mapped into x and y axes. Plot#add
returns an
instance of Nyaplot::Diagram
and you can change attributes like
color and stroke of each diagram component.
For example you can change its color by running the code below.
1 2 

Nyaplot::Colors
is the simple wrapper for
Colorbrewer, and one of its methods
Nyaplot::Colors.qual
randomly returns colorset suitable for
qualitative data.
If you execute this code in IRuby notebook, you can check if you favor the colorset through htmltable based interface. See the tutorial to learn more.
The plot generated from the code can be exported with two lines below.
1 2 

We cannot explain Nyaplot without Nyaplot::DataFrame
. Example code
above does not contain the word ‘DataFrame’, but the software
internally create an instance of Nyaplot:DataFrame
and creates plots
based on it.
To create the same scatter plot as above, run the code below.
1 2 

You may not feel any advantage of using Plot#add_with_df
instead of Plot#add
, but the former is useful when creating more complicated plots. Have a look at the tutorial to learn more.
My GSoC term has concluded, but that do not mean the end of development. There are still many things to do for improvement of this project. For example Mapnya and Bionya are both experimental implementation, and the functionality of Nyaplot::DataFrame is relatively limited. If you are interested in this project, please fork either or both of the two repositories below and send me pullrequests.
Any form of contribution is welcome.
At last I’d like to express my gratitude to my mentor Pjotr Prins and other members of SciRuby community. I would not have been able to finish my GSoC term without great help from them. Feedback from people outside of the community also helped me a lot. I had a great summer thanks to all people related to this project.
]]>1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 

If you are keen to test any function of your choice you can pull from
my Integration gem fork
and change the files in the benchmark folder. For both the files,
accuracy.rb
and speed.rb
, change the line func = lambda{x f(x)}
with f(x)
as your desired function. In case you want to perform
accuracy benchmarks, make sure that you know the exact result of the
integration operation before hand and assign this value to the
variable actual_result
Feel free to comment if you face any problem
running the benchmarks with your desired functions.
Last week I implemented the multiple panes interactivity to the frontend of Nyaplot. You can see the demo on this notebook.
Skip over single pane demo, and have a look at the paragraph ‘Multiple
panes demo’ at the bottom. In this example, the histogram and bar chart are
created individually, and then thrown into one instance of
Nyaplot::Frame. After running frame.show
, both of the diagrams
appear in one output box on the notebook. When you click the
histogram, bar chart refrects that and change its height.
In this article I will explain about the event handler of Nyaplot, which allows for interactivity among panes.
The trick is actually hidden in Nyaplot::DataFrame. In this example,
both of the two diagrams are generated from columns in one DataFrame.
When Nyaplot receives a column object (instance of Nyaplot::Series
,
defined
here), it
internally find its source data frame and remembers its location.
Consequently, Nyaplot can find that histogram and bar chart are sharing their data source, and allows them to interact with each other.
Before explaining the event handler, I want to outline Nyaplot’s diagram rendering procedure. In the backend JavaScript library, diagrams, such as histograms, fetch column data from data frames and generate their SVG DOM nodes dynamically (source code).
The key is a data frame written in JavaScript. After mouse events coming from a filter (such as the gray box on the plot area) are handled, the histogram registers its filter function to the data frame and instructs all diagrams to update their SVG DOM objects. The bar chart updates its SVG from data filtered by the new function.
As you can see, Nyaplot’s inner workings are fairly simple; and these workings are common to all diagrams supported by Nyaplot. So not only the histogram and bar chart, but other diagrams as well, can behave interactively (e.g., histogram, bar, and Venn example).
Despite, or perhaps because of, the relative simplicity of the structure, the event handler functions well. The actual interactivity in Nyaplot is based on the data frame object, both in the Ruby frontend and the JavaScript backend. As a result, handling events in DataFrame is both natural and efficient for Nyaplot.
Nyaplot and its backend library Nyaplotjs are being developed on GitHub.
If you are interesed, feel free to try it and raise issues or send pullrequests.
]]>Integration is the process of finding the summation of the value of a function at small intervals, when the width of the intervals is infinitesimally small. As there is no such thing as “infinitesimally small interval”, there are several other methods which help us to approximate the values of integrals.
Numerical integration is one such technique which helps us to estimate the value of the definite integral of a function over an interval. Numerical integration is based on the principle of evaluating the values of a function at specific points in the interval and then taking the product of those values with a corresponding weight, which is a standard constant specific to the method being used.
The Integration gem is now equipped with a host of additional algorithms for approximating the integral of a function ranging from the simple ones like Simpson’s method to the more complex ones like Gauss–Kronrod and Adaptive Quadrature method.
Let us say you need to find out the integral of a function 5*x**2 7*Math.cos(x)
over the interval (0,1)
.
We can solve this using the following snippet using the Integration gem:
1 2 

We see that the actual value of this integral is 4.2236302269886088799000849584
, which is pretty close to the value estimated by the integration gem.
Instead of {:method=>:simpson}
in the above code, you can use any one of these implemented methods:
1


Each of these algorithms gives similar results — except if the function has rapid changes in the interval of integration, as is the nature of numerical integration.
]]>I am developing Nyaplot as the frontend library for my work.
One topic on Nyaplot is API design. That is a difficult problem since each plotting library has very different methods for creating plots. For example, matplotlib and Bokeh are both written in Python, but their demo code is written in very different styles. After discussing with my mentor, I decided to implement the functionbased API.
As an exmaple of that API, here is a minimal working example for generating bar charts with Nyaplot:
1 2 3 4 

If you want to change options (e.g., color or title), put the return
value of Nyaplot::Plot.add
into a variable and call its methods.
1 2 

Interaction with IRuby is a priority for Nyaplot. IRuby is a webbased Ruby lab notebooklike environment, based on IPython, which is also useful for fast prototyping.
The image at the top of this blog post is a hyperbolic spiral which I generated with Nyaplot in IRuby. Have a look at the notebook on nbviewer, an IRuby and IPython notebook hosting services.
Nyaplot uses Nyaplotjs as its backend library. I spent a lot of time working to implement interactivity among multiple panes to Nyaplotjs. See an example here.
The input data source is a TSV file of 2,044 lines. Multiplepane interactivity is especially important when visualizing such a large dataset.
Have a look at the radio buttons beside the Venn diagram. The left three panels decide which set to put into each of three circles (VENN1, VENN2, VENN3). The right panel decides which data in each area (overlapping area, nonoverlapping area, and all) to use in the other two panes.
The gray box on the histogram decides the range of PNR values. If you select the range 0.3 to 0.7 with it, the right bar chart will reflect that and show how many of the selected data are in that range.
Nyaplotjs provides this interactivity using an event handler connected to a dataframe object. That allows us to handle unidirectional update method (e.g., histogram updates bar chart, but bar chart does not update histogram).
I finished the first half term of Google Summer of Code 2014, but I still have a lot of things to do. I would like to continue to add interactivity to both the frontend and backend libraries.
I am developing those two libraries in separate repositories on GitHub. If you are interested, feel free to raise issues or send pullrequests, even during the GSoC term.
]]>The Minimization gem now supports the following unidimensional function minimizations provided by GSL. The supported methods include the pure Ruby implementations of:
Of these, the Golden Section, Brent, and Quad Golden are also available via Minimization’s GSL interface (and are thus faster). Everything is organized in such a way that the faster C code (i.e., GSL) will be executed when GSL is available, but that otherwise the Ruby implementation will be used. I still have to beautify the code and add documentation.
The Integration gem has been transitioned from Hoe to Bundler. For Gauss–Kronrod Quadrature, I have hardcoded the values of nodes and weights (for 15, 21, 31, 41, and 61 points) — which were already hardcoded in the case of the Gauss quadrature.
Additionally, I added basic methods like Simpson’s ThreeEighths Method, Milne’s Method, Boole’s Quadrature and Open Trapezoid.
This week, I will be reviewing a pull request which aims to change the structure of the whole Integration gem.
After that I plan to implement more adaptive methods and incorporate the nonadaptive methods under a single Newton–Cotes function.
Lastly, I am brainstorming designs for symbolic integration using JScience and JRuby.
]]>In the first half of the summer, I plan to introduce some new numerical minimization methods to SciRuby’s Minimization gem. As per my proposal, I began by implementing the Powell’s multidimensional minimization method. Powell’s method has a better convergence in most cases than the Nelder–Mead algorithm, and is also a multidimensional minimization method which doesn’t use any derivative of the function.
I started by studying SciPy and Apache Commons library’s Powell’s optimizer. I decided to base my implementation on the method from the Apache Commons Mathematics Library. Powell’s method requires a line minimum searching algorithm, for which I used Brent minimizer (already available in SciRuby).
Having finished with Powell’s method, I am now working on the Fletcher–Reeves minimization method — a gradient method which uses the first derivative of the integrating function.
]]>I’m Lahiru Lasandun and I’m an undergraduate of University of Moratuwa, Sri Lanka. I’ve been selected for Google Summer of Code 2014 for SciRuby’s Minimization and Integration projects.
I was working with SciRuby about a month before GSOC started and did some tests on how to enhance the performance of these numerical computations. My first idea was to use multithreading. With the instuctions and guidance of mentors, I tested more methods such as Erlang multiprocessing, the AKKA package of multithreading, and finally OpenCL. The final decision was to use OpenCL to enhance computation power of these mathematical computations with the support of multicores and GPUs.
After GSOC started, I began working on SciRuby’s Minimization gem. I proposed multidimensional minimization methods for the Minimization gem, which already had plenty of unidimensional minimization methods. I chose two nongradient and two gradient minimization methods as well as simulated annealing.
For Integration, I proposed to replicate some unidimensional integration methods from the GNU Scientific Library, GSL. Additionally, I proposed to add OpenCL support to enhance performance of integration methods.
Currently, I am working on Nelder–Mead multidimensional minimization method which is a nongradient method, including working on the relevant test cases.
]]>