# SUMMARY notebook¶

This notebook scans the directory in which it lives to find all jupyter notebooks (other than itself) in that directory. It then prints for every notebook it finds (1) a hyperlink to the notebook, and (2) the first cell (which is always markdown) of the notebook. This way you can read a nice, automatically generated summary of all the notebooks without having to open all of them. If you find a notebook that you want to explore further, you can simply click on its link to open it.

In [8]:
import os
import json
from IPython.display import display, Markdown

# the name of this file
this_fname = 'SUMMARY.ipynb'
fname_to_md = {}
for fname in sorted(os.listdir('./')):
if fname[-6:] == '.ipynb'  and fname != this_fname:
# print('------------', fname)
with open(fname, 'r', encoding="utf-8") as f:
fname_to_md[fname] = ''.join(fdata['cells'][0]['source'])
# print(fname_to_md)
pre_sep = '\n\n<hr style="height:10px; background-color: blue;">\n\n'
full_md = ''
k = 1
num_nb = len(fname_to_md)
for fname, md in fname_to_md.items():
sep = pre_sep
sep += '[<a href="' + fname + '" target= "_blank">' + fname + '</a>] ' \
+ str(k) + '/' + str(num_nb) + '\n\n'
full_md += sep + md
k += 1
display(Markdown(full_md))


# Bell and CHSH inequalities¶


The purpose of this notebook is to simulate the CHSH experiment described in the IBM Quantum Experience tutorial in the section entitled

Multiple Qubits, Gates, and Entangled States/Entanglement and Bell Tests

[Fedortchenko-paper.ipynb] 2/27

## Teleportation experiment from paper by Fedortchenko¶

This notebook uses Qubiter to illustrate a pedagogical Teleportation experiment performed by S. Fedortchencko on IBM Quantum Experience, and described by him in the paper

https://arxiv.org/abs/1607.02398


# MeanHamilMinimizer native scipy¶

The purpose of this notebook is to describe a naive but pedagogical, first baby step, in the implementation of what is called in Qubiter the Mean Hamiltonian Minimization problem.

The qc history of this problem started with quantum chemists planning to use on a qc the phase estimation algo invented by Kitaev? (an algo that is also implemented in Qubiter) to estimate the energy levels ( eigenvalues) of simple molecules, initially H2. Then a bunch of people realized, heck, rather than trying to estimate the eigenvalues of a Hamiltonian by estimating the phase changes it causes, we can estimate those eigenvalues more efficiently by estimating the mean value of that Hamiltonian as measured empirically on a qc. Basically, just the Rayleigh-Ritz method, one of the oldest tricks in the book. One of the first papers to propose this mean idea is https://arxiv.org/abs/1304.3061 Their algo is commonly referred to by the ungainly name VQE (Variational Quantum Eigensolver) VQE was originally applied to do quantum chemistry with a qc. But now Rigetti and others have renamed it hybrid quantum-classical quantum computing and pointed out that it's an algo that has wide applicability, not just to quantum chemistry.

The idea behind hybrid quantum-classical is very simple. One has a classical box CBox and a quantum box QBox. The gates of QBox depend on N gate parameters. QBox sends info to CBox. CBox sends back to QBox N new gate parameters that will lower some cost function. This feedback process between CBox and QBox continues until the cost is minimized. The cost function is the mean value of a Hamiltonian which is estimated empirically from data obtained from the qc which resides inside the QBox.

To minimize a function of N continuous parameters, one can use some methods like simulated annealing and Powell that do not require calculating derivatives, or one can use methods that do use derivatives. Another possible separation is between methods that don't care which local minimum they find, as long as they find one of them, and those methods that try to find the best local minimum of them all, the so called global minimum. Yet another separation is between methods that allow constraints and those that don't.

Among the methods that do use derivatives, the so called gradient based methods only use the 1st derivative, whereas other methods use both first (Jacobian) and second (Hessian) derivatives. The performance of those that use both 1st and 2nd derivatives degrades quickly as N grows. Besides, calculating 2nd derivatives is very expensive. Hence, methods that use the 2nd derivatives are practically useless in the neural network field where N is usually very large. In that field, gradient based methods rule.

