How to find out is something is good or bad

June 7th, 2008

When I want to know if something is good or bad, I often find that the fastest way is to look for the bad things that people have said about it. If the only bad things about it are obscure, contrived or ill-reasoned I know that it's likely the thing itself is good. If there are convincing arguments that something is bad, it probably is.

I suppose looking for the good things that people have said about it could be done in a similar way, but looking for the bad things seems to work better in my experience.

Complex analysis and Clifford algebra

June 6th, 2008

Complex analysis is a very beautiful and useful mathematical theory. Clifford (geometric) algebra is also very beautiful and useful. So it makes sense to wonder if they can be combined. Turns out that they can. I wonder why I haven't seen more stuff about this in the wild? Probably because it's pretty new as mathematics goes. I expect it will be part of every undergradaute mathematics degree in 50 years or so. But I suppose it depends if it turns out to be as useful as it seems, by rights, it ought to be.

Extending "The Elements"

June 5th, 2008

Tom Lehrer's terrific song The Elements is unfortunately lacking in one respect - it is outdated as it does not include the elements discovered/named since the song was written.

Here is one attempt at bringing it up to date but I don't think just adding an extra verse fits well with the rest of the song. I wonder if it is possible to fit in the extra elements but keep the list format, perhaps at the expense of (part of) the last two lines. There is also some flexibility about where to put the "and"s - Lehrer doesn't use them consistently and even throws in an "also" in one place.

Rendering rings of teleportation

June 4th, 2008

Rings of teleportation are very handy things to have around. The surface bounded by one ring is equated with the surface bounded by the other, so if you put something through one ring it will come out through the other. (Like the portals in "Portal", but more portable). They don't exist, of course, but this technicality doesn't prevent us from drawing pictures of them.

Writing code to render these things is an interesting exercise. It's easy to do with a ray tracer - if a ray intersects the disc inside one ring, just continue it to the equivalent point on the other ring.

Once that's working, you can put the rings side-by-side so that light goes around in circles - if you put your eye point in the middle you can see an infinite tunnel.

A trick you can play is to reverse the orientation of one of the rings so that you look through one ring, out of the other to an object, the object will appear to you to be inverted, as in a mirror image.

Another trick is to make the rings different sizes, or shapes. As long as there is a 1:1 function equating points on one surface with points on the other, it works fine.

However, having rings of different sizes or non-circular shapes opens the possibility of putting one ring through the other. What happens then? It seems like the "infinite tunnel" then becomes a real thing rather than just an optical effect, but where does the second ring exist in real space? It seems that the only place it can appear is through the other side of the first ring, but that would mean that every point in space appears in an infinite number of places - this seems like it would have rather drastic consequences.

So it seems more likely that the second ring would be prevented from going through the first somehow (perhaps a ring edge would get in the way).

What I want from an HDR workflow

June 3rd, 2008

Once I've got my HDR camera and my HDR monitor, I'll need new photographic workflow applications to get the images looking the way I want them. I expect that there will be a few parameters that I'll almost always want to tweak, much as I almost always re-crop my photos at the moment. These parameters are likely to be:

  • Colour balance (2D slider)
  • Exposure (slider)
  • Dynamic range compression (slider)
  • Tone mapping radius (slider)

The last two of these reproduce the functionality of current HDR applications, allowing creation of tone-mapped images for non-HDR output (like printing, or legacy monitors).

The high dynamic range revolution

June 2nd, 2008

Currently some people are making beautiful HDR images like these. This takes an input image with a high dynamic range (often composed of multiple exposures with different exposure times to get good colour resolution over a wide range of brightnesses) and "compresses" the range down to monitor or printout ranges. This can give an effect similar to an oil painting (painters use similar techniques).

But such techniques will soon become unnecessary as the dynamic range that monitors can display increases. As I've mentioned before I've seen this technology in action and it's seriously impressive - the pictures are incredibly realistic, like looking out of a window. As these monitors drop in price they will become ubiquitous and then we will want to take pictures that take full advantage of them.

Shooting RAW with a good digital SLR goes some way towards this, but I think that with the new generation of monitors will come a new generation of cameras optimized for taking HDR images. This might be as simple as reading the sensor several times over the course of the exposure, or it might be a completely new sensor design.

With new monitors and new cameras, the entire graphics pipeline will be re-engineered for HDR.

Photographic workflow

June 1st, 2008

The workflow that I use for the photographs on my website has remained pretty much unchanged for many years.

  1. Copy the photos from the card to the computer and then delete them from the card.
  2. Open the folder of photos in ACDSee and delete any obvious duds.
  3. Open all the photos in Paint Shop Pro 4 (yes, I know it's ancient but it works well, I know my way around all the tools and it's fast).
  4. I look for similar photos and close the ones that are redundant or unattractive, eventually whittling it down to the set of photos that will form a nice album page.
  5. I rotate (sometimes by arbitrary angles) and crop. Sometimes I'll adjust brightness and/or contrast to save a poor photo if there's something in particular that I want to have a picture of. Sometimes I'll use a more sophistical program like Photoshop to remove redeye or do other colour manipulations.
  6. Very occasionally I will use the clone tool to erase something that I don't want in the photo.
  7. I'll resample the photos to the appropriate size and save them as jpgs.
  8. Finally I'll manipulate the directory listing in a text editor to create the html file, add captions and upload the lot.

Someday I'll trade in my trusty Olympus C3000Z and get a nice digital SLR. But I might wait a few years because the high dynamic range revolution is coming. More about that tomorrow.

Compile-time symbolic computations

May 31st, 2008

A compiler ought to be able to perform compuations at compile time. Unlike the generated code, these computations don't have to be blazingly fast (since they only happen at compile time), and don't have to conform to any particular machine's architecture (since the language should be the same for different architectures anyway) so some nice things can be done.

Arbirary-precision integer arithmetic is a nice easy one and one that is done by many scripting languages already. This allows you to write expressions such as:

const int a = 1000000000000/1000;

and have a initialized to one billion even on 32-bit machines.

Rational arithmetic is also easy and useful. This allows one to write:

const int a = (1000/3)*3;

and have a initialized to exactly 1000 even on machines lacking any sort of floating point facility.

Then there are closed forms such as:

const int a = sqrt(1000)^2;  // a==1000, not 961

One could even make a compiler understand pi as a symbolic constant of type "Real" and evaluate it to the appropriate number of significant figures for the expression and type that is being initialized. So:

const int a = truncate_cast<int>(pi*10000);

would initialize a to 31416.

Once these things are in place, a compiler can perform quite sophisticated mathematical transformations to allow programmers to write what they really mean and still obtain optimal code. Even to the level of Maple/Mathematica if the compiler writers are sophisticated enough.

Compile time metalanguages

May 30th, 2008

The C programming language actually contains two different languages - C itself (the code for which runs at run-time) and the preprocessor language which runs at compile time and has completely different syntax. It's also not very powerful - often programmers resort to writing programs which generate C code as output instead.

It would be really nice to be able to make both these approaches unnecesary, and have a compile time language that uses the same syntax as the run-time language. A compiler ought to be able to detect parts of the program which run on constant data, run them during compilation and emit the output directly into the generated binary.

Replacing #ifdefs is easy - just use the normal "if" and ensure that your compiler will optimize away false clauses for constant expressions. GCC does this and indeed the GNU coding standards recommend this.

Replacing code that performs complex transformations on data is more complicated, but not intractably so as long as the compiler can reliably determine that all the functions used in these transformations are pure.

Lexical scoping and closures

May 29th, 2008

A closure is a just a piece of code with some context - data on which it works. Such things are common in the functional programming community but were left out of the C language because they're actually quite difficult to implement properly.

The C++ language has sufficiently powerful constructs that one can create closures, but the syntax is very unwieldy. One must write:

class Totalizer
{
    int _total;
public:
    Totalizer() : _total(0) { }
    void operator(int x) { _total += x; }
    int total() const { return _total; }
};
 
int total(Vector<int> x)
{
    Totalizer t;
    for_each(x.begin(), x.end(), t);
    return t.total();
}

where one would really like to write something like:

int total(Vector<int> x)
{
    int t;
    for_each (x, lambda(int y) {t += y;} );
    return t;
}

Here the code is the "{t += y;}" bit and the context is the "t" variable, which is local to the "total" function.

C# 3.0 provides functionality like this.

What's really going on here is that an object is being created which encapulates some subset of the local variables (the "t" variable in this case) and which is passed to the for_each function (just like in the C++ version). Closures and objects are really just different syntaxes for the same thing.

If we want to return a closure from a function we can do so, but we must then allocate the object in such a way that the "t" variable will still be valid when the function exits. This is where things get really fiddly. This is one of those things that is easier in a language with garbage collection (you can just allocate the closure on the heap and the GC will take care of cleaning it up when it's finished with) but with care I think it should be possible to do it in a non-GC language as well.