Saturday, May 07, 2005

Getting closer to version 1.0 of rur-ple

I just release version 0.8 of my project, rur-ple, on sourceforge. It looks even better than what I dreamed it would when I first started working on it:
Teaching computer programming

I do find it difficult to deal with the version number issue. On the one hand, I feel the software part has all the features I wanted (and more) working when I started this project. In that sense, it is past a version 1.0.

On the other hand, the 'ple' part in rur-ple means Python Learning Environment. I mean for this to be a 'complete' tutorial in learning about programming with Python. The lessons I have written so far only cover the use of about half the Python keywords. So, I can't bring myself to calling it version 1.0. So, I've sort of settled on adding a '0.01' to the version number for each additional keyword/programming concept I manage to introduce. However, somehow, I feel that giving a sub- 1.0 number to the version is sending the message that the software part is somehow buggy or incomplete, when it is (almost) bug-free and certainly feature complete.

On a somewhat unrelated note, I have found a solution on my own as to how to
change the language used in a wxPython-based GUI APP without having to restart the application under Windows. As a friend pointed out, by not using the common I18N starndard (gettext, .po and .mo files), it might deter people from adapting it to languages other than English and French which are currently working. However, I feel uncomfortable with what seems to be an underlying assumption about the "standard" approach.

As I understand, the standard approach is based on looking for some locale information on the user's machine. If the local language is available, then the app uses that language, otherwise it reverts to the default - usually English. But what if the user is a native Spanish speaker who has some knowledge of Italian and French, but essentially none in English. And what if translation are available in Italian, French but not in Spanish. As I understand it, the average user will be presented with an English interface, and will normally have no clue that French and Italian interfaces are available. Or, if she does, she might not know how to switch locale on her computer. (I don't ... as I never needed to myself. Can it be done easily under Windows XP - just a rhetorical question; answer not really needed :-).

The approach I use is to have the available languages in a pull down list (with flags as icons on the side) AND the language names appear in that language, i.e. English, Français, etc. (and not English, French ... or anglais, français).

This strikes me as being more sensible.

Adapting/translating a French expression: It is my own opinion, and I share it completely with myself! C'est mon opinion, et je la partage entièrement avec moi-même.

Friday, April 08, 2005

Computing derivatives using Python

In a recent thread on Python edu-sig, Kirby Urner started a discussion about the use of python's decorators in mathematics. Some of the examples included numerically computing derivatives (and integrals) of functions. This generated a fair bit of discussion and the general conclusion was that this was not a good use of decorators. Some information contributed by yours truly required the reader to do a graph to properly visualise exactly what was going on. I thought it appropriate to present a summary that included the required graphical information here as a permanent record.

The mathematical definition of the derivative of a function f(x) at point x is to take a limit as "h" goes to zero of the following expression:

( f(x+h) - f(x) ) / h

An example is given below: the red curve is the function f(x) and the green curve is the tangent line at x (with same slope as the derivative). The blue curve is a line going through x whose slope equals that of the above formula with a non-zero value of h.



As you can see, the slopes of the two straight lines are quite different. A better way of numerically computing the derivative for the same value of "h" is by taking a symmetrical interval around x as follows:

( f(x + h/2) - f(x - h/2) ) / h

This is illustrated in the next picture. As you can see, the two straight lines have much more similar slopes - hence, the value computed for the derivative is going to be more accurate.




The corresponding python code is as follows:

def derivative(f):
...."""
....Computes the numerical derivative of a function.
...."""
....def df(x, h=0.1e-5):
........return ( f(x+h/2) - f(x-h/2) )/h
....return df

And we use it as follows:

# sample function
def g(x): return x*x*x

# first derivative
dg = derivative(g)

# second derivative
d2g = derivative(dg) # == derivative(derivative(g))

# printing the value computed at a given point:

print dg(3)
print dg(3, 0.001)
print dg(3, 1e-10) # smaller h is not always more precise

Sunday, March 27, 2005

Changing blog's name

Originally, it was my intention to have a blog to post alternate viewpoints (hence the former name Un autre point de vue) as well as some Python musing. Since this blog has been listed in both
Planet Python and
Daily Python-URL, I have felt that non-Python related stuff didn't really belong here. I may revive the old title in a separate blog later...

James Tauber : Simple Algorithm for Recurring Tasks

James Tauber : Simple Algorithm for Recurring Tasks talks about a product (sciral) for keeping track of recurring tasks with priorities roughly based on how late they are. Sciral is now also available for Windows, which Tauber didn't mention. This looks like a simple thing to do in python; I'll have to try to implement it using wxPython.

Thursday, March 24, 2005

