TIP: | 263 |

Title: | Quantum Tcl |

Version: | $Revision: 1.2 $ |

Author: | Lars Hellström <Lars dot Hellstrom at residenset dot net> |

State: | Draft |

Type: | Project |

Tcl-Version: | 9.2 |

Vote: | Pending |

Created: | Saturday, 01 April 2006 |

A new Tcl command **qubit** is proposed. This command makes it possible to handle quantum information in the form of qubits.

As stated in TIP #131, what Tcl needs in order to succeed in the marketplace is a feature that no other programming language provides, a "killer app" as it were. The Tk toolkit, Expect, cross-platform portability, starkits, tkcon, and excellent embed/extend-ability with respect to other languages are all well and good, but they have clearly failed to push Tcl usage to the point of having critical mass. The **qubit** command makes it possible to achieve an exponential speedup for important problems and should therefore provide a powerful enough incentive that even Perl programmers would be compelled to switch languages.

Quantum computing makes use of phenomena in quantum mechanics to, at each time step, carry out an exponential amount of work using only a linear amount of hardware. The way this maps onto physical reality is pretty mind-boggling, but for the programmer it is sufficient to think of the Quantum Processing Unit (QPU) as an extremely powerful but somewhat specialised coprocessor and leave it at that. (Chances are anyway that the QPU isn't physically located in your desktop computer, as they tend to involve lots of lasers, magnets, vacuum chambers, liquid nitrogen cooling, etc.)

Quantum information display an interesting duality in that it is analog during a computation, but becomes digital as soon as one measures it. (Wave/particle duality, in case anyone came to think of that, is the kind of "mapping onto physical reality" issue that will not be treated here.) This makes the design of quantum algorithms somewhat different from the design of classical algorithms, in a manner similar to that in which the design of analog electronic circuits is different from the design of digital electronic circuits, as one must often work out the numbers rather than rely on a discrete case-by-case analysis. Another curious feature is that all fully quantum operations must be reversible, which in particular has the effect that quantum information can neither be duplicated nor (in the absence of measurements) destroyed, only rearranged. There is in particular no quantum analogue to assignments such as [set a $b], since not only need this copy the value of b, it also irrecoverably destroys the old value of a; the closest one gets to such an assignment is exchanging the values of a and b.

For more information on quantum computing in general, see e.g.:

Wikipedia article "Quantum computer" [1].

- * J. Gruska
Quantum Computing (1999), ISBN 0-07-709503-0, [2].

The quantum computing model supported by the **qubit** command is that of *quantum bits* (more commonly called *qubits*) and *quantum boolean circuits*. While other more fancy models such as "Quantum Turing Machines" exist, this is generally considered to be the most realistic model, and it is also the one most closely related to the number-of-gates complexity measure for classical computing. Should it in the future prove desirable to support also some other model, then one may do so through a separate command.

In this model, a quantum state of N qubits is completely specified by a set of 2**N complex numbers, usually known as *probability amplitudes* (they are not probabilities as such, but they do completely determine the probabilities for various events). Many different bases are possible, but in the standard (also known as the computational) basis each of these amplitudes corresponds to a particular assignment of 0s and 1s to the qubits. Operations on a quantum state can be understood as operations on the vector of amplitudes.

The **qubit** command has the five subcommands.

qubit new?-option value?...??

Allocate/create a new qubit, and return a handle for the new qubit that identifies it in subsequent operations, or throw an error if allocation/creation failed (possible causes include, but are not limited to, lack of resources on the hardware side and user having insufficient permissions). New qubits are not entangled with any of the old ones, but their state is otherwise unspecified.

The options are meant as a means for supplying extra information about the new qubit, such as for example whether it is being protected from decoherence by a scheme of quantum error correction codes (the Tcl core can easily implement such features on platforms where the C level APIs only provide raw qubits); however at present no options are defined.

qubit operategate id0?id1?...??

Perform a quantum operation (the *gate*) on one or more qubits (specified using the handles *id0*, *id1*, etc.). Returns the operation actually applied.

In the interest of generality, gates are specified as unitary matrices (this is a universal representation for quantum gates), or more concretely as lists of lists of lists of doubles. The innermost lists must have length 2 and encode the real (index 0) and imaginary (index 1) parts of an element of the matrix. Indices in the middle list level select a column and indices in the outer list level consequently a row. Put another way,

lindex $gate $i $j 0 ; # Returns Re gate(i,j) lindex $gate $i $j 1 ; # Returns Im gate(i,j)

The row/column index corresponding to the *id0* qubit having value $r0, the *id1* qubit having value $r1, etc. is $r0*(2**0) + $r1*(2**1) + ... A *gate* for operating on *n* qubits must thus have side 2***n*. Columns correspond to qubit states before the operation and rows correspond to qubit states after the operation.

An error is thrown if the number of qubit arguments does not match the side of the *gate* matrix, if not all *idN* arguments are qubit handles, if some qubit occurs twice in the list, and if *gate* is not a proper matrix (too many or too few elements in some list, elements not recognised as doubles, etc.).

An error is *not* thrown if the *gate* is not unitary. In general the operation actually applied has to be supported by the available hardware, so the **qubit operate** command (or some lower level interface) should determine which supported operation most closely approximates the specified *gate* and apply that instead. The user can check what was done (up to numeric precision) by inspecting the return value. Using a return value from **qubit operate** as the *gate* for another call should result in the exact same operation being carried out.

qubit measureid

Measures a qubit with respect to the standard basis. Returns 0 or 1 depending on the resulting state.

*Note* that measuring a qubit changes the quantum state to one in which that qubit has a pure value. If other qubits are initially entangled with the one being measured, then these will also be affected by this operation. Measuring a qubit causes it to be disentangled from all other qubits (or perhaps entangles the state of the entire universe with the qubit, depending on your philosophical point of view).

qubit disposeid

Frees/deallocates a qubit, returning it to whatever pool of resources **qubit new** got it from, but before doing that the qubit is measured to safely disentangle it from any remaining qubits. The return value is 0 or 1 as for the corresponding **qubit measure**.

qubit names

This is an instrospection command. It returns a list of all qubit handles currently available in this interpreter.

Other subcommands may be added in the future, but this set is complete for single interpreter algorithms.

The syntax of **qubit operate** was chosen to facilitate the creation of aliases for common gates, as this should make programs more readable. An alias for the CNOT (conditional not) gate can be created as

interp alias {} CNOT {} qubit operate { { {1 0} {0 0} {0 0} {0 0} } { {0 0} {0 0} {0 0} {1 0} } { {0 0} {0 0} {1 0} {0 0} } { {0 0} {1 0} {0 0} {0 0} } }

after which one can use the command

CNOT $control $target

The more significant $target qubit is negated if the $control qubit is 1 but left alone otherwise.

Another standard gate is the Hadamard gate, which can be defined as follows.

set rsqrt2 [list [expr {1/sqrt(2)}] 0] ; # Reciprocal square root of 2. interp alias {} Hadamard {} qubit operate [ list [list $rsqrt2 $rsqrt2] [list $rsqrt2 [list [expr -sqrt(0.5)] 0]] ]

The Hadamard gate is used to create states that are uniform superpositions of 0s and 1s. A simple application of that is the following random bit generator.

proc randombit {} { set id [qubit new] ; # Allocate qubit qubit measure $id ; # Make pure 0 or pure 1 Hadamard $id ; # Make an equal mix of 0 and 1 return [qubit dispose $id]; # Measure and clean up }

Note that this (provided, of course, that one believes in the standard interpretation of quantum mechanics) is not a psuedo-random bit generator, but a truly random bit generator. Even if the Hadamard gate would be slightly off (unlikely, as this is a very standard gate, but possible) this would not affect the essential randomness of the bits produced, but only the exact probability.

A third type of elementary gate is the phase shift gate, which changes the phase (but not the size) of some probability amplitude. To change the phase of the 1 amplitude of a qubit $id by the angle $phi, one would use the command

qubit operate [list {{1.0 0.0} {0.0 0.0}} [list {0.0 0.0} [ list [expr {cos($phi)}] [expr {sin($phi)}] ]]] $id

Phase changes do not change the probability distribution for any qubit measurement, but they do affect the state in ways that can lead to different probabilities further on, and thus illustrate the fact that there is more to a quantum state than the probability distribution it gives rise to here and now. As a concrete example of this, assuming $id is a qubit, and with aliases as above, the script:

set before [qubit measure $id] Hadamard $id Hadamard $id set after [qubit measure $id] expr {$before == $after}

will with probability 1 produce the result 1, whereas the script:

set before [qubit measure $id] Hadamard $id qubit operate {{{1 0} {0 0}} {{0 0} {-1 0}}} $id Hadamard $id set after [qubit measure $id] expr {$before == $after}

will with probability 1 produce the result 0. The only difference is the 180 degrees phase shift of the 1 amplitude in the explicit **qubit operate** command, which transforms one state with equal probabilities for 0 and 1 to another state with equal probabilities for 0 and 1!

One might expect that a truly Quantum Tcl would keep quantum information as "first class data", i.e., in Tcl_Objs to be passed around by value rather than as qubits that can only be passed around by name, but that is impossible (unless one goes to such lengths as to run the entire Tcl process in a QPU, which again will probably never be possible) due to a fundamental incompatibility between the laws of quantum mechanics and Tcl's Everything Is A String principle.

Beginning with the EIAS side, one may observe that for a quantum state to be encodable into a Tcl_Obj, it must be serializable - there must be a way of generating a string that completely encodes the state. Since quantum mechanics does not permit extracting that much information about a quantum state, there are only two options: either everything is kept within the QPU (not realistic), or nothing is kept in the QPU. In the latter case, one loses entirely the advantage of quantum computation, so it is rather pointless.

On the quantum side, one may observe that most of the things that are routinely done to Tcl_Objs are simply impossible to do to quantum information. The fundamental problem here is that Tcl_Objs must be duplicatable, whereas it is a theorem in quantum mechanics that quantum states cannot be duplicated (the "No cloning" theorem). Somewhat related is the problem that quantum information can only be read (used as input to some operation) once, whereas a Tcl_Obj can be written once but read an unlimited number of times.

As the **qubit** command only manipulates data and cannot be used for any form of communication, it may in principle be made available also in safe interpreters. However since **qubit new** seizes a global resource that can be expected to be in limited supply on a system, it is probably better to be safe than sorry, and therefore the **qubit** command shall initially be hidden in a safe interpreter.

Omitting the command entirely and instead alias all qubit operations to the **qubit** command of the parent interpreter is *not* a good idea, as the quick (but sloppy) implementation of this would allow untrusted code evaluated in the safe interpreter access also to the qubits of the parent.

It should be noted that the easy access to quantum computing that this command provides would have significant implications for the security of many external systems. Such issues are outside the scope of this TIP.

Besides quantum algorithms, many interesting applications of quantum information processing involves communication through the means of a quantum state shared by different parties. While fast long distance qubit transportation is physically made possible by means of quantum teleportation (which really isn't as fancy as it sounds - basically it amounts to a combination of the old TV chef trick of having prepared something in advance, in this case physically transferring a qubit, and the patchfile trick of only transmitting a diff against what was physically distributed), there are currently no standardised protocols for this, and until the time that there is there probably isn't much point in specifying some **qubit socket** command for Tcl either. It may however be observed that *non-open* commercial systems [3] transmitting quantum information over long distances are available today.

While transferring qubits between different machines obviously present some technical problems, it may seem that transferring qubits between different interpreters in the same process should at least be straightforward, but the presence of multiple threads in the process introduce complications also for this case. Concretely, transferring a qubit from one thread to another will in general cause these threads to become entangled! In order to not make thread maintenance even more complicated by introducing the concept of quantum deadlock due to thread tangles, this TIP does not treat the subject of a mechanism for transferring qubits between interpreters.

A Tcl level emulation of the **qubit** command (minus some error checking, but also not requiring a QPU) is available as SF patch no 1462755 [4]. This emulation uses the standard Tcl rand() function for generating random numbers, so it is not cryptographically safe. Also note that it internally uses of some tcllib packages, which must therefore be available.

No C implementation exists at present, but creating one is a simple matter of programming (SMOP). In particular, since the details of the command implementations for the foreseeable future almost surely will have some dependence on the particular hardware present, it seems appropriate to assign to each subcommand an entry in the internal stubs table and then simply have the main *Tcl_QubitObjCmd* call each as appropriate.

int Tcl_QubitObjCmd( ClientData clientData, /* Might be used. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[]) /* Argument objects. */ { int index; static CONST char *options[] = { "dispose", "measure", "names", "new", "operate", (char *) NULL }; enum options { QUBIT_DISPOSE, QUBIT_MEASURE, QUBIT_NAMES, QUBIT_NEW, QUBIT_OPERATE }; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "subcmd ?arg ...?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], options, "subcommand", 0, &index) != TCL_OK) { return TCL_ERROR; } switch ((enum options) index) { case QUBIT_DISPOSE: return TclQubitDisposeObjCmd(clientData, interp, objc, objv); case QUBIT_MEASURE: return TclQubitMeasureObjCmd(clientData, interp, objc, objv); case QUBIT_NAMES: return TclQubitNamesObjCmd(clientData, interp, objc, objv); case QUBIT_NEW: return TclQubitNewObjCmd(clientData, interp, objc, objv); case QUBIT_OPERATE: return TclQubitOperateObjCmd(clientData, interp, objc, objv); } /* * We won't get this far. */ Tcl_Panic("unhandled subcommand"); return TCL_ERROR; }

A fallback definition of *TclQubitNewObjCmd* that can be used when Tcl is compiled without hardware QPU support is:

int TclQubitNewObjCmd( ClientData dummy, /* Not used. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *CONST objv[]) /* Argument objects. */ { int optArgIdx, index; static CONST char *optionStrings[] = { (char *) NULL /* Currently there are no options. */ }; if (objc % 2 != 0) { Tcl_WrongNumArgs(interp, 2, objv, "?-option value ...?"); return TCL_ERROR; } for (optArgIdx = 2 ; optArgIdx < objc ; optArgIdx += 2) { if (Tcl_GetIndexFromObj(interp, objv[optArgIdx], optionStrings, "option", TCL_EXACT, &index) != TCL_OK) { return TCL_ERROR; } /* * When options are added, handle them here. */ } /* * Fail gracefully. */ Tcl_SetErrno(ENXIO); /* QPU not configured. */ Tcl_AppendResult(interp, "couldn't allocate a qubit: ", Tcl_PosixError(interp), NULL); return TCL_ERROR; }

Other fallback definitions obviously follow the same pattern. Filling in the details should be a cultivating exercise for Robert Abitbol.

This document has been placed in the public domain.

[Index] [History] [Edit] [HTML Format] [Source Format] [LaTeX Format] [Text Format] [XML Format] [*roff Format *(experimental)*] [RTF Format *(experimental)*]