Jun 15

Although languages like APL, Prolog and COBOL might seem unusual to many of today’s programmers, they are serious languages developed to address a specific requirement or a particular model of programming. We’re looking here at those languages that have been designed, first and foremost, to be odd. Referred to as esoteric programming languages, some are intended as jokes, some as parodies of other languages, whereas others were designed to be downright strange.

Esoteric programming languages: is there room in your brain for these nutty devices?

Bizarre or not, though, all of them truly are programming languages in the sense that they really can be used to provide instructions to your PC. Our intention here isn’t to show you a lot about any one language – after all, you’re not exactly going to be using them for genuine programming projects – but to look at three of then, fairly briefly, to give you a feel for the variety of esoteric languages.

INTERCAL

The names of programming languages are often acronyms that give some clue as to their purpose. So BASIC is Beginners All-purpose Symbolic Instruction Code, COBOL is COmmon Business Oriented Language and FORTRAN is FORmula TRANslation. So you start to get a feel for INTERCAL when you read in the manual (which you can find at www.muppetlabs.com/~breadbox/intercal/intercal.txt) that its full name is “Compiler Language With No Pronounceable Acronym, which is, for obvious reasons, abbreviated INTERCAL”. It was designed with the aim of being as obtuse as humanly possible, mainly so you that you can amaze your fellow programmers by your ability to do something useful in this bizarrely complicated language which was designed specifically to have nothing at all in common with any other major language.

Ironically, since our stated aim is to show you how to program in esoteric languages, we’ve not even going to try with INTERCAL. Instead we’ll show you how to use the INTERCAL-J compiler using a sample program provided and then we’ll leave you to peruse the manual. We suggest you do this in a darkened room and clear a week or two from your diary before you start. If you consider this a dereliction of our duties, take a look at the INTERCAL program below, which has been provided to illustrate how fiendishly involved even a simple program can be. Its purpose is to read in 32-bit unsigned integers, treat them as signed, 2s-complement numbers, and print out their absolute values, terminating if the absolute value is zero. A comparable APL program runs to 16 characters.

DO (5) NEXT
(5) DO FORGET #1
PLEASE WRITE IN :1
DO .1 <- 'V":1~'#32768$#0'"$#1'~#3
DO (1) NEXT
DO :1 <- "'V":1~'#65535$#0'"$#65535'
~'#0$#65535'"$"'V":1~'#0$#65535'"
$#65535'~'#0$#65535'"
DO :2 <- #1
PLEASE DO (4) NEXT
(4) DO FORGET #1
DO .1 <- "'V":1~'#65535$#0'"$":2~'#65535
$#0'"'~'#0$#65535'"$"'V":1~'#0
$#65535'"$":2~'#65535$#0'"'~'#0$#65535'"
DO (1) NEXT
DO :2 <- ":2~'#0$#65535'"
$"'":2~'#65535$#0'"$#0'~'#32767$#1'"
DO (4) NEXT
(2) DO RESUME .1
(1) PLEASE DO (2) NEXT
PLEASE FORGET #1
DO READ OUT :1
PLEASE DO .1 <- 'V"':1~:1'~#1"$#1'~#3
DO (3) NEXT
PLEASE DO (5) NEXT
(3) DO (2) NEXT
PLEASE GIVE UP

So to business and in particular we’re going to compile and run a program that prints out prime numbers. J-INTERCAL runs from the command prompt so Select Run… from the Windows Start menu, enter ‘cmd’ into the Open box in the Run window before clicking on OK. Then, at the prompt in the command line window, type ‘cd c:\jintercal-0.12\samples\’ and you’ll notice that the prompt will change to reflect the new default directory which is, in fact, the one where you’ll find an INTERCAL source file called primes.i. To compile it, type ‘Java intercal.Compile primes.i’, noting the capital C in ‘Compile’. All being well it will create the Java class file primes.class that you’ll be able to see if you type ‘dir’ at the prompt to list all the files in the folder. Now to run it, type ‘Java primes’ and you’ll see prime numbers flash down the screen expressed as Roman numerals which is INTERCAL’s standard form of output.

