Moorshead described his projected calculator for a couple of years hence:

If, as we predict, your calculator can handle and store alphanumerics, a whole range of possibilities occur – it becomes as much a diary as a calculating machine and can store telephone numbers, appointments or any other information you might care to retain. A clock will be built in to display day, date and time and, with a small buzzer, will act as an alarm to give you notice of the events stored in the diary.

Our 1979 model will do everything that current calculators do: simple addition is still likely to be a major use but the extended keyboard will show you the last five or six figures entered so that an interruption in the entry will not be serious.

Interestingly, in 1979 Hewlett Packard released the HP-41C, which actually did implement many of the features speculated upon two years earlier.

That same year HP’s magazine *Digest* featured a specially-commissioned story by Gordon Dickson called *“Thank You, Beep…!”*.

The story is about Walter Jensen, a middle-management executive in the year 2025 who has an unscheduled overnight stop in Jakarta. He carries an “autosecretary”, an HP XX2050, which he calls “Beep”.

… as long as he had the XX2050, he needed very little else in the way of material things. The XX2050 was like a latter-day Aladdin’s lamp, which could summon up anything he needed and that either he or his company could afford. It did this by interlocking with the large, established computer nets wherever it happened to be…

When Walter had first found himself lost in the terminal, the XX2050 had used its built-in receiver to pick up a broadcast signal directing them to the nearest terminals of the airport computer net, translating the signal into a moving arrow of light on its screen for Walter’s benefit. It could, if necessary, also have directed him to the computer terminals by voice directions.

Once slotted into one of the terminals, the XX2050 had been in direct communication with the airport computer net…

The relationship of the XX2050 to the computer nets in Walter’s work and personal life was no less intricate. It was like a staff of personal secretaries, switchboard operator, and personal business manager combined.

Aside from the nets, all by itself, the XX2050 had some remarkable capabilities. In its slim shape it possessed a gigabyte of memory power. Also, it had the ability to transmit and receive on a number of frequencies, including a pulsed signal that could alert a special response in one of the communications satellites overhead at all times in orbit around the Earth.

But such communication was for emergency situations. Most was of the direct slot-connection type. Next most common was short-range air-wave talk with other computer nets, including those of the international telephone networks. The XX2050 could open safes, lock up or unlock offices and houses, translate for Walter in the basic vocabularies of over fifty different languages, or teach him to speak a new one.

It’s not hard to see that this story broadly got it right (though the 1 GB memory in 2025 seems shockingly paltry even today!). Many of these capabilities are commonly found in today’s phones, including the Siri and “OK, Google” style voice recognition facilities.

The XX2050 still looked like a chunky calculator of the late 1970s, however. So it’s interesting to go back to that Electronics Tomorrow article and see what Moorshead thought about the design of these devices even further ahead, in 1982/3:

Our two-year hence machine has a cluttered keyboard, and this will have to go. Looking into our crystal ball we see complete elimination of moving parts. We see our calculator being about the size, but half the thickness, of a packet of 20 cigarettes – or about the size of a thickish pocket diary … it will be metal except for one surface being like a glassy slate.

Does that sound familiar?

]]>

But look at the keys on the right…

The top two keys are clearly the options used in the episode (2D to 3D, and 3D to 2D). The next key, however, looks like it supports a 3D to 4D transformation, as the symbol on the right is a representation of a hypercube (aka tesseract).

The bottom key is less clear, but it appears to show a transformation from a Euclidean space to a hyperbolic negative curvature space.

It’s just a small thing, but I love the fact that they’ve made the prop support options that weren’t even used in the episode, and they’ve done so with some thought as to what those options should be given the multi-dimensional nature of Time Lord engineering. (It also implies that The Doctor, despite being under severe time pressure to get the device working, felt it necessary to include more facilities than were needed in the crisis. That’s scope creep! I suppose it’s possible that he may have thought that the options might be needed later if the first plan didn’t work.)

This is just one reason why Flatline is such a great episode.

]]>

The Red Alert Survival wallet contained an encryption/decryption device in the form of a code wheel. The idea was that Tharg could pass messages to his readers in coded form which could only be read by those who had the wallet.

In order to encrypt a message, you had to set the selector to the appropriate specified code, and look up the characters of your plaintext on the inner wheel, and read off the cipher text on the outer wheel. (Decryption is basically the same process but in reverse.)

Well, it’s been many years since the Red Alert Survival Wallet was issued, so I decided it was time for a technology update. I’ve reimplemented it in Python:

#!/usr/bin/python # # Encrypt/Decrypt 2000AD Red Alert Survival Wallet messages # # For background, see Prog 3 of 2000AD, 1977-03-12 # # Pat Galea, 4dc5.com import sys import argparse parser = argparse.ArgumentParser(description='Encrypt/Decrpyt 2000AD Red Alert Survival Wallet messages.') group = parser.add_mutually_exclusive_group() parser.add_argument("-c", "--code", type=int, default=1, choices=[1,2,3,4,5,6,7,8,9,10], help="code selection") group.add_argument('-e', '--encrypt', action="store_true", help='encrypt a message') group.add_argument('-d', '--decrypt', action="store_true", help='decrypt a message') args = parser.parse_args() # The arrangement of letters on the code wheel codewheel="XAWDGRHZIQTBLOCMJSVEYPFNUK" # The offsets for each code selection (1-10) offsets=[0,0,2,4,6,8,13,15,17,19,21] offset = offsets[args.code] for input in sys.stdin: input=input.upper() output="" for c in input: v=ord(c)-65 if v>=0 and v<26: if args.encrypt: output=output+codewheel[(v+offset)%26] else: output=output+chr((codewheel.index(c)-offset)%26+65) else: output=output+c print output

The program has simple command line options. Use -c to specify the code setting (e.g. “-c2″ for code 2). Use -e to encrypt or -d to decrypt. Input is taken from stdin.

So let’s try the supplied examples:

$ echo RUN FOR YOUR LIFE | ./redalert.py -c2 -e EFM ZJE XJFE OTZH $ echo ENEMY IN AREA | ./redalert.py -c1 -e GOGLU IO XSGX $ echo ZIGNB NV NBI LSKGZIPF | ./redalert.py -c3 -d DEATH TO THE INVADERS

Prog 4’s Invasion! strip included this important message in the bottom right corner:

As it’s a longer message, let’s store it in a file “invasion”. Then we’ll decode it using the Python script:

$ cat invasion NBLF EGTI LF NPIGNIZ NV ZINIHN G SIPKI TGF GNNGHC. LQ NBI EGTI NUPSF PIZ, EUN VS PIFELPGNVP GSZ PIEVPN NV BY LJJIZLGNIMW. $ cat invasion | ./redalert.py -c3 -d THIS PAGE IS TREATED TO DETECT A NERVE GAS ATTACK. IF THE PAGE TURNS RED, PUT ON RESPIRATOR AND REPORT TO HQ IMMEDIATELY.

Clearly an important message to the readers. I hope this Python script proves useful to modern Squaxx Dek Thargo, and I look forward to receiving further messages from Tharg the Mighty.

]]>

In this case, we define a balanced function as one in which exactly half the outputs go to one value, and the other half go to another value. We’ll define f(00) = f(01) = 1, and f(10) = f(11) = 0.

The circuit is very similar, but this time the top line is actually multiple lines (indicated by the slash-n). The input value is |**0**〉, with the bold **0** indicating that this is a set of many qubits. For the purpose of this experiment, we’ll stick to n=2 qubits.

The Hadamard transform on the top line needs to work on both qubits, so we actually need to generate H^{⊗n}, which is the n-times tensor product of the Hadamard matrix with itself. (In fact, we already have a function to generate Hadamard matrices of any order that’s a power of 2 directly. It doesn’t matter which method we use.)

I won’t go through the intermediate steps, but in summary this circuit is represented by: |ψ_{3}〉 = (H^{⊗n}⊗I)U_{f}(H^{⊗n}⊗H)(|**0**〉⊗|1〉)

