It should be a matter of simply using the package manager.
This can't be put on the main public distribution as it starts with Ju, so you will need to point to the registry:
pkg> add https://github.com/rharper2/Juqst.jl
Documentation: https://rharper2.github.io/Juqst.jl/docs/build/index.html
The exampleNotebooks directory contains, suprisingly enough, some sample notebooks that show how to work this. They assume IJulia. The one that shows how to use the Stabiliser mechanisms and plotting functions is called "A stabiliser run through". It is probably worth running that one early.
While you are able to view the notebooks on github, the latex rendering of printed arrays doesn't appear to work with the github viewer, so they might be a bit difficult to read on github. If you download them and look at them through Jupyter they should render fine. As mentioned above the workbook "A stabiliser run through" goes though the stabiliser mechanisms and plotting functions and is probably worth looking at if you are interested in the Stabiliser part of this package.
The package consolidates a number of things I use when researching better methods of characterizing noise in quantum systems (often called QCVV for Quantum Control Verification and Validation). Just now it consists of three main branches:
-
Quantum Noise - which contains all the algorithms and mechanisms necessary to extract
$2^n$ eigenvalues/probabilities from a Quantum System in a single randomized benchmarking style experiment. It basically contains all the analysis code used in Efficient Learning of quantum Noise arXiv:1907.13022. The workbooks, and graph drawing software all appear in docs/example/quantumNoise and show how to reproduce all the analysis and charts in that paper (and more), using the software in this package. - Channel conversions and random channel creation. The first leans heavily on a package open-system.jl by Blake Johnson and Marcus da Silva - although rather than just import it, I have incorporated the software so I can tweak some minor aspects of it to fit in with the rest of my sofware. There are a number of minor convenience functions I have added, including the rendering I have added for arrays, the ability to generate 'Super-Vectors' and various labels for charts etc. The second part (in rchannels.jl) deals with ways of creating random noise channels, and utilised the insights contained in a paper by Rudnicki, Puchała, Zyczkowski Gauge invariant information concerning quantum channels. This allows the creation of CPTP maps that have a nice spread of various characteristics such as fidelity and unitarity.
- CHP and Clifford creation. This implements the Stabiliser formalism of Aaronson and Gottesman and the and the ability to efficiently create/select arbitrary Cliffords by Koenig and Smolin. The Stabiliser formalism is prevalent in Quantum Computing and is going to become more relevant in QCVV as we move towards implementing error detection and correction codes. We can use this work to create the circuits we need to run. For instance by setting up a Clifford in the stabiliser state, we can automatically produce the Qiskit commands to create the Clifford.
I have still to incorporate the recent Bravyi and Maslov Hadamard-free circuits expose the structure of the Clifford group paper into this code. Futher minor todos are to check we have valid stabiliser state before we try and decompose (invalid stabiliser states can cause infinite loops) and to automate the finding of the destabilisers.
This readme mainly details the CHP part of the programs included, there is documentation on the other functionality which can be found here: https://rharper2.github.io/Juqst.jl/docs/build/index.html. As previously mentioned the docs/examples directory contains Jupyter notebooks that work through a lot of the functionality.
Below is a introduction to the CHP part of the package.
Tableau(n::Integer)
sets up and returns the a CHP Tableau for n qubits.
This is based on the formalism given by: Improved Simulation of Stabilizer Circuits, Scott Aaronson and Daniel Gottesman, arXiv:quant-ph/0406196v5
The initial tableau represents a |00...0⟩ ket in the stabiliser state This stabilises with "Z" and anti-stabilises with "X"
For the purposes of this port, the tableau is exactly replicated as per the paper i.e. the "state" (Tableau.state) is an Int32 array (used as a bit array) containing the following information.
x11 ..... x1n | z11 ... z1n | r1
. \\ . | . \\ . | .
. \\ . | . \\ . | . Destabilisers
. \\ . | . \\ . | .
xn1 \\ xnn | zn1 \\ znn| rn
______________________________________________
x(n+1)1. x(n+1)n | z(n+1) ... z(n+1)n | r(n+1)
. \\ . | . \\ . | .
. \\ . | . \\ . | . Stabilisers
. \\ . | . \\ . | .
x(2n)1 \\x(2n)n | z(2n)1 \\ z(2n)n| r(2n)
Set Tableau.showRaw to true to see the underlying state as a matrix.
state = setup(number_ofQubits)
prepares the stabiliser state for the correct number of qubits in the |000..000⟩ basis state
The state is represented internally as a matrix of the form:
Aaronson/Gottesman arXiv:quant-ph/0406196
Currently I am just using Int32 Arrays, although binary arrays would save space (if it ever becomes necessary). Rows 1 to n of the tableau represent the destabiliser generators, rows n+1 to 2n represent the stabiliser generators. Each row is read as follows: if the xij and zij are 1, the de/stabiliser is a Y, if they are both 0, its I otherwise its an X or Z depending on which one is set.
output(state)
Prints the state in a human readable form. The states above the line are the 'destabiliser' state, below the line are the 'stabiliser' states.
So in a 3 qubit system the initial state of |000> is coded as
XII
IXI
IIX
---
ZII
IZI
IIZ
The following commands are defined
hadamard(t::Tableau,qubit) # apply a hadamard to the relevant qubit
phase(t::Tableau,qubit) # apply a phase gate to the relevant qubit
cnot(t::Tableau,control,target) # apply a controlled not from control qubit to target qubit
Output of the resultant state can be enabled by adding an extra true parameter
hadamard(t::Tableau,qubit,true) # hadamard as before, but show output
NOTE that these commands alter the state passed into them. I have broken Julia convention which requires functions with side effects to be written thus - hadamard!(state,qubit), however I think it is clear enough, it is after all the intended use of the function.
(Koenig/Smolin arXiv:quant-ph/1406.2170)
The idea behind this paper is that we can implement a one-to-one mapping between the cliffords and an integer (plus a random phase string).
The mapping is as follows:
Koenig/Smolin arXiv:quant-ph/1406.2170
We can generate the alpha,beta,gamma and delta via
symplectic(i,n) # i = integer represting the clifford, n is the number of qubits
Which returns the nxn arrays (alpha->delta) coded as follows:
Koenig/Smolin arXiv:quant-ph/1406.2170
More usefully these can be placed into a stabiliser tableau (that is the equivlent of passing the state |0000⟩ through a gate that implements the unitary in question as follows:
e.g.
t = cliffordToTableau(4,23,1)
Where the qubits are 4 the Clifford chosen is 23, and we have chosen the first of
This will be made more general, but just now it decomposes an arbitrary tableau
decompose(tableau)
There is an optional parameter rationalise that defaults to true. Rationalise simply eliminates 4 phases in a row, two hadamards in a row or self cancelling cnots.
This prints out the elementary gates that would reconstruct the relevant clifford unitary.
The commands are stored as string in the vector commands
The easiest way todo this is to install the Quantikz package (using the package manager). It is quite a big package so I don't have it as a required package.
Then it is simple a matter of generating the quantikz commands and passing them through:
using Quantikz
# Convert the ciruit into quantikz commands
# For some Tableau t
c = quantikzCircuit(t)
# Then display it.
displaycircuit(c)