Thursday 26 July 2007

Quick book recommendation

This summer, I've got an undergraduate research bursary at our university's Systems Biology centre, which is wierd as I always viewed myself of more of a pure mathematician, but is absolutely fascinating.

I have jumped in at the deep end, however (my supervisor seems to think I know a lot more than I really do and maybe hasn't realised I haven't done any serious integration/differentiation or ODEs stuff since the first year...).

What I'm actually doing is looking at the response of Neurons to different types of presynaptic noise, which I am slowly learning more about. In particular, noise is random (well, duh) and so all of the models I end up with have Stochastic Differential Equations, which are typically quite unpleasant. For those interested, the toy models I'm playing with end up with Brownian motion in a harmonic potential.

So the book I'm recommending is:

Paul and Baschnagel, "Stochastic Processes, From Physics to Finance"

Don't let the reference to finance put you off - I've found it absolutely fantastic for explaining the basics of Wiener processes, brownian motion and so on. In particular, it is written for the scientist rather than the mathematician and so everything's done in the real numbers, rather than over wierd and wonderful probability spaces. I really believe that even if you want to learn stochastic integration properly as a mathematician, this is a worthwhile read, because you end up for a real feel for what's going on.

The book's published by Springer and is on Amazon here at the terrifying price of about £50 used, so you might want to try a university library!

Now back to work!

Thursday 5 July 2007

Fun with xorg.conf

So I've finally got my ALPS / Synaptics touchpad working along with a compose key on debian (the ALPS touchpad comes with, among many other laptops, the Dell Inspiron 500m which I own).

The touchpad

For the touchpad, I need to thank this walkthrough along with this forum thread.

Before anything will work, you need to make sure that the evdev module is being compiled in your kernel (it wasn't) and is being loaded (that bit worked for free for me, but one comment on the above forum post suggested you needed to add it to /etc/modules). You can find the option under Device Drivers/Input Device Support/Event Interface in the kernel config (e.g. make menuconfig)


Now you need to edit your xorg.conf (found in /etc/X11). There are three things that you need to do:

  • Load the synaptics module

  • Add a new input device to ServerLayout

  • Declare the input device


In order to load the synaptics module, add a line saying:

Load "synaptics"

to the "Module" section. Mine now looks like:

Section "Module"
Load "glx"
Load "extmod"
Load "xtrap"
Load "record"
Load "GLcore"
Load "dbe"
Load "dri"
Load "type1"
Load "synaptics"
EndSection


Now adding a new input device to ServerLayout is simple - just choose a name (I called it "ALPS") and add the line

InputDevice "your name for it here"

to the ServerLayout section just below the line saying

InputDevice "Configured Mouse"


Finally, add the declaration for the input device. A version with no clever options set is:

Section "InputDevice"
Identifier "ALPS"
Driver "synaptics"
Option "SendCoreEvents" "true"
Option "Device" "/dev/input/mouse1"
Option "Protocol" "evdev"
Option "SHMConfig" "on"
EndSection

(note that the identifier has to agree with the name you chose earlier). For a much more thorough list of settings you might wish to see the third page of the debuntu article here.

Assuming you got everything right, you should now be able to restart your X server and get exciting touchpad support. Note that to restart the X server, the best practice is to exit (gracefully) any open programs, log out of whatever desktop environment you're using and when you get to the display manager (xdm,kdm,gdm or whatever) hit Ctrl-Alt-Backspace.

The Compose Key

This is really simple, but it makes life much easier when writing auf Deutsch on an english keyboard. In your InputDevice section corresponding to your keyboard, add the line:
Option "XkbOptions" "lv3:ralt_switch, compose:ralt"
The relevant section in my xorg.conf now looks like this:

Section "InputDevice"
Identifier "Keyboard0"
Driver "kbd"
Option "XkbModel" "pc105"
Option "XkbLayout" "gb"
Option "XkbOptions" "lv3:ralt_switch, compose:ralt"
EndSection


Once you've restarted the X server, Alt-Gr S, S should give ß and you can have the fun of discovering umlauts, graves, circumflexes etc. yourself. It's a bit like a more logical version of the system they used in Microsoft Word.

Wednesday 13 June 2007

Backing up your home to DVD with debian

I've finally got a DVD writer (external - it's a laptop) and it works quite amazingly well: no setup issues at all!

Now, the whole point of the exercise was that my Dell is getting a little dodgy (you have to press down hard around the power button to flex the PCB below in order to get it to boot!) and I wanted to back up my documents, sourcecode, emails etc. in case the worst should befall my poor old laptop. But I had a German exam the next day, and while I was burning the DVD I should also be revising!

In general, burning a data DVD on linux is easy. You get a copy of mkisofs and growisofs (on debian, this is easy: apt-get install dvd+rw-tools mkisofs). Then you call mkisofs on a directory tree to create an iso image (put it in /tmp!) and growisofs to write the lot to your DVD (I got the instructions here

Ahah, but not so fast! I wanted to do my home directory whilst xfce, claws-mail, firefox and probably a whole load of other processes were writing tiddly little bits to all my hidden dot-files and dot-directories in ~/ (you know, the ones like ~/.gnome and ~/.mozilla etc.). In fact, I didn't twig the first time and mkisofs threw a wobbly! Moreover, I didn't want to make another copy of everything because there's quite a lot of stuff and I didn't really have space for that on the harddisk partition.

So here's the solution:

First I made a folder called backmeup in my home directory:
mkdir backmeup
Then I moved all of the "normal" i.e. non-hidden files in my home directory into backmeup:
mv * backmeup
This will actually complain because at some point you've asked it to move backmeup into backmeup, but ignore the complaint - it did what we wanted! Now for the dot-files. We don't want to move them into backmeup, because some of the running programs would throw a wobbly, so we will actually need to copy this lot. Now, don't run cp -Rp .* backmeup/ because it'll go horribly wrong and try to make two copies of backmeup via the .. directory I think (disclaimer: Yes, this did go horribly wrong. And it took me 5 minutes to notice!)

Instead, call the following command:
cp -Rp `find -maxdepth 1 -name '.*' | sed '/^\.$/d'` backmeup
which is what we really wanted.

Now we're almost done! Just make the iso from the backmeup tree (no-one's going to be writing automatically to something called that!):
nice -n 19 mkisofs -r -o /tmp/rupert.iso /home/rupert/backmeup
The nice command is just to stop the job hogging the whole system.

... And write the iso to the disk:
growisofs -Z /dev/scd0=/tmp/rupert.iso

(clearly the device to which you write will need to depend on what the kernel calls it - I'm trying to do something clever with udev, but haven't quite got there yet!)

Wednesday 6 June 2007

Ical subscriptions with orage

Orage looks to be an exciting program for my new Xfce desktop, but what good's a calendar if it can't subscribe to ical feeds from the internet?! Fortunately, I'm supposed to be revising at the moment, so have had an urge to hack code together...

And so we present a simple shell script to download .ics files periodically from the internet to your filesystem. The one nifty feature is that if the internet's down, this won't blat the current copies as using wget blindly would, which should be useful with my laptop.


There are probably more sophisticated systems, but I was going for the 25 minute job option. Firstly, we need a list of feeds - mine looked something like this:

## Lines must be either urls, blank, or start with a #.

# UK holidays
http://ical.mac.com/ical/UK32Holidays.ics

# NASA Space Missions
http://ical.mac.com/tonyfarley/SpaceMissions.ics

# Astronomical Events
http://hewgill.com/astrocal/astrocal.ics


The lines beginning with hashes really are comments - they get stripped by the downloading script, which uses wget:

#!/bin/sh

dir=/home/rupert/.icals/

for f in `cat $dir/feeds.list | sed -e '/^$/d' -e '/^\#/d'`
do
fout=$dir/`echo $f | md5sum | cut -f 1 -d ' '`.ics
tmp=`mktemp $dir/getfile.XXXXXX`
wget -q --tries=3 -O $tmp $f
if [ -s $tmp ]; then
mv $tmp $fout
else
rm $tmp
fi
done


To make it work, you need to call the first file feeds.list and set dir to a directory containing feeds.list and in which you'd like your downloaded .ics files to end up. The quickest way I could think of to give the files names was the md5sum of the url, so once you've got everything in place, set the executable bit on the script (which I called get_feeds.sh) and run it.

If all goes to plan, you should get some files called things like "5b7ed8afdd4a8f71525d0df0e47231e5.ics" appearing in $dir. Now we need to automate it: I used cron, so call crontab -e and add the following line to your crontab:

*/15 * * * * /home/rupert/.icals/get_feeds.sh

(well clearly, you'll need to make the directory right!) This calls the get_feeds.sh script every 15 minutes. Maybe we should slow that down, but I was testing!

Finally, use the new "Exchange Data" item on Orage's File menu to add a foreign file corresponding to the .ics you downloaded and you're away! Wahey!

Incidentally, the SVN orage that I downloaded this evening doesn't appear to be getting multiple foreign files quite right - if I can work out what's going on, I'll file a bug tomorrow!

Sunday 13 May 2007

Tree display program (update)

Well, I handed in a rather inconclusive version of the essay I mentioned. It and the program used to generate the trees are both here.

I'd love it if anyone found the program useful - and anyone's more than welcome to do anything with the code, although I'd appreciate a heads-up out of interest. Enjoy!

Copying UTF into Emacs

It's been annoying me for ages, but I never really got UTF copy/paste working right in Emacs. Finally (procrastinating from German revision) I found a solution that works for copying from Firefox at least.

The solution is detailed here and I'm eternally grateful. Basically, just put the following code somewhere in your .emacs:

(setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))


And, voila, umlauts (like ö) and I presume strange characters from other languages will appear in all their glory!

Sunday 8 April 2007

Leptonica 1.43 in debian

What a load of effort! I've been developing a program using leptonica recently, using the debian package without thinking. Irritatingly, however, debian is at version 1.37 and upstream is at 1.43.

The good news is that the debian diff still works - to get a quick and dirty install (which is all I'm interested in!) do the following:


  1. Download the debian diff from this page.
  2. Patch a copy of the current source (from here) using the command:

    patch <../leptonlib_1.37-1.diff -p1


    from within the directory into which you extracted leptonica.
  3. Make the "debian/rules" file executable:

    chmod 0755 debian/rules

  4. Edit the "debian/docs" file and remove the line with library-notes.txt (it no longer exists in the package)
  5. cd into the debian directory and run the command

    dch -v 1.44-1

    (The dch program is part of the devscripts package)
  6. Finally, make sure a copy of the original 1.43 tar.gz is in the parent directory with the name
    leptonlib_1.43.orig.tar.gz
    and call
    debuild
    from the main source directory. Hopefully, it should compile and you'll have the relevant debfiles in the parent directory from which to install leptonica 1.43!

Friday 30 March 2007

Tree display program

I've been writing away at a compulsory second year essay for what seems ages now. In particular, this one's about Goodstein's Theorem. When it's done (which will definitely be before the deadline in 3 weeks' time), I'll see what I can do about posting a version.

However, for now, I've been working on a bit in the proof of the theorem. What you need to do is express a number in hereditary base-n notation which is explained on the Wikipedia article I just linked to. Now suppose you draw a rooted finite tree in the following way (let's express 93 in base 2).

First note that:


Now build a tree one level of branches at a time. In the first level, is a branch for each term in the expansion above. Then a child of each node has children that are the terms in the exponent of that child... It'll make more sense with a picture:



I hope :)

So what I wrote was a program that would generate that sort of picture because I needed some in the essay and couldn't find something on the internet to draw it. To save problems with file formats etc., the program actually exports to SVG - to generate png images for here and for PdfLatex in the essay I used the command "inkscape -f file.svg -e file.png", which I found here. So I'm going to try and post the code below. The command line options are:

Options:

--help produce help message
-b [ --base ] arg (=2) set base of expansion
-s [ --stroke ] arg (=black) set colour of stroke
-f [ --fill ] arg (=red) set colour of fill
-w [ --width ] arg (=800) width of image
-h [ --height ] arg (=600) height of image
-o [ --output ] arg (=-) Output file

And to make the picture above, use:
maketree 93 -b 2
To compile, you just need boost program options.



Anyway, here are the sources:



Makefile:

maketree: maketree.o NumberTree.o SVGOut.o
g++ -g -lboost_program_options -o $@ $^

%.o: %.cc
g++ -O0 -g -I/usr/include/my-boost -Wall -c $<

clean:
rm *.o


NumberTree.cc:

#include "NumberTree.hh"
#include <math.h>
#include <boost/foreach.hpp>
#include <sstream>

using std::ostream;

NumberTree::NumberTree( long n, int b )
: output_width(800), output_height(600), width(-1), height(-1),
base(b)
{
while( n ) {
int hp = find_hipow(n,b);

children.push_back( TreePtr(new NumberTree(hp,b)) );
n -= static_cast<int>(pow(b,hp));
}
}

void
NumberTree::BracketPrint( ostream& os ) const
{
os << "(";
for( unsigned int i=0; i<children.size(); i++ ) {
children[i]->BracketPrint(os);
if(i<children.size()-1)
os << ",";
}
os << ")";
}

int
NumberTree::find_hipow( long n, int b ) const // TESTED
{
if(n < 1 || b < 2)
throw "Invalid parameters";
return static_cast<int>(floor(log(n)/log(b)));
}

long
NumberTree::eval( int b ) const // TESTED
{
long total=0;

BOOST_FOREACH( const TreePtr& pt, children ) {
total += static_cast<long>(pow(b, pt->eval(b)));
}

return total;
}

void
NumberTree::printSVG( SVGOut& so )
{
so.start();

std::ostringstream os;
os << eval(base);
so.annotated_circle(0.5,0,os.str());
printSVGBranches(so,0,1,1,0,0.5,
1.0/calcHeight(),1.0/calcWidths());
so.end();
}

int
NumberTree::calcWidths()
{
if( widths.size() ) return width;

if(!children.size()) return 0;

int w = 0;
BOOST_FOREACH( TreePtr& pt, children ) {
int t = pt->calcWidths();
w += t+1;
widths.push_back(t);
}

return width = w-1; // subtract one to lose padding on RHS
}

int
NumberTree::calcHeight()
{
if( height != -1 ) return height;

int max=-1;
BOOST_FOREACH( TreePtr& pt, children ) {
int th = pt->calcHeight();
if(max<th) max = th;
}
return height = max+1;
}

void
NumberTree::printSVGBranches( SVGOut& o,
float l, float t, float r, float b,
float px, float lineheight, float xscale )
{
int lhs = 0;

BOOST_FOREACH( const TreePtr& pt, children ) {
int w = pt->calcWidths();

float newmid = lhs + w/2.0;
if(calcWidths() == 0)
newmid = 0;
else
newmid /= calcWidths();
newmid *= r-l;
newmid += l;

std::ostringstream os;
os << pt->eval(base);
o.annotated_circle(newmid, lineheight+b, os.str());

o.line(newmid,lineheight+b,px,b);

pt->printSVGBranches(o, l+lhs*xscale, t, l+(lhs+w)*xscale,
b+lineheight, newmid, lineheight, xscale );

lhs += w+1;
}
}


NumberTree.hh:

#ifndef NUMBERTREE_HH
#define NUMBERTREE_HH

#include <iostream>
#include <vector>
#include <boost/shared_ptr.hpp>
#include "SVGOut.hh"

class NumberTree
{
public:
/* Construct tree from n with given base */
NumberTree( long n, int b );

/* Print as parentheses */
void BracketPrint( std::ostream& os ) const;

/* Evaluate as powers of b */
long eval( int b ) const;

/* Output SVG to stream */
void printSVG( SVGOut& so );

private:
/* Find the largest power of b that is less than n */
int find_hipow( long n, int b ) const;
/* Find the width in branches of the tree and populate knowledge of
* widths of our immediate children */
int calcWidths();
/* Find the height of the subtree below us */
int calcHeight();
/* Draw our subtree to SVG */
void printSVGBranches( SVGOut& os,
float l, float t, float r, float b,
float px, float lineheight, float xscale );

/* Output sizes for SVG */
int output_width, output_height;

/* The actual important data! */
typedef boost::shared_ptr<NumberTree> TreePtr;
std::vector<TreePtr> children;

/* Widths for printing */
std::vector<int> widths;
/* Width - must be dirtied to -1 if we change something */
int width;
/* Height - must be dirtied to -1 if we change something */
int height;

/* Base of expansion */
int base;
};

#endif


SVGOut.cc:

#include "SVGOut.hh"
#include <cmath>

using std::string;

SVGOut::SVGOut( std::ostream& os, int width, int height, int margin )
: o(os), top(margin), left(margin), right(width-margin),
bottom(height-margin), _margin(margin), fill("black"),
stroke("black")
{
set_circle_radius(0.01);
set_font_size(0.03);
}

void
SVGOut::start()
{
o << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"no\"?>\n"
<< "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n"
<< "\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n"
<< "<svg xmlns=\"http://www.w3.org/2000/svg\"\n"
<< " xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
<< " width=\""
<< static_cast<int>(fabs(right-left) + 2*_margin)
<< "\" height=\""
<< static_cast<int>(fabs(top-bottom) + 2*_margin)
<< "\">\n";
}

void
SVGOut::end()
{
o << "\n</svg>\n";
}

void
SVGOut::circle( float x, float y )
{
boost::tuple<float,float> ddpos = xyToSVG(x,y);

o << " <circle cx=\""
<< ddpos.get<0>()
<< "\" cy=\""
<< ddpos.get<1>()
<< "\" r=\"" << circle_radius << "\" style=\"stroke: "
<< stroke << "; fill: " << fill << ";\"/>\n";
}

void
SVGOut::line( float x1, float y1, float x2, float y2 )
{
boost::tuple<float,float>
ddpos1 = xyToSVG(x1,y1),
ddpos2 = xyToSVG(x2,y2);

o << " <line x1=\""
<< ddpos1.get<0>() << "\" y1=\""
<< ddpos1.get<1>() << "\" x2=\""
<< ddpos2.get<0>() << "\" y2=\""
<< ddpos2.get<1>() << "\" style=\"stroke: "
<< stroke << ";\"/>\n";
}