A method that uses no derivatives is Powell. A gradient based method that is designed to have a fast convergence rate is the Conjugate Gradient (CG) method. Another gradient based method is back-propagation (BP). BP can be implemented as distributed computing much more easily than other gradient based methods so it is favored by the most popular computer programs for doing distributed AI, such as PyTorch and Tensorflow.

Qubiter can perform minimization using various minlibs (minimization software libraries) such as 'scipy', 'autograd', 'pytorch', 'tflow'. It can also use various devices (aka simulators or backends), either virtual or real, to do the minimization.

Non-scipy minlibs implement backprop.

The 'scipy' minlib is a wrapper for the scipy function scipy.optimize.minimize. This scipy umbrella method implements many minimization methods, including Powell and CG.

https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html

By a native device, we mean one that uses Qubiter native simulators like SEO_simulator.

So, without further ado, here is an example of the use of class MeanHamilMinimizer with a scipy minlib and native device.

• Feedback loop between Qubiter and Qubiter

# MeanHamilMinimizer, native with Tensorflow¶

• Feedback loop between Qubiter and Qubiter
• minimization via tensorflow

This notebook is a counterpart to the notebook MeanHamilMinimizer_native_with_autograd. The first problem in both notebooks is identical and done all natively, but here it is done with scipy instead of autograd.

• Feedback loop between Qubiter and Qubiter
• minimization via scipy

• Feedback loop between Qubiter and Rigetti QVM

This notebook calls Rigetti's method QVMConnection() which only works if you first:

• install the Rigetti Forest SDK available at https://www.rigetti.com/forest
• open a second terminal (besides the one that runs this notebook) and type "qvm -S" in it
• open a third terminal and type "quilc -S" in it

# MeanHamilMinimizer_rigetti_scipy¶

• Feedback loop between Qubiter and Rigetti QVM
• minimization via scipy.optimize.minimize

This notebook calls Rigetti's method QVMConnection() which only works if you first:

• install the Rigetti Forest SDK available at https://www.rigetti.com/forest
• open a second terminal (besides the one that runs this notebook) and type "qvm -S" in it
• open a third terminal and type "quilc -S" in it

## Say "Hello World" With Qubiter¶

The purpose of this notebook is to illustrate how to use Qubiter to simulate ( i.e., predict the outcome of) a simple quantum circuit with a few basic gates

Below, we won't always give the precise definition of each gate. You can find the precise analytical/numerical definition of all gates implemented by Qubiter in the document entitled qubiter_rosetta_stone.pdf included with the Qubiter distribution.

# Stairs Circuit and its gradients evaluated using native simulators¶

