How Argulator presents statements

August 19th, 2009

Even before you get around to creating any arguments there is the problem of how to display a complex network of statements in a user-friendly way. Part of the trouble here is that in general there may be a lot of statements in play at any given time, and a lot of different relationships between different statements. How do we present these relationships in a way that makes intuitive sense? And how can you be sure that the statement you're looking it is the one you think it is?

Programmers deal with structured information like this all the time. They have two major techniques for doing so - one is using nested sets of parentheses (or other brackets) and the other is naming some substructure and then using that name elsewhere. Both of these techniques are rather unintuitive to non-programmers and require some thought to use - if you're using brackets you have the problem of mismatching them, and with naming you have the problem of "okay, so c is a+b, where is c defined again?"

My "aha" moment was coming across the inline-block display style in HTML. This clever device allows one to have a piece of HTML which acts like an inline element from the outside and block from the inside. This means that 2 such blocks can be composed in (at least) 2 different ways: side-by-side and one-inside-the-other, and the web browser does the hard work of figuring out where to put each block and how big to make it. These relationships can be composed arbitrarily, and the blocks scale very well from tiny (just enough to hold a single identifying number) to so large you have to scroll the web page to see the entire contents. The only downside is that they don't work properly in FireFox 2 - I think this is now sufficiently rare to not be worth bothering with, but there may be a hack to get inline-block working in this browsers if there is demand.

So a rectangular block with a thin raised border became my "UI cue" that says "hey, this is a statement - you can go and give your opinion about this or argue for/against it". The block's border also acts as a set of parentheses of a sort - containing everything within it. An argument block, for example, encapsulates subblocks showing the argument it is arguing for or against and the substatements that make up the argument - these statements appear right there in the block rather than being incorporated by reference (avoiding naming problems) and the parentheses are automatic, implicit and intuitive.

The next problem is making the statements visually distinctive, so you can see at a glance which statements are which, while keeping them similar enough that anyone can see that they're all variations on the same basic object. There are several ways this is done. The most obvious is the background/border colour. Most statements have a white background and a grey border, but "special" statements (those that have some meaning to Argulator itself) are coloured - green for "for" arguments, red for "against" arguments and blue for deletion statements. This colour scheme reflects a colour scheme that can be found throughout Argulator: red also means "disagree" and "refuted", green also means "agree" and "corroborated" and blue also means "neither agree nor disagree". Colour vision is not a requirement for being able to use Argulator, but the extra visual clues in the colours should be helpful for those who can see them.

Since becoming a professional software engineer, one thing I have become very familiar with is bug databases. Bug databases are great because every bug is given a unique number, and if one wants to refer to a particular bug, one can just refer to it by its number. The person you're communicating with might have to look the bug up in the database, but it's still much more concise and accurate to say "bug 123456" than "that crashing bug Bob found last week". One often gets to know the numbers of the bugs that are currently important (like the phone numbers of close friends) - when this happens, one doesn't even need to look in the bug database to see which bug is being referred to. However, as an aide memoire when I'm writing an email about a bug I always try to remember to paste in the title as well as the bug number.

Argulator has a similar principle - every statement block has a number inside it, towards its left-hand side (or top-left corner if it spans multiple lines). This number uniquely identifies the statement. If you know a statement's number N you can visit its page just by typing the URL: http://argulator.com/statement/N, refer to it in a statement you're creating by typing {N} or use it in an argument by using its number as the substatement text. You can also negate a statement's meaning by negating its number, so anywhere you can use a statement you can also use the negation of that statement.

In a statement's block, the number serves two other purposes as well as uniquely identifying which statement you're looking at:

  1. The colour that is used to render the number gives a quick indication of the "average" opinion that people have expressed on that statement. As well as red, green and blue mentioned above, the colours can combine - red and green combine to form yellow meaning "polarizing", green and blue combine to form cyan meaning "uncontroversial" and red and blue combine to form magneta meaning "unpopular". Other hues and saturations represent different proportions of "agree", "disagree" and "neither agree nor disagree" opinions. Lighter colours mean more opinions, darker colours mean fewer. This is another visual hint that the statement is the one you're looking at.
  2. The number itself is a link that takes you to the statement's page, where you can see much more information about it, express your opinion on it and argue for or against it.

