Saturday 27 July 2013

GSoC Week 6: First half(almost) done

First, about the work done this week. It took me some time to set up my programming environment and get used to Ubuntu's interface. I fumbled around a bit messing up some things on the way, but now I can say I am quite comfortable...at least with the basics.
For one, I got the docs for my work on the logic module merged into the master docs. Aaron also pointed me to the method for merging those changes with the development version  of the SymPy docs. I will try and get it done in a day or two, before I leave for my campus.
Second, Gilbert and I submitted a PR to Prasoon's branch with some changes that we made to his code. Since the number of merge conflicts are high, he would most probably be merging the relevant parts manually.
Third, I started working on the code for dyadics. Initially, I submitted a slightly modified version of the earlier Dyadic class, but Gilbert soon made me realise that compatibility with SymPy's core would mean a lot more than just a few changes here and there. Sigh.
So, I am now busy working on classes for dyadics, compatible with SymPy's global architecture-
1) Dyadic(Expr), the super class - all operations and initializations will be handled from here
2) BaseDyadic(Dyadic) - the class to represent basic components of dyadics, things like (R1.x|R2.y)
3) DyadicAdd(Add, Dyadic) and DyadicMul(Mul, Dyadic) - additions and multiplications of dyadics

The last two classes are a little shaky for now, and the code I have submitted at the PR at the time I write this makes it quite evident. Inspite of that, I have got the basic operations- add, sub, mul, div and some others like 'and' to work as expected(conceptually). To see how it looks as of now, you can see this (real SymPy session with mock arguments). However, it's quite obvious that getting these new classes to behave exactly according to SymPy's way of doing things and return accurate results is going to take quite some time, maybe a week more. Not to forget docs, doc examples and tests.

Anyways, I can't believe I am almost at the end of the first half of my GSoC period. I have learnt *quite* a lot, well, that's obvious from my blog posts- not just vector math, but a bunch of Python as well. I am happy with the progress till now, though nothing has been merged yet. But well, Prasoon and my projects are such that when things will get merged, a huge chunk will go in together.
I plan to get the mechanics core done perfectly before I start with the EM module..and by 'done perfectly', I mean getting the main code merged, along with a lot of commentary-style documentation on the new module. I also have to enquire about putting deprecation signs on the old module- will have to consult the mailing list for this.

As mentioned earlier, I will be moving to Goa on Tuesday, so that period is going to be quite busy with getting things in order @the insti. Then I can start working again.
The mid-term GSoC evaluations will be done from 29th to 2nd of August, after which I will get my first big payment in 4-5 days :-)

Thats all for now!
Have a great week, and 'stay tuned' :-D.

Saturday 20 July 2013

GSoC: Week5

A late post this week.
In terms of progress, last week was a bit slow, but things are going to move pretty fast now.
The past seven days, I wrote the tests for the code of MovingRefFrame, Particle and all the helper functions in the functions.py file. Trust me, if writing tests are the only thing you are doing, it can get pretty boring. Testing your code and experimenting with it is a lot of fun, but sadly, writing unit tests is not. Anyways, I finished writing most of them for the classes built till now. Some more may have to be added, but that will be after Prasoon's code gets pushed into SymPy's master repo.
Apart from that, I did some groundwork on Dyadics, which would be the focus of my GSoC work for the upcoming week. I will be taking hints from the old module's Dyadic class, but I will have to modify and hack it considerably to fit SymPy's global architecture. Plus, some methods like the __eq__ one need improvement, which I plan to do. I hope I can finish the class (operation methods as well as those for printing, etc) by the end of this week. Tests later.

One great thing that happened this week- I finally decided to give up Windows as my coding environment. Its not like you cannot code in Windows; if you are good enough for what you are trying to do, you can pretty much do whatever you want there...but in Linux, its 10x easier. Especially since any library you want is just one small command away.
My laptop's LAN card got replaced, and it prompted me to set up a dual boot system on my machine.
Anyways, I am very happy with the linux(Ubuntu 12.04 LTS) experience!

Yeah...one more thing! SymPy 0.7.3 finally got released, and this will be the first official release to include code from me (the work on sympy.logic)! However, the documentation for that code hasn't been added to the website docs, so I probably need to learn the basics of Sphinx documentation for that. I hope I can get it done this week. I tried working with Sphinx on Windows earlier, but it quite frankly was a little tricky for an impatient guy like me.

That's all the 'progress' that happened this week.
The next week's post will be the last GSoC update I'll be posting from Mumbai. I'll be going to my campus at Goa on next Tuesday, that week's work may be a little bit delayed around the Tue-Wed period.
But thats for later.
Have a great week! 