As before, refer to Yanofsky for the details about what the measurement will show. In brief, when we look at the top qubits (i.e. all but the last qubit in the measurement of |ψ_{3}〉, if we get |**0**〉 then the function is constant. If we get anything else, then the function is balanced.

Setting up a balanced function:

/* * |x>|y> -> |x>|y XOR f(x)> * Balanced function: f(00) = f(01) = 1, f(10) = f(11) = 0. */ matrix* function_bal = mat_alloc(8,8); function_bal->data[0][1] = c_num(1,0); function_bal->data[1][0] = c_num(1,0); function_bal->data[2][3] = c_num(1,0); function_bal->data[3][2] = c_num(1,0); function_bal->data[4][4] = c_num(1,0); function_bal->data[5][5] = c_num(1,0); function_bal->data[6][6] = c_num(1,0); function_bal->data[7][7] = c_num(1,0);

and the circuit:

matrix* qubit0x2 = mat_tensor(qubit(0),qubit(0)); matrix* psi0 = mat_tensor(qubit0x2,qubit(1)); matrix* hadamard3 = mat_hadamard(8); // Or we could have taken the tensor product of 3 order-2 hadamard matrices matrix* psi1 = mat_mul(hadamard3,psi0); matrix* psi2 = mat_mul(function_bal,psi1); matrix* hadamard2 = mat_hadamard(4); matrix* hadamard2_identity = mat_tensor(hadamard2,mat_identity(2)); matrix* psi3 = mat_mul(hadamard2_identity,psi2); for (int i=1;i<10;i++) { measure(psi3); }

we get the result |100〉 or |101〉, thus confirming that the function is balanced. (Note that I’ve added a loop to perform the measurement many times. On a real quantum computer, you couldn’t do this because once you’ve collapsed the state vector the information is lost. It’s useful in experiments, however, to see what kind of values the measurement can produce.)

If we change the function to be constant:

/* * |x>|y> -> |x>|y XOR f(x)> * Constant function: f(x) = 1. */ matrix* function_con = mat_alloc(8,8); function_con->data[0][1] = c_num(1,0); function_con->data[1][0] = c_num(1,0); function_con->data[2][3] = c_num(1,0); function_con->data[3][2] = c_num(1,0); function_con->data[4][5] = c_num(1,0); function_con->data[5][4] = c_num(1,0); function_con->data[6][7] = c_num(1,0); function_con->data[7][6] = c_num(1,0);

then we get the result |000〉 or |001〉, confirming that the function is constant.

Here’s the full code:

/* * Quantum Computer Emulator * Pat Galea * 4dc5.com */ #include <stdio.h> #include <stdlib.h> // Complex number typedef struct { float re; float im; } complex; // Matrix typedef struct { int rows; int cols; complex** data; } matrix; // Create a complex number from real and imaginary parts complex c_num(float re, float im) { complex num; num.re = re; num.im = im; return num; } // Add two complex numbers complex c_add(complex a, complex b) { complex z; z.re = a.re+b.re; z.im = a.im+b.im; return z; } // Subtract two complex numbers complex c_sub(complex a, complex b) { complex z; z.re = a.re-b.re; z.im = a.im-b.im; return z; } // Multiply two complex numbers complex c_mul(complex a, complex b) { complex z; z.re = a.re*b.re - a.im*b.im; z.im = a.re*b.im + a.im*b.re; return z; } // Divide two complex numbers complex c_div(complex a, complex b) { complex z; z.re = (a.re * b.re + a.im * b.im) / (b.re * b.re + b.im * b.im); z.im = (a.im * b.re - a.re * b.im) / (b.re * b.re + b.im * b.im); return z; } // Print complex number void c_print(complex a) { if (a.re!=0 && a.im>0) printf("%.1f+%.1fi",a.re,a.im); else if (a.re!=0 && a.im<0) printf("%.1f-%.1fi",a.re,-a.im); else if (a.re==0 && a.im>0) printf("%.1fi",a.im); else if (a.re==0 && a.im<0) printf("-%.1fi",-a.im); else printf("%.1f",a.re); } // Create a matrix of complex numbers (initialised to 0), m rows, n columns matrix* mat_alloc(int m,int n) { matrix* mat = malloc(sizeof(matrix)); mat->rows = m; mat->cols = n; mat->data = (complex**)malloc(sizeof(complex*)*m); for (int i=0;i<m;i++) { mat->data[i] = (complex*)malloc(sizeof(complex)*n); for (int j=0;j<n;j++) { mat->data[i][j] = c_num(0,0); } } return mat; } // Create Identity matrix of order m matrix* mat_identity(int m) { matrix* mat = mat_alloc(m,m); for (int i=0;i<m;i++) { mat->data[i][i].re = 1.0; } return mat; } // Multiply a complex scalar by a matrix matrix* mat_scalarmul(complex scalar, matrix* matold) { matrix* matnew = mat_alloc(matold->rows,matold->cols); for (int i=0;i<matold->rows;i++) { for (int j=0;j<matold->cols;j++) { matnew->data[i][j] = c_mul(scalar,matold->data[i][j]); } } return matnew; } // Perform tensor product of two matrices matrix* mat_tensor(matrix* mata, matrix* matb) { matrix* mat = mat_alloc(mata->rows*matb->rows,mata->cols*matb->cols); for (int ai=0;ai<mata->rows;ai++) { for (int bi=0;bi<matb->rows;bi++) { for (int aj=0;aj<mata->cols;aj++) { for (int bj=0;bj<matb->cols;bj++) { int row = ai*matb->rows+bi; int col = aj*matb->cols+bj; mat->data[row][col] = c_mul(mata->data[ai][aj],matb->data[bi][bj]); } } } } return mat; } // Multiply two matrices matrix* mat_mul(matrix* mata, matrix* matb) { matrix* mat = 0; if (mata->cols==matb->rows) { mat = mat_alloc(mata->rows,matb->cols); for (int ai=0;ai<mata->rows;ai++) { for (int bj=0;bj<matb->cols;bj++) { complex cellsum = c_num(0,0); for (int aj=0;aj<mata->cols;aj++) { cellsum = c_add(cellsum,c_mul(mata->data[ai][aj],matb->data[aj][bj])); } mat->data[ai][bj] = cellsum; } } } return mat; } // Free the allocated memory of a matrix (and its data) void mat_free(matrix* mat) { for (int i=0;i<mat->rows;i++) { free(mat->data[i]); } free(mat); } /* * Create a Hadamard matrix of order m. * This code only supports m ∈ {powers of 2}. Finding Hadamard matrices for other orders can be non-trivial. */ matrix* mat_hadamard(int m) { matrix* mat = 0; // If we want an order 1 Hadamard matrix, that's easy. It's [1]. if (m==1) { mat = mat_alloc(1,1); mat->data[0][0].re = 1.0; } else if (m%2==0) { mat = mat_alloc(m,m); // Find the Hadamard matrix that's half the order of this one matrix* mat_subhad = mat_hadamard(m/2); // Now copy that smaller Hadamard matrix into each quadrant of this one, but multiply the one in the bottom-right by -1. for (int i=0;i<m;i++) { for (int j=0;j<m;j++) { if (i<m/2 || j<m/2) mat->data[i][j] = mat_subhad->data[i%(m/2)][j%(m/2)]; else mat->data[i][j].re = -mat_subhad->data[i%(m/2)][j%(m/2)].re; // Bottom-right } } mat_free(mat_subhad); } return mat; } // Find the transpose of a matrix matrix* mat_transpose(matrix* matold) { matrix* matnew = mat_alloc(matold->cols,matold->rows); for (int i=0;i<matold->rows;i++) { for (int j=0;j<matold->cols;j++) { matnew->data[j][i] = matold->data[i][j]; } } return matnew; } // Find the conjugate transpose of a matrix matrix* mat_conjtranspose(matrix* matold) { matrix* matnew = mat_alloc(matold->cols,matold->rows); for (int i=0;i<matold->rows;i++) { for (int j=0;j<matold->cols;j++) { matnew->data[j][i].re = matold->data[i][j].re; matnew->data[j][i].im = -matold->data[i][j].im; } } return matnew; } /* * Invert matrix using the Gauss-Jordan elimination method. */ matrix* mat_invert(matrix* matold) { matrix* matnew = 0; int i,j,k,m; complex ratio,a; if (matold->rows==matold->cols) { m = matold->rows; matrix* mataug = mat_alloc(m,m*2); // Augmented matrix // Copy the original matrix to the left-hand side for (i=0;i<m;i++) { for (j=0;j<m;j++) { mataug->data[i][j] = matold->data[i][j]; } } // Create the identity matrix on the right-hand side for (i=0;i<m;i++) { mataug->data[i][m+i] = c_num(1,0); } // Now perform Gauss-Jordan elimination to find the reduced echelon form for (i=0;i<m;i++) { for (j=0;j<m;j++) { if (i!=j) { ratio = c_div(mataug->data[j][i],mataug->data[i][i]); for (k=0;k<2*m;k++) { mataug->data[j][k] = c_sub(mataug->data[j][k],c_mul(ratio,mataug->data[i][k])); } } } } for (i=0;i<m;i++) { a = mataug->data[i][i]; for (j=0;j<2*m;j++) { mataug->data[i][j] = c_div(mataug->data[i][j],a); } } matnew = mat_alloc(m,m); // Copy just the right-hand side, which is the inverted matrix for (i=0;i<m;i++) { for (j=0;j<m;j++) { matnew->data[i][j] = mataug->data[i][m+j]; } } mat_free(mataug); } return matnew; } // Print a matrix void mat_print(matrix* mat) { for (int i=0;i<mat->rows;i++) { for (int j=0;j<mat->cols;j++) { c_print(mat->data[i][j]); printf(" "); } printf("\n"); } } /* * Generate a vector (single column matrix) for a qubit. * Qubit 0 => |0> = [1 0]T * Qubit 1 => |1> = [0 1]T */ matrix* qubit(int qubit) { matrix* mat = mat_alloc(2,1); if (qubit == 0) mat->data[0][0].re = 1; else mat->data[1][0].re = 1; return mat; } /* * Generate a vector (single column matrix) of superposed states. * Each row has the value 1. * e.g. 2 qubits => [1 1 1 1]T */ matrix* superpose(int num_qubits) { matrix* mat = mat_alloc(1<<num_qubits,1); for (int i=0;i<mat->rows;i++) { mat->data[i][0] = c_num(1,0); } return mat; } /* * Perform measurement to 'collapse' the vector to one value. * Prints the resulting vector. */ void measure(matrix* mat) { int i,row,mask; float sum = 0, size, ran; row = mat->rows-1; // Default to the last row // Find the magnitude of the vector (by summing the square of each value) sum = 0; // Cumulative sum for (i=0;i<mat->rows;i++) { sum = sum + c_mul(mat->data[i][0],mat->data[i][0]).re; } size = sum; // Pick a random number between 0 and 1 ran = 1.0*rand()/RAND_MAX; // Use this random value to pick a row according to the size of each value sum = 0; for (i=0;i<mat->rows;i++) { sum = sum + c_mul(mat->data[i][0],mat->data[i][0]).re/size; // If the cumulative sum is bigger than the random number, then we've got our measurement if (sum>ran) { row = i; break; } } // Now print the state for this row as a ket printf("|"); mask = mat->rows>>1; while (mask>0) { if ((mask&row) >0) printf("1"); else printf("0"); mask = mask>>1; } printf(">\n"); } int main(void) { srand(1); // Fixed so it's repeatable. Change to e.g. srand(time(NULL)) to make it more 'random'. /* * |x>|y> -> |x>|y XOR f(x)> * Balanced function: f(00) = f(01) = 1, f(10) = f(11) = 0. */ matrix* function_bal = mat_alloc(8,8); function_bal->data[0][1] = c_num(1,0); function_bal->data[1][0] = c_num(1,0); function_bal->data[2][3] = c_num(1,0); function_bal->data[3][2] = c_num(1,0); function_bal->data[4][4] = c_num(1,0); function_bal->data[5][5] = c_num(1,0); function_bal->data[6][6] = c_num(1,0); function_bal->data[7][7] = c_num(1,0); /* * |x>|y> -> |x>|y XOR f(x)> * Constant function: f(x) = 1. */ matrix* function_con = mat_alloc(8,8); function_con->data[0][1] = c_num(1,0); function_con->data[1][0] = c_num(1,0); function_con->data[2][3] = c_num(1,0); function_con->data[3][2] = c_num(1,0); function_con->data[4][5] = c_num(1,0); function_con->data[5][4] = c_num(1,0); function_con->data[6][7] = c_num(1,0); function_con->data[7][6] = c_num(1,0); matrix* qubit0x2 = mat_tensor(qubit(0),qubit(0)); matrix* psi0 = mat_tensor(qubit0x2,qubit(1)); matrix* hadamard3 = mat_hadamard(8); // Or we could have taken the tensor product of 3 order-2 hadamard matrices matrix* psi1 = mat_mul(hadamard3,psi0); matrix* psi2 = mat_mul(function_con,psi1); matrix* hadamard2 = mat_hadamard(4); matrix* hadamard2_identity = mat_tensor(hadamard2,mat_identity(2)); matrix* psi3 = mat_mul(hadamard2_identity,psi2); for (int i=1;i<10;i++) { measure(psi3); } return 0; }

]]>

First, a few words about what I’ve done here. I’ve written the code in C, because it’s a language I’m very familiar with. Also, I have not used any of the mathematical libraries that are available for complex numbers, matrices, etc. That’s because I wanted to code this all from the ground up, doing everything myself. I find that’s the only way to truly understand what’s going on. It also has the benefit that if the code is ported to another platform where the libraries aren’t available, it’s in a better position to be translated. (I’m planning to build a QC emulator on FPGA later; some early experiments show that this will be a challenge, though definitely doable.) I’ve deliberately not used OO methods, so functions are separate entities, not part of classes. Note that there’s no error checking in the code, and no attempt has been made to optimize it. It is not designed to be run in a production environment; it is lab code.

I’ve been working from a couple of great books: Nielsen & Chuang’s *Quantum Computation and Quantum Information* (popularly known as “Mike & Ike”), and Yanofsky & Mannucci’s *Quantum Computing for Computer Scientists*. The first book is very comprehensive, and covers a lot of the theoretical background. The second book skips some of the detail, but is much easier to get into if you have a computer science background. It has the best explanation of the tensor product that I have ever seen.

The code I’ve written provides a bunch of types and functions that make it easy to build simple quantum algorithms. There’s a complex number type, and a matrix type which handles complex values. Functions are provided for the basic operations on the types, such as complex arithmetic, matrix multiplication, matrix inversion, conjugate transposition, and tensor product. There are also functions for generating matrices that will be useful, such as the Hadamard matrices, Identity, simple qubits, and superposition of states. Finally, there’s a measurement function which will “collapse” a state vector to a single measured value (using a random number generator to select the appropriate value).

I’ll put the full code at the end of this article, but let’s concentrate on solving a particular problem. For this first experiment, I’ll tackle Deutsch’s algorithm (as explained in Yanofsky chapter 6). This is a very simple problem in which we want to detect whether a function (which is unknown to us) is “balanced” or “constant”. (Briefly, balanced means that the output is different and unique for each input; constant means that the output is the same for each input. For example, if f(0)=1 and f(1)=0, then the function is balanced. If, however, f(0)=0 and f(1)=0, then the function is constant.)