Brainfuck

INTERCAL programs are long and convoluted, aided and abetted, to no small degree, by the requirement to write polite programs with sufficient PLEASE statements included. Not so with the inappropriately sweary Brainfuck. Its programs couldn’t be more different. The aim was to implement a language with the smallest possible compiler – the compiler we’re using is just over 2Kbytes in length (yes, Kbytes, not Mbytes) and the record is somewhat less than 200 bytes. This required simplicity and despite the fact BF is Turning complete, meaning that it can perform any computation that “serious” languages can perform, it has just eight instructions, each of which is represented by a single character. That doesn’t make for the most readable program – so again you’ll reach guru status if you can master it – but it does mean that we can teach you the language in its entirety.

There is no concept of named variables, as there is in most languages. Instead BF has a string of 8-bit memory locations and a pointer that records which of those locations the current instruction will operate on. Initially all the locations contain zero and the pointer is initialized to the left-most location. With that bit of background we can now introduce the eight instructions, which are:

+    Increment the value at the pointer
-    Decrement the value at the pointer
>    Move the pointer to the right
<    Move the pointer to the left
[    Start of loop
]    End of loop (exit if value at pointer is zero)
,    Input an ASCII character and store it at the pointer
.    Print the ASCII character at the pointer

Of course a simple instruction set invariably means a complicated program so the simplest of operations, that might be achievable in a single instruction of a conventional language, can take dozens of instructions in BF. As an example we’re going to create a program that accepts two single digit numbers as its input and outputs their sum. The program to do this is as follows and, despite the fact it has 30 instructions, it still only works correctly if the answer is represented by a single decimal digit:

, > + + + + + + [ < - - - > - ] , [ < + > - ] < .

Your first job is to create a file containing the code showed above using Notepad. Since the space character isn’t a valid instruction it’s ignored and although we put a space between each character to make the code easier to read, you can leave them out. Note also that the full-stop at the end is part of the program. Call the file add.b and place it in the c:\bfd100 folder. Actually Notepad will try to give the file the name “add.b.txt” so you’ll have to rename it in Windows Explorer.

Now start up the command line window and change the directory to c:\bfd100\ – if you’re not familiar with command line prompts we did something very similar when we started to use INTERCAL. At the prompt type ‘bfd add.b’. BF will respond with the message ‘File assembled’, and if you do a directory listing you’ll see that the file add.com has indeed been created. This is a DOS executable file so all you have to do to execute it is to type ‘add’ at the prompt. Now type in your two one-figure numbers (with no space or punctuation between them) and the program will display their sum, immediately after the input, again without a separating space.

Now a slight aside. To be quite honest, of the three languages here, BF is the only one that you might want to delve into. After all, it’s quite an interesting language in its own way, in contrast to the others which are, quite frankly, plain dumb, and that’s being charitable. So to start you on your voyage of discovery, let’s see how the simple program above manages to add together two numbers.

The comma reads the first of the two figures and places it where the pointer is positioned which is, initially, in the left most memory location. However, the value read is an ASCII character which, for the figures 0 to 9, are the codes 48 to 57 so, to yield the actual number represented, we need to subtract 48. That’s achieved with the rest of the code up to but not including the second comma. It does that by moving the pointer to the right and incrementing that memory location six times so that it contains the value 6 which will then be used as a loop counter. Next it enters a loop that decrements the ASCII code eight times and the loop counter once. Since this loop will execute eight times, and each time it will subtract six from the ASCII code, when it does exit 48 will have been subtracted from the value input. The second comma inputs a second ASCII code which, because of the position of the pointer, will be stored one location to the right of the first value and again this will be used as a loop counter. The second loop causes the first value to be input (now decremented by 48) to be incremented as many times as the value of the second ASCII code input. When the loop exits, the value in the left-hand memory location (which is a valid ASCII value for a digit since we only subtracted 48 from one of the input values) is printed out.

