Tuesday 17 February 2009

Fractals with Octave: More on the Classic Sets

The story so far

In the second instalment of this series on fractals with Octave, I will generate more images by changing some of the parameters of the different functions presented in the first article. But before doing that, I'll briefly explain how to save the generated images and say a word on colour maps.

Saving images

The images that the functions described in the previous post generate are colour mapped images. Each element of a result matrix is an integer value that corresponds to a colour index. Octave has a very easy way to save that type of images using the well named saveimage function. To save the images generated, we just need to do:

octave:1> saveimage(file name, matrix, type, colour map);

The file name parameter is the name of the image file we want to save the image to. Give it a .ppm extension, we'll see why in a second. The matrix parameter is the matrix generated by the mandelbrot or julia functions presented in the previous article. The type parameter is the type of the image: we will use the PPM type as it is supported natively by Octave so that attribute should just be ppm. The colour map attribute is a colour map to use in the file. Octave has a default colour map that contains 64 colours from dark blue to light blue, then from yellow to red and white, similar to a contour map. It can be invoked by the colormap command. Putting all this together, creating a classic Mandelbrot image and saving it can be done this way:

octave:1> M=mandelbrot(-2.1+1.05i,0.7-1.05i,320,64);
octave:2> saveimage("mandelbrot.ppm", M, "ppm", colormap);

The PPM file format is understood natively by Linux but if you want to transform it into a more widely used format such as GIF or PNG, you can use ImageMagick or The GIMP. Avoid the JPEG format as it's not well suited to that type of computer generated images.

That's all well and good but what if you want your generated images to use a different colour map from the default? Let's create one. Octave understands a colour as a row vector that has 3 elements corresponding to the red, green and blue components of a colour. Each element is a real value between 0.0 and 1.0. So for example bright red would be [1, 0, 0] and 50% grey would be [0.5, 0.5, 0.5]. A colour map is a 3 column matrix where each row in the column is a colour. As an example, the following is a 5 colour map that defines a gradient from bright red to bright green:

   1.00000   0.00000   0.00000
   0.75000   0.25000   0.00000
   0.50000   0.50000   0.00000
   0.25000   0.75000   0.00000
   0.00000   1.00000   0.00000

We can build such a gradient by using the linspace command to evenly spread values. We will need to do that for each red, green and blue component and then combine all three with the cat command. Each vector produced by linspace will represent a column in the colour map matrix. However linspace produces row vectors so we need to transpose them before concatenating them using the ' operator. The following will produce a 64 value gradient from dark blue to white:

mycolmap=cat(2,
linspace(0, 1, 64)',
linspace(0, 1, 64)',
linspace(0.2, 1, 64)'
);

The resulting colour map can then be used to save the image. Note that for best results, the number of colours in the colour map should be the same as the number of iterations used when producing the fractal image.

Zooming into the Mandelbrot set

With the preamble out of the way, let's create some more fractal images. You can now save them for posterity! Some great images can be obtained by zooming somewhere on the edges of the Mandelbrot set. Let's zoom to the top centre of the set:

octave:1> Mcz=mandelbrot(-0.27+i,0.05+0.76i,320,64);
octave:1> imagesc(Mcz)

Octave should open the Gnuplot window and display the following image:

Mandelbrot Set, Top Centre Zoom

Zoom onto the top centre edge of the Mandelbrot set

This image shows a number of artefacts that are similar to the complete set. Zooming further on those would show them in more details. And as this is a fractal set, you can zoom as much as you want and discover more interesting structures.

Mandelbrot with a non-null z0

In the first article, we built the mandelbrot function based on the assumption that the initial value of the zn series, z0, was 0 for all values of c. It doesn't have to be. So let's create a modified mandelbrot function that can set a different value for z0 and call it mandelbrotz0. Copy the mandebrot.m file described in the previous article into a mandelbrotz0.m and modify it accordingly:

mandelbrotz0.m