A "quantum cost function" is the mean value of a Hermitian operator, wherein that mean value is calculated empirically from the data yielded by a physical quantum computer. (In this notebook, however, we fake that data with a Qubiter simulator. Just warming up. Brrmm! Brrmm! Everything is setup so that calls to a real physical qc such as Rigetti's qc can be easily substituted for the calls to the Qubiter simulator)

A Stairs circuit is a quantum circuit that in its full generality can parametrize a completely general quantum state vector.

In this notebook, we consider a special quantum cost function in which a Stairs circuit provides the state vector with which the mean values are calculated. I like to say that the Stairs circuit is the kernel of the quantum cost function. Our ultimate intention is to minimize this cost function using gradient descent. But to do that, we must first calculate the derivatives (gradients) of the cost function. That is what we will do in this notebook: calculate all the derivatives of a quantum cost function whose kernel is a Stairs circuit.

In particular, this notebook runs through their paces 4 Qubiter classes that increasingly build on each other

• StairsCkt_writer, writes English and Picture files for a Stairs quantum circuit
• StairsDeriv_writer, writes English and Picture files for several quantum circuits that are needed to evaluate the derivatives of a Stairs circuit
• StairsDeriv_native, evaluates the 4 derivatives of a single gate of a Stairs circuit. It uses native Qubiter simulators to do this. Qubiter also has an analogous class StairsDeriv_rigetti that uses Rigetti simulators or their real physical qc. We will demo that class in a future notebook.
• StairsAllDeriv_native, evaluates all the derivatives, for all the gates of a Stairs circuit. It uses native Qubiter simulators to do this. Qubiter also has an analogous class StairsAllDeriv_rigetti that uses Rigetti simulators or their real physical qc. We will demo that class in a future notebook.

For an explanation of the theory behind the software that is being demo-ed in this notebook, see the following pdf included with the Qubiter distribution.

Title: Calculation of the Gradient of a Quantum Cost Function using "Threading". Application of these "threaded gradients" to a Quantum Neural Net inspired by Quantum Bayesian Networks,

# Stairs Circuit, its gradients evaluated using Rigetti QVM¶

Before reading this Jupyter notebook, we recommend that you first read the earlier notebook named

Stairs_circuit_and_its_gradients_in_native.ipynb

located in the same folder in the Qubiter repo as this notebook. In that earlier notebook, we use the Qubiter (i.e., native) simulator to evaluate the gradients of a special quantum cost function. In this notebook, we evaluate the same gradients, but, instead of the native simulator, we use the Rigetti QVM (quantum virtual machine), which is a bit more complicated than using the native simulator.

Qubiter supports, as a single gate, a general U(2) operation with any number of controls, of either the T (full circle) or F (empty circle) kind. Such gates are fundamental to the Stairs circuit that we are considering. For now at least, Rigetti doesn't support such gates in a single step, so we have figured out a work-around until they do. Programmers are masters at figuring out work-arounds.

What we do is use Qubiter's class CGateExpander to expand all multi-controlled U(2) gates into simple CNOTs and single qubit rotation gates. This is a very basic set of gates that Rigetti's real and virtual machines can handle. (Also, right before the expansion, we substitute each placeholder variable (aka parameter) by its float value.) But CGateExpander takes as input a quantum circuit written in Qubiter's language and returns a new, expanded, quantum circuit also written in Qubiter's language. So further processing is required. We then use Qubiter's class Qubiter_to_RigettiPyQuil to translate the expanded quantum circuit from Qubiter's to Rigetti's language. Once we have translated all the quantum circuits to Rigetti's language, we are home free. From there on, we just follow very similar steps to those performed in the earlier, all-native notebook.

This notebook demos 2 Qubiter classes:

• StairsDeriv_rigetti, evaluates the 4 derivatives of a single gate of a Stairs circuit. It uses Rigetti simulators or their real physical qc to do this.
• StairsAllDeriv_rigetti, evaluates all the derivatives, for all the gates of a Stairs circuit. It uses Rigetti simulators or their real physical qc to do this.

This notebook calls Rigetti's method QVMConnection() which only works if you first:

• install the Rigetti Forest SDK available at https://www.rigetti.com/forest
• open a second terminal (besides the one that runs this notebook) and type "qvm -S" in it
• open a third terminal and type "quilc -S" in it

## Teleportation example showcasing IF_M blocks¶

This notebook uses Qubiter to illustrate quantum Teleportation of the pure state of one qubit (at 0) to another qubit (at 2) with the help of an ancilla qubit (at 1).

The purpose of this notebook is not to teach about the "theory" behind quantum Teleportation. For that, the reader can go to numerous sources on the internet (Wikipedia, course notes, etc.) The purpose is to showcase some of the features of Qubiter, especially IF_M blocks (and also PRINT statements and calculations and plotting of various density matrices associated with any quantum circuit).

For a full inventory of Qubiter English file commands, see Qubiter's Rosetta Stone pdf

IBM has posted at https://github.com/QISKit/qiskit-tutorial, a jupyter notebook similar to this one, analysing the same quantum circuit for quantum Teleportation from one qubit to another. Their notebook uses IBM's qasm language instead of Qubiter's language so you might profit from comparing their notebook to this one to decide which qc language you prefer. Qubiter includes subroutines that can translate its language to IBM qasm that can then be run on IBM qc hardware.

## 量子传输和测量模块的展示¶

QUbiter也支持自动生成量子线路的语言文件。感兴趣的读者可以在此找到 Qubiter语言文件的详解

# Translating from Qubiter to Xanadu PennyLane¶

The purpose of this notebook is to illustrate how to translate a Qubiter English file for a quantum circuit, into a Xanadu Pennylane "qnode"

Next, we will create 2 Qubiter English files and then translate them to Pennylanese

References

abbreviations:

• ax= axis
• dwrt= derivative with respect to

# Examples of usage of Gate Angle Placeholder¶

The word "Placeholder" is used in Qubiter (we are in good company, Tensorflow uses this word in the same way) to mean a variable for which we delay/postpone assigning a numerical value (evaluating it) until a later time. In the case of Qubiter, it is useful to define gates with placeholders standing for angles. One can postpone evaluating those placeholders until one is ready to call the circuit simulator, and then pass the values of the placeholders as an argument to the simulator’s constructor. Placeholders of this type can be useful, for example, with quantum neural nets (QNNs). In some QNN algorithms, the circuit gate structure is fixed but the angles of the gates are varied many times, gradually, trying to lower a cost function each time.

In Qubiter, legal variable names must be of form #3 or -#3 or #3*.5 or -#3*.5 where 3 can be replaced by any non-negative int, and .5 can be replaced by anything that can be an argument of float() without throwing an exception. In this example, the 3 that follows the hash character is called the variable number

NEW! (functional placeholder variables) Now legal variable names can ALSO be of the form my_fun#1#2 or -my_fun#1#2, where

• the 1 and 2 can be replaced by any non-negative integers and there might be any number > 0 of hash variables. Thus, there need not always be precisely 2 hash variables as in the example.
• my_fun can be replaced by the name of any function with one or more input floats (2 inputs in the example), as long as the first character of the function's name is a lower case letter.

The strings my_fun#1#2 or -my_fun#1#2 indicate than one wants to use for the angle being replaced, the values of my_fun(#1, #2) or -my_fun(#1, #2), respectively, where the inputs #1 and #2 are floats standing for radians and the output is also a float standing for radians.

[forbidden_cnot_expansions.ipynb] 17/27

# Forbidden-CNot Expansions¶

Most chips are not fully connected (not all pairs of qubits are physically connected). Furthermore, even if two qubits are connected, one of them may be forbidden as a target of a CNOT between the 2 qubits. The Qubiter file ForbiddenCNotExpander.py contains an "expander" class of the same name that is designed to circumvent this chip limitation.

The class reads an English file and outputs a new English file and corresponding Picture file. The new English file differs from the initial English file in that each forbbiden CNOT is expanded into a sequence of Hadamards and allowed, elementary CNOTs.

This notebook shows 2 examples of the usage of this class.

[gate-expansions.ipynb] 18/27

# Gate Expansions¶

This notebook is intended to illustrate various gate expansions. Qubiter allows one to write on a single line in an English file many types of U(2) matrices with 0, 1, or more controls attached to it. However, there are well known identities for expanding such gates into a sequence of (1) single qubit rotations and (2) CNOTs with a single control. This is useful because most quantum computers (for example, IBM Quantum Experience) can only perform (1) and (2). Expansions into (1) and (2) can be performed automatically by Qubiter. Here is how.

The expansions used by Qubiter were all discovered long ago. They can all be found in the following 1995 quantum computing paper:

https://arxiv.org/abs/quant-ph/9503016

[ghz_state.ipynb] 19/27

# GHZ state¶


The purpose of this notebook is to simulate the GHZ experiment described in the IBM Quantum Experience tutorial in the section entitled

Multiple Qubits, Gates, and Entangled States/GHZ states

If you understand our "Bell_and_CHSH_inequalities" notebook, this notebook uses very similar math.

It uses the following results whose proofs use techniques already covered in our "Bell_and_CHSH_inequalities" notebook

$\bra{ b_X} = \bra{ b_Z} H$

$\bra{ b_Y} = \bra{ b_Z} H S^\dagger$

for $b=0, 1$.

$\bra{\psi} \sigma_A(0) \sigma_B(1) \sigma_C(2)\ket{\psi} = \sum_{b_0 + b_1 + b_2 = 0, 2} Prob(b_0, b_1, b_2) - \sum_{b_0 + b_1 + b_2 = 1, 3} Prob(b_0, b_1, b_2)$

# Loops at English File level using Loop Files¶

Before reading this notebook, we recommend that you first learn how to use placeholders in Qubiter, because placeholders and loops at the English file level are both used heavily in this notebook. They both go naturally together. Placeholder usage is illustrated in the notebook called examples_of_placeholder_usage.ipynb located in the same folder as this one.

You can have loops at either the Python library level or the machine language level (i.e., English file). Both accomplish the same purpose. This notebook is only important to you if you want to use loops in an English file. The following talk explains some of the motivation and pros and cons of doing this.

http://www.ar-tiste.com/jan2019QubiterPlaceholderAndLoops.pdf

[phase_est_examples.ipynb] 21/27

# Quantum Phase Estimation Examples¶

This notebook gives some examples of how to use Qubiter to write and simulate a quantum circuit that does quantum phase estimation (qPE).

Even though qPE was invented by Kitaev, it can be understood (See IBM Quantum Experience Tutorial for the details) as a quantum computer version of a much earlier model, namely, the von Neumann Pointer-System model for a quantum mechanical measurement.

In the case of quantum computers, the Pointer in von Neumann's model is represented by several "pointer qubits" and the System by several "system qubits". The matrix U whose eigenvalues we wish to find acts on the System qubits.


[phase_est_iterative.ipynb] 22/27

# Quantum Phase Estimation, Iterative¶


To economize in qubits, the References below advocate using the so called iterative Quantum Phase Estimation (iterative qPE). Whereas the usual qPE uses multiple pointer qubits and gives the answer in one shot (passage through a single circuit), the iterative qPE uses only a single pointer qubit but requires passage through multiple circuits, with the parameters of each circuit depending on the final pointer measurement of the previous circuit. This works because the kickback phases which each power of U sends to the pointers in the nomal qPE are cummulative: the k'th pointer gets a kickback phase which includes the kickback phases accrued by all previous pointer qubits.

In this example, we use

$U = e^{i*rads*\sigma_Z}$

for some Real number $rads$ and we use initial state $\ket{0}$, so $e^{i*rads}$ is the eigenvalue we seek.

Here are some of the equations used in the code below

for  k in range(num_reps):

|           H
|           exp(i*alpha(k)*sigz)
U^(2^k)[email protected]
|           H
|           measure n(k) here

$\alpha(0) = n(0) =0$

$\alpha(k+1) = 2\alpha(k) + \frac{\pi}{2} n(k)$

$\alpha(k) = \pi 2^{k-2}\sum_{b=0}^{k-1} \frac{n(b)}{2^{b}}$

$rads = \frac{\alpha(num\_reps-1)}{2^{num\_reps-2}}$

## References¶

2. https://arxiv.org/abs/1605.03590 by Microsoft team

[quantum_CSD_compiler_intro.ipynb] 23/27

# Quantum CSD Compiling Intro¶

The purpose of this notebook is to give a quick introduction to Qubiter's CSD quantum compiler capabilities.

By a quantum complier, we mean a computer program that takes as input an arbitrary unitary matrix $U$ of dimension $N=2^n$ and returns a SEO (sequence of elementary operations, in this case CNOTs and single qubit rotations) that equals $U$. There are various kinds of quantum compilers. Suppose $U$ is of the form $U=e^{-itH}$, where $t$ is time and $H$ is the Hamiltonian operator. If $H$ has a form which is known a priori, a situation that is common in Physics and Chemistry, then a popular way of expanding $U$ is by using the Trotter-Suzuki approximation. If the form of $H$ is not known a priori as is common in Artificial Intelligence, then we recommend using the CS (Cosine-Sine) decomposition of Linear Algebra. Both methods are already implemented in Qubiter, but this notebook is about the CSD.

Doing CSD quantum compiling with Qubiter requires using the classes in the quantum_CSD_compiler folder, which will only work properly if you install, besides all the Qubiter Python files and a Python distro that includes numpy and scipy (for example, Anaconda), some binary libraries prepared by Artiste-q.net which include a Python wrapper for a LAPACK subroutine called cuncsd.f that performs CSDs. How to install those binary libraries is explained elsewhere in this site. Henceforth, we will assume all the necessary files have been installed on your computer if you want to redo the calculations.

The quantum_CSD_compiler folder includes a pdf called csd-intro.pdf that gives an introduction to the CSD.

Some external references:

1. R.R. Tucci, A Rudimentary Quantum Compiler(2cnd Ed.) https://arxiv.org/abs/quant-ph/9902062

2. Qubiter 1.11, a C++ program whose first version was released together with Ref.1 above. Qubiter 1.11 is included in the quantum_CSD_compiler/LEGACY folder of this newer, pythonic version of Qubiter

3. R.R. Tucci, Quantum Fast Fourier Transform Viewed as a Special Case of Recursive Application of Cosine-Sine Decomposition, https://arxiv.org/abs/quant-ph/0411097

# 量子编译简介¶

1. R.R. Tucci,《初级量子编译》（第二版）

2. Qubiter 1.11: 基于 C++ 的原始 Qubiter 版本。最初一版 Qubiter 1.11 和文献1同步发布。在新的 Qubiter 版本（基于 Python）的 'quantum_CSD_compiler/LEGACY' 文件夹中包含了 Qubiter 1.11 原始程序。

3. R.R. Tucci,《量子快速傅立叶变换 - 正余弦分解递归应用举例》

# Translating Qubiter English file to AnyQasm file¶

aqasm= a quantum assembly language, a low level quantum language, containing a small but universal set of quantum gates such as CNOTs and single qubit rotations.

Note that in the device_specific folder, Qubiter contains an abstract class called Qubiter_to_AnyQasm. This abstract class is the parent to 3 other classes in the same folder called Qubiter_to_IBMqasm, Qubiter_to_GoogleCirq and Qubiter_to_RigettiPyQuil. In this notebook, we will give examples of usage of these 3 child classes. These 3 child classes translate Qubiter "English files" to "target" quantum languages IBM qasm, Google Cirq and Rigetti PyQuil, respectively. These target quantum languages were chosen because they are very popular and their companies currently offer quantum computing devices on the cloud. The parent class Qubiter_to_AnyQasm does most of the hard work, so it will be easy in future to add child classes to Qubiter for other target quantum languages.

For all 3 target quantum languages, you can write a Jupyter notebook that translates a Qubiter English file into a bridge file in the target quantum language, and then automatically transmits that bridge file to the target company's cloud service, and gets a response back from that cloud service. That way you can run a q circuit on the target company's hardware directly from a Jupyter notebook on your computer.

# Unusual Gates like $X(0)^{1.2n(1)}$ or sqrt(iSWAP)¶

The purpose of this notebook is to illustrate 2 new members in the set of gates that Qubiter recognizes. The 2 gates are

1. an arbitrary matrix U2 in U(2), parametrized as $U2 = \exp(i[ \theta_0 + \theta_1\sigma_X + \theta_2\sigma_Y + \theta_3\sigma_Z])$ for real $\theta_j$, where $\sigma_X, \sigma_Y, \sigma_Z$ are the Pauli matrices.
2. a generalization of SWAP(0, 1) which I call SWAY(0, 1). SWAY includes SWAP, sqrt(SWAP), iSWAP, sqrt(iSWAP) etc. I discuss SWAY more precisely below.

The Qubiter simulator can now handle both of these gates with any number of controls of type T or F

# Simulation of Widget-Adjustable Parametric Circuit¶

Suppose you are interested in printing out the state vector of a quantum circuit at various times (points) in its evolution, as well as at the end of the circuit. Qubiter can do that.

Furthermore, suppose that the circuit is a parametric one, and you want to vary its parameters using sliders on a gui (graphical user interface). Qubiter can do that too, via a jupyter notebook with widgets. This notebook is one such notebook.

A jupyter notebook with widgets gives you the best of both worlds, the gui world and the notebooks world.

Gui's excel at reducing the possibility of user errors, increasing the ease of use for the user, and reducing the amount of understanding of the code that is demanded from the user in order for him or her to use the code correctly.

Notebooks excel at providing a robust, flexible, ready made, familiar method of documenting and saving your work for multiple use cases. They are also great for explaining your work to others with great detail and precision.

In [ ]: