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
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 3. Controlled Rotations
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".
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.
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.
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, mathjax.org renders all the LaTeX.
Also, qiskit was the inspiration for this calculator,
and I use a modified version of the qiskit number pretty-printer.
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.
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.
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.
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.
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 \).
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().
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:
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.
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.
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.
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.
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
Gates with No Angles
Gates with Angles
Gate Generation: qcc
Gate Generation: qc
Gate Generation: perm
Random things: randomAngle and randomState
Use eq() instead of ==
The @ operator
Rounding and Pretty Printing