function M=mandelbrotz0(cmin,cmax,hpx,niter,z0)
  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

Then, let's run this function with z0=0.2+0.2i:

octave:1> Mz0=mandelbrotz0(-2.1+1.05i,0.7-1.05i,320,64,0.2+0.2i);
octave:2> imagesc(Mz0)

Octave should refresh the Gnuplot window and display the following image:

Mandelbrot Set, z0=0.2+0.2i

Mandelbrot set with z0=0.2+0.2i

Quirky! It's as if the Mandelbrot set was exploding like a ruptured balloon! Other values produce interesting results and the further they are from 0, the more distorted the set is.

Zooming into the Julia set

After the experiments with the Mandelbrot set above, let's explore the Julia set a bit more than we did last time, using c=-0.1+0.9i. Let's calculate the whole set for this value:

octave:1> Jc2=julia(-1.6+1.2i,1.6-1.2i,320,64,-0.1+0.9i);
octave:2> imagesc(Jc2)

Which produces the following image:

Julia Set, c=-0.1+0.9i

Julia set, c=-0.1+0.9i

Then, let's zoom 10 times to a point slightly off centre:

octave:1> Jc2z=julia(-0.16+0.24i,0.16,320,64,-0.1+0.9i);
octave:2> imagesc(Jc2z)

Julia Set, c=-0.1+0.9i, zoom x10

Julia set, c=-0.1+0.9i, zoom x10

And again:

octave:1> Jc2zz=julia(-0.016+0.072i,0.016+0.048i,320,64,-0.1+0.9i);
octave:2> imagesc(Jc2zz)

Julia Set, c=-0.1+0.9i, zoom x100

Julia set, c=-0.1+0.9i, zoom x100

Cool pictures, don't you think?

Bootnote

Having created a slightly more generic mandelbrotz0 function above, we can now re-write and simplify the original mandelbrot function by calling mandelbrotz0:

mandelbrot.m

function M=mandelbrot(cmin,cmax,hpx,niter)
  M=mandelbrotz0(cmin,cmax,hpx,niter,0);
endfunction

Next

In the next article of this series, Other Polynomials, we look at what happens when we use a different complex series than the standard one.

Sunday 15 February 2009

Using the LaTeX letter document class

LaTeX offers a variety of built-in document classes. One of them is letter, which is designed for writing official letters, such as the one I just did to the (inept) agency that manages my flat. However, that standard document class is not very well liked: it's the ugly little duckling of the LaTeX document classes. But when you just have to get things done, better the devil you know than the one you don't. So here's a quick summary of easy tweaks I applied to my letter to bend the default document class to my needs.

Structure

The letter document class requires a specific structure. It is designed so that you can write several letters to several recipients while using the same return address. The basic structure of a letter document looks something like this:

Basic structure of a letter document
\documentclass{letter}

\address{The return address}
\signature{Your signature}