First looks: Text Processing in Python

I just received an autographed copy of
Text Processing in Python (a book) from David Mertz (Thanks David; great service!). While the content of this book is available (in ascii format) on the author's website, I find that there is nothing like having a copy in hand, especially when it is a good quality paperback (as expected from Addison Wesley).

There is a lot of material in that book; while I am an avid reader, I suspect that it will take me quite a while to get through it. If you can't wait to learn more about this book, you might want to have a look at
this review.

Wednesday, January 26, 2005

Useful wxPython info

In an old blog, that I just stumbled upon, Golden spud gives some interesting information about wxPython. Perhaps it is possible to use his technique to change the language used in a GUI without having to restart the application under Windows.

Tuesday, January 11, 2005

Teaching an old Python keyword new tricks

In my last post, I provided some additional thoughts about maintaining Python's pseudocode appearance while adding static typing information. The notation I suggested also allowed for easy inclusion of pre-conditions and post-conditions. However, this came as a cost of adding where as a new keyword to Python. After giving some more thoughts to this idea I realise that a new keyword was not needed at all. This can be seen starting from the following example using the keyword where as introduced before:
01    def gcd(a, b):

02 where:
03 assert isinstance(a, int)
04 assert isinstance(b, int)
05 '''Returns the Greatest Common Divisor,
06 implementing Euclid's algorithm.
07 Input arguments must be integers.'''
08 while a:
09 a, b = b%a, a
10 return b
If we remove the line with where: and change the indentation level, we have essentially valid (today!) Python syntax, but with many (two in this case) lines starting with the keyword assert. If we allow this keyword to introduce the beginning of a bloc of statements, we could then write:
01    def gcd(a, b):

02 assert:
03 isinstance(a, int)
04 isinstance(b, int)
05 '''Returns the Greatest Common Divisor,
06 implementing Euclid's algorithm.
07 Input arguments must be integers.'''
08 while a:
09 a, b = b%a, a
10 return b
The idea of a keyword that allows both a bloc structure with a colon, as well as a single line expression is not new: it has been introduced in Python with the addition of list comprehensions. For example, we can have
01    for i in range(10):

02 ...
03 ...
as well as
a = [i for i in range(10)]

With this suggested syntax, pre-conditions can easily be added.
01    def gcd(a, b):

02 assert:
03 isinstance(a, int)
04 isinstance(b, int)
05 a != 0 and b != 0 # fake pre-condition
06 '''Returns the Greatest Common Divisor,
07 implementing Euclid's algorithm.
08 Input arguments must be integers.'''
09 while a:
10 a, b = b%a, a
11 return b
Keeping this block structure in mind, we can add type information on return values as follows:
01    def gcd(a, b):

02 assert:
03 isinstance(a, int)
04 isinstance(b, int)
05 return c assert:
06 isinstance(c, int)
07 '''Returns the Greatest Common Divisor,
08 implementing Euclid's algorithm.
09 Input arguments must be integers;
10 return value is an integer.'''
11 while a:
12 a, b = b%a, a
13 return b
as well as adding pre- and post-conditions:
01    def gcd(a, b):

02 assert:
03 isinstance(a, int)
04 isinstance(b, int)
05 a != 0 and b != 0 # fake pre-condition
06 return c assert:
07 isinstance(c, int)
08 c != 0 # fake post-condition
09 '''Returns the Greatest Common Divisor,
10 implementing Euclid's algorithm.
11 Input arguments must be integers;
12 return value is an integer.'''
13 while a:
14 a, b = b%a, a
15 return b
To move further towards something similar to what I suggested in my previous post, we need to identify, as Guido van Rossum had himself suggested, the statement
isinstance(object, class-or-type-or-tuple)

with
object: class-or-type-or-tuple

Doing so allows us to rewrite the last example as
01    def gcd(a, b):

02 assert:
03 a: int
04 b: int
05 a != 0 and b != 0 # fake pre-condition
06 return c assert:
07 c: int
08 c != 0 # fake post-condition
09 '''Returns the Greatest Common Divisor,
10 implementing Euclid's algorithm.
11 Input arguments must be integers;
12 return value is an integer.'''
13 while a:
14 a, b = b%a, a
15 return b
which is essentially what was written in the previous post, but with the replacement of a new keyword (where) by an old one (assert). The general form would be:
01    def foo(...):

02 assert:
. type information and/or
. pre-conditions
. return [...] assert:
. type information and/or
. post-conditions
. '''docstring'''
. ...body...
As this post is already long enough, I will not discuss the interface issue here; the ideas introduced in the previous two posts are easily translated by replacing where by assert everywhere.