There are several other mnemonic cues next in a statement's block next to the statement's number - a coloured dot showing your opinion, an eye icon if it's a statement you're watching, and a red R or a green C to show if it's been refuted or corroborated. Together, these cues are a dense source of information about a statement but their deeper purpose is give each statement a unique visual "personality" richer than just its statement number alone. I hope that these cues will make it easy to tell at a glance that a given statement is the one think it is, even if you don't remember the number exactly.

There is one more aspect of statement block display, which is expanding and collapsing. Each statement block has a small black triangle in it after the number. The triangle points left if the statement is expanded (and its text is visible) and right if it is collapsed to just the number and icons. Clicking on this triangle toggles between the two states. This allows you to see the big picture at a glance (when statements are collapsed) or drill down to see the details if you want to. This bears some similarities to the "zooming user interface", another concept from "The Humane Interface".

Argulator's user interface

August 18th, 2009

One of the key problems I identified when first planning Argulator was how to make an interface which was sufficiently easy to use given the fundamental complexity of the tasks involved in manipulating a complex network of statements. In particular, UI for creating an argument was a big sticking point. An argument has several parts (at least one but as many as you like) each of which is a statement. When creating an argument, you're actually creating a pile of statements at once. However, some of those statements may already exist (once Argulator's database is sufficiently well-populated, I expect most arguments will recycle at least one statement). However, chances are that they use slightly different phrasing or spelling, so just checking for identical text is a bit of a non-starter. And if the database gets full of nearly-duplicate statements, Argulating will get very annoying - one would end up refuting the same thing 20 different times with slightly different phrasing each time.

To minimize duplicates, I realized that I wanted to force users to search for existing statements before creating a new one. This means doing some things on the server for each statement. If I used classic CGI this would be quite an annoying, unresponsive user experience:

  • Type in statement. Click to search. Wait for page to reload.
  • Click on search result to go back to argument creator. Wait for page to reload.
  • Once all statements are in place, click to create the argument. Wait for page to reload.

I almost implemented this but I thought the site would suffer greatly from being so clunky. On the other hand, I didn't want to make it a desktop application either as that would make it that much more difficult for people to try out.

The answer came in the form of AJAX. This was just starting to take off, but it was a while before it seemed to be something practical for mere mortals like me to implement, rather than deep magic that could only be done in something as complex as Outlook Web Access or Google Maps. Once I realized I could implement an AJAX application myself, things started to pick up. The sequence would be the same but with no page reloads the user experience would be much smoother and more intuitive.

Having decided to use AJAX (and make it a requirement for using the site) it made sense to AJAXify everything in sight - page reloads hardly ever happen in Argulator (except when you go to a different URL like the page for a different statement, user or definition). The main manipulations (setting an opinion, creating an argument, and creating a deletion statement) all happen in-page. Even logging in and out doesn't cause a reload. Whenever I thought of a way to use Javascript to make the interface more interactive, I did so. I think and hope the resulting interface is a pleasure to use. Whatever you're trying to achieve with the site, the next step should always be obvious - please let me know if it isn't.