I won’t go into the details of why this is an interesting problem. In brief, it’s obvious how one would go about testing the function on a classical computer by trying various inputs and looking at the outputs. In fact, for this simple example, a quantum computer doesn’t really bring much benefit, but it is a nice problem to start with. When we expand to larger problems, the quantum computer will win.

The circuit starts with two qubits on the left. The top qubit is set to state |0〉 and the bottom qubit is set to state |1〉. The intermediate states |*ψ _{0}*〉…|

So we have the input state: |*ψ _{0}*〉 = |0〉⊗|1〉 = |01〉.

We then apply the Hadamard transform to each line: |*ψ _{1}*〉 = (H⊗H)|

Then we apply the “mystery” function: |*ψ _{2}*〉 = U

Another Hadamard transform to the top line only this time: |*ψ _{3}*〉 = (H⊗I)|

(So in summary, we have: |*ψ _{3}*〉 = (H⊗I)U

And then we measure |*ψ _{3}*〉!

Now there’s quite a bit of work to do in order to understand what this will actually tell us. Yanofsky explains this very well. In brief, when we measure |*ψ _{3}*〉, if we get |0〉 for the top qubit then we know that the function is constant. If we get |1〉 for the top qubit then we know that the function is balanced.

Given all the functions that have been defined in the code, it is quite simple to set up the problem:

/* * |x>|y> -> |x>|y XOR f(x)> * Balanced function: f(0) = 1, f(1) = 0. */ matrix* function_bal = mat_alloc(4,4); function_bal->data[0][1] = c_num(1,0); function_bal->data[1][0] = c_num(1,0); function_bal->data[2][2] = c_num(1,0); function_bal->data[3][3] = c_num(1,0);

This code gives us the matrix representing a balanced function.

Then we simply chain the operations together:

matrix* psi0 = mat_tensor(qubit(0),qubit(1)); matrix* hadamard2 = mat_hadamard(4); matrix* psi1 = mat_mul(hadamard2,psi0); matrix* psi2 = mat_mul(function_bal,psi1); matrix* hadamard_identity = mat_tensor(mat_hadamard(2),mat_identity(2)); matrix* psi3 = mat_mul(hadamard_identity,psi2); measure(psi3);

And it’s as simple as that!

When the code is executed, the measurement of |*ψ _{3}*〉 gives us a result of |10〉. The first qubit is |1〉, showing that the function is balanced, as we know from the definition. (It might alternatively have measured |11〉, as the measurement is random. The point is that the first qubit is |1〉 either way.)

If we set up a constant function instead:

/* * |x>|y> -> |x>|y XOR f(x)> * Constant function: f(0) = 0, f(1) = 0. */ matrix* function_con = mat_identity(4);

then we get the measurement of |*ψ _{3}*〉 as |00〉 (or |01〉), with the first qubit being |0〉, showing that the function is constant.

So it works!

There’s a lot more to do. The next step is to code the Deutsch-Jozsa algorithm which performs a similar task, but with multiple qubits (and that’s where things get interesting). I also need to code the Quantum Fourier Transform (QFT) which is needed to perform more sophisticated algorithms, such as Shor’s Factoring Algorithm.

Anyway, here’s the code if you want to play with what we’ve got so far.

/* * Quantum Computer Emulator * Pat Galea * 4dc5.com */ #include <stdio.h> #include <stdlib.h> // Complex number typedef struct { float re; float im; } complex; // Matrix typedef struct { int rows; int cols; complex** data; } matrix; // Create a complex number from real and imaginary parts complex c_num(float re, float im) { complex num; num.re = re; num.im = im; return num; } // Add two complex numbers complex c_add(complex a, complex b) { complex z; z.re = a.re+b.re; z.im = a.im+b.im; return z; } // Subtract two complex numbers complex c_sub(complex a, complex b) { complex z; z.re = a.re-b.re; z.im = a.im-b.im; return z; } // Multiply two complex numbers complex c_mul(complex a, complex b) { complex z; z.re = a.re*b.re - a.im*b.im; z.im = a.re*b.im + a.im*b.re; return z; } // Divide two complex numbers complex c_div(complex a, complex b) { complex z; z.re = (a.re * b.re + a.im * b.im) / (b.re * b.re + b.im * b.im); z.im = (a.im * b.re - a.re * b.im) / (b.re * b.re + b.im * b.im); return z; } // Print complex number void c_print(complex a) { if (a.re!=0 && a.im>0) printf("%.1f+%.1fi",a.re,a.im); else if (a.re!=0 && a.im<0) printf("%.1f-%.1fi",a.re,-a.im); else if (a.re==0 && a.im>0) printf("%.1fi",a.im); else if (a.re==0 && a.im<0) printf("-%.1fi",-a.im); else printf("%.1f",a.re); } // Create a matrix of complex numbers (initialised to 0), m rows, n columns matrix* mat_alloc(int m,int n) { matrix* mat = malloc(sizeof(matrix)); mat->rows = m; mat->cols = n; mat->data = (complex**)malloc(sizeof(complex*)*m); for (int i=0;i<m;i++) { mat->data[i] = (complex*)malloc(sizeof(complex)*n); for (int j=0;j<n;j++) { mat->data[i][j] = c_num(0,0); } } return mat; } // Create Identity matrix of order m matrix* mat_identity(int m) { matrix* mat = mat_alloc(m,m); for (int i=0;i<m;i++) { mat->data[i][i].re = 1.0; } return mat; } // Multiply a complex scalar by a matrix matrix* mat_scalarmul(complex scalar, matrix* matold) { matrix* matnew = mat_alloc(matold->rows,matold->cols); for (int i=0;i<matold->rows;i++) { for (int j=0;j<matold->cols;j++) { matnew->data[i][j] = c_mul(scalar,matold->data[i][j]); } } return matnew; } // Perform tensor product of two matrices matrix* mat_tensor(matrix* mata, matrix* matb) { matrix* mat = mat_alloc(mata->rows*matb->rows,mata->cols*matb->cols); for (int ai=0;ai<mata->rows;ai++) { for (int bi=0;bi<matb->rows;bi++) { for (int aj=0;aj<mata->cols;aj++) { for (int bj=0;bj<matb->cols;bj++) { int row = ai*matb->rows+bi; int col = aj*matb->cols+bj; mat->data[row][col] = c_mul(mata->data[ai][aj],matb->data[bi][bj]); } } } } return mat; } // Multiply two matrices matrix* mat_mul(matrix* mata, matrix* matb) { matrix* mat = 0; if (mata->cols==matb->rows) { mat = mat_alloc(mata->rows,matb->cols); for (int ai=0;ai<mata->rows;ai++) { for (int bj=0;bj<matb->cols;bj++) { complex cellsum = c_num(0,0); for (int aj=0;aj<mata->cols;aj++) { cellsum = c_add(cellsum,c_mul(mata->data[ai][aj],matb->data[aj][bj])); } mat->data[ai][bj] = cellsum; } } } return mat; } // Free the allocated memory of a matrix (and its data) void mat_free(matrix* mat) { for (int i=0;i<mat->rows;i++) { free(mat->data[i]); } free(mat); } /* * Create a Hadamard matrix of order m. * This code only supports m ∈ {powers of 2}. Finding Hadamard matrices for other orders can be non-trivial. */ matrix* mat_hadamard(int m) { matrix* mat = 0; // If we want an order 1 Hadamard matrix, that's easy. It's [1]. if (m==1) { mat = mat_alloc(1,1); mat->data[0][0].re = 1.0; } else if (m%2==0) { mat = mat_alloc(m,m); // Find the Hadamard matrix that's half the order of this one matrix* mat_subhad = mat_hadamard(m/2); // Now copy that smaller Hadamard matrix into each quadrant of this one, but multiply the one in the bottom-right by -1. for (int i=0;i<m;i++) { for (int j=0;j<m;j++) { if (i<m/2 || j<m/2) mat->data[i][j] = mat_subhad->data[i%(m/2)][j%(m/2)]; else mat->data[i][j].re = -mat_subhad->data[i%(m/2)][j%(m/2)].re; // Bottom-right } } mat_free(mat_subhad); } return mat; } // Find the transpose of a matrix matrix* mat_transpose(matrix* matold) { matrix* matnew = mat_alloc(matold->cols,matold->rows); for (int i=0;i<matold->rows;i++) { for (int j=0;j<matold->cols;j++) { matnew->data[j][i] = matold->data[i][j]; } } return matnew; } // Find the conjugate transpose of a matrix matrix* mat_conjtranspose(matrix* matold) { matrix* matnew = mat_alloc(matold->cols,matold->rows); for (int i=0;i<matold->rows;i++) { for (int j=0;j<matold->cols;j++) { matnew->data[j][i].re = matold->data[i][j].re; matnew->data[j][i].im = -matold->data[i][j].im; } } return matnew; } /* * Invert matrix using the Gauss-Jordan elimination method. */ matrix* mat_invert(matrix* matold) { matrix* matnew = 0; int i,j,k,m; complex ratio,a; if (matold->rows==matold->cols) { m = matold->rows; matrix* mataug = mat_alloc(m,m*2); // Augmented matrix // Copy the original matrix to the left-hand side for (i=0;i<m;i++) { for (j=0;j<m;j++) { mataug->data[i][j] = matold->data[i][j]; } } // Create the identity matrix on the right-hand side for (i=0;i<m;i++) { mataug->data[i][m+i] = c_num(1,0); } // Now perform Gauss-Jordan elimination to find the reduced echelon form for (i=0;i<m;i++) { for (j=0;j<m;j++) { if (i!=j) { ratio = c_div(mataug->data[j][i],mataug->data[i][i]); for (k=0;k<2*m;k++) { mataug->data[j][k] = c_sub(mataug->data[j][k],c_mul(ratio,mataug->data[i][k])); } } } } for (i=0;i<m;i++) { a = mataug->data[i][i]; for (j=0;j<2*m;j++) { mataug->data[i][j] = c_div(mataug->data[i][j],a); } } matnew = mat_alloc(m,m); // Copy just the right-hand side, which is the inverted matrix for (i=0;i<m;i++) { for (j=0;j<m;j++) { matnew->data[i][j] = mataug->data[i][m+j]; } } mat_free(mataug); } return matnew; } // Print a matrix void mat_print(matrix* mat) { for (int i=0;i<mat->rows;i++) { for (int j=0;j<mat->cols;j++) { c_print(mat->data[i][j]); printf(" "); } printf("\n"); } } /* * Generate a vector (single column matrix) for a qubit. * Qubit 0 => |0> = [1 0]T * Qubit 1 => |1> = [0 1]T */ matrix* qubit(int qubit) { matrix* mat = mat_alloc(2,1); if (qubit == 0) mat->data[0][0].re = 1; else mat->data[1][0].re = 1; return mat; } /* * Generate a vector (single column matrix) of superposed states. * Each row has the value 1. * e.g. 2 qubits => [1 1 1 1]T */ matrix* superpose(int num_qubits) { matrix* mat = mat_alloc(1<<num_qubits,1); for (int i=0;i<mat->rows;i++) { mat->data[i][0] = c_num(1,0); } return mat; } /* * Perform measurement to 'collapse' the vector to one value. * Prints the resulting vector. */ void measure(matrix* mat) { int i,row,mask; float sum = 0, size, ran; row = mat->rows-1; // Default to the last row // Find the magnitude of the vector (by summing the square of each value) sum = 0; // Cumulative sum for (i=0;i<mat->rows;i++) { sum = sum + c_mul(mat->data[i][0],mat->data[i][0]).re; } size = sum; // Pick a random number between 0 and 1 ran = 1.0*rand()/RAND_MAX; // Use this random value to pick a row according to the size of each value sum = 0; for (i=0;i<mat->rows;i++) { sum = sum + c_mul(mat->data[i][0],mat->data[i][0]).re/size; // If the cumulative sum is bigger than the random number, then we've got our measurement if (sum>ran) { row = i; break; } } // Now print the state for this row as a ket printf("|"); mask = mat->rows>>1; while (mask>0) { if ((mask&row) >0) printf("1"); else printf("0"); mask = mask>>1; } printf(">\n"); } int main(void) { srand(1); // Fixed so it's repeatable. Change to e.g. srand(time(NULL)) to make it more 'random'. /* * |x>|y> -> |x>|y XOR f(x)> * Balanced function: f(0) = 1, f(1) = 0. */ matrix* function_bal = mat_alloc(4,4); function_bal->data[0][1] = c_num(1,0); function_bal->data[1][0] = c_num(1,0); function_bal->data[2][2] = c_num(1,0); function_bal->data[3][3] = c_num(1,0); /* * |x>|y> -> |x>|y XOR f(x)> * Constant function: f(0) = 0, f(1) = 0. */ matrix* function_con = mat_identity(4); matrix* psi0 = mat_tensor(qubit(0),qubit(1)); matrix* hadamard2 = mat_hadamard(4); matrix* psi1 = mat_mul(hadamard2,psi0); matrix* psi2 = mat_mul(function_con,psi1); matrix* hadamard_identity = mat_tensor(mat_hadamard(2),mat_identity(2)); matrix* psi3 = mat_mul(hadamard_identity,psi2); measure(psi3); return 0; }

]]>