boost::tuple<float,float>
SVGOut::xyToSVG( float x, float y ) const
{
return
boost::make_tuple( float( (right-left)*x + left ),
float( (top-bottom)*y + bottom ) );
}

void
SVGOut::text( const string& s, float x, float y )
{
boost::tuple<float,float> ddpos = xyToSVG(x,y);

o << " <text x=\"" << ddpos.get<0>() << "\" y=\"" << ddpos.get<1>()
<< "\" font-family=\"Verdana\" font-size=\""
<< font_size << "\" fill=\"black\">"
<< s
<< "</text>\n";
}

void
SVGOut::set_fill_colour( const string& colour )
{
fill = colour;
}

void
SVGOut::set_stroke_colour( const string& colour )
{
stroke = colour;
}

void
SVGOut::set_circle_radius( float rad )
{
circle_radius = rad*fabs(right-left);
vanilla_circle_radius = rad;
}

void
SVGOut::set_font_size( float size )
{
font_size = size*fabs(top-bottom);
}

void
SVGOut::annotated_circle( float x, float y, const std::string& s )
{
circle(x,y);
text(s, x+vanilla_circle_radius*1.1, y );
}


SVGOut.hh:

#ifndef SVGOUT_HH
#define SVGOUT_HH

#include <iostream>
#include <string>
#include <boost/tuple/tuple.hpp>

class SVGOut
{
public:
SVGOut( std::ostream& os, int width, int height, int margin );

void set_fill_colour( const std::string& colour );
void set_stroke_colour( const std::string& colour );
// rad, size are compared to the [0,1]x[0,1] canvas!
void set_circle_radius( float rad );
void set_font_size( float size );

void start();
void end();

/* Element creation functions */
void circle( float x, float y );
void line( float x1, float y1, float x2, float y2 );
void text( const std::string& s, float x, float y );
void annotated_circle( float x, float y, const std::string& s );

private:
boost::tuple<float,float> xyToSVG( float x, float y ) const;

/* Output stream ref */
std::ostream& o;
/* Input sizes */
float top,left,right,bottom;
float _margin;
/* Colours */
std::string fill, stroke;

/* Other settings: Only change throught set_ functions */
float circle_radius, font_size;
float vanilla_circle_radius;
};

#endif


maketree.cc:

#include <iostream>
#include <string>
#include <errno.h>
#include <boost/program_options.hpp>
#include <fstream>
#include "NumberTree.hh"
#include "SVGOut.hh"

void usage()
{
std::cerr << "I need exactly 1 argument, which is a number.\n";
exit(1);
}

int main( int argc, char* argv[] )
{
using std::string;

namespace po = boost::program_options;
po::options_description standard("Options");
standard.add_options()
("help", "produce help message")
("base,b", po::value<unsigned int>()->default_value(2), "set base of expansion")
("stroke,s", po::value<string>()->default_value("black"), "set colour of stroke")
("fill,f", po::value<string>()->default_value("red"), "set colour of fill")
("width,w", po::value<unsigned int>()->default_value(800), "width of image")
("height,h", po::value<unsigned int>()->default_value(600), "height of image")
("output,o", po::value<string>()->default_value("-"), "Output file")
;

po::options_description hidden("Options");
hidden.add_options()
("number", po::value<unsigned long int>(), "number to be represented");

po::options_description all("Options");
all.add(standard).add(hidden);

po::positional_options_description pos;
pos.add("number", 1);

po::variables_map vm;
po::store(po::command_line_parser(argc, argv).
options(all).positional(pos).run(), vm);
po::notify(vm);

if (vm.count("help")) {
std::cerr << standard << "\n";
return 1;
}

string output = vm["output"].as<string>();

std::ostream* os;
if( output == "-" ) os = &std::cout;
else {
os = new std::ofstream(output.c_str());
if(!os) {
std::cerr << "Could not open output file.";
return 1;
}
}

if (vm.count("number")) {
NumberTree tree(vm["number"].as<unsigned long int>(),
vm["base"].as<unsigned int>() );
SVGOut sout(*os,
vm["width"].as<unsigned int>(),
vm["height"].as<unsigned int>(),
30);

sout.set_fill_colour( vm["fill"].as<string>() );
sout.set_stroke_colour( vm["stroke"].as<string>() );

tree.printSVG(sout);
}

if( output != "-" ) delete os;
}

Latex in Posts

So the question is whether as posted here will actually work. OK. So I'm impressed :)


Now can it work with ScribeFire? I fear not...