BF commands might be terse but that doesn’t mean that programs can’t be made readable. Since all but the eight characters representing instructions are ignored, comments can be placed anywhere, as the following program shows.

===INPUT NUMBER===
+      cont=1
[
-      cont=0
>,
======SUB10======
----------

[      not 10
<+>     cont=1
=====SUB38======
----------
----------
----------
--------

>
=====MUL10======
[>+>+<<-]>>[<<+>>-]< dup

>>>+++++++++
[
<<<
[>+>+<<-]>>[<<+>>-]< dup
[<<+>>-]
>>-
]
<<<[-]<
======RMOVE1====
<
[>+<-]
]
<
]

Java2K

Unlike our previous two languages which were supported by compilers, Java2K is implemented as an Integrated Development Environment (so it’s a bit of a mystery why it’s referred to as DIE for Win32 instead of IDE). But before you get too excited, this doesn’t mean a fancy integrated editor and all the works, it just means that immediately after compiling the code it runs it. To start it just double click on the Java2K.exe icon in the c:\java2k\ folder it’ll open in a command line window and announce its presence with the rather puzzling statement “ELVIS HAS LEFT THE BUILDING AT 0.0.1900 <chair>:”. To see it in action just type the name of one of the sample Java2K programs supplied, say “26”, and you’ll see the output which, in this case, is the letter “F”. Having seen something of the astonishing power of this remarkable language you’ll be eager, no doubt, to try out more of the sample programs. However if, for the moment, you can get over your understandable excitement, we’ll first take a look at Java2K behind the scenes.

Like INTERCAL and most other languages, but unlike BF, Java2K has operators that work on variables. Like BF, Java2K is obscure in the extreme but whereas in the case of BF that was by necessity (i.e. to achieve the goal of producing a tiny compiler), in the case of Java2K it’s by design. First of all, where most languages use decimal numbers, perhaps with the option of binary, octal or hexadecimal, Java2K uses numbers to the base 11 which, as the manual points out, is close enough to decimal. Because base 11 numbers require an additional digit to the usual 0-9, Java2K uses 0-9 plus space. The upshot of this is that since a space will be interpreted as the number ten, spaces can’t be used just to make programs more readable. Second, function names are numbers rather than words, and so too are the names of variables. So you can forget, for example, of using meaningful variable names such as “Total” or sensible instruction names such as “Print”. In the case of this latter instruction Java2K uses the instruction “1 1 “ (note the two spaces, after all this is a base 11 number) instead. And finally, on the subject of obscuration, because numbers are interpreted as functions or variables, you can’t use them as numerical constants. Instead, if you want to refer to the number one, you have to use some function that will produce 1 as its output. The classic way of doing this is to use the code “11 6/*/_\”. If we point out that “11 6” is the divide function, “*” returns a random number, “_” repeats the previous argument, “/” is a separator and “\” is an end-of-instruction marker, it should be clear that this will produce a 1. Surprisingly, then, this statement isn’t quite correct as we’re about to see.

1 1 /125 /131 /119 /125 /11 6/*/_\/_\/125 /13 2
/*/_\/_\\/131 /119 /125 /11 6/*/_\/_\/125 /13 2
/*/_\/_\\/119 /125 /11 6/*/_\/_\/125 /13 2/*/_\
/_\\\\/131 /119 /125 /11 6/*/_\/_\/125 /13 2/*/
_\/_\\/131 /119 /125 /11 6/*/_\/_\/125 /13 2/*/
_\/_\\/131 /119 /125 /11 6/*/_\/_\/125 /13 2/*/
_\/_\\/131 /119 /125 /11 6/*/_\/_\/125 /13 2/*/
_\/_\\/131 /119 /125 /11 6/*/_\/_\/125 /13 2/*/
_\/_\\/119 /125 /11 6/*/_\/_\/125 /13 2/*/_\/_\
\\\\\\\/*\1 1 /125 /119 /11 6/*/_\/13 2/*/_\\/
125 /131 /119 /125 /11 6/*/_\/_\/125 /13 2/*/_\
/_\\/119 /125 /11 6/*/_\/_\/125 /13 2/*/_\/_\\\
/125 /131 /119 /125 /11 6/*/_\/_\/125 /13 2/*/_
\/_\\/131 /119 /125 /11 6/*/_\/_\/125 /13 2/*/_
\/_\\/131 /119 /125 /11 6/*/_\/_\/125 /13 2/*/_
\/_\\/131 /119 /125 /11 6/*/_\/_\/125 /13 2/*/_
\/_\\/119 /125 /11 6/*/_\/_\/125 /13 2/*/_\/_\\

Using the Java2K IDE (sorry, DIE) run the program 13 which is supposed to display “Hello, World”. We’ve included a small chunk of it above. Run it a few times and you’ll probably notice something odd – it doesn’t always get it right. The reason for this is that unlike virtually any other language, Java2K is a probabilistic language rather than a deterministic one so all its functions generate the “correct” answer only 90% of the time; for the remaining 10% it will give a random result. So the method of generating a one that we saw above only has a 90% chance of success. And that’s just for generating a one. The obvious way of generating a two is to add two ones together using the code “125 /11 6/*/_\/_\” but we’re now introducing another instruction that also has a 90% chance of success so the combined likelihood of getting the expected result drops to 81%. In this light of this you might find it surprising that the program 13 manages to produce “Hello, world” as often as it does.

