User Manual for Calculator Customized for Quantum Computation Equations

Table of Contents

How to Use the Calculator
Go to a Standalone Calculator
It's all built on math.js
Why Didn't I Use [your favorite package]?
Dirac notation: ket bra braket ketbra
Gates with No Angles: I X Y Z H S Sdg T Tdg SX SXdg SWAP
Gates with Angles: P Rx Ry R U
Gate Generation: qcc, qc, and perm
Random things: randomAngle and randomState
Use eq() instead of ==
The @ operator
Rounding and Pretty Printing
Regression Tests


Among the ways to use the calculator are 1) as a stand-alone (e.g. this one), and 2) as annotation for an html document (e.g. the manual you are now reading, and regression tests for the calculator).
There are sets of equations throughout this manual, and clicking on the equations makes the input equations visible. You can then edit them and see the results. Like in a jupyter notebook, this encourages learning through experimenting.

Here's how this got started. When I read IBM's textbook "Learn Quantum Computation using Qiskit", there was a simulator for experimenting with quantum computing, but there was no calculator to experiment with equations. This is the calculator I wanted to be there. For example, if you look at this discussion of phase kickback, you'll see these equations (I copied just the latex of the equations from the textbook): $$ X|{-}\rangle = -|{-}\rangle $$ $$ \begin{aligned} \text{CNOT}|{-}0\rangle & = |{-}\rangle \otimes |0\rangle \\ & = |{-}0\rangle \\ \quad & \\ \text{CNOT}|{-}1\rangle & = X|{-}\rangle \otimes |1\rangle \\ & = -|{-}\rangle \otimes |1\rangle \\ & = -|{-}1\rangle \\ \end{aligned} $$ $$ \begin{aligned} \text{CNOT}|{-}{+}\rangle & = \tfrac{1}{\sqrt{2}}(\text{CNOT}|{-}0\rangle + \text{CNOT}|{-}1\rangle) \\ & = \tfrac{1}{\sqrt{2}}(|{-}0\rangle + X|{-}1\rangle) \\ & = \tfrac{1}{\sqrt{2}}(|{-}0\rangle -|{-}1\rangle) \\ \end{aligned} $$ $$ \begin{aligned} \text{CNOT}|{-}{+}\rangle & = |{-}\rangle \otimes \tfrac{1}{\sqrt{2}}(|{0}\rangle - |1\rangle )\\ & = |{-}{-}\rangle \\ \end{aligned} $$

Now compare them to mine:

Other than the second equation, where I defined CNOT, my equations look quite similar to the ones from the textbook. But mine are the output of my calculator. Click on the equations and you'll see the input. This allows you to experiment with the equations. Plus there's a subtle but important difference—where the textbook has \(X|{-}1\rangle\), my associated equation has \((X \otimes I) |{-}1\rangle \). I don't know if that was a typo in the textbook, or if it's a case of "you know what we mean". What they meant was to apply the X to qubit 1 and not qubit 0. The calculator demands that you make that explicit, because it doesn't "know what you mean". Executable equations keep you honest.

Continuing my sales pitch, below are identities from section 2.4, More Circuit Identities of the qiskit textbook. This shows how well the calculator handles the equations.

section 1. Making a Controlled-Z from a CNOT

section 2. Swapping Qubits

section 3. Controlled Rotations

section 4. The Toffoli

The last four equations demonstrate how the almost-CCX gate applies an X to the target when the controls are 11, does nothing when they're 00 or 01, and applies a Z when 10, which, as the textbook says, "only induces a relative phase".

How to Use the Calculator

There are two sections to each calculator. First the textarea for editing equations, then the results rendered with latex. If only the latex results are visible, click on the results to make the textarea visible.

When the textarea is visible, there are buttons between the textarea and the results. Here's what they do:

The "parenthesis" radio button selects "keep", "auto", or "all". See the "parenthesis" section of the math.js manual for an explanation of the options.

The "implicit" radio button selects "hide" or "show". See the "implicit" section of the math.js manual for an explanation of the options.

Or maybe you prefer this explanation of the parenthesis and implicit options:

Click on the equations to get the textarea and buttons. Note that the default for parenthesis is "keep", and it's leaving the equation unchanged from how it's entered in the textarea. Click on "auto" and it removes the unnecessary parens. Click on "all" and it puts in parentheses everywhere it can. Moving on to implicit, note that the default is hide, and it's hiding the implicit multiplication. Click on "show" and it shows the multiplication explicitly.

The "Re-evaluate" button does just that, re-evaluates the equations. It's unnecessary unless you've used the randomQubit or randomState function, in which case you get new random values.

The "User Manual" button opens the user manual in a new tab. Nice for checking on some function detail when you're in the middle of entering an equation. Perhaps silly if you're already in the user manual, like you are now.

A note on not bricking your browser: The calculator can handle computations with matrices large enough that their latex rendering gets painfully slow. The example below shows such matrices. You probably don't want to display one of those 6-qubit results. Click on the equations to see the original textarea and you'll see how I avoid that. One way is to use the matrices inside an expression for which the result is not a huge matrix, like the first and last lines in the example. If you want to assign a huge matrix to a variable, you can put a semicolon at the end of an assignment, and that tells the calculator not to display the assignment. The combination of "a=expr;eq(a,expr)" lets you effectively see the assignment in the form of an eq(), which shows how the matrix is built without displaying it.

Go to a Standalone Calculator

Click here to go to a standalone calculator

There's no difference between the standalone calculator linked to above, and all the calculators in this manual, other than there's just one in the standalone, and it has no initial equations in the textarea. These files can be templates for how to setup calculators for yourself.

It's all built on math.js

math.js is a basic calculation engine with hooks for customizing. So I customized it, mostly by adding the functions, and one operator, listed in the table of contents, above. Other than for my customization, see math.js for all documentation.

While I'm doling out credit, renders all the LaTeX. Also, qiskit was the inspiration for this calculator, and I use a modified version of the qiskit number pretty-printer.

Why Didn't I Use [your favorite package]?

Maybe I didn't know about it, or I tried it and it was too slow, or it required sacrificing some functionality that I didn't want to lose, or it wasn't open source. I really wanted to use Jupyter because I love the Jupyter notebook approach, but using Jupyter meant (you!) having to install stuff, and it doesn't seem to have a way to hide the inputs (just the outputs), which would mean this manual would be messier. JupyterLite has hide all inputs, although it replaces them with elipses. Not too bad. But JupyterLite has some problems, including that it's not an official project at the time of this writing. Yikes! Anyway, that's the kind of agonizing I went through when choosing what packages to use.

Dirac Notation

Probably best just to show examples:

The args are strings (e.g. '01' or "01"). The qubits of the arg are 0's, 1's, +'s, and -'s.

Gates with No Angles

Probably best just to show them all:

The gates without angles are actually constants rather than functions. If they were functions you'd have to add "()" to their names. Nobody wants that.

Gates with Angles

Probably best just to show examples:

If you're puzzled about what's going on with the angle names, it turns out math.js turns variables that are names of Greek letters into a latex rendering of the letter. How cool is that? I haven't found any mention of it in their manual. I only discovered it because I was going to add a wrapper to make that happen, and typed in a test case before coding it, and discovered it was already working.

Gate Generation: qcc

qcc() can generate a gate similarly to how one does with the simulator in qiskit. You're building a result gate with one or more internal gates. qcc() also lets you specify any number of control qubits for the internal gates. For example:

The first arg of qcc is the number of qubits. The rest of the args come in pairs, the first defining the internal gate and the second defining the control and target qubits for the internal gate. The control and target qubits are specified with a string (e.g. '01' or "01") The qubits are either all target qubits, or control qubits and target qubits separated by a '>'. The number of target qubits must match the number of qubits in the internal gate, and they must be sequential and ascending. (Yes, I considered allowing non-consequtive target qubits, and in any order, but I couldn't come up with a clean way to represent it in the display for qcc(). Use the perm() gate.) The target qubits are required. There can be 0 or more control qubits. This limits you to a ten-qubit result gate. I don't think you want to have more than that.

The gate isn't limited to internal gates without angles, like X. It could be Rx(pi/2), as you see in the examples. You could also build a gate and put it in a variable and use that as an internal gate, as you see in the examples.

The display shows each internal gate in a column, with the name of the internal gate in its target row(s), 'c' in its control rows, if there are any, and the rest are '-'. The qcc display is bracketed by curly brackets. Square brackets make it look too much like a matrix, and straight brackets (pipes) make it look like a magnitude.

The first two examples show CNOT1 and CNOT2 defined, the two forms of a controlled-X, one with the control qubit on 0, and the other with the control qubit on 1. The next two examples show how you can surround each with H's to get the other. The 3-qubit example compares \(Z \otimes Y \otimes X \) to building it with qcc(). Next, there's an example of using an internal gate with an angle. Finally, there's surrounding \(Y \otimes X \) with SWAPs to get \(X \otimes Y \).

Gate Generation: qc

I messed up. I made qc() multiply the gates from left to right. To make it look like the circuits in qiskit, it has to multiply from right to left. I left qc() unchanged for backward compatibility, and added qcc(), which stands for qc-corrected. Take a look:

The first two show the ordering. Note that it draws qc() and qcc() the same, so you have to look at the source equations to see that the first line is qc() and the second is qcc().

Gate Generation: perm

The perm gate permutes the qubits. The arg is a string listing qubits in the new order, so '012' is no change, and '021' leaves one unchanged and swaps the other two. Here are the equivalences for all the 2-qubit perms:

Here are the equivalences for all the 3-qubit perms:

Here we see that not changing the order of the qubits is the identity, as is reversing the order twice and rotating three times:

Random things: randomAngle and randomState

The "randomAngle()" function generates a random angle between \(-2\pi\) and \(2\pi\), and the "randomQubit()" function generates a random qubit, normalized so the sum of the squares of the states is 1. I would like to include symbolic evaluation and simplification, but it's not trivial, so in the meantime a trivial way to test an equivalence with some level of assurance is with random values, for example:

Click on the results to make the textarea and buttons visible, then click in the Re-evaluate button to evaluate with new values for \(\alpha\), \(\omega\), and \(\Psi\), and therefore another test of the equivalences. Not the formal verification you can get with symbolic evaluation, but, as I said, some level of assurance.

Use eq() instead of ==

When comparing matrices, the == operator in math.js returns a matrix with a 1 where they're equal, and 0 where not. That's no fun if all you want is "true" or "false". So the eq() function turns that into true iff all elements are 1. Further, math.js has some behavior that I didn't think we want in our context, so I changed that. Finally, math.js may not do what you want when you say "a==b==c". Use eq(a,b,c). Examples:

In the examples you see how == returns a matrix of element-by-element comparison results. And you see a comparison of three values. Plus you see the line breaks added to make a comparison of several elements more readable, like in the introduction at the beginning of this manual.

The @ operator

I got tired of typing in the kron() function. I wanted an operator. I repurposed the .* operator, which had the right precedence, felt kinda like \( \otimes \), and I hoped it wouldn't be missed too much. So a.*b turns into kron(a,b). Except I didn't like typing two letters, particularly those two. So you type @ into the textarea equations, that gets turned into .* before parsing, then I intercept the .* function at evaluation time and substitute kron(). And of course display it as \( \otimes \). It may seem like a lot of bother, but \( \otimes \) is such an important and frequently-used operator that I figured it was worth it.

Rounding and Pretty Printing

Quantum computing gates often look messy when their values are printed because it's not unusual to have something like \(\frac{1}{\sqrt{2}}\) as a factor. So results are "pretty-printed" by looking for common factors like \(\frac{1}{\sqrt{2}}\). Calculations are not performed symbolicly, so results that "should" be integers can be slightly off. The pretty-printer rounds to integers when they're within \(10^{-14}\). (eq() also returns true when numbers are within \(10^{-14}\).) The pretty-printer also looks for a fraction whose numerator and denominator add to less than twenty. When the printer fails to find something "nice", it prints a floating point number with five digits of precision.