Thursday, 17 May 2007

Simulation of Markov Decision Processes with enhanced generators in Python (with blood)

The language war will always go on and I consider myself as someone who has to promote the Python programming language no matter what happens (even though I know that there is no silver bullet.) Thus, I do have to use every opportunity to show the world how easy it is to connect formalisms of high scientific importance with not-so-important-but-still-cool language features.

Whatever.

Markov Decision Processes are big in machine learning. The whole field of reinforcement learning is based heavily on them since they are a good way to formalize environments in which an agent acts.

Python 2.5 brought a powerful new feature to the Python community: enhanced generators. If you want to give a function state you might consider overriding the __call__ method of your class - or you might want to go a way even more straightforward by using a generator function. If you are not familiar with Python's generators, you can read about them here.

Sending values into the generator is somehow more complex than it has to be if you do want to send in a value everytime you want to retrieve one. For example, you might want to have an adder that adds up numbers and always returns the current result:

def adder(n = 0):
  while True:
    inc = (yield None)
    n += inc
    (yield n)
That gives us in the REPL:
>>> a = adder()
>>> a.next()  # You have to forward the generator once
>>> a.send(2) # Sending in gives you a result
2
>>> a.next()  # Forward again
>>> a.send(3)
5
This can be eased with the following coroutine decorator:
def coroutine(func):
    def wrapper(*args, **kwargs):
        f = func(*args, **kwargs)
        f.next()    # Move on to the first
        def inner(message):
            while True:
                # StopIteration might be raised here, which is okay
                r = f.send(message)
                f.next()
                return r
        return inner
    return wrapper
Now you can use your adder much more easily:
>>> coAdder = coroutine(adder)
>>> a = coAdder(2)
>>> a(2)
4
>>> a(3)
7

We can use those features to simulate a Markov Decision Process. First let's recall a somewhat simpler definition: A Markov Decision Process (MDP) is defined by

  • A set of states
  • A set of actions
  • Transition probabilities P(s, a, s') that describe the probablity of transfering from state s to state s' if action a is taken
  • An initial state from the set of states

You can think of an MDP as a something that has a state and that you feed with actions - upon every action, the MDP transfers into a (possibly) new state. Let's have a look at an example:

Quentin is living together with his friends Bill and Beatrix. Bill and Beatrix have been going out together since some years, but today they have a serious argument . They run around the flat and scream at each other, swing their Hatori Hanzo blades and are about to cover the whole apartment in blood, gore and bones. Quentin is interested in not beeing in the same room with them since his two daikatanas are at the polisher. Bill and Beatrix keep chasing each other around the flat having a movie-like fight. The apartment is a little small and only has two rooms. Quentin has two actions: he can either switch the room or stay in the one he is at the moment.

There are two states - either Quentin is in the same room as the couple or he is in the other room. The fact that there are two different rooms does not matter for now, since we consider them only distinguishable on the fact who is in it.

Every time step the couple has a probability of 30% to switch the room. This leads to the following transition probabilities:

Same room, switch: 0.7 other room, 0.3 same room
Same room, stay: 0.3 other room, 0.7 same room
Other room, switch: 0.3 other room, 0.7 same room
Other room, stay: 0.7 other room, 0.3 same room

Of course, the best strategy for Quentin would be to switch rooms if they are in the same room and to stay if they are in the other room. The uber strategy "Leaving the flat" is not considered for educational reasons. ;)

How can this be implemented as a generator function? First we should think about how to represent the transition probabilites in Python, which can be done extremly easy with a dictionary:

 
transitions = {
  ('same room', 'switch'):  ((0.3, 'same room'), (0.7, 'other room')),
  ('same room', 'stay'):    ((0.7, 'same room'), (0.3, 'other room')),
  ('other room', 'switch'): ((0.3, 'same room'), (0.7, 'other room')),
  ('other room', 'stay'):   ((0.7, 'same room'), (0.3, 'other room'))}

This dictionary maps the (state, action) pairs to (propability, state') pair which is the probability that the next state is state'. The sets of states and actions are given implicitly by the probabilites.

To pick an item from a list depending on a probability, we can use this handy function:

from random import random
def randomPick(iterable):
   """Return one item of an iterable which consists of pairs (probability, item).

   The iterable is consumed."""
   # No check for correctness of probabilites to leave this to the programmer
   # and to not consume the iterable
   iterator = iter(iterable)
   s, i = 0.0, random()
   for prob, item in iterator:
       s += prob
       if i if i < s: return item

Now all we have to do to get our MDP is a very simple generator function:

@coroutine
def markovProcess(transDict, initialState):
    state = initialState
    while True:
        action = (yield None)
        state = randomPick(transDict[state, action])
        (yield state)

And this is as easy as it gets. This could of course be enhanced by using a function instead of a dictionary for the transition probabilites. But since the transitions are given by reference and not by value you can change the dictionary from the outside and the MDP will reflect this.

Thursday, 19 April 2007

Ignoring folders with TODO Bundle in TextMate

TextMate's TODO bundle lets you keep track of the TODOs in your projects. You can mark a line to show up in the TODO list with FIXME, TODO or CHANGED. The following two images show a text file with these keywords and the resulting TODO list. The only problem is that if you keep a copy of Rails in vendor/, then the TODO plugin will also show the items in Rails (or any other external libraries and plugins you have in your project. This blog entry on exdolo.com describes how to get rid of the external items in your project with a sledgehammer: Add the vendor/rails folder to your global TextMate ignore list. However, there is a cleaner way: Open TextMate's Preferences Pane, go to Advanced » Shell Variables and the shell variable TM_TODO_IGNORE. You can set this variable to a regular expression as you would use it in Ruby (since the TODO bundle is written in Ruby). Et voilá: Rails-less TODO lists.

Wednesday, 11 April 2007

The Joys Of Floating Point Numbers

Sometimes, floating point numbers are the thing that futile hours of programming are made of. Whether they come as 32, 64 or any other precision you want, they can truly give you unnecessary and unexpected work if you do not use them correctly. The problem I stumbled over yesterday was the problem of rounding errors. Consider the following C snippet
double pi = 3.1415926535897932384626433832795;
double val = sqrt(pi) * sqrt(pi);

printf("pi  = %f\n", pi);
printf("val = %f\n", val);
which yields
pi  = 3.141593
val = 3.141593
Which is what we expected! val is the same as pi (the square is the inverse of the square root as we all know). However, the following C snippet shows the problem we run into:
if (val == pi) {
 printf ("pi == val\n");
} else {
 printf ("pi != val\n");
}
which yields
pi != val
So two apparently equal values are not equal any more! Where is the problem? It is in the precision of printf(), of course. We modify the first snippet so the printf() calls print the floating point values to more significant places
printf("pi  = %.16f\n", pi);
printf("val = %.16f\n", val);
and now we get
pi  = 3.1415926535897931
val = 3.1415926535897927
So how do we resolve this? Instead of comparing floating point values directly, we calculate their difference and make sure it is below a small value, for example 1e-9:
if (abs(val - pi) < 1e-9) {
 printf ("pi == val\n");
} else {
 printf ("pi != val\n");
}
which now gives us
pi == val
I guess most programmers are aware about the problems with floating point numbers and I have also known about the problem for a long time. What made me stumble, however, was that I trusted the printed value - which was inaccurate. As far as I know, there is no generic solution to the problem with floating point inaccuracies. You will get away with comparing whether the difference between two floating point values is smaller than a given value for comparing. In Ruby, you could hack the built in Float class with the following:
class Float
  def ==(value)
    self - value < 0.01
  end
end
This allows us to compare floating point values “fuzzily”:
>> Math.sqrt(2) ** 2 == 2.0
=> false
>> require 'floathack'
=> true
>> Math.sqrt(2) ** 2 == 2.0
=> true
However, I do not think that this is a good idea! Overwriting the == operator of the Float as above breaks its transitivity, i.e. we get the following (in-)equalities 1.99 == 2.00 == 2.01 but 1.99 != 2.01 Another idea would be only to compare the first n numbers after the point, e.g. consider 3.1415926535897931 to be 3.141 for n = 2. However, this does not help us if a floating point error gives us two values just next to a “boundary”, i.e. a result of 1.999 would not be considered correct if 2.001 was expected and we only cared about the result being “sufficiently close” to the expected value. So be careful when using floating point values are checking two of them for equality. Trouble will strike and most probably find some way to trick you into wasting time. An extensive, academic - and arguably dry - discussion of the implications of floating point arithmetics can be found in What Every Computer Scientist Should Know About Floating-Point Arithmetic, by David Goldberg.

Saturday, 7 April 2007

SQLite gotcha

SQLite is great. No, really, I do mean it. If you ever need to work on structured data and editing it from the outside is a must, then SQLite is worth checking out and might be a superior choice to XML and will be a superior choice to your own proprietary format.

I cannot speak about performance - there are some outdated claims that SQLite is faster than postgres and mysql for the most common operations; but those benchmarks don't feature a single join, and that's where database implementation gets interesting and hard. I just cannot believe that SQLite stands up to any full scale DBMS.

I spent a few hours chasing down a bug in my own code after realising that I've been utterly stupid and put my parameters in the wrong order into my parameter list.

To boil it down, this is what happens in SQLite if I compare an integer field with a string in a WHERE part of a statement:

sqlite> CREATE TABLE my_favourite_numbers (number integer);
sqlite> SELECT * FROM my_favourite_numbers WHERE number = "foo";
sqlite>

You get no result. No error is thrown, like in Postgres:

# CREATE TABLE my_favourite_numbers (number integer);
# SELECT * FROM my_favourite_numbers WHERE number = 'bla';
ERROR: invalid input syntax for integer: "bla"

I know now what to look out for in the future.

Friday, 6 April 2007

First Post

Obviously, this is the first entry of the shining new Bitwiese Weblog. Feel warmly welcomed by these few bytes which propably travelled kilometre over kilometre from here to Blogger's servers and back again to you. This weblog is brought to you by Justin and me, Manuel. We hope to publish information related to the following
  • programming
  • computers in the widest sense
  • computer science (prepare for some math, hehe).
So have fun and stay tuned.
 

Header Image

Header Image
Bitwiese Header Image