The fact is that there are clever tricks that Java2K programmers can use to improve a program’s success rate but the result is that even the simplest of programs can be extremely long, not to mention virtually incomprehendable. As proof of this why don’t you take a look at program 13 using Notepad. Having done so we suggest that you use the experience to convince yourself that there are better ways of spending your time than attempting to learn Java2K. If you choose to ignore this advice you’ll find the programming manual, in all it succinct glory, at www.p-nand-q.com/humor/programming_languages/java2k/manual.html but we won’t be responsible for the consequences.

Tags: acronym, API, business, Development, device, directory, Discovery, Environment, memory, requirement, sla, space, type, Windows, XP
Jun 08

There’s always analternative to buying a new PC and that’s to upgrade the components inside your slow machine.

Everyone knows the feeling. Your PC has become slow and unresponsive, and it’s getting rather noisy too. All around you are adverts for fast new machines – PCs groaning with cutting-edge components and fancy new features; machines untouched and factory fresh. It’s easy to wilt under this kind of pressure and give into the new PC dream – but luckily we’re here to help you to renew your willpower and stand firm against such temptations! We have happy news: a few well-targeted and cost-
effective upgrades can transform your flagging PC into the machine of your dreams.

So why has your machine got so slow? Well, just as time can be particularly punishing to Windows’ boot time, so it can ravage the hardware in your system. Dust can clog fans and obstruct airflow, overheating your components and bringing their efficiency down. Add to this physical consequence of time’s passing the fact that in the years your PC has been sitting in your home, clever-clogs developers have continued to plug away at their work, creating faster components than those in your machine were even when they were factory-fresh. We’re sure you can see how the problem has arisen.

Refresh your system

This means the best way to speed up your PC is to give it a spring clean and identify the components worth upgrading. In general terms, a PC will last you for a couple of years before you either have to do a major upgrade or piece together enough smaller ones to make the system continue to be fast enough for everyday use.

Which upgrades are best for you is ultimately defined by what you use your machine for. If you’re into video editing and production then a healthy amount of memory will make moving clips around that much smoother, while a faster processor will render your effects and final edits quicker. An SSD will boost program loading times as well as your OS’s boot time.

Audiophiles have similar needs, but they should also keep an eye on how much noise the system is making. Designers benefit from an overall system refit that focuses on an SSD and embraces the current low in memory pricing. The programmers among you will be hankering after more memory as well, along with access to newer motherboard technologies such as USB 3.0 and SATA 6Gb/s – purely for research, of course.