\begin{document}
\begin{letter}{The recipient's address}

\opening{The opening, such as: Dear Sir,}

The body of the letter

\closing{The closing, such as: Best regards,}

\end{letter}
\end{document}

The letter environment that is enclosed in the document environment looks superfluous at first. The idea is that you can have several letter environments when you want to produce more than a single letter: this can be very useful for mailings.

Top space

The document class introduces a lot of white space at the top. This is good for a multi-page letter but looks really awkward on a single page letter. So, I did what the TeX FAQ suggests and added the following in the preamble, just after the \documentclass command:

Preamble to remove the initial top space

\makeatletter
\let\@texttop\relax
\makeatother

\begin{document}

Adding a reference

As my managing agent specified a reference in the letter they sent me, I wanted to include that reference in my letter, just after their address but with some small vertical space in between. There is no obvious way to do that so I just added it to the end of the recipient's address with a space of length \parskip:

Adding a reference
\begin{letter}{The recipient's address\\[\parskip]
Your ref: The reference}

Adding some vertical space before the closing sentence

The closing sentence is printed very close to the last paragraph in the letter. I wanted a bit more space so added the following just before the \closing command:

Adding space before closing
\vspace{3\parskip}
\closing{The closing, such as: Best regards,}

Adding space between the closing and the signature

When writing a letter, I like leaving enough space between the closing sentence and the printed signature so that I can add a hand written signature once it's printed. The standard space is too small for this. However, considering both lines are printed by the \closing command, there is no obvious way to include any space in between. However, looking at the letter.cls code, it appears that the standard template adds 6 times the \medskipamount length in between the two lines so the simple way to change that space is to change the relevant length just before the \closing command:

Adding between the closing and signature
\vspace{3\parskip}
\addtolength{\medskipamount}{2\medskipamount}
\closing{The closing, such as: Best regards,}

This will multiply the \medskipamount length by 3 and as result multiply the space between closing and signature by 3 as well. This works great for a single letter but will not have the intended result when you have multiple letters in the same document. The way to avoid this is to save the original length and restore it afterwards:

Adding between the closing and signature
\vspace{3\parskip}
\setlength{\oldmedskipamount}{\medskipamount}
\addtolength{\medskipamount}{2\medskipamount}
\closing{The closing, such as: Best regards,}
\setlength{\medskipamount}{\oldmedskipamount}

With those few tricks, I got a letter that was close enough to what I wanted. I could probably have spent a lot more time tweaking it or trying alternative document classes but this particular job didn't warrant me spending too much time on it.

Saturday 14 February 2009

Designing Good Error Handling

Usability is an important subject in software design. Your application can be the coolest thing since sliced bread, if it's difficult to use, people will just not bother. We all know that. There are lots of books and articles on usability. However, such material often forgets about one important aspect of usability: error handling and messages. When your application encounters an error, whether it is due to something the user did or to a bug, it is extremely important to ensure it behaves in a way that makes sense to the user, even more important than for normal behaviour. This is because when an error occurs, your user will typically be stopped in his tracks and asked to resolve a problem he wasn't expecting to be faced with. If the error handling adds to the confusion rather than help, the user will not know what to do and his confidence about the application and his own ability to understand it will significantly diminish. So here are a couple of example of what not to do, helpfully provided over the past week by applications I use at work.

Cryptic error message

We use Borland StarTeam at work to manage change and configuration. When starting the application earlier this week, I was faced with the following error message:

Borland StarTeam error message consisting of a single zero

Yes, the error message consists of a single zero. Difficult to do any shorter or any more cryptic. At that point, I am given two options: a Details button and an OK one. Assuming the Details button may lead me to a more understable explanation, I clicked it and it showed me the following message:

Borland StarTeam detailed error message showing a Java exception

This is absolutely meaningless for anybody who is not a Java developer. And even for those who are, it doesn't really help, it only shows that there is a bug in the product where an internal array is not checked for size before accessing its first entry. It doesn't tell me whether the application will keep working or whether it will horribly crash when I click OK. It so happens that clicking OK made the message box disappear and the application kept working normally after that.

So, how can we improve on such a message? The best way in my opinion would be to display a message to the user explaining that an internal problem has occurred in the application and how they can report it to Borland. What is displayed in the details screen would be invaluable to the developers in order to correct the bug. So directions on how to send that information to the product team would make the user feel that the company cares about the qulity of their product and that they are ready to receive bug reports. Not all users would actually go through the steps of reporting the bug but some would.

Lack of information

Another error I was faced with this week came from the automated backup tool. This tool, which is installed on all laptops will continually backup changes in the user's folder to a central server. It runs in the background, is relatively unobtrusive and flexible enough that you can select sub-directories that you don't want to have backed up. However, it sometimes require your attention and will pop up a message. I was faced with this one yesterday:

Error message saying: Part-complete actions have been found due to an interruption during last sync. Click OK to complete there actions before scanning. Click Cancel to continue with the scan and ignore the part-completed actions

Contrary to the previous example, this message is in plain English and I can understand every word of it. However, it is worded in such a generic way that I have no idea whether I should click OK or Cancel. I don't know what part-completed actions it refers to and therefore don't know whether those actions should be completed or not. I suspect that they should because the default button is the OK one but I can't be sure. Also note that the word scan is misleading: it only makes sense to me because I have a fair idea of how the backup tool works but it could make the user think this is a message from the anti-virus system.

So, what could be done to make it more useful? First, the message should identify what application triggered it. It is important in this case because it is triggered by a background process and is completely unrelated to what the user was doing at the time. Then the obvious thing to do would be to detail what actions are pending and require attention. However, this may not be enough. If the actions' descriptions are too cryptic, that won't help the user make a decision. So the message should also ensure that the descriptions for the pending actions are clear and concise.

Conclusion

Usability is good but it should also go hand in hand with error handling. So next time you design a piece of software, make sure all the error messages that can potentially be displayed to the user are clear and include enough information, especially if the user is expected to take a decision based on the message. If the message is triggered by an unexpected error, consider giving the user a way to report the error so that you can correct the bug in a subsequent version.

Sunday 1 February 2009

Offline Gmail with Gears

Google have just made Gmail available offline as a lab feature. It relies on another Google technology called Gears that theoretically enables any web application to also work locally without an internet connection. This can be very useful when using a dodgy connection or not having one at all. Gmail will then synchronise automatically when it can reach the servers again. I just enabled the feature and downloaded Gears on my Linux laptop to give it a whirl. I will install it on my Mac OS-X desktop later to see how the two platforms compare.

As it is still experimental, it is currently only available for some English US and English UK users. So if you don't have it available yet, be patient, it will come your way soon.

Canon and Linux, part 4

For the background to this post, see part 1, part 2 and part 3.

Having had no news from Canon for nearly a month, I was about to send them another message when I received the following email from their helpdesk:

Recently you placed a Support Request with Canon Support Centre.

To ensure you received the best possible service we would like to confirm that your request has been handled satisfactorily before it is closed. A description of your request follows:

Please use the following URL to confirm whether your service request is complete or still needs to be addressed: some long URL

YOU HAVE FIVE (5) DAYS IN WHICH TO RESPOND. IF THERE IS NO RESPONSE, YOUR REQUEST WILL AUTOMATICALLY BE CLOSED BY THE SYSTEM.

So I went to the URL provided and responded by saying that I had not had a reply at all and that my request was still open. I then received the following email the very next day:

Please find attached that latest firmware version for your EOS 5D (Version 1.1.1).

As requested I am sending it to you in a ZIP file as the EXE download is not suitable for your Linux operating system.

Please go to the following link where you can find instructions on how to upload the firmware to your camera.

http://web.canon.jp/imaging/eos5d/eos5d_firmware-e.html

Please take careful note to the End Users Licence agreement at the bottom of the page.

Also I would like to state that you have decided to take full responsibility for the installation of the firmware, and we have sent the firmware in this format knowing that you agreed to our conditions.

At last, I had a version of the firmware that I could unpack on Linux! It was then just a matter of following the instructions:

  1. Unpack the zip file and extract the .fir file that it contains;
  2. Format a memory card in the camera;
  3. Move the .fir file to the top directory of the newly formatted memory card;
  4. Insert the memory card back into the camera and upgrade the firmware.

All went without a hitch. Considering that the only reason a computer is needed in order to upgrade the firmware is to copy the .fir file to the memory card unmodified, Canon has no real software to write: any computer that can write to the memory card can do that. Therefore, I fail to see why Canon insist on providing versions of their firmware that can only be unpacked on Windows or Mac OS-X and why they go through such an effort to explicitly shift the responsibility of the upgrade to me because I use Linux. Well I suppose the reason they do this is to limit the number of variations they have to support in testing firmware upgrades. But surely, there is a better way to distribute firmware that would not require me to explicitly contact customer support for it.