One other UI principle I've tried to stick with is one from Jef Raskin's book "The Humane Interface" - there are no "are you sure" confirmation dialogs in Argulator, and just about every action is easy to undo (even deleting one's account can be undone for a year).

Introducing Argulator

August 17th, 2009

A while back I wrote about an idea I had for a website which allows arguing over the internet.

Well, it's taken almost 4 years but it's finally alive! The site is at http://argulator.com. It's a little different from how I originally envisioned it in some ways (having evolved somewhat over the years) but has many of the features I originally described.

Over the next week I'll be posting a series of articles about the development of the site.

Why is TV static in black and white?

August 16th, 2009

Have you ever looked at the static that appears on a TV screen when it isn't tuned into anything? If so, you might have noticed that it's in black and white. That fact always used to puzzle me - the patterns are random so surely all the colours that can appear on the TV should be equally likely, right?

It wasn't until fairly recently that I learned why this is. Colour TV signals are a little bit different than black-and-white TV signals - a certain frequency band within the signal is used to transmit colour information. That band corresponds to high frequency horizontal detail (patterns about 1/200th of the width of the screen). In a colour TV signal, those details are elided and the information used to carry hue and saturation information instead.

However, if you're watching a black and white programme you can get a sharper picture by using those frequencies for horizontal detail. So colour TV sets were designed to have two "modes" - colour mode and black-and-white mode. A "colour burst" signal is broadcast in an otherwise unused part of the signal which has the dual purposes of signalling that colour information is available, and calibrating the correct hue phase offset (the "colour burst" signal, if it were on screen and within gamut, would be a very dark olive green colour). This signal has to be present for about half a field before the TV will switch to colour mode. This is an imperceptably short time but stops the TV flickering in and out of colour mode if the signal is marginal.

Having a signal of the correct frequency at the correct time for that period of time is extremely unlikely to occur by chance (and even if it did, it would disappear again before you had the chance to notice it). So when the TV is showing static, it thinks it's showing an old black-and-white movie and turns off the colour interpretation circuitry, leading to black-and-white static.

3D circuit ball

August 15th, 2009

I'm sure this has been done before, but I can't seem to find any examples. I think it would be cool to make an electronic circuit with no PCB, breadboard, wire-wrapping board or anything like that just by soldering together the legs of components in 3D space, causing it to form a ball or tangle - a piece of functional art.

Edit 9th July 2010: Made one!

Here is the schematic.

Edit 14th July 2013:

Now this is is what I'm talking about!

Improved geohashing algorithm

August 14th, 2009

Geohashing is an awesome idea (though I've never actually gone to any of the hash points). However, it does suffer from some problems - often the chosen location will be too far away, or in an inaccessible area. It is also slightly biased towards the poles (though because few people live in the polar regions this isn't a particularly big deal for most people). It would be nice to have an improved algorithm which solves these problems.

We'll start the same way, by hashing the date and that date's DOW opening to get a set of 128 random bits R.

Given any area A we want to find a function (which we'll call f(A)) mapping a set of bits R onto a point x, (f(A))(R) = x. We would also like to have the property that if B is a subset of A containing x and if (f(A))(R) = x then (f(B))(R) = x. So if the New York State meetup happened to be in New York City, all the people who were just going to the New York City meetup would be there too. Another desirable property would be if the points (f(A))(R) were evenly spread throughout A.

Here is an algorithm that I think fulfills both properties.

First, use R to pick a random point on the globe, taking 64-bit random floating point fractions u and v in [0,1) from R in the usual way and then transforming them into longitude and latitude as:
\displaystyle long = 360frac(u+a(N))-180
\displaystyle lat = \frac{180}{\pi}cos^{-1}(2frac(v+b(N))-1)
Where frac takes the fractional part, leaving a number between 0 and 1 (one could also use XOR instead of add and frac) and N is the smallest integer > 0 that causes the resulting coordinates to end up inside A.

a and b are functions that find points that are furthest away from any tried so far. They have binary expansions as follows:

N  a(N)  b(N)  c(N)     d(N)
0  0.000 0.000 0.000000 0.000000
1  0.100 0.100 0.110000 0.100000
2  0.100 0.000 0.010000 0.010000
3  0.000 0.100 0.100000 0.110000
4  0.010 0.010 0.001100 0.001000
5  0.110 0.110 0.111100 0.101000
6  0.110 0.010 0.011100 0.011000
7  0.010 0.110 0.101100 0.111000
8  0.010 0.000 0.000100 0.000100
9  0.110 0.100 0.110100 0.100100
10 0.110 0.000 0.010100 0.010100
11 0.010 0.100 0.100100 0.110100
12 0.000 0.010 0.001000 0.001100
13 0.100 0.110 0.111000 0.101100
14 0.100 0.010 0.011000 0.011100
15 0.000 0.110 0.101000 0.111100
16 0.001 0.001 0.000011 0.000010

And so on, to as many binary places as you need. If you interleave the bits of a(N) and b(N) you get c(N), which looks like d(N) but with each even bit XORed with the bit to its left. d(N) is the binary expansion of the integers but with the bits in the reverse order (and flipped to the other side of the binary point).

The sequences a and b together are related to the Bayer matrix which describe a 2D ordered dither. If you want 65 shades of grey but only have a grid of 8x8 pixels, each of which can only be black or white, the most regular patterns with n black bits are described by those that have 8a(N) and 8b(N) black if N

Component pattern

August 13th, 2009

Sometimes, your object hierarchy is determined by the kinds of data you're throwing around - if you have a pile of pieces of information about each customer in a database, it's obvious that you should have a Customer object. But if this is the only rule you use for deciding when to make a class, you'll often end up with enormous classes. This tends to happen for the object representing the program itself. A program tends to have a lot of things that there are only one of, and if you stick all these things in one big object then its unwieldy.

So you break up your Singleton object into components. You can do this in whatever way makes most logical sense for your program - perhaps a set of routines and data for allocating memory go in one object, and a set of routines and data for dealing with the program's main window go in another. Then you need a master object responsible for wiring all these components together. The construction of this object may be somewhat non-trivial:

In the master constructor, each of the components is constructed. However, we don't tell the components about the master yet because it's constructor is incomplete.

Once the constructor is complete, we need to loop through all the components again and "site them" (give them a pointer to the master that they can use to obtain pointers to other components they need).

Depending on how complex the interdependencies between components are, more initialization steps may be needed. The order of the components may also make a difference.

This doesn't have to be used for just the singleton - any sufficiently complex object can benefit from being broken up this way.

I looked for this pattern in the literature but didn't see it anywhere. However, it seems to be a reasonably common thing to do so I'm recording it here.

The programmer cooperative

August 12th, 2009

If I suddenly found myself with lots of money to spare, one thing I'd like to do is hire some talented programmers to work on whatever they wanted to work on. I suspect that there are lots of talented programmers out there who have ambitious projects they'd like to take on but which they just don't have time for because they have full time jobs. Most of those projects probably have no commercial application, but it's very difficult to tell in advance what is likely to make money and what isn't. If you get enough of these projects together, at least some of them are bound to make money.

Any profits made could be shared with the entire cooperative, or used to hire more programmers. Sort of like a business and employment cooperative except for programmers rather than entrepreneurs. Ideally once it got big enough it would become self-sustaining and then undergo exponential growth. Part of the nature of software is that it requires very little capital investment (really just the programmers' salary). Another part is that because it can be copied indefinitely and exhibit network effects, once a piece of software is written it can have great influence and importance. So a successful software project can make much more money than it costs, and one only needs a small percentage of projects to be financially successful in order to sustain the entire system.

I imagine that a very large number of programmers would like to join such a cooperative - what could be better than getting paid and not having anyone tell you what to work on? So one would need some method for choosing between a very large number of applications. Let's suppose for a moment we have some infallible way of weeding out people who, given the choice, would rather go skiing or watch TV all day than write computer programs of any sort. Suppose also we have a way of weeding out those programmers who are actually working on something for someone else and want to get paid for it twice.

One way to choose amongst the remainder would be for them each to submit a few ideas of some things they would like to work on, and how much they want to be paid. The cooperative would then pick those ideas that have the most "bang per buck" (i.e. are most interesting, not too expensive and have some chance of commercial success). The member might change their mind about what they work on, but the initial idea would give some idea about what sort of things they're interested in.

Every few months, each member would give a demo of what they've been working on to the rest of the company. Or, alternatively, make regular blog posts about their progress. This gives some cross-pollination of ideas, and may lead to collaborations within the cooperative. Such collaborations can be very flexible and informal, ending as soon as they stop being fun for any of the parties involved.

CGA Hydra

August 11th, 2009

A while ago, Trixter challenged me to figure out if it was possible for a CGA card with both composite and RGB monitors attached to it to display a different image on each display. At first I thought this was impossible because the composite output is just a transformation of the RGB output - the RGB output contains all the information that the composite output contains.

But that reasoning only works if you're close up. If you stand back sufficiently far from the screens, adjacent pixels will blur into each other so this is no longer necessarily true. Suppose we have a pattern that repeats every 4 high-resolution pixels (or half an 80-column character, or 1/160th of the screen width, or one colour carrier cycle) and we stand sufficiently far back that this looks like a solid colour. On the RGB monitor this will just be an average of the 4 colours making up the pattern. So, for example, black-black-white-black and white-black-black-black will look the same on the RGB monitor, but they will look different on the composite monitor because these two patterns have different phases with respect to the color carrier, so they will have different hues.

That explains how we can get details on the composite monitor but not on the RGB monitor, but what about the other way around? This is a bit more complicated, because it requires knowing some more details about how the CGA generates (non-artifact) colour on the composite output. For each of the 8 basic colours (black, blue, green, cyan, red, magenta, yellow and white) there is a different waveform generated on the card. The waveform for the current beam colour is sent to the composite output. The waveforms for black and white are just constant high and low pulses, but the waveforms for the 6 saturated colours are all square waves of the colour carrier frequency at different phases. The green and magenta lines switch between high and low on pixel boundaries, the other 4 at half-pixel boundaries (determined by the colour adjust trimpot on the motherboard).

What this means is that if you're displaying a green and black or magenta and black image, the pixels are essentially ANDed with this square wave. The pixels corresponding to the low parts of these waves have no effect on the composite output. So you can use these pixels to make the image on the RGB monitor lighter or darker whilst having no effect on the composite image.

Here's what the finished result is supposed to look like (with another image on an MDA display as well):

Note that I've allowed the composite image to show through on the RGB monitor a little in order to improve contrast.

Floating point is not evil

August 10th, 2009

In response to this:

Floating point is not evil and it is deterministic, but you need to know what the values you're working with actually are. Basically, floating point is like scientific notation, except with 2s instead of 10s. In other words, instead storing numbers like 1.234*104 it stores numbers like 1.00110100102*210. It's actually stored as a pair of numbers, a mantissa and an exponent. The number of bits in the mantissa is fixed (it's 23 bits for single precision and 52 for double) and the leading "1" is implied. Each number representable as an IEEE floating point constant has exactly one representation except for zero (+0 and -0 have different bit patterns for complicated reasons). There are complications (denormals, NaNs and infinities) which can usually be ignored and which I won't go into.

Floating point numbers are handy for lots of purposes but they do have a couple of problems.

The first problem is that floating point numbers are inefficient. They are very quick with today's hardware but consider what you'd do if neither floating point hardware nor floating point libraries were available. For most applications, you'd use fixed point numbers - you'd store an integer and it would be implied by the type of number you're working with that the actual numeric value is obtained by dividing this integer value by 2n for some n. For most purposes you probably wouldn't store that n with each integer - all your numbers have the same number of significant digits. For example, if you're writing a graphics program you might decide that units of 1/256 of a pixel width are always enough, so n would always be -8. When writing floating-point programs, most programmers don't do this calculation to figure out what the precision needs to be, they just use single precision floating point or switch to double if that isn't precise enough. While constant precision is preferable for a general purpose calculator, most actual applications are better served by constant resolution.

The other problem is that sooner or later you'll run out of precision. If you're plotting Mandelbrot sets, sooner or later you'll zoom in far enough that adjacent pixels have complex numbers with the same floating-point representation. If you're using FFTs to multiply big integers, sooner or later you'll want to multiply integers so large that floating-point numbers won't have sufficient precision. If you're using hardware floating point, this is quite difficult to solve (you need to find or write a big-float library) and will cause a big speed hit, so most people will give up at that point. However, if you're already using fixed point bignums, it's just a question of adding another digit.