Gamers will see the biggest boost from a graphics card upgrade, because while the promise of multithreaded gaming is closer than ever, the graphics card is still the biggest bottleneck in most systems. And two years is a long time in the graphics card business – we’ve seen the release of not only affordable DirectX 10 cards in that time, but a new breed of cutting-edge DirectX 11 hardware as well.

Click the links below to discover which components you need to upgrade as we talk you through how to do it, and reveal how a tissue can help speed up existing hardware.

Upgrade Your RAM

Understanding Graphics Cards

Cool Down, Speed Up

Replacing The CPU

Select The Perfect Motherboard

Tags: business, CPU, developers, Hardware, Health, iss, memory, processor, Research, rms, rpc, system, Windows
Jun 03

Pentominoes, a simple educational toy, can reveal some surprisingly deep computer science. Although the first back-tracking solution to the puzzle was implemented in 1958, Donald Knuth devised an entirely new way of looking at the problem in 2000, and called the algorithm the Dancing Links algorithm (or more usually, DLX).
A pentomino set consists of 12 pieces, representing: all the different ways of joining 5 squares (hence pent-) along their edges to form an individual piece.

Be thankful you’re not assembling a set of 3D blocks. It’s even harder than the 2D version.

Figure 1 below shows the complete set, together with each piece’s usual name, a letter of the alphabet that most closely resembles it (F, I, L, N, P, T, U, V, W, X, Y, and Z). Since there are 12 pieces, each 5 squares in size, for a total of 60 squares, that means you could investigate solutions to fitting them all in a 3×20 rectangle, 4×15 rectangle, a 5×12 rectangle, or a 6×10 rectangle, as well as other, more fanciful, shapes.

Figure 1: The 12 pentominoes.

Back in my early teens, I was given a plastic set of Pentominoes arranged in a 6×10 box, presumably for my birthday or Christmas. I seem to remember then spending some inordinate amount of time over several months trying to find all the ways of arranging the pieces in the box. There are 2339 different ways, not counting rotations or reflections. I even used a notebook with squared paper to record the permutations I did discover (although I still have that pentomino set, the notebook has been lost in the mists of time). Needless to say, I did not find all 2339 ways.

Starting solutions

Figure 2 shows a solution for the 6×10 box (in fact, the solution I carefully kept with the box, since not knowing how to put them back would have been embarrassing), and if you look carefully, you’ll see that you can immediately generate another by swapping over T and F.

Figure 2: One of several possible solutions to the 6×10 pentomino puzzle.

After playing around with the pieces for a while, the natural question to ask is – well, natural if you are a programmer, that is – how can I write a program to generate all the solutions to a particular puzzle? Let’s look at what might be needed for a 3×20 rectangular board (there are 2 solutions to this particular puzzle, not counting rotations and reflections).

A first idea might be the following algorithm: take the pieces in order, F to Z. Place F somewhere on the empty board and mark off the squares it covers. Place the I on the board, making sure that it does not cover any of the already covered squares, and mark off the squares it does cover. Place the L likewise. At some point you will find that you won’t be able to place the next piece, so you should backtrack and move one of the already placed pieces to another position (perhaps also by rotating or flipping it over), and then try again. Continue this process, with the realization that you might have to backtrack several times at any one check, and eventually you will discover all permutations.

The big problem with this particular solution is that it will take some time. There are 144 different places and orientations for the F in a 3×20 board, 48 for the I, 136 for the L, and so on, and many of them will be completely illegal (for example, the F cannot appear right at the ends of the board, since in doing so you will always leave at least one empty square). So, in all you’ll be trying out 144 * 48 * 136 * … different permutations. Not very fast at all.

A better implementation might be to switch it around a little. Consider the square at the upper left of the board. Select a piece that covers it, and then mark off the remaining 4 squares that are also covered by this piece. Find the next uncovered square (for this type of board, because it’s so narrow, it’ll be better to search down the narrow axis rather than the long axis). Try and find a piece that covers that and that can be placed legally. If not, backtrack again and change a piece you’ve already placed. Sometimes you might have to backtrack several steps.

