Tuesday 31 March 2009

Skype Sound Issues

Skype is not available in the Ubuntu repositories but you can get hold of it (and a few other things) through medibuntu. However, it looks like that version of Skype has a problem with sound on Ubuntu 8.10 Intrepid Ibex, as detailed in this bug report. The workaround suggested in the discussion that consists in killing pulseaudio before launching Skype works for me so that's good news. Even better news, it looks like the problem is fully sorted in Ubuntu 9.04, which is currently in beta. So, until then, I will use the workaround.

One lesson to learn from this though, is that if you ever have a problem with a piece of software on Linux, a good practice is to start that software from the command line: the output in the terminal window is invaluable for developers and maintainers to understand the problem and is a good place to start in order to find a solution to it. Quite often, just putting the error message in Google will return a number of articles and bug reports on that exact problem.

Upgrading the Server from Gutsy to Hardy

My silent server that provides DNS, DHCP, Subversion and other services to my home network hadn't been upgraded since it was first installed and had been running Ubuntu 7.10 (aka Gutsy Gibbon) quite happily all this time. But with 7.10 reaching end of life in a few weeks, I felt it was time to upgrade and that today was the day to do so.

The first port of call is the upgrade notes and in particular the Hardy note to upgrade from 7.10 to 8.04. Make sure you read the "Before You Start" section at the beginning of that note before you start. So taking this into account, here is the sequence of what I did for that upgrade:

Refresh the package index

It's always good to do that once in a while and especially before an upgrade.

$ sudo apt-get update

Update all packages

Before an upgrade, it's essential to ensure that you are on the latest version of packages for your current release.

$ sudo apt-get upgrade

You will likely need to reboot after that, especially if the upgrade includes a new kernel. If in doubt, reboot anyway.

$ sudo init 6

Install update-manager-core

That's the bit that will perform the upgrade so you need to make sure it's there. If in doubt, install it, apt-get will tell you if you already have the latest version.

$ sudo apt-get install update-manager-core

Upgrade!

That's the biggie that will take a long time and may ask you some questions in the process. If you ever get any question, make sure you read them carefully. Defaults tend to be sensible so it shouldn't wreck your system but that doesn't excuse you from being sensible and paying attention.

$ sudo do-release-upgrade

A few things to note on the upgrade process:

  • I was doing my upgrade through SSH. If things go wrong, you can potentially lose connection with your server and it can all end in tears so the upgrade process warns you about this and starts a second SSH daemon on a different port (9004 in my case but it will tell you). I had no problem installing over ssh but be careful nonetheless.
  • If you have a DHCP server configured, as I do, it will probably notify you that the file /etc/dhcp3/dhcpd.conf file has been modified on your server and ask you whether you want to replace it with the new one it just downloaded or keep the old one. You need to keep the old one if you want your settings to be preserved. To be on the safe side, make a copy of it just in case.
  • Because of a well documented bug in Debian upon which Ubuntu is based, the upgrade process will re-generate any SSL key, in particular the RSA keys used by SSH. That will affect us later and I'll explain what to do about it.

Once the upgrade is finished, the script will ask you of you want to reboot immediately. Unless you have a good reason to reboot manually, you can let the upgrade process do that for you.

Updating the SSH keys on the client machine

If you attempt to reconnect to your server via ssh straight after the upgrade, you will be greeted by a worrying message and you won't be able to go further:

Helsinki:~ brunogirin$ ssh bruno@szczecin
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that the RSA host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
dc:11:1a:78:f4:34:c3:a2:ab:9d:52:1e:98:6d:7f:36.
Please contact your system administrator.
Add correct host key in /Users/brunogirin/.ssh/known_hosts to get rid of this message.
Offending key in /Users/brunogirin/.ssh/known_hosts:2
RSA host key for szczecin has changed and you have requested strict checking.
Host key verification failed.

This is normal and is due to the fact that the upgrade process has re-generated the ssh RSA keys on the server. Those keys are stored on all client machines that have previously connected to that server so that they can verify the identity of the server. To resolve that problem, the error message is giving us a hint. On the example above taken from my OS-X box, it tells me that the offending key is on line 2 of file /Users/brunogirin/.ssl/known_hosts. So open that file in an editor and remove the offending line then try to connect again. As it doesn't have the key anymore, it will ask for confirmation before adding the new one to that file and let you connect:

Helsinki:~ brunogirin$ ssh bruno@szczecin.home
The authenticity of host 'szczecin.home (192.168.1.253)' can't be established.
RSA key fingerprint is dc:11:1a:78:f4:34:c3:a2:ab:9d:52:1e:98:6d:7f:36.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'szczecin.home' (RSA) to the list of known hosts.

Note that if you have several keys for the same host, for instance if you've connected through its name and IP address in the past, it may give you another warning, as shown on my Ubuntu laptop:

Warning: the RSA host key for 'szczecin' differs from the key
 for the IP address '192.168.1.253'
Offending key for IP in /home/bruno/.ssh/known_hosts:1
Are you sure you want to connect (yes/no)?

Once again, it tells you which is the offending key so you can remove it and attempt to connect via the IP address to renew the key. Note that this only works as explained above if SSH on the client is configured so that the StrictHostKeyChecking option is set to ask. If it is set to no, it will never check and will happily connect. If it is set to yes, you will have to update the keys manually. See man ssh_config for the full details.

There you go: apart from the SSH malarkey at the end, it was rather straightforward and very quick too! In fact, it took me more time to write this post that do the upgrade.

Bootnote

Now that I have this server on 8.04, I could upgrade immediately to 8.10 but I'll leave that for another day. In fact, considering that 8.04 is an LTS release, I may leave my server on that version until the next LTS release, 9.10 aka Karmic Koala, scheduled for October.

Custom Page Numbering with LaTeX

I'm currently doing a home course on short story writing. Or should I say I attempt to as I haven't been returning my assignments very promptly. Anyway, one of the requirements is that each assignment is formatted in such a way that the footer of each page contains the page number, starting at 1 on the first page, and the letters mf for More Follows on every page except the last one. In order to do this, I need to be able to set a specific footer for the last page and one for all other pages. I tried to do that with OpenOffice.org to start with but there was no way to identify whether you were on the last page using a macro with version 2.4, which is what I was using when I started. As you would expect, it is surprisingly easy to do with LaTeX, provided you import the correct packages.

  • In order to specify a custom footer (or header), I will need the fancyhdr package;
  • I will also need to be able to use some if/then/else logic to output something different whether I am on the last page or not, this is provided by the ifthen package;
  • Finally, I will need to know whether I am on the last page, which is provided by the aptly named lastpage package.

Putting all this together, the document's code needs to do the following:

  • Import all relevant packages;
  • Set the page style to fancy;
  • Set all headers and footers to blank;
  • Set the header and footer lines to 0 points (optional, you may like the defaults);
  • Set the right hand side footer so that it implements this logic:
    • If the page is the last one, print nothing;
    • Otherwise, print mf.
  • Set the left hand side footer to the current page's number.

And here is the resulting code:

\documentclass[a4paper,12pt]{article}
\usepackage{lastpage}
\usepackage{ifthen}
\usepackage{fancyhdr}

\pagestyle{fancy}
\fancyhf{}
\renewcommand{\headrulewidth}{0pt}
\renewcommand{\footrulewidth}{0pt}
\fancyfoot[R]{\ifthenelse{\thepage=\pageref{LastPage}}{}{mf}}
\fancyfoot[L]{Page~\thepage}

\begin{document}

The content of the document goes here.

\end{document}

Monday 30 March 2009

Updated Cow Analogy

I just received the following by email:

After the recent teetering-on-the-edge-of-total-economic-and-financial-meltdown couple of weeks it seems economic systems and their workings have pushed their way into the need-to-know-category. Well, we can now simplify this all by explaining 9 economic models with cows.

Socialism

You have 2 cows.

You give one to your neighbour.

Communism

You have 2 cows.

The State takes both and gives you some milk.

Fascism

You have 2 cows.

The State takes both and sells you some milk.

Nazism

You have 2 cows.

The State takes both and shoots you.

Bureaucratism

You have 2 cows.

The State takes both, shoots one, milks the other, and then throws the milk away...

Traditional Capitalism

You have 2 cows.

You sell one and buy a bull.

Your herd multiplies, and the economy grows.

You sell them and retire on the income.

An American Corporation

You have 2 cows.

You sell one, and force the other to produce the milk of four cows.

Later, you hire a consultant to analyse why the cow has dropped dead.

2008 Venture Capitalism

You have 2 cows.