1. Install the Android SDK for Mac OS X. (I put mine in ~/android-sdk.)

2. Install the Android NDK for Mac OS X. (I put mine in ~/android-ndk-r8d.)

3. Set up your $PATH. In ~/.bash_profile, add these lines:

NDK_ROOT=~/android-ndk-r8d SDK_ROOT=~/android-sdk export PATH=$PATH:$SDK_ROOT/sdk/platform-tools export PATH=$PATH:$NDK_ROOT export PATH=$PATH:$NDK_ROOT/prebuilt/darwin-x86/bin export PATH=$PATH:$NDK_ROOT/build/tools

4. Create a new executable script called ndk-comp. Put it in $NDK_ROOT.

#!/bin/sh ANDROIDSDK='android-14' PROGDIR=`dirname $0` PROGDIR=`cd $PROGDIR && pwd` ARMEABIGCC=$PROGDIR/toolchains/arm-linux-androideabi-4.7/prebuilt/darwin-x86/bin/arm-linux-androideabi-gcc ARMEABILIB=$PROGDIR/platforms/$ANDROIDSDK/arch-arm/usr/lib ARMEABIINC=$PROGDIR/platforms/$ANDROIDSDK/arch-arm/usr/include ARMEABICRT=$PROGDIR/platforms/$ANDROIDSDK/arch-arm/usr/lib/crtbegin_dynamic.o LINKER=/system/bin/linker echo "GCC:"$ARMEABIGCC "LIB:"$ARMEABILIB "LINKER":$LINKER "PARAMS:"$@ $ARMEABIGCC $@ -Wl,-rpath-link=$ARMEABILIB,-dynamic-linker=$LINKER -L$ARMEABILIB $ARMEABICRT -I$ARMEABIINC -nostdlib -lc