Saturday 13 July 2013

GSoC Week4: Improvements

This has been a slow week, with a lot of ups and downs, work-wise.
Firstly, my laptop's LAN card decided to stop working properly, keeping me busy talking to the Dell customer service and convincing them that something is wrong with the thing. After a lot of troubleshooting and failed tests on their part (they even tried remote desktop connection to see what was going wrong), they finally agreed that something needs to be done. I hope it gets fixed before I go back to campus.

As far as the GSoC work is concerned, firstly, I got the Particle code finalised on Tuesday after a review by Gilbert.
Next, I spent the whole of Wednesday hacking the old mechanics framework to act as the base to test my own code on. I felt the need to do this, as I was anxious to see whether my own work was functioning as I thought it would, and it would take some time before Prasoon could get his framework in a completely consistent state (thats natural, considering the complexity of the work involved). It took a lot of time, as I had to tweak the old framework to support coordinate variables, use substitution on them during re-expression and time-differentiation, and so on...
Finally, I got it to work and tested my own code. It worked perfectly! There were a few errors that had to be rectified for the tuple-args format to function, but the rest of it went smoothly.

This is a real SymPy session using the hacked module and my own work-
1:  >>> O = MovingRefFrame('O')  
2:  >>> F1 = MovingRefFrame('F1', trans_vel = 3 * O.x + 4 * O.y,  
3:                    pos_vector_b = O.x + O.y + O.z, parentframe = O)  
4:  >>> F1.pos_vector_in(O)  
5:  (3*t + 1)*O.x + (4*t + 1)*O.y + O.z  
6:  >>> Q = Symbol('Q', positive = True)  
7:  >>> F2 = MovingRefFrame('F2', ang_vel = Q * O.z, parentframe = O)  
8:  >>> F3 = MovingRefFrame('F3', pos_vector = F2.x, parentframe = F2)  
9:  >>> F3.pos_vector_in(O)  
10:  F2.x  
11:  >>> O.express(F3.trans_acc_in(O))  
12:  - Q**2*cos(Q*t)*O.x - Q**2*sin(Q*t)*O.y  
13:  >>> P = Symbol('P')  
14:  >>> F4 = MovingRefFrame('F4', orient_type = 'Axis', orient_amount = [P * t, F1.x], \  
15:                    parentframe = F1)  
16:  >>> F4.ang_vel_in(F3)  
17:  P*F1.x - Q*O.z  
18:  >>> F5 = MovingRefFrame('F5', orient_type = 'Axis', orient_amount = [Q, F1.x], \  
19:                    trans_vel = ((0, 0, 1), 0), parentframe = F4)  
20:  >>> F3.express(F5.pos_vector_in(O))  
21:  (-t*sin(Q*t)*sin(P*t + Q) + 4*t*sin(Q*t) + 3*t*cos(Q*t) + sqrt(2)*sin(Q*t + pi/4))*F3.x + (-3*t*sin(Q*t) - t*sin(P*t + Q)*cos(Q*t) + 4*t*cos(Q*t) + sqrt(2)*cos(Q*t + pi/4))*F3.y + (t*cos(P*t + Q) + 1)*F3.z  
22:  >>> F5.pos_vector_in(F4)  
23:  - t*sin(Q)*F4.y + t*cos(Q)*F4.z  
24:  >>> F5.trans_vel_in(O)  
25:  (-P*t*cos(Q) - sin(Q))*F4.y + (-P*t*sin(Q) + cos(Q))*F4.z + 3*O.x + 4*O.y  

Line 3 means that frame F1 should have an initial position of O.x + O.y + O.z wrt O. Substituting t = 0 in the output at line 5 will confirm this. To put in the boundary conditions at some other value of time, user just has to enter the keyword arg 't'.
Line 21 adequately shows how complicated things can get after a while.
Line 19 is an example how a tuple argument can be used in the new framework to position/orient new frames wrt their parents. Line 19 essentially means that F5 will have a translational velocity of 1 * F5.z after being oriented as per the user's conditions.
(All these things are adequately explained in the docs)

This work with the old module convinced me that dynamicsymbols should also be a part of my own work, since it makes handling of time variables considerably simpler. Hence, I added the function in my last commit to the PR.

Last but not the least, I planned out some basic vector/scalar field functions for my E-M module. But more on that later.

Now that I have my entire workspace up and running on my old laptop (temporarily), I will continue with the following work in the coming time-
1) Enable users to enter initial orientation in the same way they enter the time-dependent orientation. As of now, they get to do so only by entering the initial rotation in terms of a vector. Awkward, I agree.
2) Write tests for the MovingRefFrame and Particle classes as well as all the helper functions. Now that I have a system to test these things on, it will be much easier to do so.
3) Start working on the last part of the new framework - dyadics.