Because you are more likely to identify impossible solutions much quicker (for example, there are only 2 possible ways to place the F to cover the top left square and both are shown to be illegal when considering what to place in the next square downwards), you’ll find that this algorithm is much more efficient at identifying valid solutions because you reject invalid positions much earlier.

If you try and implement either of the above solutions, you’ll possibly find yourself calculating the positions and which squares are covered by each of the individual pieces over and over again. It would be better to calculate them once and for all and put the values in some kind of table that you read and process as you try out various placements.

Before we discuss the best data structure for that table, let’s take an aside and consider what’s known as the Exact Cover Problem. Imagine the following scenario. You are given a matrix of ones and zeros; that is, whose cells are either 1 or 0. The first part of Figure 3 shows such a matrix. The problem you have to solve is to work out which rows of the matrix form a set that contain exactly one 1 in each column. There may be no such set of rows, there may be exactly one, or there may be more than one. A solution to this problem is known as an exact cover: a set of rows that exactly covers the columns. Take a moment to work out the exact cover for Figure 3.

Figure 3: An exact cover problem in part 1; partial steps to a solution in parts 2 and 3.

Despite the ease with which a visual inspection will provide the answer with this small matrix (rows 2, 3, and 5), it’s well known that this problem is extremely hard (it’s NP-complete, in computer science terms) the more rows and columns there are.
The algorithm for solving it is recursive. Let’s follow along with Figure 3. You’re given a matrix. Choose a column (say the first). Choose a row such that the cell at the intersection of the column and row is a 1 (let’s go for row 4). Add that row to our solution. Now since that row will have a 1 in column 1 we must remove all the other rows that have a 1 in column 1 (that would be row 5). Not only that, but we must also remove all the rows that have a 1 in the same column as this chosen row. For row 4 we hit the jackpot: We can get rid of row 5 (again), row 2 and row 6. We remove row 4 (since it’s in our possible solution) and the three columns that row 4 covered (there’s no need to recheck them since we’ve already covered them). Our matrix now looks like the second part of Figure 3.

Reduced matrix

We do the same thing with this reduced matrix. We choose row 3 as our row since it intersects with column 2 in a 1. Unfortunately, we then have to delete row 1 as well since there’s a clash in column 6, meaning that columns 5 and 7 never get covered and we failed to get an exact cover. So we backtrack. Maybe choosing row 3 was the mistake. However, there is no other possibility to cover column 2 in that particular reduced matrix, and so we must backtrack to our choice of row 4, way at the beginning. Since that choice led to no exact cover, we see if we can’t make another choice of row to cover column 1. Yes, there is: row 5. Selecting row 5 means we get rid of rows 4, 4 (again), and 1, as well as columns 1, 3, and 7 (since row 5 covers them). We’re left with the reduced matrix shown in part 3 of Figure 3.

Here we make the choice of row 3, which removes row 6, as well as columns 2 and 6. And this, as I’m sure you can see, leaves us with row 2 covering the remaining two columns. (To be pedantic, we select row 2 which removes the final two columns as well. Since there are no rows or columns left, we found a solution.) Hence our exact cover solution is rows 2, 3, and 5.

All fine and dandy but what does this exact cover problem have to do with pentominoes, and in particular defining the table of where a piece can be placed and which squares it covers? The answer is to set up the puzzle as an exact cover problem. Let’s define the columns first: the initial 12 columns will be the pentomino pieces, one column for each piece. The next 60 columns will be one per square from the board, say counting from top left across the top row (1–20), then the second row (21–40), then the final row (41–60).