That’s it!

Now to test it. In a working directory, create a simple C program test.c :

#include <stdio.h> int main() { printf("Hello world!\n"); return 0; }

Run this command to build it:

ndk-comp -o test test.c

Now connect your Android device, and push the executable to a suitable location (I’m using /data/local/tmp here):

adb push test /data/local/tmp

Now run it:

$ adb shell # cd /data/local/tmp # ./test

And you should see:

Hello world! [1] + Stopped (signal) ./test

]]>

Some people also say that if you’re going to be using your MacBook in a place where you need to be quiet, then you should ensure that you’ve muted the sound before you shut down. But this doesn’t make sense either, because you don’t always know when you shut down that the next place you’ll be turning it on is a quiet place.

Anyway, I found a method on the MacScripter forum which solves the problem quite nicely by muting the sound automatically upon logout. AppleScript is a technology that I’ve not really used much before, so I’m not aware of all the things that can be done with it. Looking through some sample scripts, it does seem to be a powerful tool for automating Mac tasks (and it’s been around a very long time, so there are lots of examples to play with).

Of course, this method only works if the logout process executes. It won’t be able to mute the sound if Mac OS crashes! But it will catch the overwhelming majority of cases.

Here’s how to mute the boot sound. (I’ve only retained the “logout” part of the solution, as that’s the only bit that I care about.)

Create a plain text file with the following as the logout script:

#!/bin/bash /usr/bin/osascript -e 'set volume with output muted'

Save the script as /usr/local/bin/logoutscript .

In Terminal, run the following command:

sudo chmod a+x /usr/local/bin/logoutscript sudo defaults write com.apple.loginwindow LogoutHook /usr/local/bin/logoutscript

If you want to remove these changes later, do this:

sudo defaults delete com.apple.loginwindow LogoutHook sudo rm /usr/local/bin/logoutscript

]]>

**Original post:**

On Mac OS X Lion, Microsoft Word reopens previously edited documents when you start it up. This can be very annoying.

To stop it, run this:

defaults write com.microsoft.Word NSQuitAlwaysKeepsWindows -bool false

You can substitute different applications for com.microsoft.Word. You can find the names in ~/Library/Saved Application State.

If you want to fix all the main Office apps (and Preview) in one go, run this script:

#!/bin/bash function runit { defaults write $1 NSQuitAlwaysKeepsWindows -bool false } runit com.microsoft.Word runit com.microsoft.Excel runit com.microsoft.Powerpoint runit com.apple.Preview

]]>

**Set up file sharing and autodiscovery**

