Despite overhearing many of my math colleagues using sage back in grad school, I was never determined to even try it on my own, when I had the seemingly all-powerful mathematica at my fingertips. Now that I am disenfranchised from the convenience of institutional software licenses, I was forced to rethink about the situation. In the back of my mind, sage took the primitive form of some highly specialized number theory command-line tool that’s good at computing Galois groups of sorts (thanks to Simon’s preachings), but was no match for commercial giants like the ma* clans in terms of general purpose symbolic calculation. Boy was I wrong about that! Encouraged by its open-source nature and mature size of 600+mb, I decided to give it a try on my spatially unlimited macbook.
The installation was a no-brainer. The interactive session can be either old-school terminal style, or web-browser based. I found the latter much more humane, since it allows you go to back and forth, in the same vein as mathematica and maple. So after figuring out how to compute 1+1, my next ambition is to transplant my earlier mathematica project over to this sagacious language.
Without revealing the exact content of my project, which is hopefully destined to be a peer-reviewed paper, I will describe some of the most thorny tasks one could impose on a symbolic processor like sage, and hopefully be demanding enough to cover some good acreage of common case usage.
The first major ill-documented task is to create a 5 x 5 matrix with entries filled with 1 through 25. I easily accomplished this with the help of the sagacious Simon:
sage: a = matrix(5,5,lambda i,j:j*5 + i + 1)
Now this is all fine and dandy, but what if I want to generalize to arbitrary dimension n? Can I create a function with input n and output the obvious generalization of the above? So I tried:
sage: f(n) = matrix(n,n,lambda i,j:j*n + i + 1)
And not surprisingly, things don’t work, for a simple reason: the function can’t assume n is an integer. So the internet suggests some promising though not taylor-made approach: do the following before the function definition:
Sorry, try again! This is usually when I start going berserk. I didn’t and probably never will have time to figure out why this hadn’t worked. Nor would I want to spend half an hour conquering every obstacle like this one going forward. Clearly I need a bigger sledgehammer. Out comes python, in which sage was written. For all my affection of online blogging, tabbing is always a pain, whenever it comes to pythonic rambling. So let’s tab by three spaces, as is customary perhaps:
return matrix(n,n,lambda i,j: j*n + i + 1)
It’s simple as that. You would think this trick would solve all my problems. But here comes my next thread: I want to define a sage-function with variable number of variables! With the spectacular inability to define even integer valued function above, my immediate hunch is to use python wrapper again. This turns out to be correct (how could it not be?). So let’s try the obvious first again:
f(list('x_%d'%i for i in range(n))) = sum(list('x_%d'%i for i in range(n)))
Before digesting the above venomous syntax, let me just point out that there is an excellent article demystifying many subtleties about functions in sage, which should be read as a prerequisite, in addition to sections on linear algebra from the same tutorial: http://www.sagemath.org/doc/tutorial/tour_functions.html
So a native sage function takes the following innocent form:
f(x,y,..,z) = sin(xy + yz + ..) + x+y..
use your imagination on the right hand side. But the left hand side is the real trouble-maker. What if you want to make the “list” x,y,..,z a variable by itself? In particular you might want to leave the number of variables customizable. It turns out this “list” of variable isn’t actually a list, nor a (sage) vector, nor a tuple or any other familiar beast. I looked through the sage python source code and discovered that it’s the output of a method called base_ring for the class Vector_callable_symbolic_dense. My guess is that a sage function is treated as a vector-element in the formal power-series ring generated by complex numbers and its argument variables. I spent at least 2 hours installing the sage source code on my laptop and set it up on eclipse only to find out it doesn’t compile, probably because I only set up the sage-main directory, but in fact need all the other 300+mb of source code. This will be a separate dairy if I figure it out eventually.
So going back to the main topic, it is rather unnatural to massage a pythonic data structure into this base_ring beast. So I came up with a cheap way, namely using the exec command, internationally prohibited in python textbooks and forums. But hey it’s one of the ultimate reasons I chose to stick with python. But even with this nuke arsenal things weren’t immediately tame:
simply doesn’t work. I get an error that suggests I can’t assign some stuff to the left hand side. This time I was not too outraged. After all, why should I expect sage to implement exec in the same verbatim fashion as a bash command would? Exec should do just fine with all python native commands, but typing a sage-specific command on the terminal could well be outside the scope of exec.
Fortunately I saved the rest of my day through the obscure forum post http://ask.sagemath.org/question/1708/how-do-i-exec-a-function-of-n-variables. You simply have to insert a preparse in between: this reminds me of the same funny situation with R when I worked with the formula object; unfortunately my energy is waning so I won’t get to that for some time. Thus the punchline of this article is justifiably:
To echo the expert warning: admire it at a distance; don’t try it at home!