Now we can define each row as being a single piece placed on the board in a particular position. Since it’s a single piece, we’ll have a 1 in only one of the first 12 columns, according to which piece it is. Now we put a 1 in each column of the next 60 that corresponds to the squares covered by the piece in that position. For example, if we take F in its “normal” orientation and place it abutting the left side, the row will have a 1 under the F column, and a 1 under columns for squares 2, 3, 21, 22, 42. All the other 66 columns for that row will be 0. (In fact, every row we add to the matrix will contain 6 1′s and 66 0′s.)

How many rows will there be? Well, we just sum all the different ways we can place each piece. For example, for F there are 18 positions for each of its orientations, and 8 orientations, making 144 distinct positions. I did the calculation and came up with the following number of positions for each piece: F 144; I 48; L 136; N 68; P 220; T 72; U 110; V 72; W 72; X 18; Y 136; Z 72. In other words, the puzzle matrix has 1168 rows. This is one huge matrix, but note that it is very sparse: only 1 in 12 cells is a 1. Now all we have to do is to find the exact covers for this 72×1168 matrix. Because we haven’t done anything to avoid solutions that would be rotations or reflections of other solutions, we’ll actually find 4 times as many solutions as expected.

The fun problem is how to actually solve the exact cover problem efficiently. I’ve already noted that it’s a non-polynomial problem (probably exponential), so, for some large matrix, it’ll all get very hard to nigh on impossible, but this particular sparse, not-that-large matrix actually can be solved pretty quickly.

The algorithm to do it is the one I mentioned above (Donald Knuth calls this algorithm, Algorithm X), however, keeping track of all the rows and columns you’re removing or adding back – the housekeeping, if you like ¬– is quite complicated. To aid in this housekeeping issue, Knuth came up with a refinement that he called Algorithm DLX for something like “Dancing Links implementation of Algorithm X” (you can get the paper from this link, it’s paper P159).

Dancing Links?

Consider a doubly linked list where each node has a Next and a Prev reference to the next and previous nodes in the list. Then, in order to delete a given node X, all we have to do is set X.Next.Prev to X.Prev and X.Prev.Next to X.Next. X will no longer be in the linked list. However, providing that we don’t alter X in any way, we can just as easily add it back into the list: set both X.Next.Prev and X.Prev.Next to X. In other words, although the linked list has no more references to X, X itself still has “knowledge” of where it was in the list.

Well, all that is very well, but so what? Consider our 72×1168 sparse matrix, how would we represent that in memory? What data structure would we use? We could just use a simple standard matrix of boolean values, so it would take 84,096 cells, but such a structure is too rigid. Better would be to use a linked list of cells containing a 1 along each row. Knuth went even further: not only are the 1 cells joined in a linked list along each row, but they are equivalently joined up and down in a linked list as well. The matrix becomes a tapestry of linked lists, with each 1 cell having a link to its left, right, up, and down neighboring 1 cells. 0 cells are not stored at all.

Figure 4: A linked list tapestry for the exact cover problem deomstarted in Figure 3.

Figure 4 shows the exact cover problem matrix that we saw in Figure 3 as a linked list matrix. Each column has a header cell and the header cells have their own single header cell. The linked lists are circular lists: the links off to the left join at the right (and vice versa) and the links off the bottom join at the top (and vice versa). Now that we have this woven data structure of linked lists, we can make use of the remove/add-back-again idea that I just introduced. To cover a column we unlink it from the column headers linked list using our code and we can easily unlink the rows it contains by the same method. If we need to backtrack, we can add the rows back, in reverse order, and finally add the column back in. The housekeeping of Algorithm X is done through this property of deleted nodes “knowing” where they came from. We don’t have to have any special additional data structure to hold the removed rows and columns: the nodes themselves keep track of all that automatically.

In essence, Algorithm DLX finds an exact cover if, during a recursive call, the header of headers node points to itself. It fails to find one if there are still column headers but they have no rows; we shall then need to backtrack. To Knuth, looking at all the breaking and making of links, the weaving of the lists, it reminded him of a dance, hence the term Dancing Links.

Tags: cell, Computer, implementation, iss, matrix, memory, notebook, polynomial, rms, Science, type, XP