# Juqst: JUlia Quantum Software Toolbox

# To install

It should be a matter of simply using the package manager. (Shortly I'll submit this to the Julia repo, which will simplify things further).

This has not yet been put on the main public distribution, so you will need to point to the registry:

`pkg> add https://github.com/rharper2/Juqst.jl`

The docs/examples directory contains, suprisingly enough, some example notebooks, which I aim to continually improve. They assume IJulia.

While you are able to view them 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. 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 if you are interested in the Stabiliser part of this package.

## Package Aims

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.

## Documentation

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 perviously 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.

# Sample use

## Stabiliser Circuits

`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 x_{ij} and z_{ij} 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), rather hadamard!(qubit) alters a globally defined variable, called state.**

## Arbitrary cliffords

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 4^{n} phase patterns (here n = 4).

# Decomposing a tableau

This will be made more general, but just now it decomposes an arbitrary tableau. This is not particulary efficient. Also it hangs if you pass in a tableau with an illformed state (All the stabilisers commute. The destabilisers anti-commute with the corresponding stabiliser, but commute with all the other stabilisers and the other destabilisers).

Todo: add sanity checks!

`decomposeState(tableau)`

This prints out the elementary gates that would reconstruct the relevant clifford unitary. 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.

The commands are stored as string in the vector commands

# Draw the circuit

This is a bit more involved, just now as it uses python packages. There should be an example in the notebooks. More details to be added.