Thats all for now.
Have a great week ahead :-)

Saturday 6 July 2013

Singletons in Python (and GSoC update)

This week, there isn't any interesting stuff to write about as far as the project is concerned, as I pretty much cleaned up what I had done in the previous two weeks. By 'clean up', I mean PEP-8 modifications to the existing code and rectification of some tiny(but serious) conceptual errors in the MovingRefFrame methods. I also spent quite some time reviewing, or rather, trying to understand Prasoon's code. I pulled his vector branch on my machine and started executing some tests on it. I have left some comments on his PR, and hopefully they will get sorted out soon. One good thing is, I also wrote the first draft of my code for Particle class-including methods for angular momentum, translational motion calculation, etc. This wasnt much of a problem, as I 'attached' a dedicated reference frame to each Particle that would be initialized. Hence, all of Particle's methods would call the relevant methods in MovingRefFrame.

I got to learn about a pretty neat method of implementing Singleton classes in Python. How? I saw the __new__ method being called in Prasoon's code, and after an hour of going from website to website, I somehow ended up learning this.

Have a look at the following code-
1:  class MutableSingletonClass(object):  
2:    instance = None  
3:      
4:    def __new__(cls, *args, **kwargs):  
5:      print ("In __new__")  
6:      instance = cls.instance  
7:      if instance is None:  
8:        print ("No instance found")  
9:        instance = cls.instance = \  
10:              object.__new__(cls)  
11:      else:  
12:        print ("Instance found")  
13:      return instance  
14:      
15:    def __init__(self, *args, **kwargs):  
16:      print ("In __init__")  
17:      pass  
18:    
19:  class Class1(MutableSingletonClass):  
20:    def __init__(self, x):  
21:      print ("In Class1 __init__")  
22:      self.x = x  

MutableSingletonClass's subclasses (and that class itself) will have only one instance being generated per session (the first time, that is). The next time you try to initialize a new instance of Class1, that same instance that was created earlier will be modified. Mind you, that one common instance WILL be modified everytime you call the constructor with new arguments. The reason this happens is, every time __new__ returns an object (which __new__ ensures is only one per session in this case), the __init__method is called. You cannot avoid that.
To get a better idea, look at the output-
1:  >>> c1 = Class1(3)  
2:  In __new__  
3:  No instance found  
4:  In Class1 __init__  
5:  >>> c2 = Class1(4)  
6:  In __new__  
7:  Instance found  
8:  In Class1 __init__  
9:  >>> c1.x  
10:  4  
11:  >>>c1 == c2  
12:  True  

Now, if we want to implement a real Singleton type, the Python docs show a nice method-

1:  class FixedSingletonClass(object):  
2:    instance = None  
3:      
4:    def __new__(cls, *args, **kwargs):  
5:      print ("In __new__")  
6:      instance = cls.instance  
7:      if instance is not None:  
8:        print ("Instance found")  
9:      else:  
10:        print ("No instance found")  
11:        instance = cls.instance = \  
12:              object.__new__(cls)  
13:        instance.init(*args, **kwargs)  
14:      return instance  
15:    
16:    def init(self, *args, **kwargs):  
17:      #This is where the subclasses should implement their  
18:      #initialization  
19:      pass  
20:      
21:    def __init__(self, *args, **kwargs):  
22:      #Subclasses should only define this as a dummy so users no which  
23:      #arguments to pass for initialization  
24:      print ("In __init__")  
25:      pass  
26:    
27:  class Class2(FixedSingletonClass):  
28:    def init(self, x):  
29:      print ("In Class2 init")  
30:      self.x = x  
31:    
32:    def __init__(self, x):  
33:      print("In Class2 __init__")  
34:      pass  

As you can see here, this implementation reduces the __init__ method to a mere formality/dummy (just to tell the users which values to enter for initialization, in the shell). Actually speaking, all the work is done by the 'init' method, which can now be controlled by the program. Hence, this real initializer (not __init__) is called only once..the first time an instance of Class2 is created. The rest of the times, __init__ is called, but it makes no changes to the existing instance. This ensures all references of Class2 point to a common instance.
Hence, the output-
1:  >>> d1 = Class2(5)  
2:  In __new__  
3:  No instance found  
4:  In Class2 init  
5:  In Class2 init  
6:  >>> d2 = Class2(10)  
7:  In __new__  
8:  Instance found  
9:  In Class2 init  
10:  >>> d1.x  
11:  5  
12:  >>> assert d1 is d2  

I hope this was useful.
That's all for now.
Have a great week ahead :-)