You sell three of them to your publicly listed company, using letters of credit opened by your brother-in-law at the bank, then execute a debt/equity swap with an associated general offer so that you get all four cows back, with a tax exemption for five cows. The milk rights of the six cows are transferred via an intermediary to a Cayman Island Company secretly owned by the majority shareholder who sells the rights to all seven cows back to your listed company. The annual report says the company owns eight cows, with an option on one more. You sell one cow to buy a new president of the United States, leaving you with nine cows. No balance sheet provided with the release. The public then buys your bull.

Friday 27 March 2009

Fractals with Octave: Other Polynomials

The story so far

In the third instalment of this series on fractals with Octave, I want to change the polynomial series used to generate the Mandelbrot and Julia sets. So far, I've used the classic series, defined by:

zn+1=zn2+c

In the previous articles, I showed what happened when you varied the initial values for z0 and c but why not go further and use a different polynomial altogether?

Code review

Before jumping into the thick of it, let's have a look at the code produced so far. We created 4 functions:

function M=mjcore(z,c,niter)
The core function shared by the mandelbrot and julia functions;
function M=mandelbrot(cmin,cmax,hpx,niter)
The function that produces a colour map image as per the Mandelbrot algorithm;
function M=mandelbrotz0(cmin,cmax,hpx,niter,z0)
A variation of the mandelbrot function that takes an extra argument in order to specify an initial z0 value;
function M=julia(zmin,zmax,hpx,niter,c)
The function that produces a colour map image as per the Julia algorithm.

There is very little difference between the mandelbrot and mandelbrotz0 functions: mandelbrot just uses a default value of 0 for z0. In fact, we could merge both functions into one using the default argument construct supported by Octave. Here's a new version of the mandelbrot.m file that uses it:

mandelbrot.m

function M=mandelbrot(cmin,cmax,hpx,niter,z0=0)
  vpx=round(hpx*abs(imag(cmax-cmin)/real(cmax-cmin)));
  z=zeros(vpx,hpx).+z0;
  [cRe,cIm]=meshgrid(linspace(real(cmin),real(cmax),hpx),
                     linspace(imag(cmin),imag(cmax),vpx));
  c=cRe+i*cIm;
  M=mjcore(z,c,niter);
endfunction

Having done this, we can now create the classic Mandelbrot image as we did previously, using four arguments:

octave-3.0.1:1> Mc=mandelbrot(-2.1+1.05i,0.7-1.05i,640,64);

Create the Mandelbrot image with z0=0.2+0.2i by adding a fifth argument:

octave-3.0.1:2> Mz0=mandelbrot(-2.1+1.05i,0.7-1.05i,640,64,0.2+0.2i);

And we can delete the mandelbrotz0.m file. Note that you could also explicitly tell Octave to use the default for the fifth argument by specifying a colon (:) in its place, so you could produce the classic Mandelbrot this way:

octave-3.0.1:3> Mc=mandelbrot(-2.1+1.05i,0.7-1.05i,640,64,:);

This is not very useful in this context but we will see a use for it later.

Function handles and anonymous functions

In order to be able to change the polynomial used to calculate the fractal image, we need to be able to specify to the mjcore function what function to use when calculating the series. We could create a whole library of mjcore derivatives but that would quickly get tedious. Instead, we can use Octave's function handles. A function handle is a fancy way to say that in Octave, any variable can be a function. Therefore, we can just pass the function as an argument of the mjcore function. And while we're at it, we'll also pass r as an argument because, as we saw in the first article, the value for r is dependant on the function used in the series. So here is a modified version of that function:

mjcore.m

function M=mjcore(z,c,niter,f,r)
  M=zeros(length(z(:,1)),length(z(1,:)));
  for s=1:niter
    mask=abs(z)<r;
    M(mask)=M(mask)+1;
    z(mask)=f(z(mask),c(mask));
  endfor
  M(mask)=0;
endfunction

That's all good and well but we've just moved the problem further into the mandelbrot and julia functions: those functions will have to specify parameters accordingly and use sensible defaults so that if we omit the values for f and r, it will calculate the classic sets using the series zn+1=zn2+c (i.e. the function f=z2+c) and r=2. To do that, we are going to use the default argument construct explained above and combine it with an anonymous function. Using anonymous functions, we can define a variable f that is a handle on a function that implements the classic algorithm:

octave-3.0.1:4> f=@(z,c) z.^2.+c;

As shown above, we can use exactly the same syntax to specify default arguments to the mandelbrot and julia functions. Here are the new versions of those two functions:

mandelbrot.m