[Source: Getting Started With Raspberry Pi]

On the Pi:

sudo apt-get install netatalk

Now from the Mac, open Finder, and hit ⌘K. Enter afp://192.168.0.22 (using the IP address of your Pi).

On the Pi:

sudo apt-get install avahi-daemon sudo update-rc.d avahi-daemon defaults

Now create a file /etc/avahi/services/afpd.service (as root):

sudo vim /etc/avahi/services/afpd.service

and add this content:

<?xml version="1.0" standalone='no'?><!--*-nxml-*--> <!DOCTYPE service-group SYSTEM "avahi-service.dtd"> <service-group> <name replace-wildcards="yes">%h</name> <service> <type>_afpovertcp._tcp</type> <port>548</port> </service> </service-group>

Then run this command:

sudo /etc/init.d/avahi-daemon restart

You should now be able to see the Pi in the Finder sidebar.

**Setting up vncserver**

[Source: Raspberry Pi forum]

On the Pi:

sudo apt-get install tightvncserver vncserver

Enter an eight character password.

Now do:

cd /etc/init.d sudo vim tightvncserver

Add the following content to the file:

#!/bin/bash # /etc/init.d/tightvncserver # # Carry out specific functions when asked to by the system case "$1" in start) su pi -c '/usr/bin/vncserver -geometry 1440x900' echo "Starting VNC server " ;; stop) pkill vncserver echo "VNC Server has been stopped (didn't double check though)" ;; *) echo "Usage: /etc/init.d/blah {start|stop}" exit 1 ;; esac exit 0

(Change the geometry setting if your monitor is a different size.)

Now do:

sudo chmod +x tightvncserver sudo pkill Xtightvnc

Check the VNC server is not running:

ps aux | grep vnc

Then do:

sudo /etc/init.d/tightvncserver start cd /etc/init.d sudo update-rc.d tightvncserver defaults

**Finding your VNC server using Bonjour**

[Source: Getting Started With Raspberry Pi]

Create the avahi rfb service file:

sudo vim /etc/avahi/services/rfb.service

and add this content:

<?xml version="1.0" standalone='no'?> <!DOCTYPE service-group SYSTEM "avahi-service.dtd"> <service-group> <name replace-wildcards="yes">%h</name> <service> <type>_rfb._tcp</type> <port>5901</port> </service> </service-group>

Then run:

sudo /etc/init.d/avahi-daemon restart

Now you should be able to see the Screen Share option for the Pi in your Finder sidebar.

If you’re also running an X session directly on the Pi (i.e. not through VNC), consider disabling the screensaver. You might forget that this X session is running if you’re not looking at the monitor (or if the monitor is turned off), and you’ll wonder what’s eating all the CPU suddenly after ten minutes. (Yes, this happened to me!)

**UPDATE:**

Tom A commented below with an improved version of the startup script. Rather than leave it hidden in the comments, I decided to bring it up into the article. I haven’t tested the script, but I present it here for information.

*Hi Pat,*

*Thanks so much for pulling this together. It saved me a lot of time getting this to work. In the spirit of adding to the solution, I can provide the following: I’ve tested this and found it to work on OSX 10.5.8, 10.6.8, 10.7.5, and 10.8.3. And I bashed your startup script against Andrew Berry’s generalized one to come up with the following version that does not pester you when you update-rc.d or perform various apt functions. This fixes what Ray was was asking about back in June of last year.*

#!/bin/bash ### BEGIN INIT INFO # Provides: tightvncserver # Required-Start: $remotefs $syslog # Required-Stop: $remotefs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start VNC server at boot time # Description: Start VNC Server at boot time ### END INIT INFO # The Username:Group that will run VNC export USER="pi" #${RUNAS} # The display that VNC will use DISPLAY="1" # Color depth (between 8 and 32) DEPTH="16" # The Desktop geometry to use. #GEOMETRY="x" #GEOMETRY="800x600" #GEOMETRY="1440x900" #GEOMETRY="1280x1024" GEOMETRY="1920x1080" # The name that the VNC Desktop will have. NAME="my-vnc-server" OPTIONS="-name ${NAME} -depth ${DEPTH} -geometry ${GEOMETRY} :${DISPLAY}" . /lib/lsb/init-functions case "$1" in start) log_action_begin_msg "Starting vncserver for user '${USER}' on localhost:${DISPLAY}" su ${USER} -c "/usr/bin/vncserver ${OPTIONS}" ;; stop) log_action_begin_msg "Stoping vncserver for user '${USER}' on localhost:${DISPLAY}" su ${USER} -c "/usr/bin/vncserver -kill :${DISPLAY}" ;; restart) $0 stop $0 start ;; esac exit 0

**UPDATE:**

Dennis Tsang has written up some instructions which look like they provide a quicker way of getting all this done. I haven’t tried them myself, but if I get feedback suggesting that Dennis’s instructions are good, I’ll make the link more prominent on this page.

]]>

I wrote this script for use on my MacBook Air. It takes the disk image file as a parameter, e.g.

./copytocard debian6-19-04-2012.img

**NOTE: The disk devices could be different on your computer. This script could wipe out the wrong disk if the wrong device numbers are used. I’m providing the script for convenience; please ensure you check it carefully before using it on your own computer.** Take a look at the simple instructions so you can check which device numbers you need.

#!/bin/bash [[ $# -eq 0 ]] && echo "I need an image file" && exit 1 IMG=$1 echo -n "Waiting for card" df -h | grep disk2s1 RES=$? while [[ $RES -gt 0 ]] ; do echo -n . sleep 1 df -h | grep disk2s1 > /dev/null RES=$? done echo echo "Disk found" echo "Unmounting..." diskutil unmount /dev/disk2s1 echo "Copying (please wait)..." dd bs=1m if=$1 of=/dev/rdisk2 echo "Ejecting..." diskutil eject /dev/rdisk2 echo "Done. Remove card."

]]>