function M=mandelbrot(cmin,cmax,hpx,niter,
                      f=@(z,c) z.^2.+c,r=2,
                      z0=0)
  vpx=round(hpx*abs(imag(cmax-cmin)/real(cmax-cmin)));
  z=zeros(vpx,hpx).+z0;
  [cRe,cIm]=meshgrid(linspace(real(cmin),real(cmax),hpx),
                     linspace(imag(cmin),imag(cmax),vpx));
  c=cRe+i*cIm;
  M=mjcore(z,c,niter,f,r);
endfunction

julia.m

function M=julia(zmin,zmax,hpx,niter,c,
                 f=@(z,c) z.^2.+c,r=2
                 )
  vpx=round(hpx*abs(imag(zmax-zmin)/real(zmax-zmin)));
  [zRe,zIm]=meshgrid(linspace(real(zmin),real(zmax),hpx),
                     linspace(imag(zmin),imag(zmax),vpx));
  z=zRe+i*zIm;
  cc=zeros(vpx,hpx)+c;
  M=mjcore(z,cc,niter,f,r);
endfunction

Cubic sets

We can now produce cubic Mandelbrot and Julia sets by setting the power to 3 instead of 2:

octave-3.0.1:5> Mn3=mandelbrot(-1.2+1.6i,1.2-1.6i,240,64,
> @(z,c) z.^3.+c);
octave-3.0.1:6> imagesc(Mn3)

Cubic Mandelbrot Set

Cubic Mandelbrot image
octave-3.0.1:7> Jn3=julia(-1.6+1.2i,1.6-1.2i,320,64,0.4,
> @(z,c) z.^3.+c);
octave-3.0.1:8> imagesc(Jn3)

Cubic Julia Set for c=0.4

Cubic Julia image for c=0.4

Quartic sets

Increasing the power to 4, we get quartic sets:

octave-3.0.1:9> Mn4=mandelbrot(-1.2+1.6i,1.2-1.6i,320,64,
> @(z,c) z.^4.+c);
octave-3.0.1:10> imagesc(Mn4)

Quartic Mandelbrot Set

Quartic Mandelbrot set
octave-3.0.1:11> Jn4=julia(-1.6+1.2i,1.6-1.2i,320,64,-1,
> @(z,c) z.^4.+c);
octave-3.0.1:12> imagesc(Jn4)

Quartic Julia Set for c=-1

Quartic Julia set for c=-1

Note that for a series defined by the equation zn+1=znp+c, the resulting Mandelbrot set will show p-1 secondary "blobs" while the Julia set will show p secondary "blobs".

Decimal power

The power doesn't have to be an integer. Using a decimal value, such as 2.5, generates the following Mandelbrot image, that is halfway between the normal and cubic sets:

octave-3.0.1:13> Mn2_5=mandelbrot(-1.6+1.2i,1.6-1.2i,320,64,
> @(z,c) z.^2.5.+c);
octave-3.0.1:14> imagesc(Mn2_5)

Mandelbrot Set for p=2.5

Mandelbrot set for p=2.5

Complex power

Using a complex power, such as 2+0.1i, generates a skewed set:

octave-3.0.1:15> Mn2_01i=mandelbrot(-2.2+1.2i,1.0-1.2i,320,64,
> @(z,c) z.^(2+.1i).+c);
octave-3.0.1:16> imagesc(Mn2_01i)

Mandelbrot Set for p=2+0.1i

Mandelbrot set for p=2+0.1i

More complex polynomial

Using a series based on a more complex polynomial, such as zn+1=zn2+zn+c, generates the following set:

octave-3.0.1:17> Mp=mandelbrot(-2+1.05i,0.8-1.05i,320,64,
> @(z,c) z.^2.+z.+c);
octave-3.0.1:18> imagesc(Mp)

Mandelbrot Set for series zn+1=zn2+zn+c

Mandelbrot set for series zn+1=zn^2+zn+c

Bootnote

Having modified the mandelbrot function to include the f and r arguments before the z0 argument, we now need to use the colon argument for f and r to produce a classic Mandelbrot with a different value of z0:

octave-3.0.1:2> Mz0=mandelbrot(-2.1+1.05i,0.7-1.05i,640,64,:,:,0.2+0.2i);

I could have left the z0 argument in fifth position to avoid having to do this but I felt that the f and r arguments were more likely to be provided so are better specified first in the function's signature.

Next

In the next article in this series, Trigonometric and Exponential Functions, we'll look at non-polynomial series.