Download A WYSIWYG Simulation Tool for Investigating the Circuit Model of

Document related concepts

Wave–particle duality wikipedia , lookup

Renormalization group wikipedia , lookup

Renormalization wikipedia , lookup

Double-slit experiment wikipedia , lookup

Topological quantum field theory wikipedia , lookup

Quantum dot cellular automaton wikipedia , lookup

Relativistic quantum mechanics wikipedia , lookup

Algorithmic cooling wikipedia , lookup

Theoretical and experimental justification for the Schrödinger equation wikipedia , lookup

Basil Hiley wikipedia , lookup

Delayed choice quantum eraser wikipedia , lookup

Bohr–Einstein debates wikipedia , lookup

Scalar field theory wikipedia , lookup

Particle in a box wikipedia , lookup

Bra–ket notation wikipedia , lookup

Bell test experiments wikipedia , lookup

Path integral formulation wikipedia , lookup

Quantum field theory wikipedia , lookup

Quantum electrodynamics wikipedia , lookup

Copenhagen interpretation wikipedia , lookup

Probability amplitude wikipedia , lookup

Coherent states wikipedia , lookup

Hydrogen atom wikipedia , lookup

Quantum decoherence wikipedia , lookup

Bell's theorem wikipedia , lookup

Quantum dot wikipedia , lookup

Measurement in quantum mechanics wikipedia , lookup

Density matrix wikipedia , lookup

Quantum entanglement wikipedia , lookup

Max Born wikipedia , lookup

Quantum fiction wikipedia , lookup

Many-worlds interpretation wikipedia , lookup

Orchestrated objective reduction wikipedia , lookup

History of quantum field theory wikipedia , lookup

EPR paradox wikipedia , lookup

Interpretations of quantum mechanics wikipedia , lookup

Quantum key distribution wikipedia , lookup

Symmetry in quantum mechanics wikipedia , lookup

Canonical quantization wikipedia , lookup

Quantum computing wikipedia , lookup

Quantum cognition wikipedia , lookup

T-symmetry wikipedia , lookup

Quantum machine learning wikipedia , lookup

Hidden variable theory wikipedia , lookup

Quantum state wikipedia , lookup

Quantum group wikipedia , lookup

Quantum teleportation wikipedia , lookup

Transcript
A WYSIWYG Simulation Tool for Investigating the Circuit
Model of Quantum Computation
Mr Christopher Fuller
For the degree of Bachelor of Science in Computer Science with Honours
The University of Bath, Faculty of Science
Supervisor: Professor Guy McCusker
April 29, 2010
A WYSIWYG Simulation Tool for Investigating the Circuit Model of
Quantum Computation
Submitted by: Mr Christopher Fuller
COPYRIGHT
Attention is drawn to the fact that copyright of this dissertation rests with its author. The
Intellectual Property Rights of the products produced as part of the project belong to the University of Bath (see http://www.bath.ac.uk/ordinances/#intelprop).
This copy of the dissertation has been supplied on condition that anyone who consults it is
understood to recognise that its copyright rests with its author and that no quotation from the
dissertation and no information derived from it may be published without the prior written
consent of the author.
Declaration
This dissertation is submitted to the University of Bath in accordance with the requirements
of the degree of Bachelor of Science in the Department of Computer Science. No portion of
the work in this dissertation has been submitted in support of an application for any other
degree or qualification of this or any other university or institution of learning. Except where
specifically acknowledged, it is the work of the author.
......................................................................................
This dissertation may be made available for consultation within the University Library and
may be photocopied or lent to other libraries for the purposes of consultation.
......................................................................................
1
Abstract
Quantum computing is a new and exciting area of science that has recently been gathering
attention. It is a multidisciplinary area of study combining computer science and quantum
mechanics from physics. This dissertation explores some of the most important concepts that
have been developed since the field was born with David Deutsch proposing his quantum version of the Turing machine in 1985. Some of the underlying principles in quantum mechanics
are introduced before looking into how quantum computers exploit these principles. The mathematics used in quantum mechanics is introduced and used to describe important ideas and
theorems. The realisation of the quantum computer is discussed by looking at some of the
greatest constructions so far. The units of information that quantum computers operate on
are described before investigating how these machines can manipulate these units. We look at
what new possibilities that have been opened up with this young field. We also look at the
current problems that researchers are tackling to progress in this area. The most successful
and popular model of describing quantum algorithms known as the circuit model of quantum
computing is presented followed by looking at the ways people have managed to simulate this
model using computer programs. This dissertation asserts that the current simulations that are
available are less than adequate for learning about quantum circuits. The overall aims that are
achieved in this project are learning about quantum computation and creating a new software
simulation of the circuit model of the quantum computer. It is intended that all the knowledge
gained in this dissertation will be represented in the new software that is aimed to be a learning
tool for the newcomers to quantum computing that there will inevitably be in the future.
Thank you Guy McCusker for all your guidance, time and enthusiasm.
Thank you Mother & Father for all the support over the course of my degree.
1
Contents
1 Introduction
5
2 Literature Review
2.1 Quantum Mechanics . . . . . . . . . . . . . . . . . . . .
2.1.1 Prerequisite Mathematics and Notation . . . . .
2.1.2 Quantum Bits . . . . . . . . . . . . . . . . . . .
2.1.3 Measuring a qubit’s state . . . . . . . . . . . . .
2.1.4 Entanglement . . . . . . . . . . . . . . . . . . . .
2.1.5 Superposition . . . . . . . . . . . . . . . . . . . .
2.2 Quantum Computing . . . . . . . . . . . . . . . . . . . .
2.2.1 Quantum Gates . . . . . . . . . . . . . . . . . . .
2.2.2 Quantum Circuitry . . . . . . . . . . . . . . . . .
2.2.3 Quantum Parallelism . . . . . . . . . . . . . . . .
2.2.4 The Quantum Fourier Transform . . . . . . . . .
2.2.5 Quantum Algorithms . . . . . . . . . . . . . . .
2.2.6 The Quantum Turing Machine . . . . . . . . . .
2.3 Realisation of The Quantum Computer . . . . . . . . .
2.3.1 Will quantum computers exist in the future? . .
2.3.2 Quantum computer technology . . . . . . . . . .
2.3.3 Current quantum computing devices . . . . . . .
2.4 Existing Quantum Simulation Software . . . . . . . . . .
2.4.1 jQuantum Quantum Computer Simulation . . .
2.4.2 libquantum . . . . . . . . . . . . . . . . . . . . .
2.4.3 QCAD: CAD for Quantum Computer Simulator
2.4.4 Summary of existing software . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3 Requirements Analysis and Requirements Specification
3.1 Requirements Gathering Process . . . . . . . . . . . . . . . . . .
3.1.1 Important strengths & weaknesses of existing simulations
3.1.2 Areas of particular importance & difficulty . . . . . . . .
3.2 Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2.1 Functional Requirements . . . . . . . . . . . . . . . . . .
3.2.2 Non-functional Requirements . . . . . . . . . . . . . . . .
3.2.3 Functional Requirements Dependancies . . . . . . . . . .
2
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
7
8
8
9
11
12
13
14
14
19
21
21
22
32
33
33
34
35
36
37
39
41
43
.
.
.
.
.
.
.
44
45
45
45
47
47
50
51
4 Design
4.1 System Decomposition . . . . . . . . . . . . . . . . . .
4.2 Architectural Design . . . . . . . . . . . . . . . . . . .
4.3 Data Structures & Algorithmics . . . . . . . . . . . . .
4.3.1 The Internal Quantum Circuit Data Structure
4.3.2 The Quantum Register Data Structure . . . . .
4.3.3 Building Quantum Gates . . . . . . . . . . . .
4.3.4 Custom Quantum Gates . . . . . . . . . . . . .
4.3.5 Performing a Quantum Measurement . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
52
53
53
56
56
57
57
64
66
5 User Interface Design
5.1 Information Presentation . . . . . .
5.1.1 Quantum Register View . . .
5.1.2 Conceptual View of circuit .
5.2 User Interface Design . . . . . . . . .
5.2.1 User analysis . . . . . . . . .
5.2.2 User Interface Prototyping .
5.2.3 Overall Layout of Interface .
5.2.4 Menubar . . . . . . . . . . .
5.2.5 Quantum Gate Buttons . . .
5.2.6 Quantum Register View . . .
5.2.7 Conceptual View of Quantum
5.2.8 Learning Panel Contents . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
68
69
69
69
70
70
71
71
71
72
72
73
73
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
Circuit
. . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
6 Detailed Design and Implementation
6.1 Programming Language and Software Tool Choices . .
6.2 Source code control and backup . . . . . . . . . . . . .
6.3 Implementation Plan & Planned Releases . . . . . . .
6.4 Data Structures & Algorithmics - The Implementation
6.4.1 The Quantum Register . . . . . . . . . . . . . .
6.4.2 Performing a Quantum Measurement . . . . .
6.4.3 Workspace Panel . . . . . . . . . . . . . . . . .
6.4.4 Learning Panel . . . . . . . . . . . . . . . . . .
6.5 Saving & Loading Circuits . . . . . . . . . . . . . . . .
6.6 Documentation & Help . . . . . . . . . . . . . . . . . .
6.7 Implementation Critique . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
74
75
75
76
77
77
81
83
85
86
87
87
7 Testing
7.1 Testing Strategy . . . . . . . . . . . . . . . . . . . . . .
7.2 System Testing . . . . . . . . . . . . . . . . . . . . . . .
7.2.1 Release Testing . . . . . . . . . . . . . . . . . . .
7.2.2 Performance Testing . . . . . . . . . . . . . . . .
7.3 Data Validation & Robustness/Stress Resistant Testing
7.3.1 Validation . . . . . . . . . . . . . . . . . . . . . .
7.3.2 Robustness/Stress Resistant Tests . . . . . . . .
7.4 Human-Computer Interaction Testing & Evaluation . .
7.4.1 User Selection . . . . . . . . . . . . . . . . . . . .
7.4.2 Experimental Preparation . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
89
90
90
90
100
100
100
102
105
106
107
3
7.4.3
7.4.4
Usability Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
Analytical Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
8 Conclusions
112
A User documentation
115
B Functional Requirements Test Results
127
C Learning Panel Contents
129
D Usability Testing Results
133
D.1 Usability Test 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
D.2 Usability Test 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
D.3 Usability Test 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
E Analytical Evaluation Results
136
E.1 Heuristic Evaluation 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
E.2 Heuristic Evaluation 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
E.3 Heuristic Evaluation 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
F Source Code
F.1 Class Files . . . . . .
F.2 Header Files . . . . .
F.3 UI Header Files . . .
F.4 Learning Panel Files
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
140
141
190
197
210
Chapter 1
Introduction
5
This project is going to reach out to a number of branches of not only computer science but
of the scientific world including quantum mechanics. For this reason it is wise to provide the
reader with an explanation of what quantum mechanics is and where quantum computation
fits into the picture. The quantum phenomenon is not the easiest of fields of understand, even
Einstein himself once said “Quantum theory is non-intuitive and defies common sense”, cited
by [28].
Quantum mechanics is such a large field that no definition fits perfectly and we often refer
to ‘quantum physics’, ‘quantum mechanics’ and ‘quantum theory’ either interchangeably or
when referring to different areas of the field. In my research the term ‘quantum mechanics’ is
used in the literature the most frequently so I will use this term throughout my project. [36]
provide this definition of quantum mechanics:
“Quantum mechanics is a mathematical framework or set of rules for the construction of
physical theories”
Nielsen and Chuang [36] build on this definition by an analogy between a computer’s operating
system and quantum mechanics: The operating system sets the basic parameters and modes
of operation, but leaves it up to the applications to solve specific problems which compares to
the relationship between quantum mechanics and specific physical theories.
Quantum computation is a subset of quantum mechanics and therefore it demands some knowledge of its superset. As discussed by [1], ordinary computers use operations with 0s and 1s
but in Nature there is the possibility of operating on an infinite set which can be described by
quantum mechanics.
One of the most famous of laws in computer science is Moore’s law:
“The number of transistors on a chip will double about every two years” [24]
A leading figure in quantum computing research is Issac Chuang who built the first quantum
computer. He comments on the relationship between Moore’s law and quantum computing:
“Quantum computing begins where Moore’s Law ends – about the year 2020, when circuit
features are predicted to be the size of atoms and molecules.” [22]
We aim to learn and understand how quantum computers work from a computer scientific and
mathematical perspective. We want to learn enough about quantum computers to be in the
position of being able to build a quantum computer simulator.
6
Chapter 2
Literature Review
7
2.1
Quantum Mechanics
To understand and appreciate the elegance of the concepts in quantum computing one needs to
be familiar with the elementary principles of quantum mechanics and its required mathematics. Therefore, this review will begin with information assimilated from introductory quantum
mechanics texts and early sections in quantum computing books.
Many subjects in the scientific world are easier to explain by using means other than directly
reading the topic in question. For example, in parallel computing it is often useful to use real
people representing threads and in computer networking, drawing diagrams of packet movements aids understanding. The author will use thought experiments in this section to unravel
quantum mechanical principles. The mathematics and notation used in this discipline will be
discussed first followed by quantum measurement, quantum entanglement and superposition.
Entanglement and superposition will be needed for when the author goes on and discusses
quantum algorithms, quantum circuits and other topics in the quantum computing section.
2.1.1
Prerequisite Mathematics and Notation
This project will assume understanding of basic linear algebra such as vector spaces, matrices,
matrix operations and complex numbers. However, the mathematics and notation used in
quantum mechanics will not be assumed so I will explain the necessaries here as well as a
few definitions and explanations that are used when explaining these bits of mathematics and
notation.
Inner-product space
An inner product space is defined below from [27]. It is defined here because it is used in the
explanation of Dirac notation and Hilbert space later on:
An inner-product space I is a complex vector space, equipped with an inner product
�· | ·� : I × I → C satisfying the following axioms for any vectors φ, ψ, φ1 , φ2 ∈ I, and any
c1 , c2 ∈ C.
�φ | ψ� = �ψ | φ�*,
�ψ | ψ� ≥ 0 and �ψ | ψ� = 0 if and only if ψ = 0,
�ψ | c1 φ1 + c2 φ2 � = c1 �ψ | φ1 � + c2 �ψ | φ2 �
Dirac Notation
When studying quantum mechanics, Dirac notation is regularly used. I acquired examples
and explanations from [13] and [36] to complete this subsection. Dirac notation is sometimes
referred to as bra-ket notation with a bra being �| and a ket being |�. The |� is basically a vector
in a vector space, we enclose the |� with a symbol (ψ in the example below) that we call the
label of the vector:
|ψ�
The ket e.g. |x�, denotes a column vector and the matching bra (�x| in this case), denotes the
conjugate transpose of |x�. Note that the conjugate transpose is just the transpose operation
8
(swapping every row with every column) followed negating the imaginary parts of the vector.
For an example we will use the orthonormal bases, {|0� , |1�}, as used by [13]. Let us define
what the orthonormal bases is first:
A subset {v0 , ..., vk } of a vector space V , with the inner product �.�, is called orthonormal if when i �= j That is, the
vectors are mutually perpendicular. Moreover, they are all required to be of unit length i.e. unit vectors. An orthonor-
mal set must be linearly independent, and so it is a vector space basis for the space it spans. Such a basis is called an
orthonormal basis [15].
Returning to the example, we can write the orthonormal basis in matrix form as {(1, 0)T , (0, 1)T }.
This can then be generalised for any complex linear combination of |0� and |1�, a |0� + b |1� and
can be written as (a, b)T .
We will often see the inner-product (defined earlier) of two vectors in quantum computing
literature. The inner-product between two vectors is written:
and often more concisely as:
�ϕ || ψ�
�ϕ | ψ�
Hilbert Space
Now some required notation has been explained I will begin with Hilbert Space, named after
David Hilbert, a German mathematician and logician. Hilbert space is a mathematical framework suitable for describing the concepts, principles, processes and laws of quantum mechanics
[27]. The literature on Hilbert space is very vast with a lot of the books being for the graduate
physicist but here we just need to define it and know that the quantum phenomenon can’t
simply be described in other spaces such as Euclidian space. We define Hilbert Space as: A
Hilbert space is a vector space H with an inner product �f, g� such that the norm defined by
�
| f | = �f, f �
turns H into a complete metric space. If the metric defined by the norm is not complete, then H
is instead an inner product space. A Hilbert space is always a Banach space, but the converse
need not hold [14]. The definitions of complete metric space, metric space and Banach space
will all be omitted because they will not be referred to anywhere in this project.
2.1.2
Quantum Bits
Here we introduce the quantum bit, commonly abbreviated to ‘qubit’. We will explain what a
qubit is in a clear and concise way. In quantum computing the quantum bit is the analogous
concept to the classical unit of information, the bit used in non-quantum computers.
Earlier we saw Dirac notation; this type of notation is used to represent a qubit. Qubits
are measured in their bases state. We commonly use the computational bases state for qubits
to act in. A single qubit system has the basis |0� and |1� in the computational bases.
We will begin by discussing quantum state spaces and comparing them to classical state spaces.
Then we will explain the quantum phenomenon known as superposition and finally finishing
this subsection with a discussion on measuring qubits.
9
State Spaces & The Tensor Product
Firstly, it is important to see the growth in state space that a classical computer with bits
operates on and then compare this to the state space growth a quantum computer with qubits
operates on.
Operating on individual state spaces of n elements combine classically through the Cartesian
product. Conversely, quantum states combine through the Tensor product, denoted ⊗. Let us
see some examples. These examples are based on those found in [13].
Let V and W both be 2-dimensional complex vector spaces with bases {v0 , v1 } and {w0 , w1 }
respectively. The cartesian product of V and W has its basis as the union of the bases of its
component spaces:
{u0 , u1 , w0 , w1 }
Now let us change V and W to {v0 , v1 , v2 } and {w0 , w1 , w2 } respectively to make it clear how
the vector bases change as we increase the size of V and W . We now get:
{u0 , u1 , u2 , w0 , w1 , w2 }
From this we can deduce that the growth of the state base in a classical system is linear.
Now let us see what happens with the Tensor product. We will start with setting the complex
vector spaces, V and W both with bases {|0� , |1�} (again using the computational bases). The
Tensor product of V and W then has bases:
{|0� ⊗ |0� , |0� ⊗ |1� , |1� ⊗ |0� , |1� ⊗ |1�}
We can write this more concisely as:
{|00� , |01� , |10� , |11�}
Again, let us see what happens to the bases when we increase the number of elements in the
system from 2 to 3:
{|000� , |001� , |010� , |011� , |100� , |101� , |110� , |111�}
From this we can deduce that the growth of the state base in a quantum system is exponential;
given n elements, we get a state space of magnitude 2n . However, the state space of a classical
system grows linearly. Why is this so significant? Well, using a quantum computer, we could
potentially harness this exponential state growth to produce a computer that can operate
exponentially faster than a classical computer.
Superposition
A vital concept relating to qubits is the notion of superpositions. The equation below describes
superposition of a one qubit system, this equation is seen in much quantum computing literature:
|ψ� = α |0� + β |1�
Before we go into what this equation shows, let us see how we can modify the equation for
an increased number of qubits in our system from 1 to 2 qubits, giving us a state space with
dimension 22 = 4 The equation below shows the superposition of the qubits in this larger
system:
10
|ψ� = a |00� + b |01� + c |10� + d |11�
What do these equations tell us? The coefficients α and β in the first equation (single qubit
system) are complex numbers (i.e. α, β ∈ C) representing the probabilities of the qubit evaluating to a 0 or 1 respectively with 0, 1 being integers. In the next section we will learn more
about this. The case is similar in the second equation too (two qubit system) with a, b, c, d ∈ C
representing the probabilities of the qubits being evaluated to the basis vector that they are in
front of.
2.1.3
Measuring a qubit’s state
In classical computation we can observe the state of a bit and determine whether the state is
0 or 1. However, with quantum computation it is a little more interesting. If we observe a
single qubit we cannot determine the values of α and β and therefore we cannot determine its
quantum state directly. This is because the system is probabilistic; when measuring a qubit we
get a result of 0 with the probability |α|2 and the result 1 with the probability |β|2 in a single
qubit system. [36] uses the analogy of flipping a coin to explain this concept. If you think of a
coin flipping in the air, when it lands it will either be heads or tails but whilst it is in the air
it exists in a continuum of states i.e. heads or tails, until it lands. Contrastingly, a qubit can
exist in a continuum of states between |0� or |1� until we observe it. An interesting an example
that is so special it is often referred to as |+� is this:
√1
2
|0� +
√1
2
|1�
which gives us a result 0 with probability 12 and result 1 with probability 12 . This is because
| √12 |2 = 12 . The following equation illustrates why we take the square of this number:
| α |2 + | β |2 = 1
This equation holds for an arbitrary sized qubit system which we will demonstrate shortly.
We will illustrate the difference between classical and quantum measurement by first showing a classical example followed by a similar quantum example.
Given a 3-bit register, there are 23 = 8 possible strings that we can make from the register because the bits can either be set to 0 or 1. We will call these eight strings a, b, c, d, e, f, g
and h with a, b, c, d, e, f, g, h being integers of either 0 or 1. Let us say that this classical
computer is also probabilistic. With a classical computer we can say that:
a+b+c+d+e+f +g+h=1
but only one of a, b, c, d, e, f, g, h can be 1, the others must be 0.
Any of these strings have an equal chance of being outputted but more importantly, they
sum to 1. Now let us see how a quantum computer is different.
This time we have a 3-qubit register. Again we have an 8-dimensional vector like before
but this time a, b, c, d, e, f, g, h ∈ C. Moreover, this time we say that:
| a |2 + | b |2 + | c |2 + | d |2 + | e |2 + | f |2 + | g |2 + | h |2 = 1
11
If you measure three qubits then you will see a three-bit string. The result will be classical,
this is referred to as the collapsing of the state. Each possible string is outputted with
probability | x |2 where x can one of the strings given by a, b, c, d, e, f, g or h. This time before
the three qubits were measured a, b, c, d, e, f, g, h didn’t have to be one single 1 and the rest
zeros, they could have be anything that makes the equation:
| a |2 + | b |2 + | c |2 + | d |2 + | e |2 + | f |2 + | g |2 + | h |2 = 1
hold.
Once we perform an experiment on a qubit that involves quantum measurement, repeating
the same experiment having measured the qubit may bring about a different result to the one
we read before. This is a fundamental problem in quantum mechanics for which there is no
classical physics explanation but it one reason why quantum computing is so interesting.
For simplicity we have chosen the computational basis in this example i.e. we have chosen
3-bit strings so the bases vectors are:
|ψ� = a |000� + b |001� + c |010� + d |011� + e |100� + f |101� + g |110� + h |111�
2.1.4
Entanglement
A further quote from Einstein: “I find the idea quite intolerable that an electron exposed to
radiation should choose out of its own free will, not only its moment to jump off, but also its
direction. In that case, I would rather be a cobbler, or even an employee in a gaming house, than
a physicist”, cited by [38] when reviewing [4]. Although electrons and radiation are interesting
topics, this is not why we quote this man. Rather, this quote is to show the trouble Einstein
had with a probabilistic universe and why he came up with entanglement.
In [27], he states that the main difference between classical and quantum computation is that
quantum computation makes use of the entanglement phenomenon. Through my research and
discussions with undergraduate physicists, I have found entanglement is a fascinating area in
itself. [27] describes entanglement by quantum information being encoded in mutual correlations between remote parts of physical systems which is then made use of most essentially.
In a paper by the famous physicist, John Bell [25] (discussed by [38]), Bell uses his colleague’s
habit of wearing different coloured socks to explain entanglement. He states that in the real
world, if his colleague (Bertlmann) was just around a corner and we could see the colour of a
single sock (let’s say pink) that Bertlmann was wearing then we could know that on his other
foot would be a sock of a different colour. This is because when Bertlmann woke up in the
morning he set the different colours of each of his socks when he put them on. The paper then
compares this analogy to the quantum world, specifically, the spin of an electron. The spin of
an electron is not set like Bertlmanns opposite coloured socks are. With a pair of entangled
electrons, if you measure the spin of one electron, the other will spin with a fixed direction
whereas before, neither electrons had a fixed direction of spin. We can think of the socks from
a quantum mechanical perspective too; both socks were every possible colour until we saw the
sock from around the corner, only then did then did we see that it was pink and the other sock
took a different fixed colour.
12
Let us see this mathematically using qubits now we know what a qubit is. I have chosen
an example from [13] that directly follows on from discussions about state space growth. Given
a two qubit system, the state |00� + |11� is a quantum state that we cannot describe in terms
of individual qubits. Mathematically, it is impossible to find a1 , a2 , b1 , b2 such that:
This is because
(a1 |0� + b1 |1�) ⊗ (a2 |0� + b2 |1�) = |00� + |11�
(a1 |0� + b1 |1�) ⊗ (a2 |0� + b2 |1�) = a1 a2 |00� + a1 b2 |01� + b1 a2 |10� + b1 b2 |11�
and a1 b2 = 0 implies that either a1 a2 = 0 or b1 b2 = 0. This shows us that this state cannot
be decomposed and therefore, the two qubits are in an entangled state. I mentioned that this
explanation follows on from state space growth; from this example, there is no way that you can
possibly represent this using mathematics describing the classical world. It is therefore only
possible to show entanglement in the quantum world and this is why quantum state spaces
grow exponentially. To put it really simply, if the quantum world can show everything that is
classical and things that the classical world cannot then the state space we represent all this in
needs to be larger than the classical state space.
2.1.5
Superposition
We have already seen superposition mathematically because it is vital to understanding what
a qubit is and how a qubit works. Having seen this phenomenon using mathematics, let us see
it in an alternative way that is accessible to someone not knowing any mathematics describing
quantum mechanics whilst perhaps making it clearer for the mathematician too.
I shall describe the concept of superposition using a popular thought experiment known as
Schrödinger’s Cat which is an easy way of explaining the concept. Schrödinger’s Cat involves
thinking of a cat in a sealed box containing a vial of poison protected from the outside world.
There is a radioactive atom in the box which may decay at any moment. There is also a Geiger
counter inside the box that measures radiation that will cause the vial to break if any radiation
is detected. If the vial breaks then the cat is killed. One interpretation of this would be that
there will come a time when the cat in the box is both alive and dead. However, if we open the
box we would see that the cat is either alive or dead and not both.
This interpretation may not be accurate though because there are other interpretations of quantum mechanics that
would conclude something else. For what I want to explain, my chosen interpretation fits; I am using the experiment to
explain superposition rather than interpretations of quantum mechanics.
We can think of the dead and alive cat being like the physical qubits in a quantum computer
which could be in an equal superposition of all being 0 and 1. This is sometimes known as the
cat state which I will explain later in the quantum computing section using some mathematics.
Another real world example would be the spin of an electron around the nucleus of an atom.
As a brief aside when we write ‘spin’, we do not mean what we immediately think of as spin e.g. a coin spinning on its
side on a table. Spin is actually a property of subatomic particles (electrons, positrons et cetera) that act under a set of
rules and has certain properties. The famous Stern-Gerlach experiment explains quantum spin and how the spin of an
electron around an atom would exceed the speed of light if we consider it as a real spin and is therefore impossible and
purely a quantum mechanical phenomenon [53].
An electron can either spin clockwise or anticlockwise but when investigating quantum mechanically, the spin could be in a superposition of clockwise and anticlockwise until we take a
measurement to determine the spin.
13
2.2
Quantum Computing
We have now covered some core quantum mechanics including entanglement, superposition and
quantum states including measuring quantum systems. This section is the largest in the literature review chapter of this document and is the most important. So far I have been vague
with why quantum computing really is of great interest and I instead left quotes from influential
figures that I thought would be motivating. Now that we know what we people mean when they
say quantum, this would be a good time to talk about the importance of this area of research.
Assumed knowledge here will be the foundations of theoretical computer science including
theoretical models of computation and complexity theory.
What happens when the world needs more and more computational power and our existing
methods start to fall short? Thinking hypothetically, what happens when we reach a limitation
to the ‘speed’ we can feed an input tape into a Turing Machine? In the physical world there are
signs of this already happening. A recent article in The Los Alamos Science and Technology
Magazine states ‘The drive for more scientific computing power is running into a brick wall.
Old speed-up tricks aren’t working, and a new paradigm is needed to sustain the rapid growth in
computing power associated with Moore’s law’ [51]. At the start of this chapter I quoted Issac
Chuang who stated that it is quantum computing that begins when Moore’s Law ends.
The earliest idea of quantum computation was when Feynman suggested that quantum mechanics could not be accurately simulated on a classical computer but could be better simulated
on a quantum computer [39]. He then went on to define a quantum automata which Deutsch
later built on when he proposed the Quantum Turing Machine [8]. These two models are the
quantum counterparts of the classical computational models: the finite automaton and the
Turing machine. The reason we hold quantum computing in good regard is because it has been
shown that there are some tasks that simply cannot be computed on ordinary computers but
can be on quantum computers. It has even been shown that one algorithm can actually break
the RSA crypto system. This is a massive breakthrough as anyone who has been exposed to
cryptography can probably appreciate. Even more exciting is that some of these tasks have
actually been implemented for real. The field of quantum computation has only been a strong
research interest for about a decade so it is still in its infancy.
I will present the popular circuit model of quantum computation by talking about quantum
bits, the fundamental unit in quantum computing and showing how we can manipulate these
quantum bits to create quantum circuits. I will also demonstrate how these circuits can
describe quantum algorithms. I will then describe three important quantum algorithms and
explain their uses and importance. Various crucial ideas are needed to harness the power of
quantum computers such as quantum parallism and the Quantum Fourier Transform, I
will explain these two concepts in this section too. Finally, the Quantum Turing Machine
will be described which is alternative way that we can model quantum computation.
2.2.1
Quantum Gates
The following section describes the fundamental quantum gates used in quantum circuitry. I
have researched the matrix representations of the gates, the circuit symbols and what the gates
do. Later on in the project I will be able to refer back to this chapter and simply use the
14
symbols and matrices for the implementation. The Pauli gates were found in an applied micro
photonics book [56] and the other gates were taken from [36].
Unitary Transformations
Given some state of a quantum system:
|ψ� = α |0� + β |1�
where | α |2 + | β |2 = 1 Quantum gates performing transformations on these qubits must
maintain this norm. Therefore, when a qubit is acted on by a transformation, this transformation must be unitary. This transformation can be represented as a matrix, a unitary matrix is
defined as follows. A square matrix is a unitary matrix if:
U H = U −1
where U H denotes the conjugate transpose and U −1 is the matrix inverse [16].
Let’s show this with an example. Let X be the the Matrix:
X = ( 01 10 )
Taking the inverse of this matrix:
X −1 =
=
1
|X|
�
0 −1
−1 0
1
(0×0)−(−1×−1)
= −1 ×
�
�
0 −1
−1 0
0 −1
−1 0
= ( 01 10 )
�
�
�
This shows us that U H = U −1 holds so the matrix is unitary. It turns out that this example
actually has a special name called the Pauli-X matrix. The ‘X’ is used for historical reasons
and the matrix is important because it’s a one of the fundamental and most simple quantum
transformation.
Matrix Representation of quantum gates
As with classical logical gates, we can represent quantum gates as matrices. Let us see how
these matrices are constructed. For this we will use this example matrix:
�1 0 0 0�
0100
0001
0010
Shortly we will see why this particular matrix is important. This matrix represents a quantum
gate that operates in a system of two qubits. Remember that this means that the dimension
of the system’s state space would be 22 = 4 so the bases vectors of the space is:
{|00� , |01� , |10� , |11�}
(using the computational bases again) and again reiterating discussions from earlier, the states
of the system are given by:
15
a |00� + b |01� + c |10� + d |11�
where
| a |2 + | b |2 + | c |2 + | d |2 = 1
Now let’s represent this as a column vector concentrating on the order of the bases:
�a�
b
c
d
Now we want to use this column vector to see how it changes when it is acted on by the example
matrix. In linear algebra, the result matrix is the product of the two input matrices so:
�1 0 0 0��a�
0100
0001
0010
b
c
d
which gives us the result column vector of:
�a�
b
d
c
There are only 4 bases vectors in our system so we can see what happens when we apply these
to the example matrix too. We can convert qubits in Dirac notation like so:
� a00 �
a00 |00� + a01 |01� + a10 |10� + a11 |11� = aa01
10
a11
Working through each basis vector getting applied to the example matrix we get the following:
�1�
�1 0 0 0��1� �1�
0
0
|00� = 0 , so 00 10 00 01
= 00
0
0
|01� =
|10� =
|11� =
�0�
1
0
0
�0�
0
1
0
�0�
0
0
1
0010
, so
, so
, so
0
�1 0 0 0��0�
0100
0001
0010
1
0
0
�1 0 0 0��0�
0100
0001
0010
0
1
0
�1 0 0 0��0�
0100
0001
0010
0
0
1
0
=
=
=
�0�
1
0
0
�0�
0
0
1
�0�
0
1
0
This example matrix is actually known as the controlled-NOT gate. This is the exact result
that we expect when we learn what this matrix is meant to do:
The controlled-NOT gate is a 2-qubit gate that flips the target qubit if the control qubit is equal
to 1, otherwise it leaves the target qubit alone.
Looking at the four results, the first two column vectors are not changed because their control
qubit is set to 0. The last two column vectors are changed; the target qubit is flipped because
the control qubit was set to 1 in the last two cases. This shows how the controlled-NOT gate is
constructed. Other matrices representing quantum transformations can be worked in the same
way we have done here. However, for 3-qubit gates, the number of dimensions is greater so the
column vectors would have rows of 23 = 8 and there would be 8 of these calculations to show.
16
Controlled-NOT
The controlled-NOT operation can implement the controlled operation: ‘If A is true then do
B’. This is powerful; classical and quantum programs both make use of this. Anyone who has
ever programmed would appreciate how useful this construct is.
Matrix representation of the Controlled-NOT gate in a 2 qubit system (as shown in the previous
example):
�1 0 0 0�
CN OT = 00 10 00 01
0010
Symbolic representation of the Controlled-NOT gate:
The Controlled-NOT circuit symbol contains a circle with a cross that looks like an addition
symbol, sometimes this is replaced with a solid black circuit that indicates negative control in
which the target qubit is flipped when the control bit is 0. The dark circle is the control qubit
and the circle with a cross is the target qubit.
The Pauli Gates
The Pauli-Gates are gates that cannot be decomposed into simpler matrix operators. The
Hadamard gate is another quantum gate primitive that also cannot be decomposed. They are
all 2 by 2 matrices that include standard 0 and 1 elements as well as complex elements.
Pauli-X Gate
Matrix representation of Pauli-X Gate:
X = ( 01 10 )
Symbolic representation of Pauli-X Gate:
The Pauli-X quantum gate works on 1-qubit and is the quantum equivalent to the classical
NOT gate. It flips a qubit |0� to |1� and |1� to |0�. We used the Pauli-X matrix as an example
earlier when describing unitary matrices.
Pauli-Z Gate
Below is the matrix representation and diagrammatical representation of the Z gate respectively.
� 0 �
Z = 10 −1
Equations for Pauli-Z Gate: Symbolic representation of Pauli-Z Gate:
The Pauli-Z quantum gate works on 1-qubit and flips |1� to − |1� and leaves |0� unchanged.
17
Pauli-Y Gate
Matrix representation of the Pauli-Y Gate:
Y =
Symbolic representation of Pauli-Y Gate:
� 0 −i �
i 0
The Pauli-Y gate is the product of the Pauli-Z and Pauli-X matrices.
Hadamard
Below is the matrix representation and diagrammatical representation of the Hadamard gate
respectively.
� 1 �
H = √12 11 −1
Symbolic representation of Hadamard Gate:
The Hadamard gate is used a lot in quantum algorithms that we shall see later. It transforms
|0� halfway between |0� and |1� and transforms |1� halfway between |1� and |0�. Applying the
Hadamard gate twice would leave the input unchanged.
Explicitly, with the Hadamard gate acting on an input of |0�, we would get:
√1
2
|0� +
√1
2
|1�,
and for the Hadamard gate acting on an input of |1�, we would get:
√1
2
|0� −
√1
2
|1�,
We can think of these two results as being halfway between 0 and 1 and halfway between 1 and
0 respectively.
Toffoli
Another name for the Toffoli gate is the controlled-controlled-not gate. However, the controllednot gate is a 2 qubit gate whereas the Toffili gate acts on 3 qubits. This gate negates the third
qubit if the first two qubits are both set to the |1� state. Without this quantum gate, there
would be no quantum equivalent of the classical AND gate because the AND gate is not a
unitary transformation. When the third qubit is set to |0� we effectively get a quantum AND
gate and when the third qubit is set to |1� we get a NAND gate. We know that NAND gates
are important from classical computation because any logical circuit can be made entirely from
NANDs.
Matrix representation of the Toffoli Gate:
18
1 0 0 0 0 0 0 0
01000000
0 0 1 0 0 0 0 0
0 0 0 1 0 0 0 0
Toffoli = 
0 0 0 0 1 0 0 0
00000010
00000100
00000001
Symbolic representation of Toffoli Gate:
Measurement
Earlier on we discussed quantum measurement and talked about the collapsing of qubits in a
superposition to a classical result. The measurement gate in a quantum circuit achieves this.
We also mentioned in the earlier section about how we have to be careful about measuring
because making repeated measurements on an experiment like a quantum circuit using the
same set of qubits can produce different results. Let us see an example of what this means with
some arbitrary quantum circuit.
If we have written some classical program using a classical logical circuit, we could observe
a bit’s value when it enters a NOT gate, observe its value after the gate has been applied and
then carry on processing the bit without worrying that our observation of the bit has changed
the bit’s value in any way. This is certainly not the case with a quantum circuit [36]. We
have to protect the circuit from external factors that can cause ‘observations’ to be made to
a circuit unintentionally so that when we do make an intended measurement/observation, the
result is valid. These external factors that could change the result unintentionally are what we
call decoherence. This is explained in [7] which defines decoherence simply as:
“Decoherence can be viewed as the loss of information from a system into the environment”
Relating back to our discussions about superposition and an electron’s spin, the spin of an
electron around an atom can be in one of two directions. In the quantum world, before we
observe the electron’s spin, it is in a superposition of spinning one way and the other. It is not
until we measure the electron’s spin that we determine what spin it has.
If a single qubit goes through a Hadamard gate then it will be in an equal superposition of 0
and 1, if we were to measure if after the Hadamard gate had been applied then we would get 0
or 1 both with probability 12 , see the qubit section and Hadamard gate explanation for why this
is so. This is not to say that we cannot manipulate qubits in a quantum circuit to produce some
desired outcome, otherwise quantum circuits would be of little use. We will discuss quantum
algorithms later on to see how circuits are designed to complete useful tasks.
2.2.2
Quantum Circuitry
Quantum circuits have a few fundamental differences to classical logical circuits. The first main
difference is that classical circuits can contain loops whereas quantum circuits must be acyclic.
19
The second difference is that quantum circuits must be reversible. Furthermore, with classical
logical circuits you can join circuits together using logical OR gates whereas in quantum circuits
you can not do this because it can make the circuit irreversible. These restrictions do not impede
the power of quantum circuitry. The following section will describe major concepts in quantum
circuits.
Wires in Quantum Circuitry
Wires in a quantum circuit diagram represent the passage of time. Circuits are drawn from left
to right with the left being one point in time and the right being a later point in time when the
circuit has finished running. In a quantum circuit, a wire carrying n qubits is denoted /n .
No-Cloning Theorem
A fundamental difference between classical and quantum computing is that in classical computation, it is possible to copy the contents of a variable to another variable whereas with quantum
computing, this is impossible; we cannot clone an unknown qubit state. We now follow through
a proof of the no-cloning theorem [13].
Proof
Let U be a unitary transformation that clones such that:
U (|a0�) = |aa� for all quantum states |a�.
Let |a� and |b� be two orthogonal (perpendicular to one another) quantum states. U (|a0�) = |aa�
and U (|b0�) = |bb�. Now let us have a quantum state |c� such that:
|c� = ( √12 )(|a� + |b�).
Unitary transformations are linear so we can perform the following:
U (|c0�) =
√1 (U (|a0�) + U (|b0�))
2
= √12 (|aa� + |bb�)
However, if U is a cloning transformation then we should have got:
U (|c0�)
= |cc�
1
= 2 (|aa� + |ab� + |ba� + |bb�)
which �= 12 (|aa� + |bb�). Since all quantum transformations must be unitary and in this proof
we used a general unitary transformation, U , there does not exist any transform than can clone
an unknown qubit state. Quod erat demonstrandum.
It would seem like this would make the future of the quantum computer questionable; how
can we debug a program if we can’t copy a variable? For example, modern interactive development environments for classical computers allow the programmer to step through an executing
program and look at multiple copies of a variable before the program has terminated. Moreover, even debugging the most trivial of programs would be cumbersome if we do not have the
facility to print out the values of a variable at different points in the program execution.
20
Fortunately Peter Shor applied our understanding of entanglement, mentioned earlier, to solve
the no-cloning theorem [41]. To copy a quantum state we have to observe the quantum information to copy which alters its quantum state; this is known as decoherence. In [41], the solution
provided is quantum error correction code which is where information of one qubit is dispersed
into an entangled state of nine qubits which protects the superposition of states against decoherence and doesn’t break the no-cloning theorem. [48] supports Shor’s work: “The basis of
this substantial advance lies in the ability to tame the hazards of decoherence by encoding the
information of a given state in a set of entangled states, without violating the no-cloning theorem of quantum mechanics”. This paper also describes quantum states as ‘fragile’, emphasising
the delicacy of the quantum phenomenon.
Shor was the first to suggest quantum error correction codes but there have been advances
made since then that reduce the number of entangled qubits required to protect against decoherence [2][46]. Quantum error correction codes are not covered in this dissertation.
2.2.3
Quantum Parallelism
Quantum parallelism is a fundamental to quantum computing because we will be seeing shortly
that quantum algorithms rely on its power to make them highly efficient. [49] goes as far to
say: “It is the opinion of this author that it is this idea, if anything, that is the essence of quantum computing”. Quantum parallism is important because given any function f (x), harnessing
quantum parallelism, we can calculate f for all values of x simultaneously. However, there is a
problem here; although you can evaluate a function for all its inputs, only one result is acquired
and what is more, you do not get a choice of which evaluation is obtained. Quantum algorithms
solve this problem using either one of two approaches. The first is finding some sort of common
property of a function we want to evaluate; we will see Shor’s algorithm uses this strategy. The
other approach is to amplify the evaluations we are interested in, we will see Grover’s algorithm
do this later on in this chapter.
Let us explain quantum parallelism using some mathematics found in [27]. Consider a 2-qubit
computer in start state |x, y� which transforms this state to |x, y ⊕ f (x)� where ⊕ is addition
modulo 2, we give this transformation a name Uf and note that it is a unitary transformation.
If y = 0 then the final state of the second qubit is just f (x). To exploit quantum parallelism we
need to show that f (0) and f (1) can be computed simultaneously. We prepare two inputs for
(1)�
√
√
y = Uf , |0� and x = | |0�+|1�
�. Then we apply Uf to the inputs and get: |0,f (0)�+|1,f
. Notice
2
2
that this resulting state contains two terms with information about f (0) and f (1) and we have
only applied f (x) once, this is quantum parallelism. We will see more of this phenomenon
throughout this chapter.
2.2.4
The Quantum Fourier Transform
Here I will presume understanding of the classical Fourier transformation and how and why it
is used. The equations and explanations below are based on [13] and [36].
The following is the output vector of complex numbers y0 , ..., yN −1 from applying the discrete Fourier transformation to a vector of complex numbers x0 , ..., xN −1 where N in both the
input and output is the length of the vector,
21
yk ≡
√1
N
�N −1
j=0
xj e
2πijk
N
The classical discrete Fourier transformation (DFT) has been defined because the quantum
version is the same transformation but the notation is different. The QFT is relatively easy to
understand because it is just the FT acting on something different to what we would normally
apply it to; in Shor’s algorithm, the QFT acts on a superposition of qubits which we talk
about in the quantum algorithms section. We define the QFT on an orthonormal basis (see
the prerequisite mathematics section of a definition of the orthonormal basis) to be a linear
operator acting on the basis states below,
� −1 2πijk
N
|j� → √1N N
|k�
k=0 e
In [36]’s book they also present an equivalent operator but on any state as shown below,
�N −1
�N −1
j=0 xj |j� →
k=0 yk |k�
where the amplitudes yk are the DFT of the amplitudes xj .
2.2.5
Quantum Algorithms
In this section I will present my research into quantum algorithms. In my opinion, these
algorithms are some of the most exciting recent developments in computer science. A lot of
new technology appearing in industry like affordable multi-core processors are based on the
computing theory that has been around since nearly the dawn of the computer. Conversely, I
think that although quantum mechanics is not something new, quantum computing is cutting
edge. Quantum algorithms will provide a glimpse into the potential power that a quantum
computer could exhibit.
Deutsch’s Algorithm
Deutsch’s algorithm was the first ever true quantum algorithm to be devised. It is a special
case of the Deutsch-Jozsa algorithm which we will discuss in the next part of this subsection.
Although the Deutsch-Jozsa algorithm is more powerful it is felt that we should include it to aid
understanding of the Deutsch-Jozsa algorithm. David Deutsch, the innovator of this algorithm
is also responsible for the first true quantum Turing machine and Deutsch’s problem is named
after David Deutsch (discussed later when we investigate the Deutsch-Jozsa algorithm). The
original algorithm was published in [8] but there it obviously was not referred to as ‘Deutsch’s
algorithm’. The paper also defines the quantum Turing machine which is covered later.
The algorithm relies on quantum parallelism like all the algorithms we discuss. It also makes use
of a quantum phenomenon called interference which was not covered in the quantum mechanics
section but not a necessary in understanding this algorithm. The version of the algorithm I describe here is partly from [36] who claim their version is a simplified and improved version of the
original. When [36] it says ‘improved’, it does not say which part of the algorithm is improved.
Furthermore, [36] does not mention anything about the algorithm having the potential to fail
unlike the paper describing the original algorithm does which states that the algorithm can fail
with probability 12 . However, comparing these a two texts may not be fair because one source
is a key text book on quantum computation whereas the other is a ground breaking paper on
more than one area of quantum computation. We also use [29] to help explain the algorithm too.
22
Let us now begin talking about what Deutsch’s algorithm does and how it works. The algorithm determines something very basic; it finds out whether a function, f (x) with parameters
0 and 1 evaluates to the same answer i.e. whether f (0) = f (1).
√
We have two qubits; the first qubit is in the superposition, |+� that can also be written, ( |0�+|1�
)
2
√
and the second qubit is in the superposition, |−� that can be written, ( |0�−|1�
). As we mentioned
2
in the quantum circuitry section, these superpositions arrive by applying a Hadamard gate to
|1� and |0� respectively. Our input state is,
|ψ0 � = |01�
This is then sent through two Hadamard gates, one for each qubit which yields,
√
√
|ψ1 � = [ |0�+|1�
][ |0�−|1�
]
2
2
Expanding this equation we get:
=
1
2
|0� (|0� − |1�) + 12 |0� (|0� − |1�)
We then apply the unitary transformation, Uf = x, y �→ ⊕f (x) on this state to get:
1
2
|0� (|0 ⊕ f (0)� − |1 ⊕ f (0)�) + 12 |1� (|0 ⊕ f (1)� − |1 ⊕ f (1)�)
= 12 (−1)f (0) |0� (|0� − |1�) + 12 (−1)f (1) |1� (|0� − |1�)
= ( √12 (−1)f (0) |0� +
√1 (−1)f (1) |1�)( √1
2
2
|0� −
√1
2
|1�)
using the fact that |0 ⊕ a� − |1 ⊕ a� = (−1)a (|0� − |1�) for a ∈ {0, 1}
The important thing that has happened here is that the factors (−1)f (0) and (−1)f (0) are
both in the first qubit’s state. I.e. an evaluation of f (0) and f (1) has appeared in the state
of the first qubit. The second qubit’s state no longer interests us so we disregard it from now
on but it was needed in the computation. It is ok to not pay any attention to the second
qubit because it did not change when the unitary transformation took place meaning that it is
independent from the state of the first qubit. We now just write the state of the first qubit:
√1 (−1)f (0) |0�
2
+
√1 (−1)f (1) |1�
2
We can write this as:
(−1)f (0) ( √12 |0� +
√1 (−1)f (0)⊕f (1) |1�)
2
We then apply a final Hadamard transform to the first qubit which brings this state to:
(−1)f (0) |f (0) ⊕ f (1)�
using the fact that:
H( √12 |0� +
√1 (−1)a |1�)
2
= |a� again for a ∈ {0, 1}
23
Gving a = 0 and a = 1, when the measurement if made, it will definitely yield f (0) ⊕ f (1). If
f (0) ⊕ f (1) = 0 if and only if we measure a 0. If a zero is measured then f (0) = f (1) and if a
one if measure then f (0) �= (1).
Recently, [52] actually physically realised Deutsch’s algorithm for the first time. [42] then
talks about using the methods they used in implementing Deutsch’s algorithm to implement
Grover’s algorithm which is an algorithm that does have real world uses. As we will see with
the Deutsch-Jozsa algorithm too, this algorithm can be seen as a stepping stone to implementing other more powerful algorithms. Secondly, this algorithm shows the ability of a quantum
algorithm to outperform classical algorithms by using quantum mechanical concepts such as
quantum parallelism. A classical algorithm would have to first evaluate f (0) and then f (1) but
this algorithm evaluates both f (0) and f (1) in only one run of the algorithm.
Deutsch-Jozsa Algorithm
The Deutsch-Jozsa algorithm was first devised by [9] in 1992; it solves the problem known as
Deutsch’s problem. There has been work on the Deutsch-Jozsa algorithm since it was first published; [43] propose an alternative algorithm to solving Deutsch’s problem and also talk about
how others have had similar ideas. Although improvements have been made to the algorithm,
it maintains its name because of how it was so inventive. The algorithm described here is the
original Deutsch-Jozsa algorithm. As mentioned in the preceding section, the Deutsch-Jozsa
algorithm is a more generalised version of Deutsch’s algorithm [8]. When looking at [9] which
is the original paper describing the Deutsch-Jozsa algorithm, it appears that the algorithm is
talked in far more detail and some of aspects of the algorithm are not talked about in [36] which
is the version of the algorithm that we will discuss. However, the version of the algorithm we
will be discussing will suffice to show the fundamental idea.
In essence, this algorithm determines whether a function f is balanced or constant for all values
of x. Balanced means that f is equal to 0 for exactly half its inputs and therefore, 1 for exactly
half its inputs. Constant means that f either returns 0 for every input or 1 for every input. [43]
state that the original algorithm actually could return a third possibility; inconclusive where
no information is return about f . [43] go on to describe a way in which the their proposed
algorithm guarantees to return either balanced or constant.
The quantum circuit below implements the Deutsch-Jozsa algorithm; it is taken from [36].
As we mentioned earlier, quantum circuits are acyclic and can be read from left to right. The
labels of the form |ψi � indicate various parts of the circuit referred to in explanations and equations. It is probably worth pointing out that the diagram uses the ⊕ symbol and the ⊗ symbol
which represent two different things; modulo 2 addition and tensor respectively. The large box
in the middle calculates f using a unitary transformation Uf : |x, y� → |x, y ⊕ f (x)�.
24
The input state consists of two registers; the query register and the answer register which are
set to |0�⊗n and |1� respectively. This can be thought of as n qubits in the state |0� followed
by a single qubit in the state |1�, fully we write,
|ψ0 � = |0�⊕n |1�
Next, a Hadamard gate is applied to the answer register and a Hadamard transform (a string
of Hadamard gates) is applied to the query register. Referring back to the diagram, we now
have,
�
√
|ψ1 � = x∈{0,1}n √|x�
[ |0�−|1�
]
2n
2
The rightmost term of the |ψ1 � is the famous result one gets when a Hadamard gate is applied
to a qubit, |1� and the leftmost term is the from applying the Hadamard transform to the query
register which is now a superposition of all the values.
The unitary transform Uf is then used to evaluate f which results in,
|ψ2 � =
�
x
(−1)f (x) |x� |0�−|1�
√
[ √2 ]
2n
The result of f should now have been evaluated. A second Hadamard transform is then applied
to the query register. [36] considers the effect of the Hadamard transform on a state |x� to help
understand how we determine the result of the Hadamard transform.
They use the cases x = 0
P
z(−1)xz |z�
√
and x = 1 separately and notice that for a single qubit H |x� =
, we get,
2
H ⊗n |x1 , ..., xn � =
P
z1 ,...,zn (−1)x1 z1 +...+xn zn |z1 ,...,zn �
√
2n
Noticing that x1 z1 + ... + xn zn is the bitwise inner product of x and z, modulo 2 means that
this simplifies to,
H ⊗n |x� =
P
z(−1)x·z |z�
√
2n
Now that we have calculated the effect of the Hadamard transform on a single qubit, |x�, we
can use the last equation and the equation for |ψ2 � to evaluate |ψ3 �,
|ψ3 � =
� � (−1)x·z+f (x)|z� |0�−|1�
z x
[ √2 ]
2n
We can now observe the query register to get our result. Some diagrams show a measurement
gate where |ψ3 � is to emphasise the place in the circuit where the measurement takes place. The
equation can either evaluate to 0 or 1, if the evaluation is 0 then the function is constant, if it is
1 then the function is�balanced. This is because we note that the amplitude of |0�⊗n is extracted
from |ψ3 � above as
x(−1)f (x)/2n so when f is constant, the amplitude is ±1 depending on
the value of what f (x) takes. |ψ3 � is of unit length so all the other amplitudes would have to
be 0 so the observation would determine that the function is constant. Conversely, in the case
where f is balanced, the amplitude of |0�⊗n would be 0 so an observation would not be 0 or 1
or more qubits in the query register meaning that the result would be balanced.
It is this author’s opinion with very little hesitation that the Deutsch-Jozsa algorithm is more
efficient than any classical algorithm anyone could ever write. This is because this algorithm
adopts quantum parallelism so it can evaluate f in one iteration of the circuit.
25
The worst case of a classical algorithm computing f can be described using a thought experiment so we can appreciate the efficiency of the Deutch-Jozsa algorithm. This experiment
involves socks like when we mentioned Bertlmann’s Socks [25] earlier when describing entanglement. We shall use Bob in this thought experiment. Bob wants to travel to London for a
mathematics conference and he has to get up very early, so early in fact, that it is still dark.
Bob forgot to pay the electricity bill so he can’t see anywhere which makes getting changed a
bit of a challenge. Bob successfully finds where his pile of socks are but different colours are
all mixed in together. However, he knows that there are exactly 100 socks and he only likes
the colours green and orange so the pile can only consist green and/or orange socks. The socks
could be either all green, all orange or exactly half green and therefore exactly half orange. The
conference in London is all about determining whether a function is either balanced or constant.
Bob decides to find out whether or not his pile of socks if balanced or constant with respect to
the colours of the socks. Being a mathematician, Bob has a little think and contemplates the
number of socks he must pick out to find whether the pile is balanced or constant. Bob regrets
even thinking about the problem because he realises that he is going to have to pick out 51
socks to take outside to look at in the street light! This is because Bob could carry on picking
out let’s say, green socks until he reaches 50 but he still would not know whether to pile is
balanced or constant because the 51st could be green or orange. In contrast, the Deutsch-Jozsa
algorithm can look at all the colours of the socks at once. This thought experiment is analogous
to 1s and 0s in an algorithm computing whether a function is balanced or constant.
We have seen what the Deutsch-Jozsa algorithm is, how it works and we have compared it
to the way a classical algorithm would solve the same problem but less efficiently. We have also
noted that further research has been carried out on the algorithm which we have not gone into
so we can study a range of quantum algorithms. The question we have asked yet is whether or
not the Deutsch-Jozsa algorithm is actually useful in the real world. From the research carried
out in this dissertation, no work has been found that has actually implemented the DeutschJozsa algorithm but as mentioned earlier, Deutsch’s algorithm was implemented by [52]. It is
the author’s opinion that in reality, the algorithm will be used rarely but it was an important
advance in the quantum computing field because it paved the way for Shor’s algorithm and
Grover’s algorithm which are sophisticated and have genuine real world uses.
Shor’s Algorithm
Shor’s algorithm is the most recently implemented quantum algorithm. Its purpose is to factorise large integers; the original paper is here: [40]. It is the writer’s opinion that Shor’s
algorithm is the most impressive quantum algorithm that has been published and implemented
because if quantum computers are constructed, the algorithm would have huge implications
not just on the way computers are constructed and their performance but also on directions of
research. That is not to say that the previous algorithms we have talked about ([8] [9]) are not
remarkable too because they provided a basis for Shor’s algorithm.
Shor’s algorithm can break RSA encryption [11] which is the method of encryption that is
used worldwide for applications such as the secure transmission of credit card details. RSA’s
name comes from the second names of Ron Rivest, Adi Shamir, and Leonard Adleman who
invented the method of encryption. An article that talks about the history of RSA [50] quotes
Adleman: “What resonated with RSA is that it didnt look like anything other than factoring
would break it.”. RSA encryption is based on the assumption that using any current classical
26
computer, you cannot find the prime factors of a very large integer in a reasonable amount of
time. No matter how much our compute power grows, the integers being processed can simply
get bigger to compensate.
Quantum cryptography is current a research interest that claims to provide secure encryption;
we quote an article from Scientific American: “In principle, the technique [quantum cryptography] provides the makings of an unbreakable cryptographic key” [18]. Research in quantum
cryptography is important because society needs secure data transmission; if quantum computers are constructed then it would be foolish to rely on the RSA encryption algorithm, however
brilliant it currently is.
Let us now begin with explaining Shor’s algorithm. My explanation came from [47]’s article on how to explain Shor’s algorithm to a someone without a heavy physics background.
One unsuccessful approach to finding the prime factors of a large integer would be to try
all divisors in parallel and instantly picking the right one. This is futile because the required
compute power would be astronomical and unfeasible. Earlier we talked about quantum parallism which could be applied here but as we also mentioned earlier, when we measure the
outcome we get a random possible answer, a divisor in this case. This is unlikely to be the
divisor we want. We are going to have to try a different approach; we need to find some sort of
structure in the factoring problem.
It’s worth briefly pointing out that the first part of Shor’s algorithm doesn’t actually use any
quantum mechanics. We are going to exploit something called period finding. We will explain
this by example, here is the sequence of powers of 2,
2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, ...
Here is the sequence of the powers of 2 mod 15,
p=4
p=4
� �� � � �� �
2, 4, 8, 1, 2, 4, 8, 1, 2, 4, ...
Notice that this gives us a periodic of the sequence. The period of the sequence here is 4. Now
look at powers of 2 mod 21,
p=6
p=6
�
��
� �
��
�
2, 4, 8, 16, 11, 1, 2, 4, 8, 16, 11, 1, 2, ...
Leonhard Euler is a famous mathematician and physicist who found a pattern relating to period
sequences. Let N be a product of two prime numbers, p and q and consider the sequence,
x mod N, x2 mod N, x3 mod N, ...
If x is not divisible by p and q then the sequence will repeat with some period that evenly divides (p − 1)(q − 1). For an example, let N = 15 which is the number [31] successfully factored
in his implementation of Shor’s algorithm. If N = 15 then the prime factors of N are p = 3
and q = 5, so (p − 1)(q − 1) = 8 and the period of the sequence is 4 which divides the result
of 8. This is important because if we can find the period of the sequence above then we could
find a divisor of (p − 1)(q − 1).
27
We need to find when the sequence above starts to repeat itself but this could be unfeasible to do on a classical computer. Instead, we could create a quantum superposition over all
the numbers in the above (now we see the quantum mechanics coming in).
We need to compute x mod N, x2 mod N, x3 mod N, ... in a feasible amount of time. We
introduce something called repeated squaring, let us use another example with N = 17, x =
3, r = 14 where r is the exponent of x. The first thing we need to do is represent r in a sum of
powers of 2,
r = 23 + 22 + 21
so we can get,
xr = 314 = 32
3 +22 +21
3
2
1
= 32 · 32 · 32 = ((32 )2 )2 · (32 )2 · 32
and we can do all the multiplications modulo N to prevent the numbers scaling quickly at each
intermediate step,
314 mod 17 = 2
which shows us that we can create a superposition over all pairs of integers of the form (r, xr
mod N ). The next step is to make use of this superposition to get the period of the sequence
out. This is done using the quantum Fourier transform (QFT).
The quantum Fourier transform is used to crucially map the quantum state encoding the
periodic sequence to a quantum state encoding the period of the sequence using a linear transformation. The result we get when we perform an observation at the end of the circuit of the
QFT is meant to give us a high probability of getting the true period.
The start of the discussion of Shor’s algorithm stated that this algorithm has been successfully implemented. This is true but some say that [31]’s implementation wasn’t a true quantum
implementation because according to [26], entanglement was not observed. I believe that the
algorithm has been implemented, whether it was [31] who first managed it, we don’t know, but
the implementation has claimed to have been done by others too including [5]. Below shows a
computer generated graphical representation of IBM’s “World’s most advanced quantum computer” [23]:
“Each of the five fluorine and two carbon-13 atoms in this molecule can act as a quantum bit,
or qubit, to solve mathematical problems because their spins can interact with each other as well
as be individually programmed (by radio frequency pulses) and detected (by nuclear magnetic
resonance).” [23]
28
Grover’s Algorithm
Consider the following well known problem called the travelling salesman, quoted from [19]:
“Suppose that it is your task to schedule the visits of a travelling salesman to 10 regional offices.
You are given a map with the 10 cities and distance in miles, and you are asked to produce the
itinerary that minimises the total distance traversed.”
There are too many tours to be examined because even if there are only 10 cities, there would be
9! itineraries. If the salesman wanted to visit say, 40 cities then this would be 39! which is larger
than 1045 itineraries which is computationally unfeasible using any classical computer. Grover’s
quantum search algorithm was invented in 1996 by Lov Grover so after Deutsch’s algorithm,
the Deutsch-Jozsa algorithm and Shor’s algorithm.√Grover’s algorithm enables the travelling
salesman problem to be solved with complexity O( N ) which is a definite improvement over
the complexity a classical computer would have to solve the problem (O(N )). This is not an
exponential speedup algorithm, it is an improvement over a classical algorithm,
Grover’s algorithm works probabilistically like the other quantum algorithms we have discussed.
The algorithms runs and gives the correct answer with a high probability. Let us explain how
the algorithm works; I will use [13]’s explanation as a guide.
Given an unstructured list of size N for an x that makes a statement true is searched using
Grover’s algorithm. Let there be a n such that 2n ≥ N and let Up be a unitary transformation
that implements the classical function P (x) that tests that the following statement is true where
true is the result of the statement being 1:
Up : |x, 0� → |x, P (x)�
The next step is similar to Shor’s algorithm and is standard in quantum algorithms since it is
how quantum parallism is realised as we have also talked about. We compute P for all inputs
xi by applying Up to a register containing the superposition
�n−1
√1
x=0 |x�
2n
of all 2n possible inputs x together we a register set to 0. This results in the following superposition
�n−1
√1
x=0 |x, P (x)�
2n
Again, as we mentioned in the quantum parallelism section, although we can seemingly evaluate
all inputs x for a function P (x) simultaneously, it is difficult to get the result we want out of
all these possible evaluations. Mathematically,
for any x0 such that P (x0 ) evaluates to true,
�n−1
1
|x0 , 1� will be part of the superposition of √2n x=0 |x, P (x)�. The he amplitude of such a state
gives us
which means that the probability of a random measurement yielding x0 is only 21n .
�
Grover’s algorithm involves changing the quantum state, √12n n−1
x=0 |x, P (x)� to increase the
amplitude of the vectors of |x, 1� for which P is true and conversely, decreasing the amplitudes
of |x, 0� for which P is false.
√1
2n
After we have performed these increases and decreases of amplitudes, we can measure the
29
last qubit of the quantum states that represents P (x). We increased and decreased the amplitudes so there is a high probability that the result we read will be 1 and a low probability
that �
the result is 0. If the result yields�1 then the measurement has projected the state,
n−1
k
1
√1
x=0 |x, P (x)� onto the subspace 2k
i=1 |xi , 1� where k is the number of solutions. Tak2n
ing measurements of further qubits will provide one of these solutions. If the result yields 0
then we would have to start from the beginning again and hope we get the result of 1 next time.
Let us look in more detail how we increase and decrease the amplitudes to give a correct answer
with a high probability. To increase or decrease these amplitudes aj , we need to change the sign
(aj to a−j ) for xj such that P (xj ) = 1. To achieve this, let Up be a transform that performs
the
1 �n−1
√
computation Up : |x, b� → |a, b ⊕ P (x)�. We apply Up to the superposition |ψ� = 2n x=0 |x�
and choose b = √12 |0� − |1� to result in a state where the sign of all x with P (x) = 1 has been
changed and b is unchanged.
We then apply a separate quantum algorithm to compute an inversion about the average to
increase the amplitude of xj with P (xj ) = 1 make the amplitude of all the xi s with P (xi ) = 0
more unnoticeable. The algorithm described in [13] is a unitary and invertible transformation
which can be represented by a set of quantum gates or a matrix is given as,
�N −1
�N −1
i=0 ai |xi � →
i=0 (2A − ai ) |xi �
√
where A denotes the average of the ai s. We then repeat these steps π4 2n times.
That is basically Grover’s algorithm put as simply as possible. If we have N search items
then on average, with a classical sequential you will need to look at an average of N/2 element
before finding the item we want. The worst case would be to look at all the search items with
the last item being the one we want which would be the worse
case of N comparisons. Using
√
Grover’s
algorithm we would get the right answer on the N th attempt on average. N/2 to
√
N is an impressive speedup but there is no way that can be improved
with this approach. In
√
[13]’s article, he claims that repeating the algorithm more than π4 2n times (in the hope that
√
we get the answer with a higher probability) to anywhere near π2 2n results in a failure rate
nearing 1 (failure every time). The reason for this is because when Hilbert Space is a complex
vector space, repeated iterations of the algorithm will move nearer to the desired result for a
while but it will eventually rotate past the required state.
What are the limitations of quantum algorithms?
This project has presented some powerful quantum algorithms that are more efficient than any
classical algorithm that could attempt the same task. However, are quantum algorithms the
definite route to the next generation of computers? The best article on the limits of quantum
that the author found is [47] by Aaronson. I want to give my view on the limits and promises
that quantum algorithms hold. I will use my understanding of complexity theory in my explanations and draw in ideas from Aaronson’s article too.
In computer science, we are interested in how much time is needed to solve a problem as
the problem size increases. We group problems into classes such as P, NP, NP-Complete and
PSPACE depending on how efficiently they can be solved. We can divide these classes further
but the ones mentioned here are some of the most widely talked about. The image below
represents the different classes and how they overlap with one another.
30
The image is an edited version of an image from [36] when they are talking about complexity
classes. What this image does not show which the author thinks is important is where the
NP-Complete class fits into the picture. NP-Complete sits inside the class NP.
The circle that embodies all the other complexity classes mentioned in the diagram is PSPACE.
PSPACE is the set of problems that can be solved by Turing machines in a polynomial amount
of space. Problems in the class P stand for polynomial time. An example of an algorithm that
runs in polynomial time is Euclid’s algorithm for finding the greatest common divisor of two
numbers. Using a classical computer we can solve problems in this class in a reasonable amount
of time. It is also believed that a quantum computer could solve these types of problems efficiently too.
The NP class is the class of problems whose solutions are easy to verify. It is a large class
because all problems in the class P and the class NP-Complete are in the NP class. A curious
and interesting example of a problem the NP class is graph isomorphism which is studied in
graph theory. It is an interesting example because this problem is not be in either NP-Complete
or P. An algorithm to solve this problem would need to test for equivalence between two graphs.
An efficient solution to one NP-Complete problem would provide us with a solution to all
problems in the NP-Complete class. There are currently no known algorithms to solve problems in the NP-Complete class. Earlier we mentioned The Travelling Salesman Problem, this is
a problem that is in the class NP. When we discussed Shor’s algorithm, we saw that it solved the
problem of factoring integers in polynomial time rather than the exponential time that would
be needed on a classical computer. This is good news but this is not an NP-Complete problem
and Shor’s algorithm structured the problem before it was solved using quantum means. This
structuring would be needed to solve more NP problems and to solve a problem (and therefore
all problems) in the NP-Complete class. [47]’s article states that structuring a problem and then
handing it over to a quantum computer is not enough to solve problems in the NP-Complete
class. He states that to solve these problems, a structuring “in ways that are unlike anything
we have ever seen” would be needed. Classical and quantum algorithms would both need to
structure problems like these before being able to solve them so maybe quantum computers are
31
not the end of the story? This is an open question.
We need to think about where the class of problems that quantum computers could solve would
fit into the picture. We call this class BQP, meaning bounded-error, quantum polynomial time.
BQP does not overlap the NP-Complete class because quantum algorithms do not promise to
solve these types of problems. The image below indicates where in the previous diagram the
class BQP might fit in:
Notice that the class BQP has dashed lines, this is because we are still unclear which problems
quantum algorithms will actually solve. In this picture and in Aaronson’s article, the BQP
class overlaps NP and P.
We now reach a crucial part of this project. Quantum computing is undoubtably a subject
of fascination but maybe quantum computers will provide us with findings greater than efficient algorithms. Maybe we haven’t pieced together everything that is needed to solve these
problems yet. As Aaronson points out, quantum theory is not believed to be the physical theory
of the universe, physicists are working on a unified theory of everything. Aaronson’s opinion
is that the greatest achievement possible in quantum computing would be to discover a fundamental reason why quantum computers would not work. This is because it would overturn the
current picture of the physical world. This might take us a step closer to coming up with a
unified theory of everything. In my opinion, whether they end up being created or not would
both produce fruitful results. I think that maybe if whole quantum computers are not created
then we could have some sort of co-processor that solves particular problems that a user might
ask the computer to solve that is not feasible for the classical processor to solve.
2.2.6
The Quantum Turing Machine
The quantum Turing machine (QTM) is generally regarded as David Deutsch’s quantum Turing
machine. There were other people such as Feynman, Pere and Benioff who proposed quantum
Turing machine too but Deutsch built on these ideas. [8]’s paper argues that Feymann’s proposed machine was actually classical. This is backed up in a more recent text book describing
32
all the machines [27] which also calls Pere’s and Benioff’s two machines to be inherently classical too. Looking at models of computation rather than the quantum circuit model of quantum
computing is a different way of thinking about the operation of a quantum computer. [3] states
that the two models are equivalent, I would believe this to be true because classical logical circuits are a just a different classical theoretical model for describing computation. The author
has found much more work on quantum circuitry; texts books do not seem to mention as much
about the QTM. In Deutsch’s paper describing the QTM he mentions a quantum automaton
that was proposed by Albert in 1993. He states that this was a true model of computation
but more limited than Deutsch’s model, the same goes for automata and Turing machines in
classical computation. We shall only look at Deutsch’s model of computation in this project
and study more indepth about the circuit model.
The author’s explanation of Deutsch’s quantum Turing machine (U ) will come from [27]. Like
with the classical Turing machine, Deutsch’s quantum Turing machine has a input tape t, that
is of infinite length. In his paper describing the machine he states that the tape has to be rigid
and there is mechanism that move the tape according to signals transmitted at a finite speed
between adjacent segments. The quantum Turing machine has a processor just like the classical
one does. There is an observable x which has any integer Z as its possible value. x is a pointer
to the current section of the tape that is being scanned. This means that U is a unit vector that
spans the space by basis vectors |x, t, m�. The movement of U is given by a constant unitary
operator U . The evolution of |ψ� holds the following:
�
|ψ(t)� = U t |ψ(0)� where |ψ(0)� = n λn |0, 0, t�
only finitely many λi are non-zero if an infinite number of elements t are non-zero. Deutsch also
proposed the universal quantum Turing machine that he claims is capable of simulating every
finitely realisable physical system and therefore any quantum computer with arbitrary high
precision. This requires understanding of dense coding that is not covered in this project. The
Turing machine has never actually been physically built, the quantum Turing machine might
never be built either. The reason for the machines to exist are to understand computation
with all the programming rules removed leaving only a pure model of computation that we can
study.
2.3
Realisation of The Quantum Computer
2.3.1
Will quantum computers exist in the future?
The author believes that the biggest open question that is asked in quantum computing is
whether or not we could build a quantum computer. When we say quantum computer, we are
referring to a machine that has escaped the physics laboratory and can be used for general
computing. This is a very vague description but some amazing quantum devices have been
built but they are not complete quantum computers with a defined architecture and interface.
They require an understanding from chemistry, physics, mathematics and computer science to
actually use them to compute something.
It is not surprising that the author is not alone in asking whether quantum computers will
be built, for example, [13] contemplates the same thing. A question that could proceed this
would be whether or not a quantum computer would actually be considerably faster than a
classical computer. The reader may ponder why the second question is asked when this chapter
33
has presented efficient quantum algorithms, a sound theoretical model of computation and some
exciting work in the field. However, some say that if quantum computers are built, they might
not be extraordinarily faster than their classical counterparts despite all the fascinating work
and ideas that have been put across in this project. Then there’s the question of money, maybe
quantum computers will turn out to be far too expensive to build. On the other hand, we may
have no choice if we reach the limits of classical computing like Chuang suggests we might in
the introduction of this dissertation.
Let us save the question of whether a quantum computer really could be faster than a classical
computer for now and talk about whether they could actually be built. When the author reads
this dissertation in the future, it is hoped that the answer to whether quantum computers will
be built will be firm yes. Relating back to the introduction to this chapter, there are other big
ideas out there that are being researched to cope with the stronger and stronger compute power
required by the world but the author chose to research the quantum computer idea because it
sounds like this area looks the most promising. We would be foolish to say quantum computers
will definitely exist in the future but the author thinks there is a great possibility and since
small quantum computers have been built, although for relatively specific purposes, the author
believes we are getting closer to the true physical realisation of a quantum computer. We will
present some of the achievements that have been made in physically realising quantum computers that we think are the most important and exciting including the most recent developments.
Papers are written to accompany these developments but contain schematics relating to how
the machines are built which is beyond the scope of this project. Press releases are also available
but these are often exaggerated or don’t come with appropriate explanations and there are often
contradictions between different articles. We will only provide information on projects where
we have found sufficient information about where they took place, who was involved and what
technology was used. The sources that we present here are mainly from the Internet because
they are more readable than machine schematics.
2.3.2
Quantum computer technology
Before we begin we should briefly describe from a very abstract perspective, what technology is
being used to make these new quantum machines and how and why it is being used. A technique
that was used to build the first 2-qubit quantum computers and later larger quantum computers
is using nuclear magnetic resonance (NMR) devices that detect radio frequency pulses. These
pulses are used to program the interactions between a set of atoms’ nuclei spins. One can imagine this process is rather complicated in itself but it has been used to create quantum computers
with increasing numbers of qubits. NMR is a technique that is widely heard of in a hospital
environment for medical diagnosis and used and by chemists and biochemists to establish the
molecular structure of a material. It works by detecting the tiny radio signals emitted from
nuclei in a magnetic field. More recently a different approach has been used called ion trapping.
[55] describes this concept as “They [Ion traps] work by trapping super-cooled ions in an electric
field. Lasers can then be used to manipulate the ions to alter their quantum states.”.
Although a number of quantum computing devices have been constructed using these technologies, [32] recently raised major concerns about whether NMR quantum computers could
scale well and even more boldly, whether the quantum mechanical concept of entanglement is
needed for quantum computers. In a very recent news article by [30], the author outlines the
34
problems and solutions of scaling up quantum computers, particularly ion trapping quantum
computers. The article is very brief and it only mentions two projects but it does mention
that ion trapping is being used in quantum computing research. It also states that there are
problems with heat build up and trying to protect against stray magnetic fields but they have
come up with solutions. In the author’s opinion, from the sources presented in here, it looks as
though the NMR approach has issues but ion trapping is producing interesting results. I can
back this opinion up with [13] who states that NMR and ion trapping are the most advanced
of the quantum computing technologies so far.
Current research in quantum computing at the moment is very broad with different institutions
undergoing different approaches including ones other than NMR and ion trapping. A project
called Quantum Information Science and Technology Road mapping Project [45] is something
that is in place to ‘help facilitate the progress of quantum computation research towards the
quantum computer science era’ [45]. It contains links summarising what each approach is
about and which institutions are researching each idea.
2.3.3
Current quantum computing devices
The first quantum device that was constructed was the Controlled-NOT gate implemented by
[6] in 1995. In 1998 quantum computing blossomed when the world’s first 2-qubit quantum
computer was presented. Two teams managed to create a 2-qubit computer, the first being
Jonathan Jones and Michele Mosca at The University of Oxford. Secondly, a group formed by
Stanford, Berkeley, MIT and IBM’s team led by Issac Chuang also created a 2-qubit quantum
computer. These devices were both built using NMR technology.
The next wave of research was the implementation of the quantum algorithms that have been
discovered. These algorithms were all discussed in detail in the quantum algorithms section
earlier. Deutsch’s algorithm, the most simple of quantum algorithms was implemented by [34]
on a ‘photonic’ computer (another research direction indicated on the quantum road mapping project); [34] notices that the future algorithms to be implemented will have to overcome
greater difficulties such as quantum decoherence which we also talked about earlier. However,
after this algorithm was realised, Grover’s algorithm was also implemented by [35] using NMR
technology. Quantum computers increased from 2-qubits all the way up to 7-qubits which was
also demonstrated by Chuang’s team at IBM (and other Universities) [31].
[30] suggests that for a quantum computer to be used ‘commercially’, the computer would
have to operate on at least 30 qubits. This is a great difference from the 7-qubits that Chuang’s
team developed. However, a company has emerged called ‘D-Wave: A Quantum Computing
Company’ who claimed in 2008 that they have constructed a 128-qubit quantum computer.
This would have huge implications because if [30] is right then this would mean that we have
a quantum computer that could be made available commercially. We should be cautious here
although because these devices are hugely different from any classical computer; building one
of these machines is just the start, a lot of development would have to be carried out for people
to use these computers. The bad news is that their claims have yet been verified and the information available is sparse. A picture of their apparent 128-qubit chip is shown below because
it would be important if it does turn out that this company have really made the chip they
claim:
35
“The left-most chiplet in the middle is an 8-qubit unit cell break-out. The chiplet to the right
of this is a 2 × 2 array of unit cells (32 qubits). The chiplet to the right of that is a 4 × 4 array
of unit cells (128 qubits)” [12]
2.4
Existing Quantum Simulation Software
We have mentioned that the biggest application of quantum computing could be subjecting
quantum mechanics to tests harder than its has ever faced before. Will we succeed in building
a commercial quantum computer? If we won’t then what will be the thing that will cause it
to fail? The author thinks that it is excellent that a large number of teams are now interested
in building these machines. Scientists will surely either build a quantum computer or find out
why they cannot; both results would be hopefully either change the world or our understanding
we have of it.
It would be unfeasible for the author to attempt construction on one of these machines. Furthermore, our approach to this field is from a computer scientific and mathematical perspective.
We will achieve more if we use the skills we have acquired in our discipline and make a piece
of software to simulate how a quantum computer would work rather than worry about the
delicate and extremely complex physical assembly of a quantum computer. At the start of this
project we talked about how there are very few pieces of software that simulate how a quantum
computer would operate. However, although there are a few tools out there, we feel as though
they do not exhibit all the good properties of software. Also, we have found that they require
a relatively deep understanding of quantum computing to figure out their operation. Our aim
is to create a unique quantum simulation that exhibits all the good properties of software and
allows users not very familiar with quantum computing to understand it better though the use
of our new simulation.
We feel as though there are two approaches to simulating a quantum computer. The first
is the simulation of the circuit model of quantum computing and the second would be the
simulation of the computational models of quantum computing. We have found a great deal
more literature on the circuit model so our understanding is far greater there. There are a few
pieces of software written to simulate the circuit model of computation, written in a variety of
programming languages. We have found a selection of different pieces of software that we have
explored and found out what functionality each piece has and whether there are any gaps that
we could fill with a new piece of software. Furthermore, to analyse how good each interface of
the simulations are, we used a heuristic evaluation technique from human computer interaction
(HCI) invented by [44]. Note that [44]’s heuristic evaluation usually does not include outlining
positive points of the interface. However, we are going to include both positive and negative
36
points to help build requirements later on in the next chapter because our intention is more than
just improving an interface. This section will be a different flavour to the preceding sections.
We have presented an introduction to quantum computing and talked about current and past
research but this section will be analysing existing software.
2.4.1
jQuantum Quantum Computer Simulation
Above shows a quantum computer simulator written in Java by Andreas de Vries that I have
labelled. It comes with a number of example circuits the user can load that simulate the
main quantum algorithms including Deutsch’s algorithm, The Deutsch-Jozsa algorithm, Shor’s
algorithm and Grover’s algorithm. It can also simulate the quantum Fourier transform. One
can see from the image that is has a full WYSIWYG graphical user interface. The user can
click on quantum gates that make them appear in the workspace to build a circuit and step
through it. Quantum circuits are built from left to right, showing that quantum circuits do not
contain loops. There are a large variety of quantum gates/transforms available to use, there are
also some that I have not mentioned in this project. The following are the gates and transforms
that the software can simulate that we have discussed in this project:
• Hadamard
• Controlled-NOT
• Pauli-X
• Pauli-Y
• Pauli-Z
• Toffoli
• Measurement gate
• Quantum Fourier transform
• Inverse Quantum Fourier transform
37
We will now show the results of our heuristic evaluation of the graphical user interface.
Consistency & Standards
(+) Every circuit is built in the same way and the results are always shown in the registers.
Help & Documentation
(-) There is documentation of the software’s website that includes a very basic introduction to
quantum computing and instructions on how to initialise and build a quantum circuit. The
documentation points the user to a different project for more information on the theory behind
quantum computers. There is no further help given and everything is rather brief, the documentation’s English language leaves a lot to be desired for.
Help Users Recognise, Diagnose and Recover from Errors
(-) There are no help messages or suggestions in the software, the documentation and software
are very separate entities.
Aesthetic & Minimalist Design
(+) The interface provides buttons for the fundamental quantum gates, a workspace to add
them and registers to store qubits. Overall minimalist yet functional with a nice looking interface.
Error Prevention
(+) It is difficult to make errors because the user is forced to only build a circuit in one way.
There is nowhere in the software where the user can type into a text box; data is automatically
validated by use of controls such as combo-boxes and buttons.
Visibility of System Status
(+) The state of the registers are always shown and there is a line indicating where in the
circuit the computer has reached.
Match Between System and Real World (+) All gates have the same symbols as they do
in quantum computing literature and Dirac notation is used.
Flexibility and Efficiency of Use
(+)(-) Circuits can be built extremely quickly and also tested with speed to. There is a delete
button which deletes gates from right to left. There should probably be a delete all button too
otherwise you have to delete the whole circuit either repeatedly pressing the delete button or
creating a new circuit.
Recognition rather than recall
(-) There is nowhere in the software that reminds the user what the various gates do. Users
have to remember exactly what the purpose of each gate is.
User Control & Freedom
(+) The user has control of the circuit as well as the size of the registers. The software provides
all the games and transforms that the user is likely to need to understand quantum computing
circuitry.
38
We think that this software could definitely be improved. The documentation needs to be
more expansive and there needs to be better help available when building quantum circuits.
From the documentation, the programmer has stated that the software’s main intention is for
learning and understanding quantum algorithms to help build new quantum algorithms. Although having a tool to aid quantum algorithm invention would be a great idea, the author
would rather create a piece of software that is there for learning about quantum computers.
Therefore, we would provide more help when creating circuits to make it easier to learn about
quantum computers and we would link the documentation from the program rather than having the program and documentation separate. The register is colour coded to represent the
complex vector plane:
This is quite a clever way of showing complex numbers but we have have doubts whether the
effort required to implement something like this would be proportional to the amount a user
could learn from the representation. We do not think that we shall adopt a representation like
this in my software. It is not very explicit which is quite serious, there is no way of telling
exactly what number is represented by a colour, especially when a number is between two
colours. The author believes that this is one of the biggest shortfalls of jQuantum.
2.4.2
libquantum
Although there are very few quantum computer simulators around at the moment, we have
found that there are libraries written that implement quantum registers, gates and algorithms.
The most well documented and promising library that was found is libquantum which is a
library for the C programming language. We have recorded what we have found out about this
library here because if a library such as libquantum was used then we may be able to produce
results faster when it comes to programming our software. It was decided however that using
someone else’s code may reduce the amount learnt from the programming experience; one of
the main aims of this project was to learn about quantum computing. Furthermore, there’s the
worry that using third party code isn’t fully correct and trying to work pre-written code into
our code and systems architecture may be cumbersome. Features that libquantum offers:
• Quantum gates
• Quantum Fourier Transform
• Shor’s algorithm
• Grover’s algorithm
• Quantum registers Implementation
The library puts effort into accurately simulating quantum algorithms. For example, quantum
algorithms have the property that they sometimes do not return a valid answer such as Grover’s
39
algorithm where it returns the correct answer with high probability. Let us run a program
included in libquantum that implements a simulation of Shor’s algorithm:
$ ./shor 150
N = 150, 41 qubits required
Random seed: 73
Measured 24576 (0.750000), fractional approximation is 3/4.
Possible period is 4.
150 = 10 * 15
$
$
$ ./shor 150
N = 150, 41 qubits required
Random seed: 113
Measured zero, try again.
$
$
$
$ ./shor 150
N = 150, 41 qubits required
Random seed: 101
Measured 16384 (0.500000), fractional approximation is 1/2.
Possible period is 2.
150 = 50 * 3
$
This is the result of running the program, shor.c three times. As you can see, the algorithm
successfully factored 150 into 50 and 3 and also 10 and 15. However, the algorithm failed to
find the factors when it was executed the second time, simulating the probabilistic nature of
quantum computers. The program lets you know how many qubits it believes that the quantum
computer that is being simulated would need. It also gives you the number of the seed that is
being used to produce the random numbers to factor the numbers (it is the author’s opinion
that this isn’t hugely useful though).
The author attempted to check what the prime factors of 1500 were but the program consumed all the laptop’s resources. This is obviously a limit to the simulation; the real quantum
algorithm would finish a lot quicker. Here lies a significant limitation of any simulation of a
quantum computer, simulating a quantum computer requires a vast amount of memory. This is
because of the exponential growth of a the state space that qubits operate in meaning that we
cannot possible have enough memory to run a simulation of any size. libquantum have a classical algorithm that is working the factors out and fails randomly to simulate the real quantum
algorithm. The memory consumption problem will be discussed in detail in the requirements
chapter
40
2.4.3
QCAD: CAD for Quantum Computer Simulator
QCAD is a quantum circuit simulator that has been in development since 2002 by Masaru Suzuki
and Junnosuke Yamazaki at The University of Tokyo. Below shows an example circuit that we
built using QCAD:
The circuit can be read from left to right. Our circuit operates on two qubits, the first qubit is
set to |0� and the second is set to |1�. A Hadamard gate is applied to the first qubit which puts
the qubit into a superposition between an observation yielding 1 and an observation yielding 0,
√
recall the superposition statement [ |0�+|1�
] from earlier. We then attached a Controlled-NOT
2
gate to the circuit with the control qubit being |1�. The Controlled-NOT gate flips the target
qubit if the control qubit is set to 1. Finally, we added a measurement gate to read the result
of the target qubit. Below shows the result of our measurement.
In this case the result is 1 on the part of the input that represents our target qubit. Notice
also that the software has given us the probability that this was going to occur, here is was 12
because of the Hadamard gate.
Let us now see the result of a heuristic evaluation that we performed on its interface. Again,
we will also note positive points in the software to help us form our requirements in the next
chapter.
Consistency & Standards
41
- No points Help & Documentation
(-) Unfortunately, the documentation for this software is very sparse. We were not able to
even find out what the different representations of the results actually meant because there is
nothing in the documentation about the various representations of the output that the software
produced. There is a brief documentation on their website with two example circuits.
Help Users Recognise, Diagnose and Recover from Errors
(-) There is a warning in the documentation that the software can consume very large amounts
of memory. They give an example that if the circuit is 32 lines long then this will use 64GB of
memory. This warning is useful but it would be better if the software warned you if you were
about to run a circuit that will probably overload your computer’s memory.
Aesthetic & Minimalist Design
- No points Error Prevention
(+) The interface forces a set routine to build a circuit; it is difficult to make any errors other
than logical ones but these are how you learn about building quantum circuits.
Visibility of System Status
(-)(+) You cannot step through circuits unlike with jQuantum but the documentation implies
that this might be added in the future. The results of measurements made after circuits have
been executed are very clear. Again, because of the lack of detailed enough documentation, the
circuit output is also given in other representations but this is not explained.
Match Between System and Real World
(+) All gates have the same symbols that appear in quantum computing literature and Dirac
notation is used.
Flexibility and Efficiency of Use
- No Points Recognition rather than recall
(+) There is a separate window that appears when you execute the circuit so you can look at
the circuit and the output side-by-side so you can make comparisons and one does not have to
remember what you used to build the circuit.
User Control & Freedom
(+) The user can have a choice of the quantity of qubits that they want but the software default
the number to 7 qubit which the user has to disable if they do not want them all.
(-) Unlike jQuantum, it runs on a Windows only platform; when we come to writing out software
we want to make it platform independent to maximise the number of users it could help.
(-) The software does feel a bit unfinished which is hinted at in the documentation. Like
with jQuantum, it could be improved to help users learn about quantum computing. For exam42
ple, taking away some of the program such as the different output representations and spending
more time on creating a better learning environment might be better. When the user decides
to build a circuit using a Toffoli gate, it would be good to have somewhere in the program that
told you exactly what this particular gate does.
2.4.4
Summary of existing software
We now come to the end of this chapter. The proceeding chapter will contain the software
requirements specification that we have developed through our research in this chapter. We
have briefly looked into the fundamentals of quantum mechanics and looked at selected areas
of quantum computing. We saw existing software being evaluated and noticed that there is a
significant lack of quantum simulation software available to students and researchers. There
are quantum mechanics simulations but very few simulate quantum computers. We also noticed that although quantum computer simulators do help a person familiar with quantum
computers to maybe gain a greater understanding, the simulations help relatively little to aid
newcomers to the field. At the start of the quantum computing section we even touched on
Feynman’s paper [39] that stated that physics would benefit in having quantum computers to
simulate quantum physics; the author believes that building simulation software to simulate
how a quantum computer would operate would be a step in Feynman’s direction.
Through the research and software evaluations, it has been decided that we should construct
a quantum computer simulator that will promote understanding to people that have an intermediate understanding of computer science such as logic gates and computational models but
not necessarily quantum computing. It is proposed that we create a user friendly, educational
simulation that truly benefits students studying quantum computing. We hope that this will
help fill the gaps that we have found in this field and it is also hoped that it will aid others in
this area of research to further their own research.
43
Chapter 3
Requirements Analysis and
Requirements Specification
44
In the last chapter we presented our extensive research into some of the main concepts in the
field of quantum computing. We focussed on the circuit model of quantum computing. We
finished the chapter with a look at the existing quantum circuit simulation software out there
and noticed that there aren’t a great deal of tools available to students and researchers at the
moment. Moreover, we also noticed that the few tools that already exist are not suited to the
newcomer of quantum computing.
From this background in quantum computing and research into the software simulations describing the circuit model of quantum computing that we now have, let us now now move on to
creating a new piece of software. This new software should fill in the gaps that these existing
simulations have.
3.1
Requirements Gathering Process
Having already completed searching for the few existing simulations that already exist, we now
need to extract and record the things that are lacking in these simulations. We should also
notice things that are good about existing simulations and decide whether to use these similar
approaches in this new software project.
3.1.1
Important strengths & weaknesses of existing simulations
Common Weaknesses
• No explanations of what any quantum gates do
• Help and recovery from errors are lacking
• Users are limited to the quantum gates that are pre-programmed
• No warnings are given for when users build resource consuming circuits
• Representations of qubit states are sometimes not meaningful e.g. colours representing
complex numbers
Common Strengths
• A WYSIWYG interface means users do not have to remember commands and spend more
time actually learning about quantum circuits
• Stepping through a circuit helps the user understand what each gate is doing to the input
• Buttons using the quantum gate symbols that appear in literature makes things consistent
and aids recognition
• Saving and loading of circuits and deleting gates are obvious advantages
3.1.2
Areas of particular importance & difficulty
State space growth
We saw in the last chapter that linear quantum state space growth corresponds to exponential
increase classically. Although this is an interesting and powerful property of quantum computers, it also presents us with a fundamental problem that we need to address when constructing
45
any simulation. This linear-exponential correspondence will be evident when we simulate a
quantum computer. The problem that we will have is that we are never going to have enough
resources available to create large simulations of quantum circuits. All quantum circuit simulations have this problem and this software will have to deal with it too.
The state space growth problem will mean that a large amount of computer memory will
be consumed by the software and the processing power moving the data around will be large
too. This means we need to think hard about which programming language and tools are to be
used to deal with this issue, this will be discussed in the Detailed Design and Implementation
chapter. Furthermore, we need to make calculations to determine what our fundamentals limits
are going to be.
Let us use the theory of state space growth from the literature review chapter to calculate
how much memory will be needed to construct our quantum circuits. This will allow us to
form an important functional requirement which will state how many qubits a user can select
and how many gates a circuit can hold. The author carried out a number of experimental
calculations to determine how large a circuit could sensibly be. Let is summarise the results
here.
Let n be the size of an arbitrary qubit register. Let l be the number of quantum gates in a
quantum circuit.
The reader may ask how one can calculate a limit on the number of qubits and length of
the circuit that the user will be restricted to for any given computer. It could seem like we
are disregarding the idea that some users could have superior computers. However, as the
state space growth is exponential, the difference between a qubit register size n and an n + 1
qubit register size can be huge when we reach a large value of n so we will be able to come
up with results that will map to a large number of computers. So even if a user were to double their compute power, this would only give them the ability to simulate one additional qubit.
Let us say that we are to implement this software in C + + for now so we can use its storage
requirements for its data types. We discuss programming language choice in the implementation chapter.
Size of single float primitive data type in C + +: 4 bytes
Size of complex<float> data type 2 · 4 = 8 bytes
Recall that given say a qubit system of size 1, the state space for a single qubit is of size
2n = 21 = 2. Thus the basis is then α |0� + β |1� where α, β ∈ C. So for a single qubit system,
the values of both α and β need to be stored which is 2 · 8 = 16 bytes. The user is going to
want to step back and forth through the circuit so if the user constructs a single qubit circuit
of length 20 then this would require (2 · 8) · 20 = 320 bytes. We will see in chapter 6 that
we also want to store the internal mathematical structure of the circuit which is going to be
a large matrix of matrices representing all the gates being applied to the register. This large
multidimensional matrix will require (2n · 8 · 2n ) · 20 · 2n bytes of memory. This formula was
derived using a memory allocation loop for allocating a 4D matrix (see chapter 6 for more
details on this) and using a variable to store the number of bytes required so it is proven to be
correct.
46
To determine the largest possible circuits that could be constructed we made a number of
calculations of varying sized circuits:
From this graph it is easy to conclude that 7 qubits will be the maximum number we should
allow in our program. We can see that for 7 qubits, memory requirements for all circuit sizes
are no more than 1GB whereas for 8 qubits we see that the memory requirements could be up
to 3GB. There is a strong possibility that users may have 3GB of memory but other parts of
the program will use memory too and the application is likely to be less responsive.
3.2
Requirements
In this section the functional (F) and non-functional requirements (NF) are defined. We also
consider the functionality that shall not be considered in this project. Each requirement is
assigned a unique name made up from a number and an ‘F’ or ‘NF’.
Priorities are assigned to each requirement ranging from 1 to 3 with 1 being the highest priority.
A larger number of priority numbers could have been chosen if the software project was much
larger but 3 levels are sufficient here. Priority 1 means the requirement has to be completed and
priority 2 means that the requirement should be completed but it is not essential to deeming
the software a success and priority 3 means the requirement will only be considered if the high
priority requirements are completed in good time.
3.2.1
Functional Requirements
• F.1. Priority 1: The user will have a graphical user interface where they can click and
place quantum gates into a workspace. The quantum gates will resemble representations
47
of gates found in literature relating to quantum computing. The workspace containing the
circuit in construction will be only allow the circuit to be built from left to right and the
circuit will be forced to be acyclic.
One of Nielsen’s usability heuristics is that the interface should promote recognition rather
than recall [44]. If users have read anything about quantum gates then if we use symbols
from quantum computing literature then they will likely recognise the symbols, this is
recognition. Functional Requirement F.2. will help users that have no previous experience.
The circuits must be acyclic because it is crucial property of a quantum circuit. The
reasons for the circuit having to be acyclic are given in the previous chapter. Theoretically, there is no difference to going from left to right or the other way round but quantum
circuits are drawn from left to right in their literature.
• F.2. Priority 1: There will have a learning panel on the right hand side of the workspace
which should contain the following:
– A high level description of what the gate achieves
– An example of the gate transforming an input
– The matrix representation of the gate
The danger of having some sort of reading material available that is actually implemented
into a program is that it can become lost. With a dedicated panel containing gate information that crucially changes by itself as the user selects different gates will make the
program and learning material be one and divert the user’s attention switching to and
from the learning material.
• F.3. Priority 1: The user will be able to add all the gates researched in the literature
review, these are the following:
– Controlled-NOT
– Pauli-X
– Pauli-Y
– Pauli-Z
– Hadamard
– Toffoli
– Measurement
We saw in the previous chapter that these gates were some of the most fundamental
to creating quantum circuits. Having just the essential gates will make the interface
as simple as possible. These gates are enough to learn about the basics of the circuit
model of quantum computation. If the user does want alternative gates then functional
requirement F.7. deals with this. When these gates are added the user will be able to
step through the circuit either in one go or one step at a time. The user will also be
able to move backwards. There will be a panel which displays the contents of the qubit
register which will change as the circuit is executed. For a circuit to be built it needs to
be initialised. The user will be able to measure qubits as we discussed in chapter 2. The
48
qubit register will show the result of the measurement including the probabilities of the
measurement yielding the basis vector that was yielded and the basis vector that could
have been yielded.
• F.4. Priority 1: The user will have the option to reset the workspace to having no gates.
This is a simple requirement but simulations such as jQuantum did not have this facility. It is likely that the user will want to experiment with a number of circuits in a
single session and this will provide this functionality.
• F.5. Priority 1: There will be help on how to use the software provided in the software.
This help should be easily locatable in the menu bar.
A weakness in all the quantum circuit simulations that we saw was the lack of documentation or its poor quality. Software is defined to be a program with its associated
documentation; documentation is extremely important. However useful a program might
be, it is of no use at all if users do not know how to operate it. In the menubar will be a
help a ‘help’ option which will point the user to a help document. This document and the
learning panel will provide help on the program’s operation and help about quantum gates.
The help document must be clearly laid out and only long enough to explain how all
the main parts of the software work. The parts of the software that need to be described
are the following:
– How to Save/Load or Delete a circuit
– How to build a circuit
– How to delete a component of the circuit
– How to step through a circuit
– How to input a new gate
The explanations must contain screenshots of the various operations with concise text
descriptions to accompany the screenshots. There should be a contents page so the
document can be easily navigated. Information appearing in the learning panel is not
needed in the documentation.
• F.6. Priority 1: The user should be able to input a matrix representing a new quantum
gate. This matrix should be validated to make sure it represents a unitary transformation.
If the matrix is valid then it should appear as a button in the button panel.
This will allow the user to create a gate that is not included in the program. The previous
chapter mentioned that quantum transformations must be unitary so the validation check
for the new gate being unitary must be implemented.
No existing simulations were found to have the ability to do something like this. It
is the opinion of the author that functionality would really help students and researchers
understand quantum transformations and for this reason it is assigned the highest priority
of 1.
49
• F.7. Priority 1: The interface will comply well with the criteria stated by Nielsen’s
usability heuristics [44] and will be usable.
Time has been put aside for interface evaluation; Nielsen’s heuristics have been chosen because of their effectiveness in the author’s previous projects. These heuristics are
meant for the people who are active in development of software so this must be carried
out by evaluators other than myself. [44] stated that three people are sufficient to perform
this usability test. The author will not carry out the evaluation to eliminate bias. [44]
lists a number of other HCI experts who have challenged his suggested required number of
evaluators saying that three is too few but the number required depends on the software.
It is the opinion of the author that the interface of the software itself is not going to be
complicated enough to inherit the need for more than three testers.
When we say ‘usable’ we mean that the software performs well against usability tests.
This is discussed in the system testing chapter.
• F.8. Priority 1: The software should prevent the user from creating circuits larger than
7 qubits. The length of the circuit should be limited to 20 gates per line.
These numbers came from our calculations earlier.
• F.9. Priority 2: The user should be able to delete a single stage in the circuit.
This feature will allow the user to recover from placing an unintended gate or column
of gates in the workspace without having to clear the whole circuit.
• F.10. Priority 2: The User should be able to save and load simulations.
Common to all existing software we have seen is this functional requirement. We are
going adopt it too for its obvious advantage.
3.2.2
Non-functional Requirements
• NF.1. Priority 1: The interface will promote learning for newcomers to the field of
quantum computing.
F.2. is in place to promote learning for newcomers. A questionnaire will be designed
to find out what people think of this software as a learning too for beginners. There is
currently no course in quantum computing at this university so it can be tested on a number of computer science students who have never seen or heard of quantum computing.
Students from physics may also be asked to get a wider variety of opinions.
• NF.2. Priority 1: The software will run smoothly and quickly. This means there will
be no noticeable delays in any areas of the software.
This will be largely down to my programming skills and making sure memory is freed
after it is finished with and writing efficient code throughout the program. It is going
to be more of a challenge than usual because we know that this software could quickly
consume a large amount of memory.
50
3.2.3
Functional Requirements Dependancies
Below shows a diagram representing the dependancies that exist between the functional requirements. An arrow can be read, ‘Depends on’ from its bottom to the way it’s pointing.
Circles that are not connected mean they can be implemented independently and are placed in
no particular position in the diagram.
The fact that there are many independent requirements is a good thing because if one fails
to be completed then no other requirements suffer. However, many requirements rely on the
user being able to use the core quantum gates, F.3. and this relies on there being a working
front end of the software, F.1.
51
Chapter 4
Design
52
In light of the requirements that we formed, we now design a solution to our problem. Let us
begin with the structure of the chapter. We start by outlying the main parts of our system and
describing what they will do. We then propose an overall software architecture that takes these
parts and forms an sensible architectural pattern. Towards the end of the chapter we design
the various algorithms that will be needed to implement our system. After this chapter is a
further design chapter dedicated entirely to the user interface design.
Before we decompose our system we need to mention how this was influenced. We saw from
the literature that we explored in chapter 2 that we can look at a quantum circuit in two forms.
We can observe quantum gate symbols connected by wires or we can look at the matrices that
they represent. The user wouldn’t want to observe a circuit in matrix form for even a medium
sized circuit because the exponential state space growth would result in many huge matrices
having to displayed. On the other hand, a quantum circuit needs to be stored in this matrix
form for computation to happen. It is obvious that the system needs to be split up into parts
here. Less different is the way the quantum register is stored and the way it is shown to the
user. However, the internal structure of the register will need to undergo some computation so
the user can view their chosen parts of it.
4.1
System Decomposition
Let us decompose the system into its main components:
• Quantum register representation
• Matrix representation of quantum register
• Quantum circuit representation in the form of quantum gates symbols
• Matrix representation of quantum circuit
• Learning Panel
• Custom Quantum Gate Input
There are then system processes that drive the system based on the user’s inputs and interactions.
4.2
Architectural Design
The overall architecture of the system that was chosen is the Model View Controller (MVC)
[21]. MVC is the most appropriate architecture of choice and there are no strong competing
architectures that warrant detailed discussion.
A diagrammatical representation of the MVC is shown below:
53
We need to assign the main parts of the system to either Model, View or Controller:
Model
• Structure of conceptual quantum circuit, with;
• Mathematical structure of circuit and;
• Register history
View
• Conceptual quantum circuit
• Quantum register
Controller
• Receiving user’s choices and calling model objects
Let us see exactly why and how these components fit into either Model, View or Controller and
let’s note why it’s beneficial to use this architecture for our particular program.
[54] states that the MVC is used to bridge the gap between the human user’s mental model
and the digital model that exists in the computer. This is immensely important in this project
because there is the conceptual model of the circuit which is very simple and then we have
the much more complicated matrix representation of the circuit. From chapter 2 we saw the
exponential state space growth that quantum computers experience, this means that for each
gate we could have a huge matrix which would be nearly unreadable to a human so it is incredibly important that we successfully separate out this mathematical model with the user’s
conceptual view of the circuit:
54
Model:

View:
1
0

0

0

0

0

0
0
0
1
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
1
0
0
0
0
0
0
0
0
0
0
1

0
0

0

0

0

0

1
0
Controller: Get user’s inputs, make calls to generate matrix used by model.
The case is similar with the quantum register but less dramatic because internally the program will use a matrix of column vectors representing the state of the quantum register at
different points in the circuit as follows:
Model:


a0 a1 a2
 b0 b 1 b 2 


 c0 c1 c2 


 d0 d1 d2 


.
.
.


.
.
.
.
.
.
where ai , bi , ci are elements of the quantum register’s column vector of bases amounts at a stage
i (ai , bi , ci ∈ C).
Then the view of the quantum register will the matrix but with the elements extracted in
such a way that they are separated out for clarity (ai , bi , ci ∈ C):
View:
a0 |00� − − − a1 |00� − − − a2 |00�
b0 |01� − − − b1 |00� − − − b2 |00�
c0 |10� − − − c1 |00� − − − c2 |00�
d0 |11� − − − d1 |00� − − − d2 |00�
where ‘− − −’ is simply used to separate out the stages.
55
Controller: Get user’s inputs (move forward, move backwards), make calls to calculate columns
of a circuit to populate model’s matrix of amounts of bases vectors for a stage.
A further justification for choosing the MVC is that the Model does not depend on the View so
it is easy to make changes to the View without having to worry about the Model needing to be
altered. This is advantageous because we are going to make use of user interface prototyping
when we get to the implementation chapter later. We will be able to build a prototype view of
the conceptual circuit and register, complete the large amount of back-end programming and
then come back to improving the views later on. The views will then potentially need altering
again if we find that the interface evaluation later on reveals some possible changes that need
to be made.
4.3
Data Structures & Algorithmics
We now move on to talk about the most fundamental and interesting algorithms that need
to be designed and well thought out as well as the most important data structures involved.
This section takes the word, ‘algorithmics’ from [10]’s book on the study of algorithms. The
implementation of these areas of the program are talked about in the next chapter.
4.3.1
The Internal Quantum Circuit Data Structure
The internal structure of the quantum circuit is part of the Model in the MVC architecture.
The best way to understand this is using a diagram as follows:
Note that the ai s are labels that perhaps link to quantum gates; if there is no quantum gate
in that place then they don’t link anywhere. The ‘G’ symbol represents a quantum gate and
the ‘-’ represents a place in the circuit where there is no gate. There are three matrices in
the left of the diagram and one on the right. Each left matrix is a quantum gate, G with two
56
dimensions. The size of the left gates have x and y dimensions of 2n . These matrices slot into
another matrix that has x, y dimensions of n. This right matrix therefore has 4 dimensions; it
should be clear how this is so, think of each element of the right matrix as an index to a whole
other matrix.
4.3.2
The Quantum Register Data Structure
We touched on the data structure used for the quantum register in discussions about the MVC
architecture. Recall the following matrix:


a0 a1 a2
 b0 b 1 b 2 


 c0 c1 c2 


 d0 d1 d2 


.

.
.


.
.
.
.
.
.
Each column is the quantum register at a stage in the circuit. In reality, 20 columns will be
allocated at runtime (from calculations on state space growth in chapter 3) so we have:

a0 a1
 b0 b1

 c0 c1

 d0 d1

.
.

.
.
.
.
...
...
...
...
...
...
...

a19
b19 

c19 

d19 

. 

. 
.
Let us briefly introduce some notation that we have not seen yet. Recall that a complex
number is seen as a real part and an imaginary part. We can express this as (r, ci) where r is
the real part and c is the imaginary part.
Going back to our example, the first column will be assigned a combinations of (0.0, 0.0i)
and (1.0, 0.0i) which the user will be forced to enter before they build a circuit. The rest of the
matrix will be defaulted to (0.0, 0.0i) before the user starts stepping through the circuit.
4.3.3
Building Quantum Gates
The program will come pre-loaded with all the fundamental gates but these cannot be applied
to an arbitrary register on selected qubit(s) without a rather cumbersome algorithm being run
to process the matrix. The matrix needs to be the same size as the register (2n where n is the
number of qubits) and be constructed so it refers to the control and target qubits that the user
selects. This reason for the matrix having to be of size 2n is because the state space in the
quantum world combines through the Tensor product like we saw in chapter 2. What our
program actually does is apply the Tensor operation to the fundamental quantum gate and an
identity matrix.
57
Now let’s look at the design of this algorithm. Recall that many functional requirements depend
on functional requirement F.3 which involves having all the core quantum gates implemented.
F.3. requires that this matrix generation process is complete so it will be well thought out here.
The main stages:
• Generating vector bases for given qubit register size in a fixed order.
• Selecting which qubits in the register are needed.
• Building appropriate matrices for gates considering the size of the register and selected
qubits.
• Processing each basis vector (applying the selected pre-loaded gate to each basis vector).
• Converting this result back to Dirac form.
• Building a new basis order in the order determined by the multiplications.
• Expressing these new vector bases in matrix form with dimension identical to register
size.
• Multiplying this matrix by the quantum register column vector.
Generating Bases Vectors
Given an arbitrary sized qubit register, n the user will select which qubits they wish to act
on. This could be a single qubit, multiple quits and will either use all the qubits in the register
or just some.
When the qubit register is initialised, memory will be allocated for the bases vectors of the
register. Recall from chapter two, that 2n bases vectors are required for n qubits. There is
simple and elegant algorithm implemented for the bases to be calculated in a specific order and
stored in an array.
The easiest way to explain this is by example. Let us see how this works on an input n = 3.
Number of bases vectors, i is 23 = 8. First we minus 1 from the number of bases vectors
(i = 8 − 1 = 7). We then take this number and modulo 2 it (i = i%2), this will be part of the
basis that we store. Then we then repeat this with i/2. If i/2 isn’t a whole number then we
take floor(i/2). We repeat the above n times and then the whole process i times to get:
7 % 2 = 1
3 % 2 = 1 /∗ 7/2 i s n ' t a whole number s o u s e f l o o r ( 7 / 2 ) ∗/
1 % 2 = 1
6 % 2 = 0 /∗ 6/2 i s a whole number s o u s e 6/2 ∗/
3 % 2 = 1
1 % 2 = 1
5 % 2 = 1
2 % 2 = 0
1 % 2 = 1
4 % 2 = 0
58
2 % 2 = 0
1 % 2 = 1 /∗ we r e a d each v e c t o r from bottom t o top s o h e r e we g e t 100 ∗/
3 % 2 = 1
1 % 2 = 1
0 % 2 = 0
2 % 2 = 0
1 % 2 = 1
0 % 2 = 0
1 % 2 = 1
0 % 2 = 0 /∗ once we g e t a z e r o on t h e f i r s t operand o f t h e LHS , we a l w a y s g e t 0 ∗/
0 % 2 = 0
0 % 2 = 0
0 % 2 = 0
0 % 2 = 0
When we reverse the order of these bases we get {(000),(001),(010),(011),(100),(101),(110),(111)}
so we are done.
Selecting required qubits in register
We want to leave all the qubits alone in the register apart from the ones that are needed
for a particular quantum transformation. This is best shown by example, let’s say we have a
3-qubit system with bases:
|000�, |001�, |010�, |011�, |100�, |101�, |110�, |111�.
Let’s say we want to select the first and third qubits:
|000�, |001�, |010�, |011�, |100�, |101�, |110�, |111�.
We simply generate an array on the fly with just the qubits in question:
|00�, |01�, |00�, |01�, |10�, |11�, |10�, |11�.
Converting from Dirac form to column vector form for every basis vector
To apply a set of qubits to a matrix the qubits need to be represented in column vector form
so the qubits above would become the following:
               
1
0
1
0
0
0
0
0
0 1 0 1 0 0 0 0
 , , , , , , , .
0 0 0 0 1 0 1 0
0
0
0
0
0
1
0
1
This conversion will use the ordered bases vectors generation algorithm that we saw earlier.
Instead of creating bases vectors of three qubits we create bases for two qubits and for each
|00�, |01�, |00�, |01�, |10�, |11�, |10�, |11� we search for each of these 2-qubit combinations in the
bases vectors and return the index in the array of which basis vector the 2-qubit combination
59
is. This index is then the element in the column vector that is set to one, all the other elements
will be set to zero.
Processing Each Bases Vector
As each qubit combination above has the same column vector length as the dimension of
the matrix that it is going to be interacted with, we can perform a multiplication between
the two objects. We maintain the order of the qubits as shown above, apply the matrix and
then observe a new order. This new order will help us in our overall goal of constructing a
matrix representing the quantum gate in question being applied only to the selected qubits in
the register.
Let us continue our example using a three qubit register and selecting two qubits. We will
introduce the Controlled-NOT gate that we saw in the previous chapter as our example. We
apply the column vectors we saw earlier to the CNOT matrix as follows:
 
    
  
1
1 0 0 0
1
0
1 0 0 0
0
0 0 1 0 0 0 1 0 1 0 0 1

    
  
1) 
0 0 0 0 1 = 0 2) 0 0 0 0 1 = 0
0
0 0 1 0
0
0
0 0 1 0
0
 
1
1
0 0

3) 
0 0
0
0
0
1
0
0
0
0
0
1
0
1
0
0
0
0
0
1
 
0
1
0 0

7) 
1 0
0
0
0
1
0
0
0
0
0
1
 
0
1
0 0

5) 
1 0
0
0
    
0
1
0
1
0 1 0
0
 =   4)   
1 0 0 0
0
0
0
0
0
1
0
0
0
0
0
1
0
1
0
0
0
0
0
1
    
0
0
0
1






0 0 0 0
=
8)
1 0 0 0
0
1
1
0
0
1
0
0
0
0
0
1
    
0
0
0
1
0 0 0
0
 =   6)   
1 0 0 0
0
1
1
0
  
0
0
1
0
= 
1 0
0
0
  
0
0
0
0
= 
1 0
0
1
  
0
0


0 0

=
1 1
0
0
We then use the positions of the 1s in the column vectors to convert to Dirac form. To do this
we take the position of where the 1 is, generate an ordered bases vectors array and look at the
basis vector at the position where the 1 was found and this gives us the Dirac form. So in this
example we would get: |00� , |01� , |00� , |01� , |11� , |10� , |11� , |10�.
However, the CNOT gate is a deceptively simple quantum gate in that it guarantees that
if we have a quantum register with just zeros and ones, the result will also be just zeros and
ones. We have to remember that these zeros and ones are actually complex values and resultant
column vectors could be something less simple like:
 1

( √2 , 0.0i)


(0.0, 0.0i)
 √1

( 2 , 0.0i)
(0.0, 0.0i)
60
Here we have included the imaginary parts of a column vector and we have real values which
aren’t just zero or one. There are always real and imaginary parts but it is commonplace to
write down just a zero or one when we have only one and zeros. The algorithm we described
above with the Controlled-NOT gate is a very specific example of how this part of the whole
process happens.
We saw that the algorithm looks at a column vector such as:
 
0
1
 
0
0
and searches the vector for where a one is, stops and uses this position to convert the vector
to Dirac form. So here we remember that we get |01� from the ordered bases that we made
earlier. For a more complicated column vector like the one where we have included the real and
imaginary parts, we take this a step further and don’t look for a one but look at any element
that is not a zero and do exactly as we did before. So we use any number that isn’t zero and
follow through the same process that we did with finding a one earlier. This means that for
a given column vector we could have more than one Dirac vector which is correct. In the less
simple example that we saw earlier we would get two Dirac vectors instead of one:
( √12 , 0.0i) |00� , ( √12 , 0.0i) |10�
Quantum Gate transforms on Bases Vector to Get New Bases Order
Let us return to our CNOT example as we were. The next step is to look again at our register
bases:
|000�,
|001�,
|010�,
|011�,
|100�,
|101�,
|110�,
|111�
and just replace the selected qubits (in bold) with the new values we have just calculated.
This gives us the bases of the register but now in potentially altered order.
Every time a quantum gate is applied to a register, these reordered bases vectors will be created
on the fly. In our example we would get:
|000�,
|001�,
|010�,
|011�,
|101�,
61
|100�,
|111�,
|110�.
Again, this gets a little more cumbersome when we consider that we could have some of one
Dirac basus and some of one or more other Dirac bases for a single basis column vector that we
got from applying a quantum gate to every basis. In a case like this we get all possible bases
vectors that could arise (as opposed to there only being one possibility) and do the same as
above for all the possibilities.
Let us go back to our non-only zero/one example that produced the two Dirac vectors, ( √12 , 0.0i) |00�
and ( √12 , 0.0i) |10�. Let us say that we are again considering a 3-qubit system and we want some
quantum gate to act on qubits 1 and 3. Let us also imagine that this example is the result
for the first basis vector (let us not begin a whole new example and calculate results for all 8
bases vectors). Applying the process that we just saw above on only the first basis vector would
result in: √12 |000�, and we have a second possibility ( √12 , 0.0i) |10� meaning the the following
basis vector needs to be altered too like so: √12 |100�. So when we write out the list of bases
vectors with altered order like we did before we would get:
|000� or √12 |100�
... (and 7 more lines with one or more Dirac vectors per line).
√1
2
Building Appropriate Matrices For Gates
The penultimate stage involves creating a matrix from the altered bases orders and possibilities. Let us continue our example from before which was creating a matrix that represents
the Controlled-NOT transformation on the qubits 1 and 3 on a register of size 3. We use the
same method as before to convert our register to column vector form (again bearing in mind
that we can do this for column vectors with numbers other than one and zero too):
               
1
0
0
0
0
0
0
0
0 1 0 0 0 0 0 0
               
0 0 1 0 0 0 0 0
               
0 0 0 1 0 0 0 0
 , , , , , , , 
0 0 0 0 0 1 0 0
               
0 0 0 0 1 0 0 0
               
0 0 0 0 0 0 0 1
0
0
0
0
0
0
1
0
62
Finally we stack this column vectors
aiming to build:

1
0

0

0

0

0

0
0
on top of one another to get the matrix we have been
0
1
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
1
0
0
0
0
0
0
0
0
0
0
1

0
0

0

0

0

0

1
0
and we have now completed all the steps required to be ready to apply a quantum gate to a
quantum register. The matrix above is a simple matrix with just ones and zeros and only one
non-zero element per column, a permutation matrix. Recall that we can have several possible
Dirac vectors that can be formed after the multiplication between the quantum transform and
each of the column vectors, this would mean that a matrix row could have more than one
non-zero element.
Recall our example of where saw the order of the bases changing and there being more than one
possibility for each basis. Remember we saw an example and got these Dirac vectors: √12 |000�
and √12 |100�. In this case we convert both these vectors into one column vector using the
process we described in at the end of subsection 6.4.3. This would give us:
 1 
√
2
0
 
0
 
 
0
 √1 
 2
 
0
 
0
0
we then simply do the same as above when we turned all the rows around and stacked them
up to form a matrix. Remember our example here is the row of the matrix relating to the first
bases vector so we won’t see the whole matrix here.
The final step is again simply multiplying the matrix by the register.
Applying a Quantum Gate to The Quantum Register
The quantum register is going to be the product of the quantum register’s column vector
of length 2n and all the matrices for a given stage in the circuit. From the example in section
4.3.1, two matrix-column vector multiplications would occur (where the two first Gs are) which
would alter the register. On the second stage, the register would be multiplied by another G.
Remember that this register will actually be a register and a history of previous register states
so we can step forwards and backwards through a quantum circuit.
Explanation through diagram:
63
Step forward once:
Step forward again:
The left matrix is the quantum register with each of its columns being a stage in the circuit.
Before a step is taken, the next column in the register matrix should be replaced from its default
value of (0.0, 0.0i) to a copy of its respective element in the same place in the previous column
of the register.
The multiplication between the matrices and register should only happen when we step forwards through the circuit or run the circuit. This means that more complex numbers need to
be stored but the program should be more responsive whilst building the circuit where the user
us likely to be adding and removing gates a lot.
The actual matrix multiplication is trivial and does not warrant detailed discussion. We deal
with the simplest case of matrix multiplication in this part of the program; column vectormatrix multiplication so we just get the following process:

  

a11 a12 ... a1n
x1
a11 x1 + a12 x2 + ... +a1n xn
 a21 a22 ... a2n   x2   a21 x1 + a22 x2 + ... +a2n xn 

  

 .
  

.
.
. 
.
.
.
.

 .  = 

 .
  

.
.
. 
.
.
.
.

 .  

 .





.
.
.
.
.
.
.
.
am1 am2 ... amn
xn
am1 x1 + am2 x2 + ... +amn xn
4.3.4
Custom Quantum Gates
In chapter 2 we saw that there does not exist a quantum circuit simulation that allows users the
freedom of defining their own quantum transformation. Over the course of this project, new or
64
at least more available software simulations have emerged but it still appears as though these
programs limit the users to the quantum gates that are hardcoded into the software. It is the
opinion of the author that the functionality implemented into this new software will be useful
to new quantum computing students and researchers. Here we will give a high level design of
this feature.
The process of creating a new quantum gate is should be split up into a number of stages.
The main stages will be:
• The quantum transformation is stored as a matrix so we allocate memory for a square
matrix of dimension 2n where n is the register size.
• A new custom matrix is inputted.
• The matrix is checked to make sure it is unitary, if it isn’t then stop here.
• The unitary matrix icon is then added to the conceptual View of the circuit and put
into the Model of the circuit which is the 4D mathematical internal representation of the
circuit. The rest of the process is exactly the same as the process of applying a quantum
gate to a register which we have already seen.
• A gate icon is simply added to every qubit in the conceptual View of the circuit. No
calculations will be made to determine the functionality of the matrix that the user has
implemented. It will be up to the user to choose which qubits are for controls and which
are for targets.
The most important step here is the unitary matrix checking. Let us build on what we talked
about in literature review when we mentioned unitary matrices.
We recall from the literature review chapter that a matrix U is only unitary if U H = U −1
where U H denotes the conjugate transpose and U −1 is the inverse of U . We also know that
U H U = In where In is the identity matrix in n dimensions. Using either U H = U −1 or
U H U = In we can construct an algorithm to check whether a matrix is unitary. The second
equation should be used because finding the inverse of a matrix is more complicated to implement because it requires the use of a method such as Gauss-Jordan elimination [17].
The program should start by finding the transpose the the matrix in question, for example:
�
�T �
�
(1.0, 0.0i) (2.0, 0.0i)
(1.0, 0.0i) (3.0, 0.0i)
=
(3.0, 0.0i) (4.0, 0.0i)
(2.0, 0.0i) (4.0, 0.0i)
and then finds the conjugate transpose by negating the imaginary parts of the complex numbers
and leaving the real parts alone:
�
�
(1.0, −0.0i) (3.0, −0.0i)
(2.0, −0.0i) (4.0, −0.0i)
and multiplies this with the original matrix:
�
� �
� �
�
(1.0, −0.0i) (3.0, −0.0i)
(1.0, 0.0i) (2.0, 0.0i)
(10.0, −0.0i) (14.0, −0.0i)
·
=
(2.0, −0.0i) (4.0, −0.0i)
(3.0, 0.0i) (4.0, 0.0i)
(14.0, −0.0i) (20.0, −0.0i)
65
we then generate an identity matrix In of size n and compare this to our product matrix:
�
� �
�
(1.0, −0.0i) (3.0, −0.0i)
(1.0, 0.0i) (0.0, 0.0i)
�=
(2.0, −0.0i) (4.0, −0.0i)
(0.0, 0.0i) (1.0, 0.0i)
If the two matrices equal each other then the custom matrix is accepted, otherwise it is rejected.
In this case the matrix that we entered is obviously not a unitary matrix so we disallow this to
be applied to the register.
4.3.5
Performing a Quantum Measurement
Recall from chapter 2 that quantum measurement is one of the phenomena of quantum mechanics and one has to understand how and why it works before implementation. Alongside being
able to apply a quantum gate to a quantum register, quantum measurement is an extremely
important part of the implementation. We will first look at a general example and then move
onto a real, specific example:
Let us have some 2-qubit system with bases:
a |00�
b |01�
c |10�
d |11� (a, b, c, d) ∈ C)
We decide that we want to measure the first qubit:
a |00�
b |01�
c |10�
d |11�
Let us measure the first qubit and let us say that the result is 0. What we need to do is
now renormalise the bases now we know that the first qubit is definitely 0. To do this we
simply want to normalise bases with amounts a and b because these are the only bases that
have 0 as the first qubit so for a we have:
a= √
a
|a|2 +|b|2
and similarly for b:
b= √
b
|a|2 +|b|2
so the full set of bases vectors is then:
a
|a|2 +|b|2
√ 2b 2
|a| +|b|
√
c |10�
d |11�
|00�
|01�
66
Now let us see a more specific example using the Hadamard gate as we know it is an ideal
gate for explaining quantum measurement. Let us consider the 2-qubit system again with a
Hadamard gate placed on the first qubit so we have an equal chance of measuring a 0 or 1 on
the first qubit:
|0� − H − M −
|0� − − − −−
Stepping through the circuit up to the first gate will yield the following bases:
√1
2
|00�
0 |01�
√1 |10�
2
0 |11�
We then step to the final stage which involves measuring the first qubit. Again, we measure 0 but now we want to see what this more specific case gives us when we renormalise our
bases:
√1
2
q
| √1 |2 +|0|2
2
0
q
| √1 |2 +|0|2
2
|00�
|01�
0 |10�
0 |11�
which is simply:
1 |00�
0 |01�
0 |10�
0 |11�
so we are done. This method scales to multi-qubit measurements and to larger qubit systems.
67
Chapter 5
User Interface Design
68
5.1
Information Presentation
Information presentation is particularly important so we dedicate a section to it. Recall in our
design that we had various Views from the Model View Control architecture that we adopted:
• Quantum Register View
• Conceptual View of circuit
5.1.1
Quantum Register View
Let us begin with how we plan to present the view of the register to the user. Recall that the
register will be the bases vectors of a particular register size together with the complex amounts
of each of these bases. The obvious question here is how do we present a complex number to
the user. A complex number has a real part and an imaginary part. Recall that jQuantum had
an interesting approach to this and used colours with different colours for the different parts of
the complex number plane:
It was the opinion of the author that this presentation was aesthetically pleasing but the it was
not an explicit representation at all; we do not know what number is exactly being represented.
It was the author’s experience that this made learning about how the quantum register works
actually even more confusing. We propose that we need an explicit representation of the register.
Instead of colours we should simply list each bases vector and its amount in a column and have
different columns for different stages in the circuit. This type of representation does have its
disadvantages because as we know, the state space goes up exponentially so we will have large
lists of numbers. However, an explicit representation will be easier to analyse circuits with
and learn. We learn later on in this dissertation from heuristic evaluations that we need to do
something about the long list of bases vectors to make them more clear to the user which is
then implemented.
5.1.2
Conceptual View of circuit
The conceptual View of a quantum circuit is based on circuit symbols found in text books that
are joined up by wires. We will maintain consistency and design our View of the circuit using
these same symbols. We will constructively criticise jQuantum’s system again here as it does
seem to be most popular system but the author still believes that it has its shortfalls. One
problem with jQuantum’s conceptual view is you cannot have two different types of gates on
the same column. When we say column we mean the same position along the qubit lines in the
circuit but for a different qubits. Let’s see this limitation in a screenshot from jQuantum:
69
The Pauli-X gate cannot be placed on the same column as the Hadamard gate. You can spread
a multi-qubit gate across more than one qubit on the same column though. We will strive for
a very similar View but without this limitation.
It was found that there is no particular gate symbol for an arbitrary unitary quantum transform
apart from being referred to as Uf . A gate with Uf could have been used but this could be
mistaken as the user believing that there is a fundamental quantum gate known as Uf so an
interesting, colourful symbol was found showing that it isn’t a built in gate:
5.2
5.2.1
User Interface Design
User analysis
If we are going to design a good user interface for our users then we need to understand what
they want from the software. This investigation is usually completed by using techniques such
as:
• Task analysis
• User interviews
• User questionnaires
• User observations
However, in our case we are not in the position of having students at our university that take
classes in quantum computing. The physics department at our university do some work on
quantum computing but it was found when demonstrating the software to a single physics
student, it was obvious that their interests lied in the physical realisation of the quantum
computer rather than the learning about computation. On the other hand, one of the author’s
main objectives of this project was to learn about quantum computing himself. For this reason,
a user analysis could be formulated by the experience of the author learning about the field.
70
5.2.2
User Interface Prototyping
User interface prototyping will be discussed in detail when we reach the planned releases section
in the implementation chapter. We will see that we will create a rough interface to begin with
to get the complicated and important back-end implemented before we worry about producing
an elegant interface. We will see that we make changes to the interface that we saw as needed
before any usability testing was carried out. Later we will see that these changes along with
minor bug fixes will bring us to our first release. Our second release will be after usability
testing and interface evaluation is completed.
5.2.3
Overall Layout of Interface
The central Views of the software are the conceptual view of the circuit and the contents of the
register so these will feature in the centre of the screen, the learning panel will be at right of
the screen and all the buttons and controls will be on the left. The image below summarises
the overall layout:
5.2.4
Menubar
The menubar will be as simple as possible an will include the less used features of the system
such as save, load, initialise register and exit. Features such as control buttons and quantum
gate buttons will be more frequently used so will have their own buttons. The image below
shows the design of the menubar with each menu’s items that drop down:
71
5.2.5
Quantum Gate Buttons
The quantum gate symbols will at least initially be the exact ones that we saw in the literature
review. We will see in the first release that we do make some alterations. The conceptual View
of the circuit will be programmed in HTML so the gate icons will simply be image loads which
will make this part of programming trivial. For multi-qubit gates we will use similar icons for
control and qubits but the buttons will have labels on them to tell the difference. Again, we
will see changes that get made to this later too. Below shows the layout of quantum buttons we
have chosen. Their isn’t a set order to the buttons but the measurement gate will be at the top
because it’s different from the other gates and the Pauli-X, Y and Z gates are kept together.
The new quantum gate button is placed at the bottom because its workings are different to the
other gates:
5.2.6
Quantum Register View
As we mentioned in the information presentation section earlier, we have chosen an explicit
presentation of the register. The UI design of the register below is an idea of how the register
will look for a 2 qubit system over four stages of the circuit:
72
5.2.7
Conceptual View of Quantum Circuit
We emit a UI design for this subsection because of its similarity to jQuantum’s conceptual circuit
View. Refer back to the information presentation section for more details on the differences
that we will adopt and the screenshot of jQuantum’s conceptual circuit View.
5.2.8
Learning Panel Contents
At the design stage we are already in the position of being able to define exactly what will be
in each of the learning panels for each gate. These learning panels will fill with information on
the gate that the user has clicked on. Screen captures are provided in this document of all the
learning panels that are just HTML files. These are emitted here an put into the appendix.
73
Chapter 6
Detailed Design and Implementation
74
6.1
Programming Language and Software Tool Choices
Recall from the requirements chapter that we have the problem of exponential vector state
space growth to workaround. It is important that we choose the right programming language
and tools to best manage the resources on the system so the programmer knows exactly where
resources, particularly memory are being used.
We need to use a programming language that provides fine control of system resources to
maximise the speed and efficiency of the program. The C programming language is an obvious
choice because it is high level enough to create large programs easily and low level enough to
allow the control of allocating and freeing memory. This still won’t allow the creation of large
circuits but if the programming is done well including the memory management then we should
have a program that runs quickly and efficiently on circuits that are smaller than the maximum
size that we chose to limit the user to in chapter 3.
The software is going to be a graphical application so we also need a tool to build graphical user interfaces (GUIs) using C. Qt is an interactive development environment (IDE) for the
C++ programming language and includes a GUI builder. C++ is C’s successor and is widely
used commercially, still allows the fine control of memory and at the same time uses the object
orientated (OO) style of programming. The OO style allows better structuring of code and
promotes code reuse.
Java would be another possibility because there are plenty of GUI builders for Java too. However, Java is inherently slower that C/C++, this is because of the Java virtual machine used in
the compilation process. The author has experience with the Qt IDE, the Qt GUI builder and
the C/C++ programming languages.
This project could provide an opportunity for the author to learn a new programming language. However, learning about quantum computing is more important than becoming fluent
in a further programming language because the implementation details are quite complex as it
is. Furthermore, C++ with Qt would appear as a good combination of programming language,
interactive development environment and graphical user interface builder for the reasons highlighted in this above.
6.2
Source code control and backup
The implementation was completed on the author’s personal laptop so the responsibility for
source code control and backup was left entirely to myself. It is known by any experienced
programmer that when writing complex programs it is easy to break code and want to revert
back to an older, more correct version. Backup is at least of equal importance. These two issues
were dealt with by the use of Apple’s Time Machine program where the project was automatically backed-up every 10 minutes and copied every time so old versions of the software could
be retrieved. This was done on an external hard drive for obvious reasons. Version control
was also considered but Time Machine has been so successful in previous projects and doesn’t
require any effort on behalf of the programmer. The software itself was also saved into a new
folder when new milestones were met or a major next step was about to be taken.
75
The newer cloud computing model was also used in addition to the traditional client (this
author) and the mainframe (the mainframe is actually just an external hard drive) model. At
the end of each day the dissertation and code was uploaded to the cloud using a service called
Dropbox at www.dropbox.com. A folder is on the user’s machine that is used to drag and drop
the latest work from the author’s machine into the folder which is a secure connection to the
author’s private cloud.
Version control was considered for this project. However,it was decided against because the
scale of the project didn’t warrant its use. Version Control such as SVN is particularly useful
when working on a group piece of software where different users are working on the same piece
of software which isn’t something that happened in this project. Automatic, regular, backup
copies coupled with the use of the cloud provided security, reversibility of code alterations and
required minimal effort once it was all set up.
6.3
Implementation Plan & Planned Releases
The implementation will be completed in a number of planned stages with releases being made
when certain parts of the implementation have been completed. Firstly, a prototype interface
will be developed which will include:
• Conceptual View of Circuit
• Gate Panel
• Learning Panel
• Menubar
• Forwards, Backwards, Delete buttons
These parts of the interface will have little functionality apart from the gate icons being pressed
and the respective gates appearing in the workspace and the learning panel contents that will
change as the user selects gates.
RC1 will be the prototype interface along with all the main parts that we outlined in each
of the Model, View and Control parts of the system’s architecture. To reiterate, the main parts
are:
• Structure of conceptual quantum circuit (Model)
• Mathematical structure of circuit (Model)
• Register history (Model)
• Conceptual quantum circuit (View)
• Quantum register (View)
• Controlling code
RC2 will be RC1 after usability testing, interface evaluation and all release testing (see systems
testing chapter) has been complete. The testing chapter will be based on release testing but
only on RC1 where most bugs and fixes should have been found during the integration testing
that happens during the implementation part of the software lifecycle.
76
6.4
Data Structures & Algorithmics - The Implementation
We follow the same approach here to when we tackled the design chapter. In the design we
discussed only the important designs that need to be made. Here we do the same thing but
focus on how each of these designs were implemented.
6.4.1
The Quantum Register
The two most important data structures in the quantum computer simulator are the quantum
register and the 4-Dimensional matrix that represents the circuit. Let us consider the register
in this section.
Initialisation
The initialisation of the qubit register is an interesting implementation feature. This is because
it turned out that after what was thought as to be the whole software lifecycle, this part of the
implementation was extended. We do not spread this feature into any chapters other than this
one. In any of the qubit initialisation screenshots in this document, we have something looking
like the following:
The new initialisation screen now looks like the following:
77
The limitations of just a classical state were discussed and it was believed that having the ability
of a superposition of bases vectors as an initial state would allow more flexibility. It is true that
the user can input an quantum gate to gate to the same state but this would sometimes require
some quite hard unnecessary thinking to get to the desired state. The user just selects one or
more bases vectors from the list and the selected complex numbers relating to each basis gets
transformed into a superposition. The simplest case would be having only one basis selected so
there would be no superposition. More interesting cases are when multiple bases are selected.
We use:
| a |2 + | b |2 + | c |2 + | d |2 + | e |2 + | f |2 + | g |2 + | h |2 = 1
to work out the superposition (a, b, ..., h ∈ C).
Let us say that we select bases vectors with the amounts a, d, f . We would get a, d, f =
b, c, d, e, g, h = 0.
To verify this we see that:
|
√1 |2
3
+ | 0 |2 + | 0 |2 + |
√1 |2
3
+ | 0 |2 + |
The View of the circuit is then updated to:
78
√1 |2
3
+ | 0 |2 + | 0 |2 = 1
√1
3
and
There is no way to assign anything more informative than this in the circuit View because we
just have the three qubits. However, let us verify that this works by selecting 5 vector bases in
a 3-qubit register, adding some quantum gate and then running the circuit:
0.447... is the estimation of
chose not to select.
√1
5
which is correct. The bases that are zero are the ones that we
In the back-end of the system a 2D matrix is initialised which is of the form:
complex number type qubitRegister[position][which qubit].
So when the register is initialised, qubitRegister[0][all qubits...] is updated.
Running a Circuit
When we step forwards through a circuit qubitRegister[0][all qubits...] is copied to
qubitRegister[number of forward steps][all qubits...] which is then multiplied by
the appropriate matrices that represent the gates that the user has put on the circuit.
Graphical Representation
We will discuss the workspace later which contains the conceptual View of the circuit. As we
step through the circuit it is displayed in the workspace, we see the quantum register representation changing as well step through. If we steps backwards then the register also changes, we
can also delete parts of the circuit and this alters the qubit register View too. Let us see some
examples of the register representation in action.
Below shows a 3-qubit circuit in our new simulator. We have decided to only use two of
the qubits here. There are two steps in the circuit and we will step through the circuit rather
than just run it.
79
By pressing the forward button, in the first step we just have two Pauli-X gates that flip the first
and second qubits. We have used the qubit register initialisation that we used in the previous
section so the first qubit gets flipped from (0.0, 0.0i) to (1.0, 0.0i) and the second qubit gets
flipped from (1.0, 0.0i) to (0.0, 0.0i). This means we have to have the basis |100� and nothing
else so we have the probability (1.0, 0.0i) for |100� and (0.0, 0.0i) everywhere else.
We then make another step and reach nothing for the second and third qubits but we see
a Hadamard gate for the first qubit. We see that qubits bases vectors |000� and |100� now
have the probabilities (0.707107, 0i) and (−0.707107, 0i) in front of them respectively. These
numbers are approximations to √12 and 1 √12 respectively and are stored with greater precision
in the Model of the internal circuit. We see that this result is correct because from the previous
set of bases, |100� was certain and we have put the first qubit into a superposition between
(0.0, 0.0i) and (1.0, 0.0i).
80
The circuit has now finished but if try and move further forwards then nothing happens internally and we get a message box informing the user that they can’t go any further:
The user can move backwards too and no reverse calculations have to be made because each
step that we made we stored all previous steps too.
6.4.2
Performing a Quantum Measurement
The implementation of the quantum measurement process that was discussed in the design
chapter was implemented successfully.
A quantum computer works with perfect mathematical probability. We needed to use probabilities in our program and evaluate results from these probabilities. The method that was
chosen was C/C++’s random number generator that uses seeds; lists of numbers stored in the
computer. We can request different seeds to use different sets of numbers. We chose to use a
time function to get the current time and use random numbers based on this time to ensure
that we are likely to get different seeds. Computer components can be purchased that use radioactive materials and determine when radiation is released from radioactive atoms’ nuclei to
generate number that are more random. This would make the whole process more realistic but
it is only really important to use this for programs such as casino games where money is at stake.
Although we are using seeds which aren’t truly random, the implementation does attempt
to use these seeds to create probabilistic behaviour with certain measurements. The simplest
81
probability is a certainty or impossibility; if these occur then the measurement will evaluate to
a definite answer:
The example above is a quantum register initialised to |000� with a Pauli-X gate on the first
qubit resulting in a definite answer of |100�. The state does end up being |100� with probability
1.
The user is told that the answer is definite. No probabilities are used in these cases. The case is
slightly more interesting with a Hadamard gate when there’s a 0.5 chance of a qubit evaluating
to 0 or 1. In this case, a random number between 0 and 1 is generated and if the answer is
between 0 and 0.5 then the answer is 0 and if we have 0 ≤ r < 0.5 then the result is 1. For
other cases when there is say a 0.3 chance of the qubit being in the one state and 0.7 chance of
being in the zero state, this is also simulated in a similar way. We would have random numbers
again but the chance of one would be a any random number occurring between 0 ≤ r < 0.7
and the chance of zero would be trivial.
82
6.4.3
Workspace Panel
We have seen how the Model of the circuit is stored in a 4D matrix. We now move on to look
at the conceptual View of the circuit.
A prototype circuit representation was used at first. This was done for a number of reasons, the first being because the implementation relied on myself having a total understanding
of how quantum circuits work and a very large portion of the programming had to be complete
before there was software that had any merit of being a quantum computer simulator. For this
reason it was in the programmer’s best interest to build a very quick graphical representation
and test all the underlying algorithms and data structures before time was dedicated to GUI
programming. Designing a good interface is extremely important but useless unless it was representing a working quantum computer simulator.
Below shows the prototype interface before any internal programming had started:
There was one obvious problem with the prototype that needed to be addressed before any
usability testing or interface evaluation begun. The Controlled-NOT gates and Toffoli gates
both use control qubits and there were only two icons for the CNOT gate (control and target)
and three for the Toffoli gate (control qubit 1, control qubit 2 and the target qubit). This
meant that when the user built circuits containing either a Toffoli gate and a CNOT gate or
multiple CNOTs or multiple Toffolis, it was extremely difficult to work out which control qubits
belonged to which target qubits. The second problem was that the Toffoli and CNOT symbols
were very similar.
In the updated and final conceptual View of the circuit we have solved both of these problems. To help distinguish Toffoli icons from CNOT icons, the Toffoli icon was changed from:
to a new icon:
83
to distinguish it from the similar looking icon that was the CNOT:
One could argue that this goes against Nielsen’s famous usability hueristic: ‘Recognition rather
than recall’ [44] because we are using a new icon that isn’t the icon that is used in the literature
that users might be familiar with. However, the author believes that distinguising gates is
important and the ‘T’ symbol is consistent with all the other gates that have letters as their
symbols.
The next addition to the conceptual View of the circuit that was made now means that we
can have a large number of CNOT and Toffoli gates in one workspace and we easily tell the
difference between the different control and target qubits. This is achieved by changing a gate’s
colour as it is added to the workspace so if there is already a CNOT gate before a further
CNOT is added, the new CNOT will be a different colour. Below shows a very large and
crowded circuit which is still clear:
As an aside, although the circuit is large, notice that it doesn’t actually do anything because
the control qubits never see a non-zero state.
The conceptual circuit View is showing the result of HTML code being read. As well as
having an circuit Model which is the mathematical version of the circuit, there is a further 2D
matrix that is made up of strings that point to the paths of the gates that the user adds. We
can use these strings to find out what we have at particular places in the circuit as we step
through the matrix of image paths.
84
There is a counter that increments when more than one CNOT or Toffoli gate is added to
the workspace and this counter is used to cycle through a list of strings pointing to the paths of
different coloured gates. There are 9 different colours that are used but if the user adds more
than 9 CNOT or Toffoli gates then the colours start again from the beginning. This idea would
not scale well but we are fortunate the circuits cannot get larger than 7 qubits with 20 columns
so 9 colours are enough.
6.4.4
Learning Panel
The learning panel along with the ability for the user to input their own quantum gate form
the two most novel features in the software. As we mentioned in chapter 2, no software currently provides any form of interactive learning material apart from the results coming out of
executing a circuit. Every time the user clicks on a quantum gate they are asked where they
wish to place it and at the same time they can also scroll through an HTML enabled panel that
contains concise and informative help on the current gate that the user has clicked on. The
user can then either go ahead and place the gate into the circuit or they can cancel.
Below shows an example of the learning panel’s content when the Hadamard gate is clicked:
Notice that because the learning panel is written in HTML we can load images into the panel.
We have the matrix representation of the Hadamard gate, a summary of what is does and an
example what what the Hadamard gates do to an input of |0� and an input of |1�.
85
6.5
Saving & Loading Circuits
The user can save a circuit they have built whether it has been executed, partly executed or
just built. This is done using C++’s serialisation and de-serialisation techniques. The main
things that need to be saved and loaded are the Model parts of the MVC which by now we are
familiar with what these are. When the user loads their circuit, the circuit is started at the
beginning again.
The programming to do this isn’t very cumbersome, the matrices are simply iterated so every
element is looked at and this is just serialised. For an example, for the 4D-matrix representing
the mathematical structure of the circuit we just do:
f o r ( every qubit ) {
f o r ( every line ) {
f o r ( every x in quantum gate matrix ) {
f o r ( every y in quantum gate matrix ) {
serialise element
}
}
}
}
and similarly for the GUI representation. Then for the de-serialisation we do the reverse:
f o r ( every qubit ) {
f o r ( every line ) {
f o r ( every x in quantum gate matrix ) {
f o r ( every y in quantum gate matrix ) {
de−serialise element
}
}
}
}
Saving and loading for the user is also trivial, first select save:
Then input the name of the save file:
86
Then observe the two .quantum files that were created, here is the file with the mathematical
internal representation of the circuit:
6.6
Documentation & Help
Recall that it was noticed in chapter 2 that the documentation available for the simulations we
saw was quite poor. For this new quantum computer simulator we have built the documentation
will load from the menubar and goes through simple, clear and concise examples of all the main
things any user would want to do with the simulation. See the Appendix for a copy of this
documentation. The documentation alongside the learning panel and messages throughout
the program will provide a decent amount of help for a new user that hasn’t got a quantum
computing background.
6.7
Implementation Critique
We will see in the testing chapter that every functional and non-functional requirement was
implemented successfully. The implementation was a success in this respect. A new piece of
software has been created that does offer features that simply don’t exist at the moment so
we do have a success and the author is pleased with the work. However, there are things in
the design chapter that should have been followed much better in the implementation stage.
It is this main criticism the author has with the the project and it is definitely worth explaining.
We saw at the start of this chapter and in the design chapter that a prototype interface was to
be created first. Recall that this was so we could have a rough interface to work with so that
the more complicated and important back-end of the circuit could be worked on. As discussed
in the requirements chapter, the Qt IDE was used alongside the C++ programming language.
Although the author has had moderate previous experience with Qt and C++, it took time to
87
work out how the standard object orientated concepts work with Qt and C++. Qt has its own
built in classes for use with C++ so it’s perhaps more than just an IDE. For this reason, there was
a reasonably steep learning curve. This learning curve coupled with the fact that to program a
quantum circuit simulator, one has to have a total understanding of how quantum circuits work
meant that the systems architecture didn’t take precedence. The prototype interface involved a
collection of classes that didn’t necessarily abide by the MVC architecture and what transpired
was that the author added in new classes as different parts of the implementation progressed but
this meant that the resulting classes do not entirely exhibit an MVC architecture. Below shows
the final class diagram of the whole system listing only the necessary functions and variables
to save space:
Notice that the mainwindow class is the central Controller class with the Model and the Views.
Then we have other classes for loading & saving, getting pre-loaded gates, applying gates, information for users, and creating custom gates. These other classes are largely Controller classes
or business code classes. However, the actual code in the mainwindow class (see appendix)
doesn’t clearly show the use of the MVC architecture because the code has basically evolved
from a prototype to the final program where the prototype didn’t have an architecture in mind
because of other stronger priorities. There are functions that are dedicated to either the Model
or the View but there are large portions of code that call both Model and View parts so they’re
not separate entities. The main consequence of this that the code will lack some degree of
maintainability and understandability. Other readers should be able to read about the software
architecture and see it reflected in the code but this may not be as easy as it should be.
88
Chapter 7
Testing
89
7.1
Testing Strategy
We are going to use a requirements testing based approach, a general principle from requirements engineering. We will refer back to the Requirements Analysis and Requirements Specification chapter and test the functional requirements. We will carry out one of the two main
types of testing; system testing. The project handbook makes no mention of the other major
type of testing; component testing [33] but we will go into component detail for the important
parts of the implementation that will require heavy testing.
Release testing will be carried out in system testing but not integration testing because we
have debugged all known problems before we reached the testing stage of the software lifecycle
so the version we are testing here is a release version of the software. We will also carry out
performance testing to test emergent properties of the system, namely non-functional requirement 2 (NF.2). The NF.1 will be tested at the end of this when we reach usability testing and
interface evaluation. NF.1 and NF.2 are the only two non-functional requirements.
Due to the necessary time constraints bearing on the project, it will be unfeasible to apply
rigorous testing to every area of the software so we will be selective and test the most important parts of the software. Furthermore, we will make judicious use of appendices by listing
simple tests as either PASS or FAIL. These PASS/FAIL tests will either be those that don’t warrant discussion or are relied on enough by other tests (see functional requirements dependancies
in chapter 3) so much that it would not be worth creating separate tests for them.
7.2
7.2.1
System Testing
Release Testing
We will consider release testing as a black box style of testing as [21] suggests. We will derive a
number of tests for all functional requirements, focussing particularly on edge case tests; tests
that are most likely to break the system and expose any bugs. As we have mentioned, we will
omit more trivial and less vital tests to the appendix. Let us first summarise our functional
requirements from chapter 4:
90
We now reduce these functional requirements to not simply the ones with the highest priority
but the ones which require heavier or more complex testing:
The greyed-out requirements will be tested at the end of this chapter but their discussion will
be less detailed.
Users will be able to add the fundamental quantum gates
This requirement is fundamental, refer back to the requirements specification for its full detail.
Adding the gates means that we will be able to run the circuit and the qubit register View will be
changed as we do so. This was a large task, refer back to the implementation chapter for details.
91
Let us start with the gates that require the use of control qubits. We should see that the
program will use the gates’ hardcoded matrices to construct a new matrix that can be applied
to the qubit register so specified targets qubits can be flipped or left unchanged. Let’s us the
Controlled-NOT gate and look at cases where the single control qubit is set and then not set
so that the target qubit is flipped when the control is set and left unaltered when it isn’t set:
Test Result: PASS
Similarly, let’s do the same with the Toffoli gate where two control qubits have to be set
for the target qubit to be flipped. Let’s see cases where there are no controls set, one control
set and both controls set:
Both controls set, target flipped:
92
Test Result: PASS
We have seen the Pauli-X gate before so now let’s look at the Pauli-Y and Pauli-Z gate. First
we will observe a circuit run with a single Pauli-Y gate:
We then recall from the literature review that the Pauli-Y gate is actually a combination of
the Pauli-X and Pauli-Z gate in succession. Getting the same result as a single Pauli-Y on the
same input will provide strong evidence for a pass here:
93
Test Result: PASS
We now move on to quantum measurement. Let us run some test cases for single qubit quantum
measurements. Recall how we can use the Hadamard to place qubits in an equal superposition of being zero and one, let’s see an example where we just use a Hadamard gate and a
measurement gate to get both possible measurement results:
Test Result: PASS
Now let us look at multi-qubit measurement. We will follow the same approach as the previous
example and verify that it is possible to get all the possible results from a multi-qubit measurement. Let us initialise a 3-qubit register to the |000� initial state, place a Hadamard gate on
qubits 1 and 2 and a measurement immediately after both Hadamard gates. We will want to
observe the probabilities of a zero or one occurring in each case. Multi-qubit measurements are
a series of single qubit measurements so we would hope that the probability of the qubit being
measured to yield 0 or 1 will be 12 in both qubits’ cases.
The first two tests are to first verify that both measurements can yield 0 to put the qubit
register into the state |000� and secondly to test that we can end up in the state |010�:
94
The probabilities and results of the measurements are shown to the user as follows:
The other two possible final states we can in are |100� and |110�.
Finally, recall that quantum measurements can be used as conditions in circuits so let us
construct a circuit that flips a target qubit depending on whether a control qubit is set. We
will us a Hadamard and CNOT gate for this:
95
We can see that the target qubit was flipped from a zero (because two Pauli-X means that we
had 0 �→ 1 �→ 0) to a one because the measurement yielded a zero which was the control qubit
for the CNOT gate.
Test Result: PASS
Users will be able to clear the workspace
This requirement seems rather trivial at first but we must be able to clear a circuit and start
working on a new one without fear that there are data structures with remnants of the previous
circuit in still. There is little to document here apart from one important piece of functionality.
We must be able to initialise the register, build a circuit, clear the circuit and be able to run
the new circuit with the register still intact and obviously with the circuit running only on the
new circuit.
Let us first initialise the register to |111� and run a simple circuit to the end:
Then let us clear the circuit, run a new one and observe that the register is still intact:
96
Test Result: PASS
Users will be able to add their own quantum gates
We now move on to the final important part of the system we need to test; allowing users to add
their own quantum gates. We will see two tests, one test will be the program rejecting a user
defined matrix and the other will be an allowed matrix where we will also test the correctness
of the matrix by executing the circuit with it.
Firstly, we specify that we want a two qubit system with an initialised register in the start
state |00�. We input the following non-unitary matrix:


(0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (1.0, 0.0i)
(0.0, 0.0i) (0.0, 0.0i) (1.0, 0.0i) (0.0, 0.0i)


(0.0, 0.0i) (1.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i)
(0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i)
The matrix would have been unitary if the bottom, leftmost element had been (1.0, 0.0i):
97
We then get the message rejecting the matrix as we expected:
Now let us move onto a more interesting example, a matrix that is unitary and does have a use.
Let’s say that the user was trying to work out how to build a matrix for a Controlled-NOT
gate for a 3-qubit system that has the control qubit as the second qubit and the target qubit as
the third qubit. This means that if we had a qubit register in initial state |010� then we should
get the final state |011�. The user knows from any key text on quantum computing that the
CNOT gate on a 2-qubit system with the control qubit as the first qubit is the following:


(1.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i)
(0.0, 0.0i) (1.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i)


(0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (1.0, 0.0i)
(0.0, 0.0i) (0.0, 0.0i) (1.0, 0.0i) (0.0, 0.0i)
Let us initialise qubit register to |010�:
98
Recall from the implementation chapter that we saw an example of creating a CNOT matrix
for this particular test case:


(1.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i)
(0.0, 0.0i) (1.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i)


(0.0, 0.0i) (0.0, 0.0i) (1.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i)


(0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (1.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i)


(0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (1.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i)


(0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (1.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i)


(0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (1.0, 0.0i)
(0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (0.0, 0.0i) (1.0, 0.0i) (0.0, 0.0i)
We then input the correct matrix, this passes the unitary matrix check:
Then finally we execute circuit and get the correct action on the qubits:
99
Test Result: PASS
7.2.2
Performance Testing
Performance testing requires the tester to gradually increment the load on the system until the
performance is unacceptable [21]. This type of testing is particularly easy on this system because
of the exponential state space growth that consumes memory so quickly. Recall our calculations
made in the requirements chapter that worked out that 7 qubits with 20 gates per qubit will
probably be our maximum. Even with the memory required for variables, temporary matrices
and the like, this prediction does seem to be accurate. We also noted that the responsiveness
of the program should be fairly constant throughout once the program has loaded and thus
performed all the necessary memory allocations, this is the case too. On the tester’s system,
the allocation of 7 qubits does take time but once the program is running, it runs smoothly.
7.3
7.3.1
Data Validation & Robustness/Stress Resistant Testing
Validation
Part of the implementation deals with the validation of the user’s input to prevent algorithms
receiving erroneous inputs. Let us see how our software copes with validating inputs throughout
the important parts of the program. It is the opinion of the programmer that the most important
parts are the following:
• Initialising the quantum register
• Placing a quantum gate onto the circuit
• Inputting a new quantum gate
• Stepping through the circuit
100
For each of these main features let us look at how they check for the following different types
of validation:
• Range checks
• Type checks
• Presence checks
• Uniqueness checks
Initialising the quantum register
Here is a reminder of what the qubit initialisation looks like:
Qt’s GUI builder allows a type of control called the spin box which is like a text box but the
up and down keys cycle through a type of number that you specifiy so it type checks. It also
allows you to set a lower and upper bound; we have used 0 and 1 for these respectively, this is
the range checking. The presence check is also automatically validated because you can either
have a 0 or 1 in the spin box or nothing. Uniqueness checking isn’t relevant here.
Placing a quantum gate onto the circuit
The dialog the user gets when adding a quantum gate:
We use spin boxes again here with the lower bound being zero and the upper bound being the
size of the qubit register. The validation is similar to the initialisation of the register.
Inputting a new quantum gate
The validation here is slightly less simple but is still in place. Range checking is irrelevant
because matrices are checked to see whether they are unitary, a range check doesn’t really
101
make sense here. Uniqueness is not relevant either and presence checks and type checks are
done by the code rather than the GUI controls. Users are encouraged to use the correct form
and type of input for the complex numbers because all elements of the matrix are defaulted to
(0.0, 0.0i):
Stepping through the circuit
The only type of validation that is relevant here is range checks and we saw how users are
prevented from moving to non-existent parts of the circuit earlier.
7.3.2
Robustness/Stress Resistant Tests
There are parts of the system that are not regarded as the most important features but need to
be thoroughly tested because if they’re not they could cause the software to break and terminate
if not fully tested. These sorts of errors don’t fall into any of the categories of validation that
we tested above. Here are our stress and robustness tests:
• Use an invalid save name
• Load a non-existant circuit
• Running empty circuits
• Deleting/removing non-existent circuits or parts of circuits
• Running uninitialised circuits
• Running too far forwards/backwards in circuit
• Creating a circuit that is too large
We will run test cases for each test, capture screenshots for proof of PASS/FAIL and mark each
test as either PASS/FAIL.
102
Use an invalid save name (1)
The system automatically appends the .quantum extension, we don’t want a .quantum.quantum
so this is prevented:
Test Result: PASS
Use an invalid save name (2)
The system makes sure there is something after the slash character to make up a valid filename:
Test Result: PASS
Load a non-existant circuit
The system checks that there does exist a file that the user has inputted:
103
Test Result: PASS
Running empty circuits
Nothing happens when there is no circuit and we get an information box:
Test Result: PASS
Deleting/removing non-existent circuits or parts of circuits
If we don’t create a circuit but then press the delete button, nothing happens and we get
a information box:
Test Result: PASS
Running uninitialised circuits
There is no way that the user can add a gate without the register being initialised, this has been
mentioned elsewhere in this project. The user is forced to initialise the register, a screenshot
wouldn’t show this in action but it is tested.
104
Test Result: PASS
Running too far forwards/backwards in circuit
Preventing the user from running too far forwards has been shown already. Let us check
that the circuit is also protected from being executed too far backwards:
Test Result: PASS
Creating a circuit that is too large
Recall that the maximum number of qubits is 7 and the maximum number of gates per qubit
is 20. We have already seen that the user cannot enter more than 7 qubits but let’s check that
the user is limited to 20 gates:
Test Result: PASS
7.4
Human-Computer Interaction Testing & Evaluation
One of the most famous results and most cited papers in HCI is Nielsen’s heuristic evaluation
[44]. We saw this being used when we evaluated existing simulations in the literature review.
Now that we have our own software built we are going to perform a heuristic evaluation on
our software but with three evaluators like Nielsen suggests. Before we just wanted a general
idea of the pros and cons of existing simulations’ interface and features to help us form our
requirements, now we want a heavier evaluation to make sure that we have at least not missed
the key good interface principles that other simulations have by checking that our interface
conforms to all of the heuristics.
105
This section will come in two parts, the first will be usability testing and the second will
be analytical evaluation using Nielsen’s heuristics. [20] states that the alternative to usability
testing is field studies. Usability testing measures:
• effectiveness
• ease of use
• satisfaction
Whereas field studies are more ‘messy’ as ’[20] puts it. Field studies are used when the product is being used in everyday life in an informal setting to determine how people think about,
interact and integrate products into the setting that they’re being used in.
It is the opinion of the author that the first type of evaluation is better suited here. It would be
difficult to see how people use this product in their working day because the software is specifically for being who wish to learn about quantum computing, it would be difficult to place the
software in the environment that it will be used in.
7.4.1
User Selection
Recall from the user analysis subsection in the UI design chapter that we found it satisfactory
to build an interface without formal user analysis using task analysis or any of the methods
listed. This was because the author himself was learning about quantum computing so it was
ok for the author to be the user in this case. However, now we have reached the end of the
testing stage we need to gather together other users to test the system. The author carried out
informal usability tests by asking non-professional users to ‘try out’ the software before formal
tests were to be carried out. This failed because the users we selected had very little knowledge
how even the classical computer operates on bits but it did was iron out some minor bugs:
• One user clicked on the forward button with an empty circuit caused the program to
terminate. This was noted and addressed in the stress tests section.
• The same user did the same thing with the back button which caused the program to
terminate, this was also remedied.
• One user tried to load a non-existent circuit which also caused a program termination.
This was also fixed in the stress test section.
As the author anticipated, we do need to test this software on computer science users. We need
people who already have an understanding of classical computation. Users who don’t have this
prerequisite understanding would probably not be studying quantum computing. The author
chose three final year computer science students who all have an understanding of classical logic
gates for both the usability testing and analytical evaluation. Heuristic evaluations require
professional users whatever the software is designed to do but usability testing requires users
that will be directly involved in using the software. We are in an interesting position in that
these two types of users will very much overlap. We could get two types of students, one type
could be students studying quantum computing and the other could be those who aren’t but
have an understanding of classical computation. The two types of users are too related and
specific and we would struggle to find these two distinct types of user so let us use the same
users for each test but bear in mind that we need to carry out experimental preparation before
the two tests begin.
106
7.4.2
Experimental Preparation
Users will test and evaluate in one sitting with time set aside before any of the tasks are carried
out. Users will be given up to 5 minutes to familiarise themselves with the software before they
test or evaluate. It is the experience of the author that this is sometimes unnecessary because
users familiarise themselves at different speeds so we will say up to 5 minutes.
The users will not be able to read any of the material regarding the usability testing but
they will have a prepared document with Nielsen’s heuristics on so they don’t have to recall
them from memory.
The tests and evaluations will be carried out in a controlled office environment. The users
are friends or colleagues and will come to the author’s flat to carry out the tasks. The users will
be informed that they should not hold back on recording negativities of the software. The users
won’t be allowed help from the author unless it is relating to the process of heuristic evaluation
or anything relating to the prerequisite mathematics required to understand the mathematics
behind quantum mechanics, this might include some of the linear algebra.
It turned out that the first user was very thorough and found some major bugs at the familiarisation stage which needed to be addressed before the testing and evaluation continued.
The bugs were as follows:
• There was a particular case where loading a non-existent caused the circuit to crash even
though this had been tested by myself in the stress tests.
• There was an issue with the delete button that deletes a single stage of the circuit. This
always worked but in some cases the program terminated when a new gate was added
after a deleted one.
• Adding a measurement gate before any other gate caused the program to terminate.
Bug fixes have now been implemented for all of the above.
7.4.3
Usability Testing
We noted the three things that usability testing is meant to measure at the start of this section.
Effectiveness and ease of use can be measured quantitatively using the time it takes to complete
a task and the number of errors that the user makes. Satisfaction is something less numerical
and can be measured using an informal interview after the users have completed their set tasks.
Let us formulate a list of tasks the users will be asked to carry out followed by the interview
questions that they will be asked after the test. Let us also construct feedback forms for the
author to use when observing the users.
Effectiveness & ease of use questions
Initialise the qubit register to 5 qubits
Set register to start state |00000�
Add a single qubit quantum gate to the workspace
107
Add a multi-qubit quantum gate to the workspace
Run the whole quantum circuit that you have built
Step one place backwards in the circuit
Delete a stage of the circuit i.e. a column of gates in the workspace
Clear the whole circuit
Input a new quantum gate that you have created
Add a Hadamard gate to the workspace followed by a measurement gate and run it so you
perform a quantum measurement on your circuit
End of tasks
The following is the feedback form that the author will fill in as each task is being completed:
Usability Testing Results Discussion
The overall results for the usability tests are pleasing. Participants all used the initial 5 minutes
of familiarisation where they worked out the basics of the system which helped in the tests.
Every task was completed in under 1 minute which is a good result.
Mistakes were sometimes made when finding a multi-qubit gate to add. One participant used
trial and error to get the right sort of gate but two users read from the learning panels which
was good to see because this is a feature that other simulations do not offer.
108
Considerable time was spent trying to create a new matrix in most cases. The issue was not
finding the correct button but it was inputting the matrix. The tester told them that a simple
matrix that could be inputted to remove the chance of one user being better with linear algebra
than the other. Users often removed the values (0.0, 0.0i) and then started typing the whole
thing again but with perhaps the real part changed to a 1.0 which took a long time in some cases.
There were no major changes that needed to be made to the interface or program from the
usability tests carried out.
7.4.4
Analytical Evaluation
The outline of the heuristic evaluation form that evaluators will have (excluding extra whitespace) is as follows:
Heuristic Evaluation
Consistency & Standards:
Help & Documentation:
Help Users Recognise, Diagnose and Recover from Errors:
Aesthetic & Minimalist Design:
Error Prevention:
Visibility of System Status:
Match Between System and Real World:
Flexibility and Efficiency of Use:
Recognition rather than recall:
User Control & Freedom:
End of document
Analytical Evaluation Results Discussion
Notice from the analytical evaluation results in the appendix that we have only included negative points rather than both negative and positive unlike we did in chapter 2. This is the usual
way for carrying out heuristic evaluations, we only included good points about the software in
the literature review chapter because we were using the evaluation to help us gather requirements. The results in the appendix have been amended slightly from what users actually said
to formalise it, for example “When I added one of these things..” would be changed to “When
the user adds a quantum gate..”.
109
The findings of the heuristics evaluation did give us some ideas and suggestions on how we
could improve the interface. The findings were not surprising because none of them were in our
original requirements. From the three evaluations we can summarise the weaknesses or gaps in
our software:
• Scroll bars of register and circuit should automatically shift to the right when gates don’t
fit on the screen.
• Initialising the register should immediately show in the conceptual circuit View in addition
to the message box that shows to enforce the visibility of the system status.
• Multi-qubit gates should have their input boxes for qubit selection defaulted to different
qubits rather than all zeroes. This will prevent errors.
• New quantum gates are added into the workspace but we are not told which icons are for
the control qubits and which are for the targets.
• When there are large numbers of bases vectors, it is difficult to see which bases vectors
are of interest. Improving this could help learning and improve efficiency.
From these suggestions we need to extract the ones that are the most important and are feasible
to implement at this stage of the software lifecycle.
We chose not to attempt to implement a different way for new quantum gates to be displayed
on the workspace. This is because it would involve a considerable amount of programming
to determine what qubits the user has asked to be control qubits and which are to be target
qubits. Furthermore, users may well benefit from having to create a matrix on their own and
observing the results that the matrix produces rather than having the software trying to work
out what the user is trying to achieve.
All of the targeted problems have now been solved. The only one that warrants a screen
capture is the final one to make it more clear which bases vectors are of interest:
110
There are two changes here, the main one are the colours that were introduced. A check is done
before the bases vectors are printed and if the amount of a bases vector is 0 then the colour is
red and any other bases vectors are green. This means that the user can focus mostly on the
green vectors which will make everything clearer, especially with a large qubit register. The
second alteration was actually made before any usability testing or interface evaluation which
is expressing a fixed length number for the real and imaginary parts of a complex number. This
second improvement is to ensure that each set of bases vectors are lined up correctly, before
this was implemented misalignments sometimes occurred.
111
Chapter 8
Conclusions
112
We begun this project with the overall aim to learn and understand how quantum computers
work from a computer scientific and mathematical perspective. We aimed to learn enough
about quantum computers to be able to construct a quantum computer simulator.
The expectation was that throughout the literature survey and review stage, the author would
have a clear overview of the past and current work in the field along with all the required theory
and mathematics fully understood. This would be a good position to be in before development
commenced. A great respect for the field was awoken at this point but parts of the theory
weren’t quite there yet and had to be thought long and hard about whilst the implementation
stood still.
“If quantum mechanics hasn’t profoundly shocked you, you haven’t understood it yet”. [37]
We quote Niels Bohr here, a nobel prizing winning physicist. This project has definitely produced quite a few shocks so from Bohr’s quote, this may well indicate that we have started to
understand the field of quantum computing.
The research untaken at the start of the project was extensive and was a success even though
it cut into the implementation. It was a very enjoyable experience because the field was so
new, exciting and promising. A large number of topics were covered including the required
mathematics, the underlying quantum mechanics and a selection of the main topics in quantum computing. We chose to focus on the circuit model of quantum computing, the model with
the most contributed work so far. It was decided that we would simulate this model by looking
at the few existing simulations and fill in their shortcomings.
The implementation moved slowly whilst the author worked on gaining a total understanding the theory behind the quantum circuit model. Programming was running alongside this
steep learning curve so effort was made to try and get something implemented as quickly as
possible. Software engineering principles, particularly design methodology were understood
but they unfortunately didn’t get demonstrated extremely well when the author the serious
problems of knowing what needed to be implemented to meet the basic requirements. Lessons
learned here were that more attention needed to be paid to the overall architecture of the system. The code doesn’t reflect the software architecture very well. If the program part of the
software were to be rewritten then the required distinctions between different parts of the code
would be made totally clear and would perfectly represent what was described in the design
chapter. Now that the author has all the theoretical understanding needed, rewriting the program again would be a far easier feat.
We have successfully managed to construct a quantum computer simulator and we will soon
see whether it will contend with its few alternatives. Every requirement of every priority was
completed within good time. Test cases were made for all of the requirements which all passed.
The software was shown to final year computer science students and then after some fixes it
was tested for usability and its interface was evaluated.
The reader will hopefully see why this simulator builds upon what similar simulators have
on offer. From reading about the existing simulators, it seems as though more simulators
come from the physics end of the field. It is less likely that software engineering methods and
human-computer interaction practices were of high priority in these simulations. Our project
113
will hopefully have a better level of usability, a more fully evaluated interface and better tested
set of requirements.
Our new simulator offers a quantum computing learning experience with our introduction of
a learning panel which nobody has done yet. We saw that users actually made use of this in
out systems testing chapter. A concise, clear and helpful document has been written that is
linked to by the program; other simulators lacked this. Perhaps the most novel feature is that
the user is never limited by the software on what quantum gate they wish to test. No other
simulation can be found that offers the feature that we have where the user can input any
quantum gate they wish. From the author’s experience, having this feature would really benefit
learning about the quantum circuit model.
We now come to the end of this project so let us consider what is to be done next. The
software we have written will be made available online for others to learn from, comment on or
build upon. The software will be released on an open source software website and possibly the
author’s website. This project has had a broad look at the field of quantum computing. It will
hopefully help others understand some of the theory more easily now my software is available.
The author will be continuing his studies into the theory side of computer science, particularly
quantum computing and information after award of this degree. It is hoped that the author will
be able to find an area of focus within the field now that he has made his first contribution.
114
Appendix A
User documentation
115
Quantum Computer Simulator
Mr Christopher Fuller
The University of Bath, Faculty of Science
Supervisor: Professor Guy McCusker
April 18, 2010
1
Contents
1 Building Circuits
3
2 Running Circuits
2.1 Making a quantum measurement . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
5
3 Saving Circuits
7
4 Opening Saved Circuits
8
5 Deleting Quantum Gates
5.1 Deleting an Entire Circuit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.2 Deleting part of a Circuit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
9
9
6 Creating a New Quantum Gate
10
2
1
Building Circuits
Step 1: Click Edit.
Step 2: Click Initialise Register.
Step 3: Choose a quantum gate.
Step 4: Select qubit for gate to interact with.
Step 4.5: Observe current circuit.
3
4
2
Running Circuits
Once the circuit has been built (previous section) we can run the whole circuit or step through
the circuit.
Below shows the result of clicking on the play button on a rather simple circuit:
The Pauli-X gate just flips the qubit is is acting on. Notice that second and third qubits are
left alone and the first qubit is flipped (0 �→ 1 �→ 0 �→ 1).
2.1
Making a quantum measurement
Step 1: Add a measurement gate to the qubit you wish to be measured.
Step 2: Run the circuit up to the measurement gate. You will see a message box with the
result of the measurement, the probability that led to the result and the probability that the
answer would have come out the opposite to what it did.
5
Step 3: The register will be altered depending on the result that was yielded from the measurement.
6
3
Saving Circuits
Step 1: Click File.
Step 2: Click Save.
Step 2: Enter file name and directory. The .quantum extension will be added automatically.
7
4
Opening Saved Circuits
Step 1: Click File (same step as step 1 of save).
Step 2: Click Open.
Step 2: Make sure qubit register is initialised (see building circuits section for instructions on
how to do this). You will be forced to do this before opening a circuit. Step 3: Enter path of
the saved circuit.
The circuit will then be loaded into the workspace with no parts of the circuit being executed
before your say so.
8
5
5.1
Deleting Quantum Gates
Deleting an Entire Circuit
Step 1: Click on Edit in the menubar and click Clear Workspace
Step 2: You will be shown a notification of the circuit being deleted
5.2
Deleting part of a Circuit
You can press the red cross in the button panel to delete the line furthest to the right in the
circuit, you can do this any number of times whilst there is still part of the circuit left undeleted.
The register contents will be cleared when this happens and you will need to re-run any parts
of the circuit that were executed.
9
6
Creating a New Quantum Gate
This is feature that allows you to construct an arbitrary quantum gate.
Step 1: Press the coloured custom gate button in the button panel.
Step 2: You will not be asked for the dimension of the matrix you wish to create, it always has to be of size 2n where n is the size of the qubit register.
Step 3: A set of boxes will be generated. The number of boxes created depends on the
size of the qubit register.
Step 4: Enter a unitary matrix like the example above. The help panel in the program
walks you through what a unitary matrix is. The numbers to the left of the commas in the box
are the real parts of the complex numbers and the numbers to the right are the imaginary parts.
Step 5: A custom gate icon will appear on all qubits. This is regardless whether you input a one qubit gate or multiple qubit gate, it is up to the user to know which part of their
circuit gets transformed by the gate they have inputted.
10
Step 5: Run the circuit as normal. Our example simply the identity matrix which does
nothing.
11
Appendix B
Functional Requirements Test
Results
127
F.1
Tested (PASS), seen in other chapters.
F.2
Tested (PASS), seen in other chapters.
F.3
Tested (PASS), see testing chapter.
F.4
Tested (PASS), see testing chapter.
F.5
Tested (PASS), see appendix for learning panel contents and user documentation.
F.6
Tested (PASS), see testing chapter.
F.7
Tested (PASS), see testing chapter.
F.8
Users will be limited to 7 qubits and 20 gates per qubit
Tested (PASS).
Trivial, the first dialog that pops up to the user is compulsory and only allows numbers from 1
to 7 to be inputted.
F.9
Users will be able to delete a stage of the circuit.
Tested (PASS)
This is simply achieved by pressing the red cross on the circuit and was used in development a
lot and works.
F.10
Tested (PASS), see implementation chapter
128
Appendix C
Learning Panel Contents
129
Figure C.1: Welcome
Figure C.2: Pauli-X
Figure C.3: Pauli-Y
Figure C.4: Pauli-Z
130
Figure C.5: Hadamard
Figure C.6: CNOT
Figure C.8: Toffoli(2)
Figure C.7: Toffoli(1)
131
Figure C.9: Measurement
132
Appendix D
Usability Testing Results
133
D.1
Usability Test 1
D.2
Usability Test 2
134
D.3
Usability Test 3
135
Appendix E
Analytical Evaluation Results
136
E.1
Heuristic Evaluation 1
Consistency & Standards:
• The Toffoli gate and CNOT gate icons are slightly different to what appears on the
workspace when you click them.
Help & Documentation:
• - No Points Help Users Recognise, Diagnose and Recover from Errors:
• - No Points Aesthetic & Minimalist Design:
• Larger numbers of qubits mean that there are many bases vectors, it is difficult to watch
a run of the circuit where a change in a particular bases in one stage is far away from
another stage.
Error Prevention:
• - No Points Visibility of System Status:
• Initialising the register does notify the user with a message box but the register contents
aren’t shown until a gate is added.
Match Between System and Real World:
• - No Points Flexibility and Efficiency of Use:
• - No Points Recognition rather than recall:
• - No Points User Control & Freedom:
• - No Points End of document
137
E.2
Heuristic Evaluation 2
Consistency & Standards:
• - No Points Help & Documentation:
• - No Points Help Users Recognise, Diagnose and Recover from Errors:
• - No Points Aesthetic & Minimalist Design:
• - No Points Error Prevention:
• As multi-qubit gates need to act on different qubits, it could be better to default the
chosen qubits to different numbers rather than just all zeroes.
Visibility of System Status:
• Moving the scroll bars in the register and view of the circuit would give the user a better
indication of where they are in the circuit. Alternatively, some sort of object such as an
arrow could move along the circuit as it is played.
Match Between System and Real World:
• - No Points Flexibility and Efficiency of Use:
• - No Points Recognition rather than recall:
• - No Points User Control & Freedom:
• - No Points End of document
E.3
Heuristic Evaluation 3
Consistency & Standards:
• - No Points Help & Documentation:
• - No Points 138
Help Users Recognise, Diagnose and Recover from Errors:
• Entering a new quantum gate doesn’t tell you which qubits are controls and which is the
target, you have to know the theory behind how the matrices are constructed.
Aesthetic & Minimalist Design:
• - No Points Error Prevention:
• The multi-qubit gates should be defaulted to different qubits instead of being all the same
which isn’t allowed.
Visibility of System Status:
• - No Points Match Between System and Real World:
• - No Points Flexibility and Efficiency of Use:
• - No Points Recognition rather than recall:
• - No Points User Control & Freedom:
• - No Points End of document
139
Appendix F
Source Code
140
F.1
Class Files
141
untitled.h
28/04/2010 23:59
/********************************************************************
*******************************************************************
main.cpp
- Program entry point.
Programmer: Mr Chris Fuller, The University of Bath
*******************************************************************
******************************************************************/
#include <QtGui/QApplication>
#include "mainwindow.h"
#include <QtGui/QGraphicsView>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Page 1 of 1
untitled.h
29/04/2010 00:00
/********************************************************************
*******************************************************************
mainwindow class
- This is the central class to the program.
Programmer: Mr Chris Fuller, The University of Bath
*******************************************************************
******************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
"mainwindow.h"
"ui_mainwindow.h"
<QApplication>
<QtGui>
<math.h>
<complex>
<iostream>
<stdio.h>
<string.h>
<QDataStream>
/* constructor */
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) {
ui->setupUi(this); //Qt function, uses automatically generated code from Qt Designer
setQubitRegisterSize();
allocateAndInitialiseMatricesAndColumnVectors();
constructControls();
initialise = new initialiseRegister(this, this);
msg = new message();
trans = new transformation();
app = new apply();
measure = new measurement();
saveCircuit = new save();
setButtonImages(); //images on buttons
Page 1 of 46
untitled.h
29/04/2010 00:00
setButtonSizes(); //sizes of buttons
setButtonActions(); //what the buttons do
setGateImagePaths(); //where the images for the buttons come from
setControlsToLayouts(); //where everything goes on the interface (Qt Designer) automates some layouts
too
thereExistsAcircuit = firstControlSet = done = measurementGate = movedUpDirectory = false;
noOfLinesSoFar = currentColour = currentColourToffoli = 0;
noOfForwardSteps = 1;
}
/* Destructor */
MainWindow::~MainWindow() {
delete ui;
}
void MainWindow::setButtonActions() {
/* Make connections between quantum gate buttons and the learning panel.
When a button is clicked, the method associated with that button is
called. These methods populate the learning panel with information */
QObject::connect(pauliXbutton, SIGNAL(clicked()), this, SLOT(pauliXHTML()));
QObject::connect(pauliYbutton, SIGNAL(clicked()), this, SLOT(pauliYHTML()));
QObject::connect(pauliZbutton, SIGNAL(clicked()), this, SLOT(pauliZHTML()));
QObject::connect(controlledNotButton, SIGNAL(clicked()), this, SLOT(controlledNotHTML()));
QObject::connect(hadamardButton, SIGNAL(clicked()), this, SLOT(hadamardHTML()));
QObject::connect(measurementButton, SIGNAL(clicked()), this, SLOT(measurementHTML()));
QObject::connect(toffoliButton, SIGNAL(clicked()), this, SLOT(toffoliHTML()));
QObject::connect(unitaryMatrixButton, SIGNAL(clicked()), this, SLOT(unitaryFunc()));
QObject::connect(backwardButton, SIGNAL(clicked()), this, SLOT(backwardFunc()));
QObject::connect(forwardButton, SIGNAL(clicked()), this, SLOT(forwardFunc()));
QObject::connect(deleteButton, SIGNAL(clicked()), this, SLOT(deleteFunc()));
QObject::connect(playButton, SIGNAL(clicked()), this, SLOT(playFunc()));
/* Menu bar connections */
connect(ui->actionAbout_this_simulation, SIGNAL(triggered()), this, SLOT(aboutAction()));
connect(ui->actionInitialise_register, SIGNAL(triggered()), this, SLOT(initialiseRegisterFunc()));
connect(ui->actionClear_Workspace, SIGNAL(triggered()), this, SLOT(clearWorkspace()));
connect(ui->actionSave_As, SIGNAL(triggered()), this, SLOT(saveCircuitToFile()));
Page 2 of 46
untitled.h
29/04/2010 00:00
connect(ui->actionOpen_2, SIGNAL(triggered()), this, SLOT(loadCircuitFromFile()));
connect(ui->actionDocumentation, SIGNAL(triggered()), this, SLOT(openDocumentation()));
connect(ui->actionExit, SIGNAL(triggered()), this, SLOT(exitSystem()));
}
/* Create the quantum gate buttons. This are
symbols */
void MainWindow::constructControls() {
measurementButton = new QToolButton;
pauliYbutton = new QToolButton;
controlledNotButton = new QToolButton;
toffoliButton = new QToolButton;
forwardButton = new QToolButton;
playButton = new QToolButton;
}
QToolButtons with icons in them representing the quantum gate
pauliXbutton = new QToolButton;
pauliZbutton = new QToolButton;
hadamardButton = new QToolButton;
unitaryMatrixButton = new QToolButton;
backwardButton = new QToolButton;
deleteButton = new QToolButton;
/* set image paths for the gate buttons */
void MainWindow::setGateImagePaths() {
xPath = "-<img src=\"./GateButtons/X.png\" align = \"middle\">";
yPath = "-<img src=\"./GateButtons/Y.png\" align = \"middle\">";
zPath = "-<img src=\"./GateButtons/Z.png\" align = \"middle\">";
mPath = "-<img src=\"./GateButtons/M.png\" align = \"middle\">";
hPath = "-<img src=\"./GateButtons/H.png\" align = \"middle\">";
ttPath = "-<img src=\"./GateButtons/ToffoliTarget.png\" align = \"middle\">";
tcPath = "-<img src=\"./GateButtons/ToffoliControl.png\" align = \"middle\">";
cnotcPath = "-<img src=\"./GateButtons/CNOTcontrol.png\" align = \"middle\">";
cnottPath = "-<img src=\"./GateButtons/CNOTtarget.png\" align = \"middle\">";
customPath = "-<img src=\"./GateButtons/Custom.png\" align = \"middle\">";
}
/* Set the icons of the buttons */
void MainWindow::setButtonImages() {
measurementButton->setIcon(QIcon("./GateButtons/M.png"));
pauliXbutton->setIcon(QIcon("./GateButtons/X.png"));
pauliYbutton->setIcon(QIcon("./GateButtons/Y.png"));
pauliZbutton->setIcon(QIcon("./GateButtons/Z.png"));
controlledNotButton->setIcon(QIcon("./GateButtons/CNOT.png"));
hadamardButton->setIcon(QIcon("./GateButtons/H.png"));
Page 3 of 46
untitled.h
29/04/2010 00:00
toffoliButton->setIcon(QIcon("./GateButtons/T.png"));
unitaryMatrixButton->setIcon(QIcon("./GateButtons/Custom.png"));
forwardButton->setIcon(QIcon("./ControlButtons/forward.png"));
backwardButton->setIcon(QIcon("./ControlButtons/backward.png"));
playButton->setIcon(QIcon("./ControlButtons/play.png"));
deleteButton->setIcon(QIcon("./ControlButtons/delete.png"));
}
/* Put all the buttons onto the GUI */
void MainWindow::setControlsToLayouts() {
/* Give the quantum gate buttons a vertical layout within the quantum gate group box on the left hand
side */
ui->verticalLayout_3->addWidget(measurementButton);
ui->verticalLayout_3->addWidget(pauliXbutton);
ui->verticalLayout_3->addWidget(pauliYbutton);
ui->verticalLayout_3->addWidget(pauliZbutton);
ui->verticalLayout_3->addWidget(controlledNotButton);
ui->verticalLayout_3->addWidget(hadamardButton);
ui->verticalLayout_3->addWidget(toffoliButton);
ui->verticalLayout_3->addWidget(unitaryMatrixButton);
/* Button section of main screen */
ui->horizontalLayout->addWidget(backwardButton);
ui->horizontalLayout->addWidget(playButton);
ui->horizontalLayout->addWidget(forwardButton);
ui->horizontalLayout->addWidget(deleteButton);
}
/* Use the large icon size QStyle for the icons */
void MainWindow::setButtonSizes() {
int size = style()->pixelMetric(QStyle::PM_LargeIconSize);
QSize iconSize(size, size);
measurementButton->setIconSize(iconSize);
pauliXbutton->setIconSize(iconSize);
pauliYbutton->setIconSize(iconSize);
pauliZbutton->setIconSize(iconSize);
controlledNotButton->setIconSize(iconSize);
hadamardButton->setIconSize(iconSize);
toffoliButton->setIconSize(iconSize);
unitaryMatrixButton->setIconSize(iconSize);
forwardButton->setIconSize(iconSize);
backwardButton->setIconSize(iconSize);
playButton->setIconSize(iconSize);
deleteButton->setIconSize(iconSize);
Page 4 of 46
untitled.h
29/04/2010 00:00
}
/* Memory allocation for matrices and column vectors */
void MainWindow::allocateAndInitialiseMatricesAndColumnVectors() {
qubitChoiceG = (int*) malloc(qubitRegisterSizeClassicalG*sizeof(int)); //how far along circuit for given
qubit
diracForm = (complex<float>*) malloc(qubitRegisterSizeClassicalG*sizeof(complex<float>)); //register
bases in Dirac form
dataFromQubitInput = (int*) malloc(qubitRegisterSizeClassicalG*sizeof(int)); //data from inputting where
control and target qubits are to go
initialisedRegister = (complex<float>*) malloc(qubitRegisterSizeG*sizeof(complex<float>)); //when we
clear circuit, maintain initialised register in here
magnitudeOfEachBases = (complex<float>**) malloc(MAX_NO_OF_LINES*sizeof(complex<float>*)); //'amounts'
of each bases vector
customMatrix = (complex<float>**) malloc(qubitRegisterSizeG*sizeof(complex<float>*)); //matrix inputted
by user
typeOfTransform = (complex<float>**) malloc(qubitRegisterSizeG*sizeof(complex<float>*)); //type of
transform e.g. Pauli-X/Y/Z
basesVectors = (complex<float>**) malloc(qubitRegisterSizeG*sizeof(complex<float>*));
int i;
for(i = 0; i < qubitRegisterSizeClassicalG; i++) {
qubitChoiceG[i] = 0;
diracForm[i] = NULL;
}
for(i = 0; i < qubitRegisterSizeG; i++) {
customMatrix[i] = (complex<float>*) malloc(qubitRegisterSizeG * sizeof(complex<float>));
typeOfTransform[i] = (complex<float>*) malloc(qubitRegisterSizeG * sizeof(complex<float>));
basesVectors[i] = (complex<float>*) malloc(qubitRegisterSizeG * sizeof(complex<float>));
}
for(i = 0; i < MAX_NO_OF_LINES; i++) {
magnitudeOfEachBases[i] = (complex<float>*) malloc(qubitRegisterSizeG * sizeof(complex<float>));
}
temp = (complex<float>*) malloc(qubitRegisterSizeG * sizeof(complex<float>));
internalCircuit = allocateMathematicalInternalCircuitRepresentationMemory(qubitRegisterSizeClassicalG,
MAX_NO_OF_LINES, qubitRegisterSizeG);
}
/* The "About" menu-bar action */
Page 5 of 46
untitled.h
29/04/2010 00:00
void MainWindow::aboutAction() {
msg->aboutMessage();
}
/* Open help documentation */
void MainWindow::openDocumentation() {
system("open ./Documentation/Documentation.pdf");
}
/* Exit system */
void MainWindow::exitSystem() {
exit(0);
}
/* Initialise register by bringing up the initialise register form */
void MainWindow::initialiseRegisterFunc() {
initialise->show();
initialise->setFocus();
initialise->activateWindow();
linesAreSet = false;
}
/* Create a new quantum gate */
void MainWindow::unitaryFunc() {
if(isRegisterInitialised()) {
if(qubitRegisterSizeClassicalG <= 4) { //anything above (2^3)^2=64 would be too many text boxes e.g.
(2^4)^2=256
unitary = new UnitaryMatrixInput(this, this, qubitRegisterSizeG);
unitary->show();
unitary->setFocus();
unitary->activateWindow();
}
else {
msg->customTooBig();
}
}
}
/* An HTML file containing the contents of the learning panel for each gate is loaded and set into the panel
Page 6 of 46
untitled.h
29/04/2010 00:00
Load the Pauli-X's HTML file and set the learning panel with its contents */
void MainWindow::pauliXHTML() {
QString src;
if(!movedUpDirectory) {
src = "./LearningPanelPages/pauliXgateSource.html";
}
else {
src = "./pauliXgateSource.html";
}
ui->textBrowser->setSource(src);
setPauliXmatrix();
movedUpDirectory = true;
}
/* Load the Pauli-Y's HTML file and set the learning panel with its contents */
void MainWindow::pauliYHTML() {
QString src;
if(!movedUpDirectory) {
src = "./LearningPanelPages/pauliYgateSource.html";
}
else {
src = "./pauliYgateSource.html";
}
ui->textBrowser->setSource(src);
setPauliYmatrix();
movedUpDirectory = true;
}
/* Load the Pauli-Z's HTML file and set the learning panel with its contents */
void MainWindow::pauliZHTML() {
QString src;
if(!movedUpDirectory) {
src = "./LearningPanelPages/pauliZgateSource.html";
}
else {
src = "./pauliZgateSource.html";
Page 7 of 46
untitled.h
29/04/2010 00:00
}
ui->textBrowser->setSource(src);
setPauliZmatrix();
movedUpDirectory = true;
}
/* Load the controlled-NOT's HTML file and set the learning panel with its contents */
void MainWindow::controlledNotHTML() {
QString src;
if(!movedUpDirectory) {
src = "./LearningPanelPages/controlledNotSource.html";
}
else {
src = "./controlledNotSource.html";
}
ui->textBrowser->setSource(src);
setControlledNOTmatrix();
movedUpDirectory = true;
}
/* Load the Hadamards's HTML file and set the learning panel with its contents */
void MainWindow::hadamardHTML() {
QString src;
if(!movedUpDirectory) {
src = "./LearningPanelPages/hadamardGateSource.html";
}
else {
src = "./hadamardGateSource.html";
}
ui->textBrowser->setSource(src);
setHadamardMatrix();
movedUpDirectory = true;
}
/* Load the Measurements's HTML file and set the learning panel with its contents */
void MainWindow::measurementHTML() {
QString src;
if(!movedUpDirectory) {
Page 8 of 46
untitled.h
29/04/2010 00:00
src = "./LearningPanelPages/measurementGateSource.html";
}
else {
src = "./measurementGateSource.html";
}
ui->textBrowser->setSource(src);
setMeasurement();
movedUpDirectory = true;
}
/* Load the Toffoli's's HTML file and set the learningpanel with its contents */
void MainWindow::toffoliHTML() {
QString src;
if(!movedUpDirectory) {
src = "./LearningPanelPages/toffoliGateSource.html";
}
else {
src = "./toffoliGateSource.html";
}
ui->textBrowser->setSource(src);
setToffoliMatrix();
movedUpDirectory = true;
}
/* Allocate memory for a given size matrix */
complex <float>** allocateMatrixMemory(int dimension) {
complex <float>** matrix;
matrix = (complex <float>**) malloc(dimension*sizeof(complex <float>*));
int i;
for(i = 0; i < dimension; i++) {
matrix[i] = (complex <float>*) malloc(dimension * sizeof(complex <float>));
}
return matrix;
}
/* 4D array representing the qubit register's matrices */
complex <float>**** MainWindow::allocateMathematicalInternalCircuitRepresentationMemory(int noOfQubits, int
noOfPositionsInLine, int sizeOfRegister) {
Page 9 of 46
untitled.h
29/04/2010 00:00
complex <float>**** internalCircuit;
int i, j, k, h, noOfQubitsC;
double noOfQubitsD;
noOfQubitsC = noOfQubits; //copy of noOfQubits variable
noOfQubitsD = double(noOfQubits); //double version of noOfQubits variable
noOfQubitsD = pow(2, noOfQubitsD);
noOfQubits = int(noOfQubitsD);
internalCircuit = (complex <float>****)malloc(sizeof(complex <float>***) * noOfQubits);
for (i = 0 ; i < noOfQubits; i++) {
internalCircuit[i] = (complex <float>***)malloc(sizeof(complex <float>**) * noOfPositionsInLine);
for (j = 0; j < noOfPositionsInLine; j++) {
internalCircuit[i][j] = (complex <float>**)malloc(sizeof(complex <float>*) * sizeOfRegister);
for (h = 0; h < sizeOfRegister; h++) {
internalCircuit[i][j][h] = (complex <float>*)malloc(sizeof(complex <float>) * sizeOfRegister
);
}
}
}
/* Set internal circuit to all 0s */
for(i = 0; i < noOfQubits; i++) {
for(j = 0; j < noOfPositionsInLine; j++) {
for(k = 0; k < sizeOfRegister; k++) {
for(h = 0; h < sizeOfRegister; h++) {
internalCircuit[i][j][k][h] = 0;
}
}
}
}
return internalCircuit;
}
/* Set up the Pauli-X matrix */
using namespace std;
void MainWindow::setPauliXmatrix() {
if(isRegisterInitialised()) {
Page 10 of 46
untitled.h
29/04/2010 00:00
QString typeOfGate = "X";
bool ok;
int qubitsSelected[1];
int qubitChoice = -1;
int sizeOfSelectedQubitsBases = 1;
int sizeOfSelectedQubitsBasesC;
double sizeOfSelectedQubitsBasesD;
sizeOfSelectedQubitsBasesC = sizeOfSelectedQubitsBases; //copy of noOfQubits variable
sizeOfSelectedQubitsBasesD = double(sizeOfSelectedQubitsBases); //double version of noOfQubits
variable
sizeOfSelectedQubitsBasesD = pow(2, sizeOfSelectedQubitsBasesD);
sizeOfSelectedQubitsBases = int(sizeOfSelectedQubitsBasesD);
qubitChoice = QInputDialog::getInt(this, tr("Qubit choice"),
tr("Enter which qubit this gate is to act upon:"),
0, 0, qubitRegisterSizeClassicalG-1, 1, &ok);
if(!ok) {
return;
}
typeOfTransform = trans->setPauliXmatrix();
updateInternalCircuit(typeOfGate, qubitsSelected, sizeOfSelectedQubitsBases,
sizeOfSelectedQubitsBasesC, qubitChoice, xPath, typeOfTransform);
}
}
/* update internal, mathematical Model of circuit */
void MainWindow::updateInternalCircuit(QString typeOfGate, int* qubitsSelected, int
sizeOfSelectedQubitsBases, int sizeOfSelectedQubitsBasesC, int qubitChoice, char* path, complex<float>**
typeOfTransform) {
if(qubitChoiceG[qubitChoice] + 1 < MAX_NO_OF_LINES) { //check that we have not reached our circuit limit
on the chosen qubit (limit=20)
qubitChoiceG[qubitChoice]++;
circuit[qubitChoice][qubitChoiceG[qubitChoice]] = path;
updateWorkspace(qubitChoice, typeOfGate);
qubitsSelected[0] = qubitChoice;
Page 11 of 46
untitled.h
29/04/2010 00:00
complex<float>** bases;
bases = (complex<float>**) malloc(qubitRegisterSizeG * sizeof(complex<float>*));
int i;
for(i = 0; i < qubitRegisterSizeG; i++) {
bases[i] = (complex<float>*) malloc(qubitRegisterSizeClassicalG * sizeof(complex<float>));
}
bases = app->generateBasesVectors(qubitRegisterSizeClassicalG);
/* When the user selects the two qubits they want to operate on, choose the qubits in every bases
that this choice relates to and build an array of these results */
complex<float>** selectedQubitsBases;
selectedQubitsBases = (complex<float>**) malloc(sizeOfSelectedQubitsBases * sizeof(complex<float>*))
;
for(i = 0; i < sizeOfSelectedQubitsBases; i++) {
selectedQubitsBases[i] = (complex<float>*) malloc(sizeOfSelectedQubitsBasesC * sizeof(complex<
float>));
}
/* Example of what this func call does: 3-qubit register, we want qubits 1 & 3 so we get bases |00>,
|01>, |01>, .... , |11> */
selectedQubitsBases = app->getSelectedQubitsFromBases(sizeOfSelectedQubitsBasesC, qubitRegisterSizeG
, qubitRegisterSizeClassicalG, qubitsSelected);
complex<float>** selectedQubitsAppliedToGate;
selectedQubitsAppliedToGate = (complex<float>**) malloc(qubitRegisterSizeG * sizeof(complex<float>*)
);
for(i = 0; i < qubitRegisterSizeG; i++) {
selectedQubitsAppliedToGate[i] = (complex<float>*) malloc(qubitRegisterSizeClassicalG * sizeof
(complex<float>));
}
/* Example of what this does: with our |00>, |01>, |01>, .... , |11> we made earlier, convert this
to column vectors so
we have [1000], [0100], ... , [0001]*/
for(i = 0; i < qubitRegisterSizeG; i++) {
selectedQubitsAppliedToGate[i] = app->convertQubitsToColumnVectorForm(selectedQubitsBases[i],
sizeOfSelectedQubitsBasesC, true);
}
Page 12 of 46
untitled.h
29/04/2010 00:00
/* multiply gate by all column vectors that we just made ([1000], [0100], ... , [0001]) */
for(i = 0; i < qubitRegisterSizeG; i++) {
selectedQubitsAppliedToGate[i] = app->multiplyMatrixAndColumnVector(typeOfTransform,
selectedQubitsAppliedToGate[i], sizeOfSelectedQubitsBases);
}
complex<float>** selectedQubitsInDiracForm;
selectedQubitsInDiracForm = (complex<float>**) malloc(qubitRegisterSizeG * sizeof(complex<float>*));
for(i = 0; i < qubitRegisterSizeG; i++) {
selectedQubitsInDiracForm[i] = (complex<float>*) malloc(qubitRegisterSizeG * sizeof(complex<
float>));
}
/* convert the results back to Dirac form, for a given bases we may have more than one Dirac vector
if there
was a non-(0 or 1) probability somewhere in matrix multiplication result*/
selectedQubitsInDiracForm = app->convertQubitsDiracForm(sizeOfSelectedQubitsBasesC,
qubitRegisterSizeG, qubitRegisterSizeClassicalG, selectedQubitsBases,
selectedQubitsAppliedToGate, qubitsSelected);
int j;
for(i = 0; i < qubitRegisterSizeG; i++) {
for(j = 0; j < qubitRegisterSizeG; j++) {
/* store in mathematical internal representation of circuit */
internalCircuit[qubitChoice][qubitChoiceG[qubitChoice]-1][i][j] = selectedQubitsInDiracForm
[i][j];
}
}
}
else {
msg->tooManyLines(); //we've added too many gates to chosen qubit's line
}
}
/* check whether the register is initialised, if it isn't then bring up the initialisation window */
bool MainWindow::isRegisterInitialised() {
if(done == false) {
msg->qubitRegisterNotInitialised();
initialise->show();
Page 13 of 46
untitled.h
29/04/2010 00:00
initialise->setFocus();
initialise->activateWindow();
linesAreSet = false;
done = true;
return false;
}
else {
return true;
}
}
/* Set up the Pauli-Z matrix */
void MainWindow::setPauliZmatrix() {
if(isRegisterInitialised()) {
bool ok;
int qubitChoice;
QString typeOfGate = "Z";
int qubitsSelected[1];
int sizeOfSelectedQubitsBases = 1; //one-qubit gate
int sizeOfSelectedQubitsBasesC;
double sizeOfSelectedQubitsBasesD;
sizeOfSelectedQubitsBasesC = sizeOfSelectedQubitsBases; //copy of noOfQubits variable
sizeOfSelectedQubitsBasesD = double(sizeOfSelectedQubitsBases); //double version of noOfQubits
variable
sizeOfSelectedQubitsBasesD = pow(2, sizeOfSelectedQubitsBasesD);
sizeOfSelectedQubitsBases = int(sizeOfSelectedQubitsBasesD); //matrix dimension 2^1
qubitChoice = QInputDialog::getInt(this, tr("Qubit choice"),
tr("Enter which qubit this gate is to act upon:"),
0, 0, qubitRegisterSizeClassicalG-1, 1, &ok);
if(!ok) {
return; //return if user presses cancel
}
typeOfTransform = trans->setPauliZmatrix(); //get matrix for pauili-z transform
updateInternalCircuit(typeOfGate, qubitsSelected, sizeOfSelectedQubitsBases,
sizeOfSelectedQubitsBasesC, qubitChoice, zPath, typeOfTransform);
}
Page 14 of 46
untitled.h
29/04/2010 00:00
}
/* Set up the Pauli-Y matrix */
using namespace std;
void MainWindow::setPauliYmatrix() {
if(isRegisterInitialised()) {
bool ok;
int qubitChoice;
QString typeOfGate = "Y";
int qubitsSelected[1];
int sizeOfSelectedQubitsBases = 1; //one qubit gate
int sizeOfSelectedQubitsBasesC;
double sizeOfSelectedQubitsBasesD;
sizeOfSelectedQubitsBasesC = sizeOfSelectedQubitsBases; //copy of noOfQubits variable
sizeOfSelectedQubitsBasesD = double(sizeOfSelectedQubitsBases); //double version of noOfQubits
variable
sizeOfSelectedQubitsBasesD = pow(2, sizeOfSelectedQubitsBasesD);
sizeOfSelectedQubitsBases = int(sizeOfSelectedQubitsBasesD); //2^1 sized matrix
qubitChoice = QInputDialog::getInt(this, tr("Qubit choice"),
tr("Enter which qubit this gate is to act upon:"),
0, 0, qubitRegisterSizeClassicalG-1, 1, &ok);
if(!ok) {
return; //user hit cancel
}
typeOfTransform = trans->setPauliYmatrix(); //get pauili-y matrix
updateInternalCircuit(typeOfGate, qubitsSelected, sizeOfSelectedQubitsBases,
sizeOfSelectedQubitsBasesC, qubitChoice, yPath, typeOfTransform);
}
}
/* Set the Toffoli matrix up */
void MainWindow::setToffoliMatrix() {
if(isRegisterInitialised()) { //bring up qubit choice input if not initialised, 3 inputs needed for a
toffoli gate
input = new qubitInput(this, this, 3, "toffoli");
input->show();
Page 15 of 46
untitled.h
29/04/2010 00:00
input->setFocus();
input->activateWindow();
}
}
/* Apply toffoli gate to register. Multi-qubit gates have their own functions for being applied to the
register
so prevent the updateInternalCircuit(...) getting complicated */
void MainWindow::setToffoliMatrixHelper() {
int firstControlQubitChoice, secondControlQubitChoice, targetQubitChoice;
int qubitsSelected[3];
targetQubitChoice = dataFromQubitInput[0];
firstControlQubitChoice = dataFromQubitInput[1];
secondControlQubitChoice = dataFromQubitInput[2];
int sizeOfSelectedQubitsBases = 3; //3-qubit gate
int sizeOfSelectedQubitsBasesC;
double sizeOfSelectedQubitsBasesD;
sizeOfSelectedQubitsBasesC = sizeOfSelectedQubitsBases; //copy of noOfQubits variable
sizeOfSelectedQubitsBasesD = double(sizeOfSelectedQubitsBases); //double version of noOfQubits variable
sizeOfSelectedQubitsBasesD = pow(2, sizeOfSelectedQubitsBasesD);
sizeOfSelectedQubitsBases = int(sizeOfSelectedQubitsBasesD); //2^3 sized matrix for toffoli
/* make sure we haven't added too many gates for all the chosen 3 qubits */
if(qubitChoiceG[targetQubitChoice] + 1 < MAX_NO_OF_LINES || qubitChoiceG[firstControlQubitChoice] + 1 <
MAX_NO_OF_LINES || qubitChoiceG[secondControlQubitChoice] + 1 < MAX_NO_OF_LINES) {
/* make sure the qubits are on different lines */
if(targetQubitChoice == firstControlQubitChoice || targetQubitChoice == secondControlQubitChoice ||
firstControlQubitChoice == secondControlQubitChoice) {
msg->multiQubitSelectionNotUnique();
}
else {
/* make sure the 2 control qubits and target qubit are on the same column, this isn't a
necessary in quantum computing, just the program's requirement */
if(qubitChoiceG[firstControlQubitChoice] != qubitChoiceG[secondControlQubitChoice] ||
qubitChoiceG[firstControlQubitChoice] != qubitChoiceG[targetQubitChoice]) {
msg->erroneousAllignment();
return;
Page 16 of 46
untitled.h
29/04/2010 00:00
}
qubitChoiceG[firstControlQubitChoice]++; //move along 1 place for chosen qubits
qubitChoiceG[secondControlQubitChoice]++;
qubitChoiceG[targetQubitChoice]++;
/* update front-end of circuit */
circuit[firstControlQubitChoice][qubitChoiceG[firstControlQubitChoice]] = tcPath;
updateWorkspace(firstControlQubitChoice, "ToffoliControl");
circuit[secondControlQubitChoice][qubitChoiceG[secondControlQubitChoice]] = tcPath;
updateWorkspace(secondControlQubitChoice, "ToffoliControl");
circuit[targetQubitChoice][qubitChoiceG[targetQubitChoice]] = ttPath;
updateWorkspace(targetQubitChoice, "ToffoliTarget");
qubitsSelected[0] = firstControlQubitChoice;
qubitsSelected[1] = secondControlQubitChoice;
qubitsSelected[2] = targetQubitChoice;
complex<float>** bases;
bases = (complex<float>**) malloc(qubitRegisterSizeG * sizeof(complex<float>*));
int i;
for(i = 0; i < qubitRegisterSizeG; i++) {
bases[i] = (complex<float>*) malloc(qubitRegisterSizeClassicalG * sizeof(complex<float>));
}
bases = app->generateBasesVectors(qubitRegisterSizeClassicalG);
int sizeOfSelectedQubitsBases = 3;
int sizeOfSelectedQubitsBasesC;
double sizeOfSelectedQubitsBasesD;
sizeOfSelectedQubitsBasesC = sizeOfSelectedQubitsBases; //copy of noOfQubits variable
sizeOfSelectedQubitsBasesD = double(sizeOfSelectedQubitsBases); //double version of noOfQubits
variable
sizeOfSelectedQubitsBasesD = pow(2, sizeOfSelectedQubitsBasesD);
sizeOfSelectedQubitsBases = int(sizeOfSelectedQubitsBasesD);
/************ see updateInternalCircuit(...) for comments on qubit gate being applied to
register,
everything's very similar here ******************/
Page 17 of 46
untitled.h
29/04/2010 00:00
complex<float>** selectedQubitsBases;
selectedQubitsBases = (complex<float>**) malloc(sizeOfSelectedQubitsBases * sizeof(complex<float
>*));
for(i = 0; i < sizeOfSelectedQubitsBases; i++) {
selectedQubitsBases[i] = (complex<float>*) malloc(sizeOfSelectedQubitsBasesC * sizeof
(complex<float>));
}
selectedQubitsBases = app->getSelectedQubitsFromBases(3, qubitRegisterSizeG,
qubitRegisterSizeClassicalG, qubitsSelected);
complex<float>** selectedQubitsAppliedToGate;
selectedQubitsAppliedToGate = (complex<float>**) malloc(qubitRegisterSizeG * sizeof(complex<
float>*));
for(i = 0; i < qubitRegisterSizeG; i++) {
selectedQubitsAppliedToGate[i] = (complex<float>*) malloc(qubitRegisterSizeClassicalG *
sizeof(complex<float>));
}
for(i = 0; i < qubitRegisterSizeG; i++) {
selectedQubitsAppliedToGate[i] = app->convertQubitsToColumnVectorForm(selectedQubitsBases[i]
, 3, true);
}
for(i = 0; i < qubitRegisterSizeG; i++) {
selectedQubitsAppliedToGate[i] = app->multiplyMatrixAndColumnVector(trans->setToffoliMatrix
(), selectedQubitsAppliedToGate[i], 8);
}
complex<float>** selectedQubitsInDiracForm;
selectedQubitsInDiracForm = (complex<float>**) malloc(qubitRegisterSizeG * sizeof(complex<float>
*));
for(i = 0; i < qubitRegisterSizeG; i++) {
selectedQubitsInDiracForm[i] = (complex<float>*) malloc(3 * sizeof(complex<float>));
}
selectedQubitsInDiracForm = app->convertQubitsDiracForm(3, qubitRegisterSizeG,
qubitRegisterSizeClassicalG, selectedQubitsBases, selectedQubitsAppliedToGate,
qubitsSelected);
int j;
Page 18 of 46
untitled.h
29/04/2010 00:00
for(i = 0; i < qubitRegisterSizeG; i++) {
for(j = 0; j < qubitRegisterSizeG; j++) {
internalCircuit[targetQubitChoice][qubitChoiceG[targetQubitChoice]-1][i][j] =
selectedQubitsInDiracForm[i][j];
}
}
}
}
else {
msg->tooManyLines();
}
}
/* Set up the controlled-NOT matrix */
void MainWindow::setControlledNOTmatrix() {
if(isRegisterInitialised()) {
input = new qubitInput(this, this, 2, "cnot");
input->show();
input->setFocus();
input->activateWindow();
}
}
void MainWindow::setControlledNOTmatrixHelper() {
int targetQubitChoice, controlQubitChoice;
targetQubitChoice = dataFromQubitInput[0];
controlQubitChoice = dataFromQubitInput[1];
int qubitsSelected[2];
if(qubitChoiceG[targetQubitChoice] + 1 < MAX_NO_OF_LINES || qubitChoiceG[controlQubitChoice] + 1 <
MAX_NO_OF_LINES) {
if(targetQubitChoice == controlQubitChoice) {
msg->multiQubitSelectionNotUnique();
return;
}
if(qubitChoiceG[controlQubitChoice] != qubitChoiceG[targetQubitChoice]) {
Page 19 of 46
untitled.h
29/04/2010 00:00
msg->erroneousAllignment();
return;
}
qubitChoiceG[controlQubitChoice]++;
qubitChoiceG[targetQubitChoice]++;
circuit[controlQubitChoice][qubitChoiceG[controlQubitChoice]] = cnotcPath;
updateWorkspace(controlQubitChoice, "CNOTcontrol");
circuit[targetQubitChoice][qubitChoiceG[targetQubitChoice]] = cnottPath;
updateWorkspace(targetQubitChoice, "CNOTtarget");
qubitsSelected[0] = controlQubitChoice;
qubitsSelected[1] = targetQubitChoice;
complex<float>** bases;
bases = (complex<float>**) malloc(qubitRegisterSizeG * sizeof(complex<float>*));
int i, j;
for(i = 0; i < qubitRegisterSizeG; i++) {
bases[i] = (complex<float>*) malloc(qubitRegisterSizeClassicalG * sizeof(complex<float>));
}
bases = app->generateBasesVectors(qubitRegisterSizeClassicalG);
int sizeOfSelectedQubitsBases = 2;
int sizeOfSelectedQubitsBasesC;
double sizeOfSelectedQubitsBasesD;
sizeOfSelectedQubitsBasesC = sizeOfSelectedQubitsBases; //copy of noOfQubits variable
sizeOfSelectedQubitsBasesD = double(sizeOfSelectedQubitsBases); //double version of noOfQubits
variable
sizeOfSelectedQubitsBasesD = pow(2, sizeOfSelectedQubitsBasesD);
sizeOfSelectedQubitsBases = int(sizeOfSelectedQubitsBasesD);
/************ see updateInternalCircuit(...) for comments on qubit gate being applied to register,
everything's very similar here ******************/
complex<float>** selectedQubitsBases;
selectedQubitsBases = (complex<float>**) malloc(sizeOfSelectedQubitsBases * sizeof(complex<float>*))
;
Page 20 of 46
untitled.h
29/04/2010 00:00
for(i = 0; i < sizeOfSelectedQubitsBases; i++) {
selectedQubitsBases[i] = (complex<float>*) malloc(sizeOfSelectedQubitsBasesC * sizeof(complex<
float>));
}
selectedQubitsBases = app->getSelectedQubitsFromBases(2, qubitRegisterSizeG,
qubitRegisterSizeClassicalG, qubitsSelected);
/* column vectors of selected qubits in register */
complex<float>** selectedQubitsAppliedToGate;
selectedQubitsAppliedToGate = (complex<float>**) malloc(qubitRegisterSizeG * sizeof(complex<float>*)
);
for(i = 0; i < qubitRegisterSizeG; i++) {
selectedQubitsAppliedToGate[i] = (complex<float>*) malloc(qubitRegisterSizeClassicalG * sizeof
(complex<float>));
}
for(i = 0; i < qubitRegisterSizeG; i++) {
selectedQubitsAppliedToGate[i] = app->convertQubitsToColumnVectorForm(selectedQubitsBases[i], 2,
true);
}
/* column vectors after all being applied to gate */
for(i = 0; i < qubitRegisterSizeG; i++) {
selectedQubitsAppliedToGate[i] = app->multiplyMatrixAndColumnVector(trans->
setControlledNOTmatrix(), selectedQubitsAppliedToGate[i], 4);
}
complex<float>** selectedQubitsInDiracForm;
selectedQubitsInDiracForm = (complex<float>**) malloc(qubitRegisterSizeG * sizeof(complex<float>*));
for(i = 0; i < qubitRegisterSizeG; i++) {
selectedQubitsInDiracForm[i] = (complex<float>*) malloc(2 * sizeof(complex<float>));
}
selectedQubitsInDiracForm = app->convertQubitsDiracForm(2, qubitRegisterSizeG,
qubitRegisterSizeClassicalG, selectedQubitsBases, selectedQubitsAppliedToGate, qubitsSelected);
for(i = 0; i < qubitRegisterSizeG; i++) {
for(j = 0; j < qubitRegisterSizeG; j++) {
internalCircuit[targetQubitChoice][qubitChoiceG[targetQubitChoice]-1][i][j] =
selectedQubitsInDiracForm[i][j];
Page 21 of 46
untitled.h
29/04/2010 00:00
}
}
}
else {
msg->tooManyLines();
}
}
/* Set up the Hadamard matrix */
void MainWindow::setHadamardMatrix() {
bool ok;
int qubitChoice;
int qubitsSelected[1];
QString typeOfGate = "Hadamard";
int sizeOfSelectedQubitsBases = 1; //one-qubit gate
int sizeOfSelectedQubitsBasesC;
double sizeOfSelectedQubitsBasesD;
sizeOfSelectedQubitsBasesC = sizeOfSelectedQubitsBases; //copy of noOfQubits variable
sizeOfSelectedQubitsBasesD = double(sizeOfSelectedQubitsBases); //double version of noOfQubits variable
sizeOfSelectedQubitsBasesD = pow(2, sizeOfSelectedQubitsBasesD);
sizeOfSelectedQubitsBases = int(sizeOfSelectedQubitsBasesD); //2^1 sized matrix for this gate
if(isRegisterInitialised()) {
qubitChoice = QInputDialog::getInt(this, tr("Qubit choice"),
tr("Enter which qubit this gate is to act upon:"),
0, 0, qubitRegisterSizeClassicalG-1, 1, &ok);
if(!ok) {
return; //user pressed cancel
}
typeOfTransform = trans->setHadamardMatrix(); //get Hadmard matrix
updateInternalCircuit(typeOfGate, qubitsSelected, sizeOfSelectedQubitsBases,
sizeOfSelectedQubitsBasesC, qubitChoice, yPath, typeOfTransform);
}
}
/* Make a quantum measurement, updateWorkspace(.., ..) will use the measurement class */
Page 22 of 46
untitled.h
29/04/2010 00:00
void MainWindow::setMeasurement() {
if(isRegisterInitialised()) {
bool ok;
int qubitChoice;
qubitChoice = QInputDialog::getInt(this, tr("Qubit choice"),
tr("Enter which qubit this gate is to act upon:"),
0, 0, qubitRegisterSizeClassicalG-1, 1, &ok);
if(!ok) {
return; //user cancelled
}
if(qubitChoiceG[qubitChoice] + 1 < MAX_NO_OF_LINES) { //check not too many gates for this qubit
QString typeOfGate = "Measurement";
qubitChoiceG[qubitChoice]++;
/******** measurement is performed by the updateWorkspace(...) func instantiating measurement
class **********/
updateWorkspace(qubitChoice, typeOfGate);
}
else {
msg->tooManyLines();
}
}
}
/* Get user's required qubit register size, allocate the memory needed for
that size quantum register and then initialise each qubit in the register
to all zeroes */
void MainWindow::setQubitRegisterSize(void) {
/* Take an integer input from the user, force the user to either input an integer
by pressing the up and down keys (forces integer validation) or exit the program */
bool ok;
int qubitRegisterSize, qubitRegisterSizeClassical;
float qubitRegisterSizeD;
while (1) {
qubitRegisterSize = QInputDialog::getInt(this, tr("Qubit register size"),
tr("Please enter size of qubit register:"), 3, 1, 7, 1, &ok
);
qubitRegisterSizeClassical = qubitRegisterSize;
qubitRegisterSizeD = float(qubitRegisterSize);
Page 23 of 46
untitled.h
29/04/2010 00:00
qubitRegisterSizeD = pow(2, qubitRegisterSizeD);
qubitRegisterSize = int(qubitRegisterSizeD);
if(ok) {
break; //carry on with program
}
else {
exit(0); //user has decided to quit the program straight after execution so exit
}
}
qubitRegisterSizeG = qubitRegisterSize;
qubitRegisterSizeClassicalG = qubitRegisterSizeClassical;
}
void MainWindow::deleteFunc() {
int i, longest = 0;
/* Find position of gate furthest to the right */
for(i = 0; i < qubitRegisterSizeClassicalG; i++) {
if(qubitChoiceG[i] > longest) {
longest = qubitChoiceG[i];
}
}
if(longest == 0) {
msg->nothingToDelete();
return;
}
for(i = 0; i < qubitRegisterSizeClassicalG; i++) {
if(qubitChoiceG[i] >= longest) { //found gate furthest to right
circuit[i][qubitChoiceG[i]] = ""; //clear gate from workspace
qubitChoiceG[i]--; //one less gate on this line
updateWorkspace(-1, "not applicable"); //function arguments tell function that we don't want to
add a gate
ui->quantumRegisterDisplay->clear();
/* Re-enable buttons */
measurementButton->setEnabled(true);
pauliXbutton->setEnabled(true);
pauliYbutton->setEnabled(true);
pauliZbutton->setEnabled(true);
controlledNotButton->setEnabled(true); hadamardButton->setEnabled(true);
Page 24 of 46
untitled.h
29/04/2010 00:00
toffoliButton->setEnabled(true);
unitaryMatrixButton->setEnabled(true);
}
}
/* Set bases amounts back to initialised register values*/
for(i = 0; i < qubitRegisterSizeG; i++) {
magnitudeOfEachBases[0][i] = initialisedRegister[i];
}
noOfForwardSteps = 0; //go back to start of circuit
}
/* Run a single stage of the circuit, playing the circuit calls this many times */
void MainWindow::forwardFunc() {
int i, j, k, h;
largest = 0;
/* Find gate furthest to right */
for(i = 0; i < qubitRegisterSizeClassicalG; i++) {
if(qubitChoiceG[i] > largest) {
largest = qubitChoiceG[i];
}
}
/* there's no circuit so we can't move forward */
if(largest == 0) {
msg->reachedEndOfCircuit();
return;
}
/* We've gone further than the gate furthest to the right, do not allow this */
if((noOfForwardSteps) >= largest) {
msg->reachedEndOfCircuit();
return;
}
else {
noOfForwardSteps++; //we've moved forward
}
/* Matrices have been generated and stored and now the user has pressed the forward button
Page 25 of 46
untitled.h
29/04/2010 00:00
meaning that some of these matrices can now be applied to the register */
bool isAtransformation = false;
complex<float> zero(0.0, 0.0);
complex<float>** transform;
/* memory allocation */
transform = (complex<float>**) malloc(qubitRegisterSizeG*sizeof(complex<float>*));
for(i = 0; i < qubitRegisterSizeG; i++) {
transform[i] = (complex<float>*) malloc(qubitRegisterSizeG * sizeof(complex<float>));
}
i = noOfForwardSteps - 1;
for(j = 0; j < qubitRegisterSizeClassicalG; j++) {
if(circuit[j][i+1] == mPath) { //found measurement gate
measurementGate = true;
/* perform measurement */
measure->performMeasurement(j, i + 1, magnitudeOfEachBases, qubitRegisterSizeG,
qubitRegisterSizeClassicalG);
magnitudeOfEachBases[i-2] = measure->var; //line of circuit before the part of the line that we
measured
updateRegisterDisplay(); //update register with measured qubits
}
}
/* look for all quantum transformations up to where we have moved */
for(j = 0; j < qubitRegisterSizeG; j++) {
isAtransformation = false;
for(k = 0; k < qubitRegisterSizeG; k++) {
for(h = 0; h < qubitRegisterSizeG; h++) {
transform[k][h] = internalCircuit[j][i][k][h];
if(transform[k][h] != zero) {
isAtransformation = true; //found a gate
}
}
}
/* apply gate */
if(isAtransformation) {
/* if we're in the first column of circuit then use the initialised register as a column vector
Page 26 of 46
untitled.h
29/04/2010 00:00
and apply gate to this */
if(i == 0) {
magnitudeOfEachBases[i] = app->multiplyMatrixAndColumnVector(transform, magnitudeOfEachBases
[i], qubitRegisterSizeG);
}
else {
magnitudeOfEachBases[i] = app->multiplyMatrixAndColumnVector(transform, magnitudeOfEachBases
[i-1], qubitRegisterSizeG);
magnitudeOfEachBases[i-1] = magnitudeOfEachBases[i];
}
}
}
updateRegisterDisplay(); //update register contents
/* Prevent user from constructing circuit
measurementButton->setEnabled(false);
pauliYbutton->setEnabled(false);
controlledNotButton->setEnabled(false);
toffoliButton->setEnabled(false);
whilst it's being run */
pauliXbutton->setEnabled(false);
pauliZbutton->setEnabled(false);
hadamardButton->setEnabled(false);
unitaryMatrixButton->setEnabled(false);
}
/* play the whole circuit */
void MainWindow::playFunc() {
int i, overallMax = 0;
for(i = 0; i < qubitRegisterSizeClassicalG; i++) {
/* find gate furthest to the right */
if(qubitChoiceG[i] > overallMax) {
overallMax = qubitChoiceG[i];
}
}
/* move forwards up to the gate furthest to the right */
for(i = 0; i < overallMax; i++) {
forwardFunc();
}
}
/* Step backwards in the circuit, circuit would have been executed by the time this has been pressed (unless
it is then it
Page 27 of 46
untitled.h
29/04/2010 00:00
wouldn't do anything). This function just reads from the quantum register history matrix */
void MainWindow::backwardFunc() {
noOfForwardSteps--;
if(noOfForwardSteps == 1) { //updateRegisterDisplay requires this to happen because of the way
noOfForwardSteps gets incremented
noOfForwardSteps = 0;
}
else if(noOfForwardSteps < 1) { //don't let the user try an view parts of the circuit that don't exist
ui->quantumRegisterDisplay->clear();
noOfForwardSteps = 0;
msg->tooFarBackwards();
return;
}
updateRegisterDisplay(); //update register using new value of noOfForwardSteps
}
/* Update the register display in the GUI */
void MainWindow::updateRegisterDisplay() {
int i, j, k;
QString bases, pad;
complex<float> zero(0.0,0.0);
basesVectors = app->generateBasesVectors(qubitRegisterSizeClassicalG);
ui->quantumRegisterDisplay->clear();
for(i = 0; i < qubitRegisterSizeG; i++) {
bases = pad = "";
if(noOfForwardSteps == 1) { //first step forward requires an additional step but the others don't
temp[i] = magnitudeOfEachBases[0][i];
bases.append("(");
pad = QString::number(real(temp[i]));
while(pad.length() != 9) { //9 is the length of the decimal that will be displayed
if(pad.length() == 1) { pad.append("."); } else { pad.append("0"); }
}
if(temp[i] != zero) {
bases.append("<FONT color = \"green\">");
bases.append(pad);
bases.append("</FONT>");
}
Page 28 of 46
untitled.h
29/04/2010 00:00
else {
bases.append("<FONT color = \"red\">");
bases.append(pad);
bases.append("</FONT>");
}
bases.append(", ");
pad = QString::number(imag(temp[i]));
while(pad.length() != 9) {
if(pad.length() == 1) { pad.append("."); } else { pad.append("0"); }
}
if(temp[i] != zero) {
bases.append("<FONT color = \"green\">");
bases.append(pad);
bases.append("i");
bases.append("</FONT>");
}
else {
bases.append("<FONT color = \"red\">");
bases.append(pad);
bases.append("i");
bases.append("</FONT>");
}
bases.append(")");
bases.append("|");
if(temp[i] != zero) {
for(j = 0; j < qubitRegisterSizeClassicalG; j++) {
bases.append("<FONT color = \"green\">");
bases.append(QString::number(real(basesVectors[i][j])));
bases.append("</FONT>");
}
}
else {
for(j = 0; j < qubitRegisterSizeClassicalG; j++) {
bases.append("<FONT color = \"red\">");
bases.append(QString::number(real(basesVectors[i][j])));
bases.append("</FONT>");
}
Page 29 of 46
untitled.h
29/04/2010 00:00
}
bases.append(">");
bases.append("--");
}
/* see comments in the if branch above, they all apply here too */
else {
bases.append("(");
pad = QString::number(real(temp[i]));
while(pad.length() != 9) {
if(pad.length() == 1) { pad.append("."); } else { pad.append("0"); }
}
if(temp[i] != zero) {
bases.append("<FONT color = \"green\">");
bases.append(pad);
bases.append("</FONT>");
}
else {
bases.append("<FONT color = \"red\">");
bases.append(pad);
bases.append("</FONT>");
}
bases.append(", ");
pad = QString::number(imag(temp[i]));
while(pad.length() != 9) {
if(pad.length() == 1) { pad.append("."); } else { pad.append("0"); }
}
if(temp[i] != zero) {
bases.append("<FONT color = \"green\">");
bases.append(pad);
bases.append("i");
bases.append("</FONT>");
}
else {
bases.append("<FONT color = \"red\">");
bases.append(pad);
bases.append("i");
bases.append("</FONT>");
Page 30 of 46
untitled.h
29/04/2010 00:00
}
bases.append(")");
bases.append("|");
if(temp[i] != zero) {
for(j = 0; j < qubitRegisterSizeClassicalG; j++) {
bases.append("<FONT color = \"green\">");
bases.append(QString::number(real(basesVectors[i][j])));
bases.append("</FONT>");
}
}
else {
for(j = 0; j < qubitRegisterSizeClassicalG; j++) {
bases.append("<FONT color = \"red\">");
bases.append(QString::number(real(basesVectors[i][j])));
bases.append("</FONT>");
}
}
bases.append(">");
bases.append("--");
for(k = 0; k < noOfForwardSteps - 1; k++) {
bases.append("(");
pad = QString::number(real(magnitudeOfEachBases[k][i]));
while(pad.length() != 9) {
if(pad.length() == 1) { pad.append("."); } else { pad.append("0"); }
}
if(magnitudeOfEachBases[k][i] != zero) {
bases.append("<FONT color = \"green\">");
bases.append(pad);
bases.append("</FONT>");
}
else {
bases.append("<FONT color = \"red\">");
bases.append(pad);
bases.append("</FONT>");
Page 31 of 46
untitled.h
29/04/2010 00:00
}
bases.append(", ");
pad = QString::number(imag(magnitudeOfEachBases[k][i]));
while(pad.length() != 9) {
if(pad.length() == 1) { pad.append("."); } else { pad.append("0"); }
}
if(magnitudeOfEachBases[k][i] != zero) {
bases.append("<FONT color = \"green\">");
bases.append(pad);
bases.append("i");
bases.append("</FONT>");
}
else {
bases.append("<FONT color = \"red\">");
bases.append(pad);
bases.append("i");
bases.append("</FONT>");
}
bases.append(")");
bases.append("|");
if(magnitudeOfEachBases[k][i] != zero) {
for(j = 0; j < qubitRegisterSizeClassicalG; j++) {
bases.append("<FONT color = \"green\">");
bases.append(QString::number(real(basesVectors[i][j])));
bases.append("</FONT>");
}
}
else {
for(j = 0; j < qubitRegisterSizeClassicalG; j++) {
bases.append("<FONT color = \"red\">");
bases.append(QString::number(real(basesVectors[i][j])));
bases.append("</FONT>");
}
}
Page 32 of 46
untitled.h
29/04/2010 00:00
bases.append(">");
bases.append("---");
}
}
ui->quantumRegisterDisplay->append(bases); //add the current bases vector to the display
}
ui->quantumRegisterDisplay->horizontalScrollBar()->setValue(ui->quantumRegisterDisplay->
horizontalScrollBar()->maximum());
}
/* Update the workspace with the latest circuit. This is not the internal representation of the circuit, it
is only for GUI purposes */
void MainWindow::updateWorkspace(int qubitNumber, QString typeOfGate) {
noOfLinesSoFar++;
QString qubitLabel, htmlStart = "<html><head></head><body>";
QString htmlEnd = "</body></html>", htmlBody = "";
char* path;
int i, j;
complex<float> complexZero(0.0,0.0);
complex<float> complexOne(1.0,0.0);
if(qubitNumber != -1) { //if function is being called for workspace to be updated with a new gate
/* Directory of the various gates' images */
if(typeOfGate == "X") {
path = xPath;
}
else if(typeOfGate == "Y") {
path = yPath;
}
else if(typeOfGate == "Z") {
path = zPath;
}
else if(typeOfGate == "Hadamard") {
path = hPath;
}
else if(typeOfGate == "CNOTtarget") {
path = CNOTtargetColourList();
}
Page 33 of 46
untitled.h
29/04/2010 00:00
else if(typeOfGate == "CNOTcontrol") {
path = CNOTcontrolColourList();
}
else if(typeOfGate == "ToffoliControl") {
if(!firstControlSet) {
path = toffoliControl1ColourList();
firstControlSet = true;
}
else {
path = toffoliControl2ColourList();
firstControlSet = false;
}
}
else if(typeOfGate == "ToffoliTarget") {
path = toffoliTargetColourList();
}
else if(typeOfGate == "Measurement") {
path = mPath;
}
else if(typeOfGate == "Custom") {
path = customPath;
}
/* Initialise all the lines of the circuit.
a number of lines representing each qubit.
if(linesAreSet == false) {
linesAreSet = true;
if(done == false) {
initialise->show();
initialise->setFocus();
linesAreSet = false;
done = true;
}
}
The circuit is represented as
The gates are placed on these lines */
/* The is a position in the array for each line. This position starts
off as an empty string and grows as new paths are added on to the end */
circuit[qubitNumber][qubitChoiceG[qubitNumber]] = path;
Page 34 of 46
untitled.h
29/04/2010 00:00
}
/* Clear the workspace and add all the lines that have been built to the circuit */
ui->workspace->clear();
QString num;
const char* temp;
thereExistsAcircuit = false;
bool registerIsSuperimposed = false;
for(i = 0; i < qubitRegisterSizeG; i++) {
if(initialisedRegister[i] != complexZero && initialisedRegister[i] != complexOne) {
registerIsSuperimposed = true;
break;
}
}
/* Get the contents of the circuit from the 2D array and display it in the workspace */
for(i = 0; i < qubitRegisterSizeClassicalG; i++) {
if(!registerIsSuperimposed) {
num = QString::number(real(diracForm[i])); //Get initialised qubit state for this line
htmlBody.append(qubitLabel.setNum(i) + " "+ "|" + num + ">"); //Show this in LHS of workspace
}
else {
htmlBody.append(qubitLabel.setNum(i) + " "+ "|(superposition)>");
}
for(j = 0; j < qubitChoiceG[i] + 1; j++) {
temp = circuit[i][j].c_str();
htmlBody.append(temp);
}
htmlBody.append("<hr>"); //Seperate each line with a horizonal HTML line
}
ui->workspace->setHtml(htmlStart + htmlBody + htmlEnd);
thereExistsAcircuit = true; //For circuit deletion warnings
ui->workspace->horizontalScrollBar()->setValue(ui->workspace->horizontalScrollBar()->maximum()); //move
right as far as possible
}
/* Delete the whole circuit */
void MainWindow::clearWorkspace() {
Page 35 of 46
untitled.h
29/04/2010 00:00
int i, j, x, y;
complex<float> zero(0.0, 0.0);
for(i = 0; i < qubitRegisterSizeClassicalG; i++) {
/* Delete graphical representation of circuit */
for(j = 0; j < qubitRegisterSizeClassicalG; j++) {
circuit[j][i] = "";
}
qubitChoiceG[i] = 0; //reset how many gates there are per qubit
}
/* delete mathematical, internal representation of circuit */
for(i = 0; i < qubitRegisterSizeClassicalG; i++) {
for(j = 0; j < MAX_NO_OF_LINES; j++) {
for(x = 0; x < qubitRegisterSizeG; x++) {
for(y = 0; y < qubitRegisterSizeG; y++) {
internalCircuit[i][j][x][y] = zero;
}
}
}
}
/* Put first amounts of bases back to what they were initialised to */
for(i = 0; i < qubitRegisterSizeG; i++) {
magnitudeOfEachBases[0][i] = initialisedRegister[i];
}
/* Zero out all the other amounts from further on in the circuit */
for(i = 0; i < qubitRegisterSizeG; i++) {
for(j = 1; j < MAX_NO_OF_LINES; j++) { //start from 1 to keep initialised register
magnitudeOfEachBases[j][i] = 0;
}
}
currentColour = currentColourToffoli = 0;
largest = noOfForwardSteps = 0;
/* Re-enable buttons */
Page 36 of 46
untitled.h
29/04/2010 00:00
measurementButton->setEnabled(true);
pauliYbutton->setEnabled(true);
controlledNotButton->setEnabled(true);
toffoliButton->setEnabled(true);
ui->workspace->clear();
clearRegisterDisplay();
if(!isRegisterInitialised()) {
msg->circuitCleared();
}
pauliXbutton->setEnabled(true);
pauliZbutton->setEnabled(true);
hadamardButton->setEnabled(true);
unitaryMatrixButton->setEnabled(true);
}
/* ui-> is protected, this function can be called by the initialise
register function to clear the register from there */
void MainWindow::clearRegisterDisplay() {
ui->quantumRegisterDisplay->clear();
}
/* Automatically generated by Qt. */
void MainWindow::changeEvent(QEvent *e) {
QMainWindow::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
default:
break;
}
}
/* This is called by the UnitaryMatrixInput class if it gets an inputted matrix that is unitary and can be
added to the workspace */
void MainWindow::setUnitaryMatrixFromDialog(complex<float>** customMatrix) {
if(found) {
bool roomForGate = true;
int i;
int qubitsSelected[1];
/* A custom matrix puts a gate icon on every qubit line regardless so we need to check all qubits
line for space */
Page 37 of 46
untitled.h
29/04/2010 00:00
for(i = 0; i < qubitRegisterSizeClassicalG; i++) {
if(qubitChoiceG[i] + 1 >= MAX_NO_OF_LINES) {
roomForGate = false;
break;
}
}
if(roomForGate) { //if there's room for this new gate
QString typeOfGate = "Custom";
for(i = 0; i < qubitRegisterSizeClassicalG; i++) {
qubitChoiceG[i]++;
qubitsSelected[i] = i;
circuit[i][qubitChoiceG[i]] = customPath;
updateWorkspace(i, typeOfGate);
}
int j, i;
/* apply user defined matrix to internal circuit */
for(i = 0; i < qubitRegisterSizeG; i++) {
for(j = 0; j < qubitRegisterSizeG; j++) {
internalCircuit[0][qubitChoiceG[0]-1][i][j] = customMatrix[i][j];
}
}
}
else {
msg->tooManyLines();
}
}
}
/* get new cnot target icon image */
char* MainWindow::CNOTtargetColourList() {
char* unusedColour;
char* CNOTtargetColourListPaths[9];
CNOTtargetColourListPaths[0] = "-<img src=\"./Images/CNOTs/CNOTtargetBlack.png\" align = \"middle\">";
CNOTtargetColourListPaths[1] = "-<img src=\"./Images/CNOTs/CNOTtargetDarkRed.png\" align = \"middle\">";
CNOTtargetColourListPaths[2] = "-<img src=\"./Images/CNOTs/CNOTtargetRed.png\" align = \"middle\">";
CNOTtargetColourListPaths[3] = "-<img src=\"./Images/CNOTs/CNOTtargetOrange.png\" align = \"middle\">";
CNOTtargetColourListPaths[4] = "-<img src=\"./Images/CNOTs/CNOTtargetYellow.png\" align = \"middle\">";
Page 38 of 46
untitled.h
29/04/2010 00:00
CNOTtargetColourListPaths[5] = "-<img src=\"./Images/CNOTs/CNOTtargetDarkGreen.png\" align = \"middle\
">";
CNOTtargetColourListPaths[6] = "-<img src=\"./Images/CNOTs/CNOTtargetBlue.png\" align = \"middle\">";
CNOTtargetColourListPaths[7] = "-<img src=\"./Images/CNOTs/CNOTtargetDarkBlue.png\" align = \"middle\">"
;
CNOTtargetColourListPaths[8] = "-<img src=\"./Images/CNOTs/CNOTtargetPurple.png\" align = \"middle\">";
unusedColour = CNOTtargetColourListPaths[currentColour];
currentColour++;
if(currentColour == 9) {
currentColour = 0;
}
return unusedColour;
}
/* get new cnot control icon image */
char* MainWindow::CNOTcontrolColourList() {
char* unusedColour;
char* CNOTcontrolColourListPaths[9];
CNOTcontrolColourListPaths[0] = "-<img src=\"./Images/CNOTs/CNOTcontrolBlack.png\" align = \"middle\">";
CNOTcontrolColourListPaths[1] = "-<img src=\"./Images/CNOTs/CNOTcontrolDarkRed.png\" align = \"middle\
">";
CNOTcontrolColourListPaths[2] = "-<img src=\"./Images/CNOTs/CNOTcontrolRed.png\" align = \"middle\">";
CNOTcontrolColourListPaths[3] = "-<img src=\"./Images/CNOTs/CNOTcontrolOrange.png\" align = \"middle\">"
;
CNOTcontrolColourListPaths[4] = "-<img src=\"./Images/CNOTs/CNOTcontrolYellow.png\" align = \"middle\">"
;
CNOTcontrolColourListPaths[5] = "-<img src=\"./Images/CNOTs/CNOTcontrolDarkGreen.png\" align = \"middle
\">";
CNOTcontrolColourListPaths[6] = "-<img src=\"./Images/CNOTs/CNOTcontrolBlue.png\" align = \"middle\">";
CNOTcontrolColourListPaths[7] = "-<img src=\"./Images/CNOTs/CNOTcontrolDarkBlue.png\" align = \"middle\
">";
CNOTcontrolColourListPaths[8] = "-<img src=\"./Images/CNOTs/CNOTcontrolPurple.png\" align = \"middle\">"
;
unusedColour = CNOTcontrolColourListPaths[currentColour];
return unusedColour;
}
/* get new toffoli first control icon image */
Page 39 of 46
untitled.h
29/04/2010 00:00
char* MainWindow::toffoliControl1ColourList() {
char* unusedColour;
char* toffoliControl1ColourListPaths[9];
toffoliControl1ColourListPaths[0] = "-<img src=\"./Images/Toffolis/ToffoliControl1Black.png.jpg\" align
= \"middle\">";
toffoliControl1ColourListPaths[4] = "-<img src=\"./Images/Toffolis/ToffoliControl1DarkRed.png.jpg\"
align = \"middle\">";
toffoliControl1ColourListPaths[2] = "-<img src=\"./Images/Toffolis/ToffoliControl1Red.png.jpg\" align =
\"middle\">";
toffoliControl1ColourListPaths[3] = "-<img src=\"./Images/Toffolis/ToffoliControl1Orange.png.jpg\" align
= \"middle\">";
toffoliControl1ColourListPaths[1] = "-<img src=\"./Images/Toffolis/ToffoliControl1Yellow.png.jpg\" align
= \"middle\">";
toffoliControl1ColourListPaths[5] = "-<img src=\"./Images/Toffolis/ToffoliControl1DarkGreen.png.jpg\"
align = \"middle\">";
toffoliControl1ColourListPaths[6] = "-<img src=\"./Images/Toffolis/ToffoliControl1Blue.png.jpg\" align =
\"middle\">";
toffoliControl1ColourListPaths[7] = "-<img src=\"./Images/Toffolis/ToffoliControl1DarkBlue.png.jpg\"
align = \"middle\">";
toffoliControl1ColourListPaths[8] = "-<img src=\"./Images/Toffolis/ToffoliControl1Purple.png.jpg\" align
= \"middle\">";
unusedColour = toffoliControl1ColourListPaths[currentColourToffoli];
return unusedColour;
}
/* get new toffoli second control icon image */
char* MainWindow::toffoliControl2ColourList() {
char* unusedColour;
char* toffoliControl2ColourListPaths[9];
toffoliControl2ColourListPaths[0] = "-<img src=\"./Images/Toffolis/ToffoliControl2Black.png.jpg\" align
= \"middle\">";
toffoliControl2ColourListPaths[4] = "-<img src=\"./Images/Toffolis/ToffoliControl2DarkRed.png.jpg\"
align = \"middle\">";
toffoliControl2ColourListPaths[2] = "-<img src=\"./Images/Toffolis/ToffoliControl2Red.png.jpg\" align =
\"middle\">";
toffoliControl2ColourListPaths[3] = "-<img src=\"./Images/Toffolis/ToffoliControl2Orange.png.jpg\" align
= \"middle\">";
toffoliControl2ColourListPaths[1] = "-<img src=\"./Images/Toffolis/ToffoliControl2Yellow.png.jpg\" align
Page 40 of 46
untitled.h
29/04/2010 00:00
= \"middle\">";
toffoliControl2ColourListPaths[5] = "-<img src=\"./Images/Toffolis/ToffoliControl2DarkGreen.png.jpg\"
align = \"middle\">";
toffoliControl2ColourListPaths[6] = "-<img src=\"./Images/Toffolis/ToffoliControl2Blue.png.jpg\" align =
\"middle\">";
toffoliControl2ColourListPaths[7] = "-<img src=\"./Images/Toffolis/ToffoliControl2DarkBlue.png.jpg\"
align = \"middle\">";
toffoliControl2ColourListPaths[8] = "-<img src=\"./Images/Toffolis/ToffoliControl2Purple.png.jpg\" align
= \"middle\">";
unusedColour = toffoliControl2ColourListPaths[currentColourToffoli];
return unusedColour;
}
/* get new toffoli first target icon image */
char* MainWindow::toffoliTargetColourList() {
char* unusedColour;
char* toffoliTargetColourListPaths[9];
toffoliTargetColourListPaths[0] = "-<img src=\"./Images/Toffolis/ToffoliTargetBlack.png.jpg\" align = \
"middle\">";
toffoliTargetColourListPaths[4] = "-<img src=\"./Images/Toffolis/ToffoliTargetDarkRed.png.jpg\" align =
\"middle\">";
toffoliTargetColourListPaths[2] = "-<img src=\"./Images/Toffolis/ToffoliTargetRed.png.jpg\" align = \
"middle\">";
toffoliTargetColourListPaths[3] = "-<img src=\"./Images/Toffolis/ToffoliTargetOrange.png.jpg\" align =
\"middle\">";
toffoliTargetColourListPaths[1] = "-<img src=\"./Images/Toffolis/ToffoliTargetYellow.png.jpg\" align =
\"middle\">";
toffoliTargetColourListPaths[5] = "-<img src=\"./Images/Toffolis/ToffoliTargetDarkGreen.png.jpg\" align
= \"middle\">";
toffoliTargetColourListPaths[6] = "-<img src=\"./Images/Toffolis/ToffoliTargetBlue.png.jpg\" align = \
"middle\">";
toffoliTargetColourListPaths[7] = "-<img src=\"./Images/Toffolis/ToffoliTargetDarkBlue.png.jpg\" align =
\"middle\">";
toffoliTargetColourListPaths[8] = "-<img src=\"./Images/Toffolis/ToffoliTargetPurple.png.jpg\" align =
\"middle\">";
unusedColour = toffoliTargetColourListPaths[currentColourToffoli];
currentColourToffoli++;
if(currentColourToffoli == 9) {
Page 41 of 46
untitled.h
29/04/2010 00:00
currentColourToffoli = 0;
}
return unusedColour;
}
/* save current circuit to file, do this using serialisation */
void MainWindow::saveCircuitToFile() {
int i, j, x, y;
nameOfSaveFileRegister = saveCircuit->createSaveFile(qubitRegisterSizeClassicalG, qubitRegisterSizeG,
internalCircuit);
if(nameOfSaveFileRegister.contains("/.quantum")) {
msg->invalidFileName();
return;
}
nameOfSaveFileView = nameOfSaveFileRegister;
nameOfSaveFileView.chop(8); //get rid of the .quantum
nameOfSaveFileView.append("View.quantum"); //and replace with View.quantum so we have two different
files, both with .quantum extension
QFile saveFileRegister(nameOfSaveFileRegister);
saveFileRegister.open(QIODevice::WriteOnly);
QDataStream outputRegister(&saveFileRegister);
/* internal mathematical representation of circuit is a 4D array so we need 4 nested loops */
for(i = 0; i < qubitRegisterSizeClassicalG; i++) {
for(j = 0; j < MAX_NO_OF_LINES; j++) {
for(x = 0; x < qubitRegisterSizeG; x++) {
for(y = 0; y < qubitRegisterSizeG; y++) {
QString realS = QString::number(internalCircuit[i][j][x][y].real()); //real part
QString imagS = QString::number(internalCircuit[i][j][x][y].imag()); //imaginary part
outputRegister << realS;
outputRegister << imagS;
}
}
}
}
saveFileRegister.close(); //we're done saving the internal representation so close file
Page 42 of 46
untitled.h
29/04/2010 00:00
/* Serialise View representation of circuit to a file */
QFile saveFileView(nameOfSaveFileView);
saveFileView.open(QIODevice::WriteOnly);
QDataStream output(&saveFileView);
for(i = 0; i < MAX_NO_OF_LINES; i++) { //for all gates on a line
for(j = 0; j < qubitRegisterSizeClassicalG; j++) {
QString gate;
gate = circuit[j][i].c_str();
if(gate == "") {
gate = "..."; //use a "..." if there's no gate to save somewhere (likely), we can then look
for "..." when loading
}
output << gate;
// serialise a string
}
}
saveFileView.close(); //we're done saving the View part of circuit too so close the file
}
/* load circuit from file */
void MainWindow::loadCircuitFromFile() {
clearWorkspace(); //clear current circuit
if(!isRegisterInitialised()) { //check register is initialised
initialise->show();
}
else {
int i, j , x, y;
bool ok;
QDialog *dialog;
QString defaultLocation;
QDir *dir;
/* get the user's home directory and let this be the default load path */
dialog = new QDialog();
dir = new QDir();
defaultLocation = dir->homePath().toAscii();
defaultLocation.append("/");
/* get requested filename from user */
Page 43 of 46
untitled.h
29/04/2010 00:00
QString loadFileNameRegister, loadFileNameView;
loadFileNameRegister = QInputDialog::getText(dialog, "Load Circuit", "Enter saved circuit's path
excluding .quantum file:", QLineEdit::Normal,
defaultLocation, &ok);
loadFileNameView = loadFileNameRegister;
loadFileNameView.append("View.quantum");
loadFileNameRegister.append(".quantum");
/* first load the back-end of the circuit, use de-serialisation to do this */
QFile saveFileRegister(loadFileNameRegister);
if(!saveFileRegister.exists() || loadFileNameRegister.contains("/.quantum")) {
msg->invalidFile();
return;
}
saveFileRegister.open(QIODevice::ReadOnly);
QDataStream inputRegister(&saveFileRegister);
QString curElement;
/* internal mathematical structure of circuit is a 4D matrix so we need 4 nested loop */
for(i = 0; i < qubitRegisterSizeClassicalG; i++) {
for(j = 0; j < MAX_NO_OF_LINES; j++) {
for(x = 0; x < qubitRegisterSizeG; x++) {
for(y = 0; y < qubitRegisterSizeG; y++) {
float real; //real part
inputRegister >> curElement;
real = curElement.toFloat(); //toFloat because we read the file as a string
float imag; //imaginary part
inputRegister >> curElement;
imag = curElement.toFloat();
complex<float> curElementConverted(real, imag);
internalCircuit[i][j][x][y] = curElementConverted;
}
}
}
}
saveFileRegister.close(); //close file containing internal part of circuit
Page 44 of 46
untitled.h
29/04/2010 00:00
/* de-serialise View representation of circuit to a file */
QFile saveFileView(loadFileNameView);
saveFileView.open(QIODevice::ReadOnly);
QDataStream input(&saveFileView);
QString curLine;
for(i = 0; i < MAX_NO_OF_LINES; i++) {
for(j = 0; j < qubitRegisterSizeClassicalG; j++) {
input >> curLine;
if(curLine.toStdString() != "...") {
qubitChoiceG[j]++;
circuit[j][i] = curLine.toStdString();
QString test = getGateKey(circuit[j][i]);
/* if we read that there's a cnot or toffoli gate then we need to make
sure that the colours of the gate are the same as what they were saved as */
if(test.contains("CNOTcontrol")) {
currentColour--;
updateWorkspace(j, getGateKey(circuit[j][i])); //use getGateKey func to get the
correct colour
currentColour++;
}
else if(test.contains("ToffoliControl")) {
currentColourToffoli--;
updateWorkspace(j, getGateKey(circuit[j][i]));
currentColourToffoli++;
}
else {
updateWorkspace(j, getGateKey(circuit[j][i]));
}
}
}
}
saveFileView.close(); //close file containing View end of the circuit
}
}
/* Helper function just to get the key of a gate from just its path */
QString MainWindow::getGateKey(string path) {
Page 45 of 46
untitled.h
29/04/2010 00:00
if(path == xPath) {
return "X";
}
else if(path == yPath) {
return "Y";
}
else if(path == zPath) {
return "Z";
}
else if(path == hPath) {
return "Hadamard";
}
/* there are many different toffoli and CNOT paths but they all have the same structure so
just look for part of the path */
else if(path.find("ToffoliTarget") != -1) {
return "ToffoliTarget";
}
else if(path.find("ToffoliControl") != -1) {
return "ToffoliControl";
}
else if(path.find("CNOTtarget") != -1) {
return "CNOTtarget";
}
else if(path.find("CNOTcontrol") != -1) {
return "CNOTcontrol";
}
else if(path == customPath) {
return "Custom";
}
}
Page 46 of 46
untitled.h
28/04/2010 23:58
/********************************************************************
*******************************************************************
quantum register initialisation class
- Initialises the quantum register, something that has to be done
before any circuits are built.
Programmer: Mr Chris Fuller, The University of Bath
*******************************************************************
******************************************************************/
#include
#include
#include
#include
#include
#include
"initialiseRegister.h"
<mainwindow.h>
<apply.h>
<iostream>
<stdio.h>
<QSpinBox>
initialiseRegister::initialiseRegister(QWidget *parent, MainWindow *window) : QDialog(parent) {
ui.setupUi(this);
this->window = window;
app = new apply();
buildButtons();
cancelButton = new QPushButton;
cancelButton->setText("Cancel");
ui.horizontalLayout_2->addWidget(cancelButton);
QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); //connect cancel button
cancelButton2 = new QPushButton;
cancelButton2->setText("Cancel");
ui.horizontalLayout_4->addWidget(cancelButton2);
QObject::connect(cancelButton2, SIGNAL(clicked()), this, SLOT(reject())); //connect cancel button
okButton = new QPushButton;
okButton->setText("Initialise");
Page 1 of 7
untitled.h
28/04/2010 23:58
okButton->setDefault(true);
ui.horizontalLayout_2->addWidget(okButton);
QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(convertSpinBoxesToColumnVector())); //connect
OK button
okButtonSuperposition = new QPushButton;
okButtonSuperposition->setText("Initialise (with superposition)");
ui.horizontalLayout_4->addWidget(cancelButton2);
ui.horizontalLayout_4->addWidget(okButtonSuperposition);
QObject::connect(okButtonSuperposition, SIGNAL(clicked()), this, SLOT(generateInitialSuperposition()));
//connect OK butto
}
MainWindow* initialiseRegister::getMainWindow() {
return window;
}
/* Make as many buttons as the number of qubits that exist in the system */
void initialiseRegister::buildButtons() {
int i, j;
for(i = 0; i < window->qubitRegisterSizeClassicalG; i++) {
objects = new QSpinBox(this);
objects->setMaximum(1);
ui.horizontalLayout->addWidget(objects);
listOfSpinBoxes.append(objects);
}
QStringList list;
QString basis;
complex<float>** basesVectors;
basesVectors = (complex<float>**) malloc(window->qubitRegisterSizeG*sizeof(complex<float>*));
for(i = 0; i < window->qubitRegisterSizeG; i++) {
basesVectors[i] = (complex<float>*) malloc(window->qubitRegisterSizeG * sizeof(complex<float>));
}
basesVectors = app->generateBasesVectors(window->qubitRegisterSizeClassicalG);
for(i = 0; i < window->qubitRegisterSizeG; i++) {
basis = "";
for(j = 0; j < window->qubitRegisterSizeClassicalG; j++) {
Page 2 of 7
untitled.h
28/04/2010 23:58
basis.append(QString::number(real(basesVectors[i][j])));
}
list << basis;
}
model = new QStringListModel(list);
ui.listView->setSelectionMode(QListView::MultiSelection);
ui.listView->setModel(model);
}
/* get what the user put into the spin boxes and put the result into
a column vector which will be the initialised register */
void initialiseRegister::convertSpinBoxesToColumnVector() {
int i, j, yesOrNo, startBases;
bool found;
complex<float>** bases;
bases = (complex<float>**) malloc(window->qubitRegisterSizeG*sizeof(complex<float>*));
for(i = 0; i < window->qubitRegisterSizeG; i++) {
bases[i] = (complex<float>*) malloc(window->qubitRegisterSizeClassicalG * sizeof(complex<float>));
}
bases = app->generateBasesVectors(window->qubitRegisterSizeClassicalG); //generate bases vectors for
given sized register
if(window->thereExistsAcircuit) { //if user initialses register when there is a circuit present, warn
them first
QMessageBox msgBox;
yesOrNo = msgBox.warning(this, "Warning: Circuit deleting", "Initialising the qubit register will
destroy any current circuit, do you wish to continue?", tr("&Yes"), tr("&No"));
}
if(yesOrNo == 0 || !window->thereExistsAcircuit) { //continue if there's no circuit or the user says it
's ok to delete the circuit
/* convert inputs in spin boxes to integers */
for(i = 0; i < window->qubitRegisterSizeClassicalG; i++) {
window->diracForm[i] = listOfSpinBoxes[i]->text().toInt();
}
Page 3 of 7
untitled.h
28/04/2010 23:58
/* find which bases vector the user initialised the register to, there can only ever be one single
vector,
not combinations of vectors */
for(i = 0; i < window->qubitRegisterSizeG; i++) {
found = false;
for(j = 0; j < window->qubitRegisterSizeClassicalG; j++) {
if(window->diracForm[j] == bases[i][j]) {
found = true;
}
else {
found = false;
break; //use breaks for faster code
}
}
if(found) {
startBases = i; //record where we found the bases vector that the register was initialised
to
break;
}
}
complex<float> complexZero( 0.0 , 0.0 );
/* firstly initialise register to all zeroes and a copy of the register too so we can revert
back to the same initialised register contents when a circuit has been destroyed */
for(i = 0; i < window->qubitRegisterSizeG; i++) {
window->magnitudeOfEachBases[0][i] = complexZero;
window->initialisedRegister[i] = complexZero;
}
complex<float> complexOne( 1.0 , 0.0 );
/* put a single (1.0, 0.0i) where we found the respective bases that the register is initialised to
*/
window->magnitudeOfEachBases[0][startBases] = complexOne;
window->initialisedRegister[startBases] = complexOne;
window->noOfForwardSteps = 0; //make sure we start at the beginning of the circuit, not the middle
of a non-existent old one
Page 4 of 7
untitled.h
28/04/2010 23:58
window->done = true; //tell the window class that the register is initialised
window->clearWorkspace(); //clear the circuit display
window->clearRegisterDisplay(); //clear the register display
msg->qubitRegisterInitialised(); //inform the user that the initialisation has taken place
window->updateWorkspace(-1, "not applicable");
accept();
}
}
void initialiseRegister::generateInitialSuperposition() {
complex<float> amountOfBases(0.0,0.0);
complex<float> complexZero(0.0,0.0);
complex<float>** bases;
complex<float> superimposeAmount;
int* basesToUpdate;
int i, j, count, row;
QModelIndex index, it;
string selected;
QModelIndexList indexes;
bool found;
basesToUpdate = (int*) malloc(window->qubitRegisterSizeG*sizeof(int));
bases = (complex<float>**) malloc(window->qubitRegisterSizeG*sizeof(complex<float>*));
for(i = 0; i < window->qubitRegisterSizeG; i++) {
bases[i] = (complex<float>*) malloc(window->qubitRegisterSizeClassicalG * sizeof(complex<float>));
}
bases = app->generateBasesVectors(window->qubitRegisterSizeClassicalG); //generate bases vectors for
given sized register
selectionModel = ui.listView->selectionModel();
indexes = selectionModel->selectedIndexes(); //selected rows
count = 0;
/* Getting data from what is selected turns out to be unnecessarily
complicated. Requires C++ <-> Qt type conversion. All the foreach
loop is for doing this. */
foreach (index, indexes) {
found = true;
Page 5 of 7
untitled.h
28/04/2010 23:58
QVariant varName = model->data(index, Qt::DisplayRole);
selected = varName.toString().toStdString(); //QVariant to C++ string
for(i = 0; i < window->qubitRegisterSizeG; i++) {
found = true;
for(j = 0; j < window->qubitRegisterSizeClassicalG; j++) {
/* Work around, need to use QVariant and compare this to
part of a basis vector */
char temp = selected.at(j);
QChar temp2 = QString::number(real(bases[i][j])).at(0);
if(temp2 == temp) {
found = false;
break; //no match
}
}
if(found) {
basesToUpdate[count] = i; //store selected basis vector
count++;
}
}
}
/* Zeroes everywhere where the user didn't select */
for(i = 0; i < window->qubitRegisterSizeG; i++) {
window->magnitudeOfEachBases[0][i] = 0;
window->initialisedRegister[i] = 0;
}
/* sqrt(1 / no of selected bases) everywhere where the user did select */
superimposeAmount = sqrt(1 / (float)count);
for(i = 0; i < count; i++) {
window->magnitudeOfEachBases[0][basesToUpdate[i]] = superimposeAmount;
window->initialisedRegister[basesToUpdate[i]] = superimposeAmount;
}
for(i = 0; i < window->qubitRegisterSizeG; i++) {
cout << window->magnitudeOfEachBases[0][i] << "\n";
}
window->noOfForwardSteps = 0; //make sure we start at the beginning of the circuit, not the middle of a
Page 6 of 7
untitled.h
28/04/2010 23:58
non-existent old one
window->done = true; //tell the window class that the register is initialised
window->clearWorkspace(); //clear the circuit display
window->clearRegisterDisplay(); //clear the register display
msg->qubitRegisterInitialised(); //inform the user that the initialisation has taken place
window->updateWorkspace(-1, "not applicable");
accept();
}
Page 7 of 7
untitled.h
28/04/2010 23:57
/********************************************************************
*******************************************************************
apply class
- Applies a quantum gate to the register.
Programmer: Mr Chris Fuller, The University of Bath
*******************************************************************
******************************************************************/
#include
#include
#include
#include
#include
#include
"apply.h"
<mainwindow.h>
<iostream>
<stdio.h>
<math.h>
<complex>
apply::apply() {
}
void apply::allocateMemory() {
}
/* Given an arbitrary sized qubit register, genetate its bases vectors */
complex<float>** apply::generateBasesVectors(int noOfQubits) {
complex<float>* mod;
complex<float>* reverse;
int i, j, temp, count, noOfQubitsC;
double noOfQubitsD;
count = noOfQubits;
/* Conversion of ints into doubles for the pow
function. A copy is made for later when the un-squared
number is needed, this saves computation of a square root and
Page 1 of 10
untitled.h
28/04/2010 23:57
stops precision errors e.g. if n = 256, sqrt(256) != 16 which is
the answer that comes out */
noOfQubitsC = noOfQubits; //copy of noOfQubits variable
noOfQubitsD = double(noOfQubits); //double version of noOfQubits variable
noOfQubitsD = pow(2, noOfQubitsD);
noOfQubits = int(noOfQubitsD);
mod = (complex<float>*) malloc(noOfQubits*sizeof(complex<float>));
reverse = (complex<float>*) malloc(noOfQubits*sizeof(complex<float>));
bases = (complex<float>**) malloc(noOfQubits*sizeof(complex<float>*));
for(i = 0; i < noOfQubits; i++) {
bases[i] = (complex<float>*) malloc(noOfQubitsC * sizeof(complex<float>));
}
complex<float> zero(0.0, 0.0);
for(j = 0; j < count; j++) { //makes sure we do not print out unassigned memory (realloc instead?)
mod[j] = zero;
}
/* Given a noOfQubits, find its bases by applying
modulo 2 to the size and recording the remainder. Repeat
this for all the (+ve) integers less than register size */
for(i = 0; i < noOfQubits; i++) {
temp = i;
while(temp > 0) {
mod[count] = temp % 2; //will either be 0 or 1 i.e. remainder 0 or 1 after %2 is applied
count++;
if((temp % 2) == 0) {
temp = temp / 2; //e.g. 32 % 2 = 0 so use 32
}
else {
temp = floor(temp / 2); //e.g. 33 % 2 = 1 so use 16
}
}
count = 0;
/* algorithm produces each bases vector in reverse so reverse each bases*/
for(j = (noOfQubitsC - 1); j > -1; j--) {
bases[i][count] = mod[j];
Page 2 of 10
untitled.h
28/04/2010 23:57
count++;
}
count = 0;
}
/* For testing, print out bases array */
for(i = 0; i < noOfQubits; i++) {
for(j = 0; j < noOfQubitsC; j++) {
//cout << bases[i][j];
}
//cout << "\n";
}
return bases;
}
/* Given a vector in Dirac form, convert it to a column vector so that is can be applied to a matrix.
*/
complex<float>* apply::convertQubitsToColumnVectorForm(complex<float>* qubitsToConvert, int noOfQubits, bool
generatingStandardColumnVector) {
complex<float>* columnVector;
complex<float>** columnVectors;
int noOfQubitsC, i, j;
double noOfQubitsD;
bool found = false;
noOfQubitsC = noOfQubits; //copy of noOfQubits variable
noOfQubitsD = double(noOfQubits); //double version of noOfQubits variable
noOfQubitsD = pow(2, noOfQubitsD);
noOfQubits = int(noOfQubitsD);
complex<float>** bases; //matrix of bases of selected qubits
complex<float>** registerBases; //matrix of all register bases
int* matchedIndex;
matchedIndex = (int*) malloc(noOfQubits * sizeof(int));
/* Memory allocation */
bases = (complex<float>**) malloc(noOfQubits * sizeof(complex<float>*));
registerBases = (complex<float>**) malloc(noOfQubits * sizeof(complex<float>*));
Page 3 of 10
untitled.h
28/04/2010 23:57
columnVector = (complex<float>*) malloc(noOfQubits * sizeof(complex<float>));
columnVectors = (complex<float>**) malloc(noOfQubits * sizeof(complex<float>*));
for(i = 0; i < noOfQubits; i++) {
bases[i] = (complex<float>*) malloc(noOfQubitsC * sizeof(complex<float>));
registerBases[i] = (complex<float>*) malloc(noOfQubitsC * sizeof(complex<float>));
columnVectors[i] = (complex<float>*) malloc(noOfQubitsC * sizeof(complex<float>));
}
bases = generateBasesVectors(noOfQubitsC); //Generate bases for given number of qubits
/* Find which bases vector is the given qubit to convert */
int count = 0;
for(i = 0; i < noOfQubits; i++) {
for(j = 0; j < noOfQubitsC; j++) {
if(bases[i][j] != qubitsToConvert[j]) {
break;
}
if(j == noOfQubitsC - 1) { //we have got to end of loop without breaking, must be a match
matchedIndex[count] = i;
found = true;
count++;
}
}
}
/* Building a column vector out of qubits in Dirac form.
Does two different things. 1) Converts from Dirac form to column vector form 2) Program can search
this vector for magnitudes of bases when it has been applied to a gate. The second conditional
checks if we want 1).. */
complex<float> zero(0.0, 0.0);
complex<float> one(1.0, 0.0);
for(j = 0; j < count; j++) {
for(i = 0; i < noOfQubits; i++) {
if(i != matchedIndex[j]) {
columnVector[i] = zero;
}
else if(generatingStandardColumnVector) {
columnVector[i] = one;
}
Page 4 of 10
untitled.h
28/04/2010 23:57
else {
columnVector[i] = mag;
}
}
}
return columnVector;
}
/* Given qubits in Dirac form, convert to matrix form */
complex<float>** apply::convertQubitsDiracForm(int noOfQubitsSelected, int qubitRegisterSizeG, int
qubitRegisterSizeClassicalG, complex<float>** selectedQubitsBases, complex<float>**
selectedQubitsAppliedToGate, int* qubitsSelected) {
int noOfQubitsSelectedC, i, j;
double noOfQubitsSelectedD;
complex<float> complexZero( 0.0 , 0.0 );
noOfQubitsSelectedC = noOfQubitsSelected; //copy of noOfQubits variable
noOfQubitsSelectedD = double(noOfQubitsSelected); //double version of noOfQubits variable
noOfQubitsSelectedD = pow(2, noOfQubitsSelectedD);
noOfQubitsSelected = int(noOfQubitsSelectedD);
/* Memory allocation */
complex<float>** test;
test = (complex<float>**) malloc(qubitRegisterSizeG * sizeof(complex<float>*));
selectedQubitsInDiracForm = (complex<float>**) malloc(qubitRegisterSizeG * sizeof(complex<float>*));
qubitsInDiracFormWholeRegister = (complex <float>**)malloc(sizeof(complex <float>*) * qubitRegisterSizeG
);
for (i = 0 ; i < qubitRegisterSizeG; i++) {
selectedQubitsInDiracForm[i] = (complex<float>*) malloc(qubitRegisterSizeG * sizeof(complex<float>))
;
qubitsInDiracFormWholeRegister[i] = (complex <float>*)malloc(sizeof(complex <float>) *
qubitRegisterSizeG);
test[i] = (complex <float>*)malloc(sizeof(complex <float>) * qubitRegisterSizeG);
}
overall = (complex <float>*)malloc(sizeof(complex <float>) * qubitRegisterSizeG);
magnitudes = (complex <float>*)malloc(sizeof(complex <float>) * qubitRegisterSizeG);
Page 5 of 10
untitled.h
28/04/2010 23:57
/* Generate bases vectors for the register */
qubitsInDiracFormWholeRegister = generateBasesVectors(qubitRegisterSizeClassicalG);
/*for(i = 0; i < qubitRegisterSizeG; i++) {
for(j = 0; j < 3; j++) {
cout << qubitsInDiracFormWholeRegister[i][j];
}
cout << "\n";
}*/
int count, k = 0;
for(i = 0; i < qubitRegisterSizeG; i++) { //making a column vector to go on matrix (as row)
for(k = 0; k < qubitRegisterSizeG; k++) {
overall[k] = complexZero;
}
count = 0;
for(j = 0; j < noOfQubitsSelected; j++) { //j smaller than length of colum vector after mult
if(selectedQubitsAppliedToGate[i][j] != complexZero) { //if something other than a 0 somewhere
in col vector after mult
selectedQubitsInDiracForm[i] = generateBasesVectors(noOfQubitsSelectedC)[j]; //which smaller
bases
/*cout << "Column vector in question: \n";
for(k = 0; k < 4; k++) {
cout << selectedQubitsAppliedToGate[i][k];
}
cout << "\n";*/
/*cout << "Updating length 3 vector with: \n";
for(k = 0; k < 2; k++) {
//cout << selectedQubitsInDiracForm[i][k];
}
cout << "\n";*/
currentBases = qubitsInDiracFormWholeRegister[i]; //current bases we are looking at in
register
Page 6 of 10
untitled.h
28/04/2010 23:57
/*cout << "Length 3 vector being updated: \n";
for(k = 0; k < 3; k++) {
cout << currentBases[k];
}
cout << "\n";*/
for(k = 0; k < noOfQubitsSelectedC; k++) {
currentBases[qubitsSelected[k]] = selectedQubitsInDiracForm[i][k];
}
/*cout << "overall altered: \n";
for(k = 0; k < 3; k++) {
cout << currentBases[k];
}
cout << "\n";*/
magnitudes[count] = selectedQubitsAppliedToGate[i][j]; //get new 'amounts' of bases
mag = selectedQubitsAppliedToGate[i][j];
/* Convert new bases of current bases in register being looked at. Use false parameter to
show we want the magnitudes stored in this column vector because it's going in the matrix *
/
currentBases = convertQubitsToColumnVectorForm(currentBases, qubitRegisterSizeClassicalG,
false);
/* Use the above to update the overall variable that stores the whole matrix that is being
built */
for(k = 0; k < qubitRegisterSizeG; k++) {
if(overall[k] == complexZero && currentBases[k] != complexZero) {
overall[k] = currentBases[k];
}
}
count++;
}
}
int count2 = 0;
for(k = 0; k < qubitRegisterSizeG; k++) {
if(currentBases[k] != complexZero) {
Page 7 of 10
untitled.h
28/04/2010 23:57
currentBases[k] = magnitudes[count2];
count2++;
}
}
for(k = 0; k < qubitRegisterSizeG; k++) {
test[i][k] = overall[k];
}
}
/* Print out matrix that has been formed, for testing*/
for(i = 0; i < qubitRegisterSizeG ; i++) {
for(j = 0; j < qubitRegisterSizeG; j++) {
//cout << test[i][j];
}
//cout << "\n";
}
return test;
}
complex<float>** apply::getSelectedQubitsFromBases(int noOfQubitsSelected, int qubitRegisterSizeG, int
qubitRegisterSizeClassicalG, int* qubitsSelected) {
complex<float>** qubitsFromBases;
complex<float>** bases;
int i, j;
int noOfQubitsSelectedC;
double noOfQubitsSelectedD;
noOfQubitsSelectedC = noOfQubitsSelected; //copy of noOfQubits variable
noOfQubitsSelectedD = double(noOfQubitsSelected); //double version of noOfQubits variable
noOfQubitsSelectedD = pow(2, noOfQubitsSelectedD);
noOfQubitsSelected = int(noOfQubitsSelectedD);
/* Bases of number of selected qubits */
qubitsFromBases = (complex<float>**) malloc(qubitRegisterSizeG * sizeof(complex<float>*));
for(i = 0; i < qubitRegisterSizeG; i++) {
qubitsFromBases[i] = (complex<float>*) malloc(noOfQubitsSelectedC * sizeof(complex<float>));
}
Page 8 of 10
untitled.h
28/04/2010 23:57
/* Bases of register */
bases = (complex<float>**) malloc(qubitRegisterSizeG * sizeof(complex<float>*));
for(i = 0; i < qubitRegisterSizeG; i++) {
bases[i] = (complex<float>*) malloc(qubitRegisterSizeClassicalG * sizeof(complex<float>));
}
bases = generateBasesVectors(qubitRegisterSizeClassicalG);
/* Get the selected qubit numbers from the qubit register an place
them in an array */
for(i = 0; i < qubitRegisterSizeG; i++) {
for(j = 0; j < noOfQubitsSelectedC; j++) {
qubitsFromBases[i][j] = bases[i][qubitsSelected[j]];
}
}
/* Testing, print out extracted qubits from register */
/*for(i = 0; i < qubitRegisterSizeG; i++) {
for(j = 0; j < noOfQubitsSelectedC; j++) {
cout << qubitsFromBases[i][j];
}
cout << "\n";
}*/
return qubitsFromBases;
}
complex <float>* apply::multiplyMatrixAndColumnVector(complex <float>** matrix, complex<float>* columnVector
, int lengthOfVector) {
complex <float>* multiplied;
multiplied = (complex <float>*) malloc(lengthOfVector*sizeof(complex <float>));
/* Standard matrix multiplication but simplified because
only one side is a matrix */
int i, j;
complex <float> zero(0.0, 0.0);
complex <float> temp(0.0, 0.0);
for(i = 0; i < lengthOfVector; i++) {
temp = zero;
for(j = 0; j < lengthOfVector; j++) {
Page 9 of 10
untitled.h
28/04/2010 23:57
temp += (columnVector[j] * matrix[i][j]);
}
multiplied[i] = temp;
}
return multiplied;
}
Page 10 of 10
untitled.h
29/04/2010 00:03
/********************************************************************
*******************************************************************
quantum measurement class
- Used for when user executes a part of a circuit containing a
quantum measurement gate.
Programmer: Mr Chris Fuller, The University of Bath
*******************************************************************
******************************************************************/
#include
#include
#include
#include
#include
#include
#include
"measurement.h"
"apply.h"
<mainwindow.h>
<iostream>
<stdio.h>
<math.h>
<complex>
measurement::measurement() {
app = new apply();
msg = new message();
}
void measurement::performMeasurement(int qubitNumber, int lineNumber, complex<float>** magnitudeOfEachBases,
int qubitRegisterSizeG, int qubitRegisterSizeClassicalG) {
/* memory allocation */
impossibleBasesVectorOpp = (complex<float>*) malloc(qubitRegisterSizeClassicalG*sizeof(complex<float>));
poss = (complex<float>*) malloc(qubitRegisterSizeClassicalG*sizeof(complex<float>));
oppToImpossibility = (complex<float>*) malloc(qubitRegisterSizeClassicalG*sizeof(complex<float>));
/* calculate probabilties of measurements yielding zero or ones */
calculateProbabilities(qubitNumber, lineNumber, magnitudeOfEachBases, qubitRegisterSizeG,
qubitRegisterSizeClassicalG);
/* use these probabilities to get result and alter the bases magnitudes depending of the result */
getResult(qubitNumber, lineNumber, magnitudeOfEachBases, qubitRegisterSizeG, qubitRegisterSizeClassicalG
Page 1 of 5
untitled.h
29/04/2010 00:03
);
}
/* Calculate the chance of a measurement on a particular qubit yielding 0 or 1 */
void measurement::calculateProbabilities(int qubitNumber, int lineNumber, complex<float>**
magnitudeOfEachBases, int qubitRegisterSizeG, int qubitRegisterSizeClassicalG) {
int i, numberOfZeroProbabilities, numberOfOneProbabilities;
complex<float> zero(0.0, 0.0);
complex<float>* zeroProbabilities;
complex<float>* oneProbabilities;
float realPart, imaginaryPart, sqrtOfRealAndImagSquares;
totalProbabilityOfZero = totalProbabilityOfOne = 0;
/* memory allocation*/
zeroProbabilities = (complex<float>*) malloc(qubitRegisterSizeG*sizeof(complex<float>));
oneProbabilities = (complex<float>*) malloc(qubitRegisterSizeG*sizeof(complex<float>));
bases = (complex<float>**) malloc(qubitRegisterSizeG * sizeof(complex<float>*));
for(i = 0; i < qubitRegisterSizeG; i++) {
bases[i] = (complex<float>*) malloc(qubitRegisterSizeClassicalG * sizeof(complex<float>));
}
/* generate bases vectors */
bases = app->generateBasesVectors(qubitRegisterSizeClassicalG);
/* zero or one at chosen qubit when we look at the bases vectors */
numberOfZeroProbabilities = numberOfOneProbabilities = 0;
for(i = 0; i < qubitRegisterSizeG; i++) {
if(bases[i][qubitNumber] == zero) {
zeroProbabilities[numberOfZeroProbabilities] = magnitudeOfEachBases[qubitNumber][i];
numberOfZeroProbabilities++;
}
else {
oneProbabilities[numberOfOneProbabilities] = magnitudeOfEachBases[qubitNumber][i];
numberOfOneProbabilities++;
}
}
Page 2 of 5
untitled.h
29/04/2010 00:03
/* Calculate probability of being zero */
for(i = 0; i < numberOfZeroProbabilities; i++) {
/* Square real part */
realPart = zeroProbabilities[i].real() * zeroProbabilities[i].real();
/* Square imaginary part */
imaginaryPart = zeroProbabilities[i].imag() * zeroProbabilities[i].imag();
/* Square root of sum of real part and imaginary part */
sqrtOfRealAndImagSquares = sqrt(realPart + imaginaryPart);
/* Square the square root of sum of real part and imaginary part */
sqrtOfRealAndImagSquares *= sqrtOfRealAndImagSquares;
/* Add this to the total probability of measurement being zero */
totalProbabilityOfZero += sqrtOfRealAndImagSquares;
}
/* Calculate probability of being one */
for(i = 0; i < numberOfOneProbabilities; i++) {
/* Square real part */
realPart = oneProbabilities[i].real() * oneProbabilities[i].real();
/* Square imaginary part */
imaginaryPart = oneProbabilities[i].imag() * oneProbabilities[i].imag();
/* Square root of sum of real part and imaginary part */
sqrtOfRealAndImagSquares = sqrt(realPart + imaginaryPart);
/* Square the square root of sum of real part and imaginary part */
sqrtOfRealAndImagSquares *= sqrtOfRealAndImagSquares;
/* Add this to the total probability of measurement being one */
totalProbabilityOfOne += sqrtOfRealAndImagSquares;
}
}
void measurement::getResult(int qubitNumber, int lineNumber, complex<float>** magnitudeOfEachBases, int
qubitRegisterSizeG, int qubitRegisterSizeClassicalG) {
int i, j, h, w;
bool test = false;
complex<float> complexOne(1.0, 0.0);
complex<float> complexZero(0.0, 0.0);
complex<float> oneOrZero;
if((lineNumber-2) != -1) {
Page 3 of 5
untitled.h
29/04/2010 00:03
for(w = 0; w < qubitRegisterSizeG ; w++) {
var[w] = magnitudeOfEachBases[lineNumber-2][w];
}
}
else {
return;
}
/* there is an equal chance of a measurement yielding zero or one so do something random (comparing two
random numbers )
to determine result of measurement */
if(totalProbabilityOfOne == totalProbabilityOfZero) {
float random, random2;
srand(time(NULL)); //random seed dependant on the current time, helps getting non-repeating random
numbers
random = (rand() / ((float)RAND_MAX));
random2 = (rand() / ((float)RAND_MAX));
if(random <= random2) {
oneOrZero = complexZero; //result yielded a zero
msg->performingMeasurement(totalProbabilityOfZero, totalProbabilityOfOne, 0, qubitNumber);
}
else {
oneOrZero = complexOne; //result yielded one
msg->performingMeasurement(totalProbabilityOfZero, totalProbabilityOfOne, 1, qubitNumber);
}
}
/* Definite chance of getting one */
else if(totalProbabilityOfOne == 1) {
oneOrZero = complexOne;
msg->performingMeasurement(totalProbabilityOfZero, totalProbabilityOfOne, 1, qubitNumber);
}
/* Definite chance of getting zero */
else if(totalProbabilityOfZero == 1) {
oneOrZero = complexZero;
/* inform user measurement is being made */
msg->performingMeasurement(totalProbabilityOfZero, totalProbabilityOfOne, 0, qubitNumber);
}
Page 4 of 5
untitled.h
29/04/2010 00:03
///start re-implemented measurement code///
complex<float> sum, current;
complex<float>* measuredState;
measuredState = (complex<float>*) malloc(qubitRegisterSizeG*sizeof(complex<float>));
int t, p, count = 0;
bases = app->generateBasesVectors(qubitRegisterSizeClassicalG); //generate bases
for(p = 0 ; p < qubitRegisterSizeG; p++) {
for(h = 0 ; h < qubitRegisterSizeG; h++) {
if(bases[h][qubitNumber] == oneOrZero) { //element in basis vector is what was measured
if(h == p) {
current = magnitudeOfEachBases[lineNumber-2][h];
}
sum += magnitudeOfEachBases[lineNumber-2][h]*magnitudeOfEachBases[lineNumber-2][h];
}
}
current = current / sqrt(sum);
measuredState[p] = current;
current = complexZero;
sum = complexZero;
}
for(p = 0 ; p < qubitRegisterSizeG; p++) {
if((lineNumber-2) < 0) {
magnitudeOfEachBases[0][p] = measuredState[p];
}
else {
magnitudeOfEachBases[lineNumber-2][p] = measuredState[p];
magnitudeOfEachBases[lineNumber-1][p] = magnitudeOfEachBases[lineNumber-2][p];
}
}
///end re-implemented measurement code///
}
Page 5 of 5
untitled.h
29/04/2010 00:04
/********************************************************************
*******************************************************************
message class
- information messages
- confirmation messages
- error messages
Programmer: Mr Chris Fuller, The University of Bath
*******************************************************************
******************************************************************/
#include
#include
#include
#include
#include
#include
"message.h"
<unitaryMatrixInputWindow.h>
<QWidget>
<iostream>
<stdio.h>
<mainwindow.h>
message::message() {
}
void message::invalidMatrixDimension() {
msgBox.setText("You entered in a matrix dimension that is invalid. Please enter matrix size smaller or
equal to 8 but greater or equal to 2");
msgBox.setInformativeText("Press Ok to return to the main screen");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
}
void message::qubitRegisterNotInitialised() {
msgBox.setText("The qubit register is not initialised.");
msgBox.setInformativeText("Press input the qubit register before placing a gate");
msgBox.setStandardButtons(QMessageBox::Ok);
Page 1 of 6
untitled.h
29/04/2010 00:04
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
}
void message::qubitRegisterInitialised() {
QMessageBox msgBox;
msgBox.setText("Qubit register is now initialised");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
}
void message::multiQubitSelectionNotUnique() {
msgBox.setText("The qubits you have entered aren't unique.");
msgBox.setInformativeText("Please enter unique quibits");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
}
void message::nonUnitaryMatrix() {
msgBox.setText("The matrix you entered is not unitary");
msgBox.setInformativeText("Press Ok to return to the matrix input screen");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
}
void message::aboutMessage() {
QMessageBox msgBox;
msgBox.setText("About Quantum Computer Simulator");
msgBox.setInformativeText("<b>Programmer: Mr. Chris Fuller</b><br><br>Version: 0.1<br><br>Institution:
The University of Bath<br><br>Software part of dissertation for the degree of BSc (Hons) Computer
Science<br><br>Special thanks to Professor. Guy McCusker for all the support and guidance throughout
this dissertation");
msgBox.setDetailedText("Resources: Custom quantum gate icon is a modifed image from http://military.
barewalls.com. Forwards, backward and play buttons from http://www.iconspedia.com/. Delete button
from http://thumbs.dreamstime.com");
Page 2 of 6
untitled.h
29/04/2010 00:04
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
}
void message::reachedEndOfCircuit() {
QMessageBox msgBox;
msgBox.setText("Cannot move further forwards");
msgBox.setInformativeText("You have reached the end of the circuit.");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
}
void message::errorStartOfCircuitAlreadyReached() {
QMessageBox msgBox;
msgBox.setText("Cannot move further backwards");
msgBox.setInformativeText("You are at the start of the circuit already.");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
}
void message::tooManyLines() {
QMessageBox msgBox;
msgBox.setText("Cannot have more than 20 lines in the circuit");
msgBox.setInformativeText("Memory comsumption could be too high.");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
}
void message::performingMeasurement(float totalProbabilityOfZero, float totalProbabilityOfOne, int result,
int qubitNumber) {
QMessageBox msgBox;
QString message;
message = "A quantum measurement was performed on qubit number:\n\n";
message.append(QString::number(qubitNumber));
Page 3 of 6
untitled.h
29/04/2010 00:04
if(totalProbabilityOfOne != totalProbabilityOfZero) {
message.append("\n\nProbability of result being one was:\n\n");
message.append(QString::number(totalProbabilityOfOne));
message.append("\n");
message.append("\nProbability of result being zero was:\n\n");
message.append(QString::number(totalProbabilityOfZero));
}
else {
message.append("\n\nEqual chance of measurement yielding 0 or 1");
}
message.append("\n\nMeasurement yielded:\n\n");
message.append(QString::number(result));
msgBox.setText("Quantum measurement");
msgBox.setInformativeText(message);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
}
void message::invalidFileExtension() {
QMessageBox msgBox;
msgBox.setText("Invalid file extension");
msgBox.setInformativeText("Files will automatically be appended with the '.quantum' extension, please
enter filename with no extension");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
}
void message::circuitCleared() {
QMessageBox msgBox;
msgBox.setText("Circuit has been deleted");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
}
void message::customTooBig() {
Page 4 of 6
untitled.h
29/04/2010 00:04
QMessageBox msgBox;
msgBox.setText("A custom matrix with a qubit register size of any more than 4 would require a matrix too
large for any normally sized screen");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
}
void message::erroneousAllignment() {
QMessageBox msgBox;
msgBox.setText("Control qubits and target qubits all need to be in the same column");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
}
void message::invalidFileName() {
QMessageBox msgBox;
msgBox.setText("You entered an invalid filename");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
}
void message::invalidFile() {
QMessageBox msgBox;
msgBox.setText("You entered filename that doesn't exist on your system");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
}
void message::nothingToDelete() {
QMessageBox msgBox;
msgBox.setText("There is no circuit to delete");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
Page 5 of 6
untitled.h
29/04/2010 00:04
}
void message::tooFarBackwards() {
QMessageBox msgBox;
msgBox.setText("Cannot move any further backwards");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
}
Page 6 of 6
untitled.h
29/04/2010 00:04
/********************************************************************
*******************************************************************
qubit input class
- Used for when users select Toffoli or CNOT gates that require
dialog boxes with more than one input box on a dialog, Qt doesn't
have a built in multi-input dialog boxes.
Programmer: Mr Chris Fuller, The University of Bath
*******************************************************************
******************************************************************/
#include
#include
#include
#include
#include
#include
#include
"qubitInput.h"
<mainwindow.h>
<QWidget>
<QApplication>
<QtGui>
<iostream>
<stdio.h>
qubitInput::qubitInput(QWidget *parent, MainWindow *window, int noOfInputs, QString typeOfGate) : QDialog
(parent) {
ui2.setupUi(this);
this->window = window;
noOfInputsG = noOfInputs;
typeOfGateG = typeOfGate;
buildSpinBoxes(noOfInputs);
cancelButton = new QPushButton;
cancelButton->setText("Cancel");
ui2.horizontalLayout->addWidget(cancelButton);
QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); //connect cancel button
okButton = new QPushButton;
okButton->setText("Ok");
okButton->setDefault(true); //default to OK
Page 1 of 2
untitled.h
29/04/2010 00:04
ui2.horizontalLayout->addWidget(okButton);
QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(getFromSpinBoxes())); //connect ok button
}
/* build an arbitrary number of spin input boxes so 2 for the cnot and 3 for the toffoli,
all other gates are only 1 qubit gates a built in function for single spin box inputs,
custom matrices don't need qubit selection, it's all in the matrix that is bein built */
void qubitInput::buildSpinBoxes(int noOfInputs) {
int i;
int max = window->qubitRegisterSizeClassicalG;
for(i = 0; i < noOfInputs; i++) {
boxes = new QSpinBox(this);
boxes->setMaximum(max - 1); //automatic range validation
boxes->setValue(i);
ui2.verticalLayout->addWidget(boxes);
listOfSpinBoxes.append(boxes);
}
}
void qubitInput::getFromSpinBoxes() {
int i;
QString temp;
for(i = 0; i < noOfInputsG; i++) {
temp = listOfSpinBoxes[i]->text();
window->dataFromQubitInput[i] = temp.toInt(); //convert inputs to integer and put them in array
}
accept(); //send accept signal as user has pressed OK
/* will only ever be these two types of gates */
if(typeOfGateG == "toffoli") {
window->setToffoliMatrixHelper(); //apply toffoli gate to register
}
else if(typeOfGateG == "cnot") {
window->setControlledNOTmatrixHelper(); //apply cnot gate to register
}
}
Page 2 of 2
untitled.h
29/04/2010 00:04
/********************************************************************
*******************************************************************
save/load class
- Used for saving and loading circuits.
Programmer: Mr Chris Fuller, The University of Bath
*******************************************************************
******************************************************************/
#include
#include
#include
#include
#include
#include
#include
"save.h"
<mainwindow.h>
<message.h>
<iostream>
<fstream>
<stdio.h>
<QInputDialog>
save::save() {
msg = new message();
}
/* Create a file with the name and directory specified by the user for saving the circuit */
QString save::createSaveFile(int qubitRegisterSizeClassicalG, int qubitRegisterSizeG, complex<float>****
qubitRegisterG) {
ofstream saveFile;
QDialog *dialog;
QString defaultLocation;
QDir *dir;
bool ok;
/* save needing to have QDialog as parent class */
dialog = new QDialog();
/* get user's home directory, append a '/' to the string of that and let this be the default
folder that the user can save their circuit in */
Page 1 of 2
untitled.h
29/04/2010 00:04
dir = new QDir();
defaultLocation = dir->homePath().toAscii();
defaultLocation.append("/");
/* get user's input for filename */
fileName = QInputDialog::getText(dialog, "New file", "Enter file name:", QLineEdit::Normal,
defaultLocation, &ok);
if(fileName.contains(".")) { //check for invalid file extensions
msg->invalidFileExtension();
return "";
}
fileName.append(".quantum"); //.quantum file extension
saveFile.open (fileName.toAscii());
saveFile.close();
return fileName;
}
Page 2 of 2
untitled.h
29/04/2010 00:05
/********************************************************************
*******************************************************************
transformation class
- Used for returning built-in quantum gates' respective matrices.
Programmer: Mr Chris Fuller, The University of Bath
*******************************************************************
******************************************************************/
#include
#include
#include
#include
#include
#include
"transformation.h"
<QWidget>
<iostream>
<stdio.h>
<mainwindow.h>
<complex>
transformation::transformation() {
}
complex <float>** transformation::setPauliXmatrix() {
pauliXmatrix = (complex <float>**) malloc(2*sizeof(complex <float>*));
int i;
for(i = 0; i < 2; i++) {
pauliXmatrix[i] = (complex <float>*) malloc(2 * sizeof(complex <float>));
}
pauliXmatrix[0][0] = 0; pauliXmatrix[0][1] = 1;
pauliXmatrix[1][0] = 1; pauliXmatrix[1][1] = 0;
return pauliXmatrix;
}
complex <float>** transformation::setPauliYmatrix() {
Page 1 of 5
untitled.h
29/04/2010 00:05
pauliYmatrix = (complex <float>**) malloc(2 * sizeof(complex <float>*));
int i;
for(i = 0; i < 2; i++) {
pauliYmatrix[i] = (complex <float>*) malloc(2 * sizeof(complex <float>));
}
complex <float> imag ( 0.0 , 1.0 );
complex <float> negativeImag ( 0.0 , -1.0 );
/* Assign the Pauli-Y's elements */
pauliYmatrix[0][0] = 0; pauliYmatrix[0][1] = imag;
pauliYmatrix[1][0] = negativeImag; pauliYmatrix[1][1] = 0;
return pauliYmatrix;
}
complex <float>** transformation::setPauliZmatrix() {
pauliZmatrix = (complex <float>**) malloc(2 * sizeof(complex <float>*));
int i;
for(i = 0; i < 2; i++) {
pauliZmatrix[i] = (complex <float>*) malloc(2 * sizeof(complex <float>));
}
pauliZmatrix[0][0] = 0; pauliZmatrix[0][1] = 1;
pauliZmatrix[1][0] = 1; pauliZmatrix[1][1] = 0;
return pauliZmatrix;
}
complex <float>** transformation::setHadamardMatrix() {
hadamardMatrix = (complex <float>**) malloc(2 * sizeof(complex <float>*));
int i;
for(i = 0; i < 2; i++) {
hadamardMatrix[i] = (complex <float>*) malloc(2 * sizeof(complex <float>));
}
Page 2 of 5
untitled.h
29/04/2010 00:05
hadamardMatrix[0][0] = (1 / sqrt(2)); hadamardMatrix[0][1] = (1 / sqrt(2));
hadamardMatrix[1][0] = (1 / sqrt(2)); hadamardMatrix[1][1] = (-1 * (1 / sqrt(2)));
return hadamardMatrix;
}
complex <float>** transformation::setControlledNOTmatrix() {
complex <float>** controlledNOTmatrix = (complex <float>**) malloc(4*sizeof(complex <float>*));
int i;
for(i = 0; i < 4; i++) {
controlledNOTmatrix[i] = (complex <float>*) malloc(4 * sizeof(complex <float>));
}
complex<float> one(1.0, 0.0);
complex<float> zero(0.0, 0.0);
controlledNOTmatrix[0][0] = one; controlledNOTmatrix[0][1] = zero;
controlledNOTmatrix[1][0] = zero; controlledNOTmatrix[1][1] = one;
controlledNOTmatrix[2][0] = zero; controlledNOTmatrix[2][1] = zero;
controlledNOTmatrix[3][0] = zero; controlledNOTmatrix[3][1] = zero;
controlledNOTmatrix[0][2]
controlledNOTmatrix[1][2]
controlledNOTmatrix[2][2]
controlledNOTmatrix[3][2]
=
=
=
=
zero; controlledNOTmatrix[0][3] = zero;
zero; controlledNOTmatrix[1][3] = zero;
zero; controlledNOTmatrix[2][3] = one;
one; controlledNOTmatrix[3][3] = zero;
return controlledNOTmatrix;
}
complex <float>** transformation::setToffoliMatrix() {
toffoliMatrix = (complex <float>**) malloc(8*sizeof(complex <float>*));
int i;
for(i = 0; i < 8; i++) {
toffoliMatrix[i] = (complex <float>*) malloc(8 * sizeof(complex <float>));
}
complex<float> one(1.0, 0.0);
complex<float> zero(0.0, 0.0);
Page 3 of 5
untitled.h
29/04/2010 00:05
/* Assign all the elements of the Toffoli matrix */
toffoliMatrix[0][0] = one; toffoliMatrix[0][1] = zero;
toffoliMatrix[1][0] = zero; toffoliMatrix[1][1] = one;
toffoliMatrix[2][0] = zero; toffoliMatrix[2][1] = zero;
toffoliMatrix[3][0] = zero; toffoliMatrix[3][1] = zero;
toffoliMatrix[4][0] = zero; toffoliMatrix[4][1] = zero;
toffoliMatrix[5][0] = zero; toffoliMatrix[5][1] = zero;
toffoliMatrix[6][0] = zero; toffoliMatrix[6][1] = zero;
toffoliMatrix[7][0] = zero; toffoliMatrix[7][1] = zero;
toffoliMatrix[0][2]
toffoliMatrix[1][2]
toffoliMatrix[2][2]
toffoliMatrix[3][2]
toffoliMatrix[4][2]
toffoliMatrix[5][2]
toffoliMatrix[6][2]
toffoliMatrix[7][2]
=
=
=
=
=
=
=
=
zero; toffoliMatrix[0][3] = zero;
zero; toffoliMatrix[1][3] = zero;
one; toffoliMatrix[2][3] = zero;
zero; toffoliMatrix[3][3] = one;
zero; toffoliMatrix[4][3] = zero;
zero; toffoliMatrix[5][3] = zero;
zero; toffoliMatrix[6][3] = zero;
zero; toffoliMatrix[7][3] = zero;
toffoliMatrix[0][4]
toffoliMatrix[1][4]
toffoliMatrix[2][4]
toffoliMatrix[3][4]
toffoliMatrix[4][4]
toffoliMatrix[5][4]
toffoliMatrix[6][4]
toffoliMatrix[7][4]
=
=
=
=
=
=
=
=
zero; toffoliMatrix[0][5] = zero;
zero; toffoliMatrix[1][5] = zero;
zero; toffoliMatrix[2][5] = zero;
zero; toffoliMatrix[3][5] = zero;
one; toffoliMatrix[4][5] = zero;
zero; toffoliMatrix[5][5] = one;
zero; toffoliMatrix[6][5] = zero;
zero; toffoliMatrix[7][5] = zero;
toffoliMatrix[0][6]
toffoliMatrix[1][6]
toffoliMatrix[2][6]
toffoliMatrix[3][6]
toffoliMatrix[4][6]
toffoliMatrix[5][6]
toffoliMatrix[6][6]
toffoliMatrix[7][6]
=
=
=
=
=
=
=
=
zero; toffoliMatrix[0][7] = zero;
zero; toffoliMatrix[1][7] = zero;
zero; toffoliMatrix[2][7] = zero;
zero; toffoliMatrix[3][7] = zero;
zero; toffoliMatrix[4][7] = zero;
zero; toffoliMatrix[5][7] = zero;
zero; toffoliMatrix[6][7] = one;
one; toffoliMatrix[7][7] = zero;
Page 4 of 5
untitled.h
29/04/2010 00:05
return toffoliMatrix;
}
Page 5 of 5
untitled.h
29/04/2010 00:05
/********************************************************************
*******************************************************************
unitary matrix input class
- Create a user defined quantum gate and check that it is a valid
unitary matrix.
Programmer: Mr Chris Fuller, The University of Bath
*******************************************************************
******************************************************************/
#include
#include
#include
#include
#include
#include
<unitaryMatrixInputWindow.h>
<QWidget>
<iostream>
<stdio.h>
<mainwindow.h>
<complex>
UnitaryMatrixInput::UnitaryMatrixInput(QWidget *parent, MainWindow *window, int dimension) : QDialog(parent)
{
ui.setupUi(this);
this->window = window;
buildTextEdits(dimension);
dimensionG = dimension;
cancelButton = new QPushButton;
cancelButton->setText("Cancel");
ui.horizontalLayout->addWidget(cancelButton);
QObject::connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
okButton = new QPushButton;
okButton->setText("Ok");
okButton->setDefault(true);
ui.horizontalLayout->addWidget(okButton);
QObject::connect(okButton, SIGNAL(clicked()), this, SLOT(convertTextEditDataToMatrix()));
}
Page 1 of 7
untitled.h
29/04/2010 00:05
/* Given the size of the user's desired matrix dimension from
taken from the main window, populate this new form with
the appropriate number of editable text areas */
void UnitaryMatrixInput::buildTextEdits(int dimension) {
int i, j;
for(i = 0; i < dimension; i++) {
for(j = 0; j < dimension; j++) {
objects = new QLineEdit(this);
objects->setFixedSize(65, 40);
objects->setText("0.0,0.0i");
ui.gridLayout->addWidget(objects, i, j);
listOfLineEdits.append(objects);
}
}
}
/* Once the user has filled out the text boxes, get all the values
they inputted and put them into a matrix in a form identical to
the other forms used elsewhere */
void UnitaryMatrixInput::convertTextEditDataToMatrix() {
int count, i, j;
complex<float> **matrix;
int dimension = dimensionG;
QString temp; //temp for storing inputted data as text
float LHS;
float RHS;
matrix = (complex<float>**) malloc(dimension*sizeof(complex<float>*));
for(i = 0; i < dimension; i++) {
matrix[i] = (complex<float>*) malloc(dimension * sizeof(complex<float>));
}
count = 0;
for(i = 0; i < dimension; i++) {
for(j = 0; j < dimension; j++) {
temp = "";
temp.append(listOfLineEdits[count]->text().data()[0]);
temp.append(listOfLineEdits[count]->text().data()[1]);
Page 2 of 7
untitled.h
29/04/2010 00:05
temp.append(listOfLineEdits[count]->text().data()[2]);
LHS = temp.toFloat();
temp = "";
/* Check if there's a '-' sign, if there is then include it,
if there isn't then don't include that part of the box because
it may be a comma */
if(listOfLineEdits[count]->text().data()[4] != '-') {
temp.append(listOfLineEdits[count]->text().data()[4]);
temp.append(listOfLineEdits[count]->text().data()[5]);
temp.append(listOfLineEdits[count]->text().data()[6]);
}
else {
temp.append(listOfLineEdits[count]->text().data()[3]);
temp.append(listOfLineEdits[count]->text().data()[4]);
temp.append(listOfLineEdits[count]->text().data()[5]);
temp.append(listOfLineEdits[count]->text().data()[6]);
}
RHS = temp.toFloat();
complex<float> whole(LHS, RHS);
matrix[j][i] = whole;
count++;
}
}
/* Check that matrix is unitary */
isUnitary(matrix, dimension);
}
/* Validate that an user's inputted, custom matrix is unitary.
A matrix is unitary is its conjugate transpose is equal
to its inverse */
void UnitaryMatrixInput::isUnitary(complex<float>** matrix, int dimension) {
/* Matrices for conjugate transpose, inverse matrix the
two matrices multiplied together */
complex<float>** transpose;
Page 3 of 7
untitled.h
29/04/2010 00:05
complex<float>** conjugate;
complex<float>** inverse;
complex<float>** multiplied;
/* Allocate memory for all the matrices */
transpose = (complex<float>**) malloc(dimension*sizeof(complex<float>*));
conjugate = (complex<float>**) malloc(dimension*sizeof(complex<float>*));
inverse = (complex<float>**) malloc(dimension*sizeof(complex<float>*));
multiplied = (complex<float>**) malloc(dimension*sizeof(complex<float>*));
int i;
for(i = 0; i < dimension; i++) {
transpose[i] = (complex<float>*) malloc(dimension * sizeof(complex<float>));
conjugate[i] = (complex<float>*) malloc(dimension * sizeof(complex<float>));
inverse[i] = (complex<float>*) malloc(dimension * sizeof(complex<float>));
multiplied[i] = (complex<float>*) malloc(dimension * sizeof(complex<float>));
}
/* Conjugate transpose */
transpose = transposeMatrix(matrix, dimension);
conjugate = conjugateOfMatrix(transpose, dimension);
/* Product of two matrices */
multiplied = multiplyMatrices(matrix, conjugate, dimension);
/* Read result of unitary matrix check */
if(isIdentityMatrix(multiplied, dimension)) {
accept(); //Close the dialog once the matrix check is complete
window->found = true;
window->setUnitaryMatrixFromDialog(matrix);
}
else {
msg = new message();
msg->nonUnitaryMatrix();
}
}
/* Multiply two matrices together.
One matrix is likely to be a quantum gate
Page 4 of 7
untitled.h
29/04/2010 00:05
with the other matrix being a quantum register */
complex<float>** UnitaryMatrixInput::multiplyMatrices(complex<float>** matrix1, complex<float>** matrix2,
int dimension) {
int i, j, k;
complex<float>** resultMatrix;
resultMatrix = (complex<float>**) malloc(dimension*sizeof(complex<float>*));
for(i = 0; i < dimension; i++) {
resultMatrix[i] = (complex<float>*) malloc(dimension * sizeof(complex<float>));
}
for(i = 0; i < dimension; i++) {
for(j = 0; j < dimension; j++) {
resultMatrix[i][j] = 0;
for(k = 0; k < dimension; k++) {
resultMatrix[i][j] += matrix1[i][k] * matrix2[k][j];
}
}
}
return resultMatrix;
}
/* Test whether a matrix is the identity matrix */
bool UnitaryMatrixInput::isIdentityMatrix(complex<float>**matrix, int dimension) {
bool boolIdentity = true;
int i, j;
complex<float> zero(0.0, 0.0);
complex<float> one(1.0, 0.0);
complex<float>** arbitraryIdentityMatrix;
arbitraryIdentityMatrix = (complex<float>**) malloc(dimension*sizeof(complex<float>*));
for(i = 0; i < dimension; i++) {
arbitraryIdentityMatrix[i] = (complex<float>*) malloc(dimension * sizeof(complex<float>));
}
/* Build an identity matrix of arbitrary size */
for(i = 0; i < dimension; i++) {
for(j = 0; j < dimension; j++) {
arbitraryIdentityMatrix[i][j] = 0;
}
Page 5 of 7
untitled.h
29/04/2010 00:05
}
for(i = 0; i < dimension; i++) {
arbitraryIdentityMatrix[i][i] = 1;
}
/* Determine whether a given matrix is the identity matrix.
If any element means that the matrix is not the identity then
break out of iterating */
for(i = 0; i < dimension; i++) {
for(j = 0; j < dimension; j++) {
if(matrix[i][j] != zero && i != j) {
boolIdentity = false;
break;
}
}
if(boolIdentity == false) {
break;
}
}
if(boolIdentity == true) {
for(i = 0; i < dimension; i++) {
if(matrix[i][i] != one) {
boolIdentity = false;
}
}
}
return boolIdentity;
}
/* Transpose of a given matrix */
complex<float>** UnitaryMatrixInput::transposeMatrix(complex<float>** matrix, int dimension) {
int i, j;
complex<float> temp;
for(i = 0; i < dimension; i++) {
for(j = 0; j < i; j++) {
temp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = temp;
Page 6 of 7
untitled.h
29/04/2010 00:05
}
}
return matrix;
}
/* Negate imaginary parts of each complex number in given matrix */
complex<float>** UnitaryMatrixInput::conjugateOfMatrix(complex<float>** matrix, int dimension) {
int i, j;
float realPart;
float complexPart;
for(i = 0; i < dimension; i++) {
for(j = 0; j < dimension; j++) {
realPart = real(matrix[j][i]);
complexPart = imag(matrix[j][i])*-1;
complex<float> whole(realPart, complexPart);
matrix[j][i] = whole;
}
}
return matrix;
}
Page 7 of 7
F.2
Header Files
190
untitled.h
29/04/2010 00:07
using namespace std;
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#define MAX_NO_OF_LINES 21 //note that we use <21 so max is actually 20
#define MAX_NO_OF_QUBITS 7
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
class
class
class
class
class
class
class
class
class
<QMainWindow>
<complex>
<QtGui>
<unitaryMatrixInputWindow.h>
<initialiseRegister.h>
<message.h>
<transformation.h>
<qubitInput.h>
<apply.h>
<measurement.h>
<save.h>
UnitaryMatrixInput;
initialiseRegister;
message;
transformation;
qubitInput;
apply;
measurement;
save;
load;
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
Page 1 of 6
untitled.h
29/04/2010 00:07
~MainWindow();
/* Entry points for generating matrices for selected gates and applying them to
void setToffoliMatrix(void);
void setToffoliMatrixHelper(void);
void setControlledNOTmatrix(void);
void setControlledNOTmatrixHelper(void);
void setHadamardMatrix(void);
void setPauliXmatrix(void);
void setPauliYmatrix(void);
void setPauliZmatrix(void);
the register */
/* quantum measurement, calls updateWorkspace(...) which instantiates measurement class */
void setMeasurement(void);
/* GUI building functions */
void setGateImagePaths(void);
void setButtonActions(void);
void setControlsToLayouts(void);
void setButtonSizes(void);
void setButtonImages(void);
void constructControls(void);
/* majority of memory allocation done in here */
void allocateAndInitialiseMatricesAndColumnVectors(void);
/* allocate 4D matrix representing internal mathematical representation of circuit */
complex <float>**** allocateMathematicalInternalCircuitRepresentationMemory(int noOfQubits, int
noOfPositionsInLine, int sizeOfRegister);
/* get register size */
void setQubitRegisterSize(void);
/* update workspace (front-end) */
void updateWorkspace(int qubitNumber, QString typeOfGate);
/* update mathematical internal representation of circuit, note that cnot and toffoli gates do it using
their own functions though */
Page 2 of 6
untitled.h
29/04/2010 00:07
void updateInternalCircuit(QString typeOfGate, int* qubitsSelected, int sizeOfSelectedQubitsBases, int
sizeOfSelectedQubitsBasesC, int qubitChoice, char* path, complex<float>** typeOfTransform);
/* For creating new quantum gate */
void setUnitaryMatrixFromDialog(complex<float>** customMatrix); //Sets new unitary matrix in the
workspace front end
bool isRegisterInitialised(void);
void updateRegisterDisplay(void);
void clearRegisterDisplay(void);
/* upgrade from prototype: generate different coloured gates for multi-qubit gates so we can tell the
difference between the
different control and target qubits belonging to different gates of the same type */
char* CNOTtargetColourList(void);
char* CNOTcontrolColourList(void);
char* toffoliControl1ColourList(void);
char* toffoliControl2ColourList(void);
char* toffoliTargetColourList(void);
int currentColour, currentColourToffoli; //current colours, making sure we don't repeat colours that are
already nearby
bool measurementGate;
/* get a gate's type just from its unique path/filename */
QString getGateKey(string path);
/* All the buttons on the main screen */
QToolButton *measurementButton;
QToolButton *pauliXbutton;
QToolButton *pauliYbutton;
QToolButton *pauliZbutton;
QToolButton *controlledNotButton;
QToolButton *hadamardButton;
QToolButton *toffoliButton;
QToolButton *unitaryMatrixButton;
QToolButton *forwardButton;
QToolButton *backwardButton;
QToolButton *playButton;
Page 3 of 6
untitled.h
29/04/2010 00:07
QToolButton *deleteButton;
QTextBrowser *quantumRegisterDisplay;
QLabel *positionLabel;
QPixmap *positionLabelPic;
string circuit[MAX_NO_OF_QUBITS][MAX_NO_OF_LINES]; //stores front end of circuit
/* kept for possible upgrade in future for being able to add multi-qubit gates with control and target
qubits on different columns of the workspace */
//int circuitDependancies[MAX_NO_OF_QUBITS][MAX_NO_OF_LINES], circuitDependanciesC[MAX_NO_OF_QUBITS]
[MAX_NO_OF_LINES];
complex <float>**** internalCircuit; //qubit register 4D matrix
complex<float>** magnitudeOfEachBases; //complex number of each bases vector for every step in circuit
complex<float>* initialisedRegister;
complex<float>* temp; //temp variable used in displaying register contents
complex<float>** customMatrix;
complex<float>** typeOfTransform;
complex<float>** basesVectors;
bool linesAreSet; //is the register contents set to workspace
bool done; //is register initialised
bool thereExistsAcircuit; //is there is circuit in workspace, checked before workspace cleared
int qubitRegisterSizeG; //quantum register length
int qubitRegisterSizeClassicalG; //quantum register evaluated length
int largest; //qubit line with the most gates on
bool found; //is a matrix unitary
complex<float>** foundUnitaryMatrix; //custom matrix
int* qubitChoiceG; //stores how many gates there are on each qubit line
complex<float>* diracForm;
int* dataFromQubitInput;
int noOfLinesSoFar; //used to check length of circuit isn't exceeding its maximum length of
MAX_NO_OF_LINES
bool firstControlSet, movedUpDirectory;
/* two files created for saving, first holds internal circuit, second for View circuit */
QString nameOfSaveFileRegister;
QString nameOfSaveFileView;
Page 4 of 6
untitled.h
29/04/2010 00:07
/* paths of images for buttons*/
QString gateImagePath;
char* xPath;
char* yPath;
char* zPath;
char* mPath;
char* ttPath;
char* tcPath;
char* hPath;
char* cnottPath;
char* cnotcPath;
char* customPath;
int noOfForwardSteps; //how far we have executed the circuit
int sizeOfCustomMatrix;
public slots:
/* For setting the learning panel screens */
void pauliXHTML(void);
void pauliYHTML(void);
void pauliZHTML(void);
void controlledNotHTML(void);
void hadamardHTML(void);
void measurementHTML(void);
void toffoliHTML(void);
/* Performs some validations and produces a dialog for entering a new unitary matrix */
void unitaryFunc(void);
void initialiseRegisterFunc(void);
/* Menubar button actions */
void aboutAction(); //about software
void forwardFunc(void); //move forwards in circuit
void playFunc(void);
void backwardFunc(void); //move backwards
void deleteFunc(void); //delete the whole circuit
void clearWorkspace(void); //clear the contents of workspace
void saveCircuitToFile(void);
Page 5 of 6
untitled.h
29/04/2010 00:07
void loadCircuitFromFile(void);
void openDocumentation(void);
void exitSystem(void);
protected:
void changeEvent(QEvent *e);
private:
Ui::MainWindow *ui;
UnitaryMatrixInput *unitary;
initialiseRegister *initialise;
message *msg;
transformation *trans;
qubitInput *input;
apply *app;
measurement *measure;
save *saveCircuit;
};
#endif // MAINWINDOW_H
Page 6 of 6
untitled.h
29/04/2010 00:07
#ifndef INITIALISEREGISTER_H
#define INITIALISEREGISTER_H
#include
#include
#include
#include
#include
#include
<QApplication>
<QtGui>
"MainWindow.h"
"ui_initialiseRegister.h"
"message.h"
"apply.h"
class MainWindow;
class message;
class apply;
class initialiseRegister : public QDialog {
Q_OBJECT
public:
initialiseRegister(QWidget *parent, MainWindow *window);
MainWindow* getMainWindow();
void buildButtons(void);
QList<QSpinBox*> listOfSpinBoxes; //arbitrary sized list of spin boxes
QList<QCheckBox*> listOfTicks;
QSpinBox *objects; //arbitrary number of spin noxes
QCheckBox *objectsTicks;
QPushButton *okButton;
QPushButton *cancelButton;
QPushButton *cancelButton2;
QPushButton *okButtonSuperposition;
QStringListModel *model;
QItemSelectionModel *selectionModel;
public slots:
/* on press of OK, convert inputs to column vectors */
void convertSpinBoxesToColumnVector();
void generateInitialSuperposition();
Page 1 of 2
untitled.h
29/04/2010 00:07
private:
Ui::Dialog2 ui;
MainWindow *window;
message *msg;
apply *app;
};
#endif // INITIALISEREGISTER_H
Page 2 of 2
untitled.h
29/04/2010 00:08
#ifndef MEASUREMENT_H
#define MEASUREMENT_H
#include
#include
#include
#include
#include
"MainWindow.h"
<QApplication>
<QtGui>
<complex>
<apply.h>
class MainWindow;
class message;
class measurement
{
public:
measurement();
void performMeasurement(int qubitNumber, int lineNumber, complex<float>** magnitudeOfEachBases, int
qubitRegisterSizeG, int qubitRegisterSizeClassicalG);
void calculateProbabilities(int qubitNumber, int lineNumber, complex<float>** magnitudeOfEachBases, int
qubitRegisterSizeG, int qubitRegisterSizeClassicalG);
void memoryAllocation(void);
void getResult(int qubitNumber, int lineNumber, complex<float>** magnitudeOfEachBases, int
qubitRegisterSizeG, int qubitRegisterSizeClassicalG);
complex<float>** diracForm;
complex<float>** bases;
float totalProbabilityOfZero, totalProbabilityOfOne;
complex<float>* impossibleBasesVectorOpp;
complex<float>* poss;
complex<float> sum;
complex<float> sum2;
complex<float>* oppToImpossibility;
complex<float> var[8];
private:
MainWindow *window;
apply *app;
message *msg;
Page 1 of 2
untitled.h
29/04/2010 00:08
};
#endif // MEASUREMENT_H
Page 2 of 2
untitled.h
29/04/2010 00:06
#ifndef APPLY_H
#define APPLY_H
#include
#include
#include
#include
"MainWindow.h"
<QApplication>
<QtGui>
<complex>
class MainWindow;
class apply {
public:
apply();
/* convert Dirac vectors to column vector form */
complex<float>* convertQubitsToColumnVectorForm(complex<float>* qubitsToConvert, int noOfQubits, bool
generatingStandardColumnVector);
/* generate bases vectors of a given size */
complex<float>** generateBasesVectors(int noOfQubits);
/* given bases vectors, if user selects particular qubits, extract these from the bases vectors */
complex<float>** getSelectedQubitsFromBases(int noOfQubitsSelected, int qubitRegisterSizeG, int
qubitRegisterSizeClassicalG, int* qubitsSelected);
/* convert from column vector to Dirac vector */
complex<float>** convertQubitsDiracForm(int noOfQubitsSelected, int qubitRegisterSizeG, int
qubitRegisterSizeClassicalG, complex<float>** selectedQubitsBases, complex<float>**
selectedQubitsAppliedToGate, int* qubitsSelected);
/* multiply a quantum gate with the register */
complex <float>* multiplyMatrixAndColumnVector(complex <float>** matrix, complex<float>* columnVector,
int lengthOfVector);
/* allocate the required memory in the class */
void allocateMemory();
complex<float>** bases; //matrix of all bases of a given size
Page 1 of 2
untitled.h
29/04/2010 00:06
/* convertQubitsDiracForm is used for differently depending on its context (see its function body).
Have this variable that can be accessed by one context the function is called in instead of two
nearly identical functions and passing it as a parameter */
complex<float> mag;
complex<float>** selectedQubitsInDiracForm; //extracted qubits
complex<float>** qubitsInDiracFormWholeRegister; //Dirac vectors that qubits are being extracted from
complex<float>* currentBases; //We consider all bases in a register, this holds the current one being
processed
complex<float>* overall; //holds a single row of a matrix being built
complex<float>* magnitudes; //holds 'amount' of each bases vector
private:
MainWindow *window;
};
#endif // APPLY_H
Page 2 of 2
F.3
UI Header Files
197
transformation.h
29/04/2010 00:12
/********************************************************************************
** Form generated from reading UI file 'initialiseRegister.ui'
**
** Created: Wed Apr 28 11:55:09 2010
**
by: Qt User Interface Compiler version 4.6.1
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef UI_INITIALISEREGISTER_H
#define UI_INITIALISEREGISTER_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
<QtCore/QVariant>
<QtGui/QAction>
<QtGui/QApplication>
<QtGui/QButtonGroup>
<QtGui/QDialog>
<QtGui/QGroupBox>
<QtGui/QHBoxLayout>
<QtGui/QHeaderView>
<QtGui/QLabel>
<QtGui/QListView>
<QtGui/QWidget>
QT_BEGIN_NAMESPACE
class Ui_Dialog2
{
public:
QGroupBox *groupBox;
QWidget *horizontalLayoutWidget;
QHBoxLayout *horizontalLayout;
QWidget *horizontalLayoutWidget_2;
QHBoxLayout *horizontalLayout_2;
QLabel *label;
QLabel *label_2;
QLabel *label_3;
QGroupBox *groupBox_2;
Page 1 of 4
transformation.h
29/04/2010 00:12
QListView *listView;
QWidget *horizontalLayoutWidget_4;
QHBoxLayout *horizontalLayout_4;
void setupUi(QDialog *Dialog2)
{
if (Dialog2->objectName().isEmpty())
Dialog2->setObjectName(QString::fromUtf8("Dialog2"));
Dialog2->resize(615, 430);
groupBox = new QGroupBox(Dialog2);
groupBox->setObjectName(QString::fromUtf8("groupBox"));
groupBox->setGeometry(QRect(10, 20, 601, 61));
horizontalLayoutWidget = new QWidget(groupBox);
horizontalLayoutWidget->setObjectName(QString::fromUtf8("horizontalLayoutWidget"));
horizontalLayoutWidget->setGeometry(QRect(10, 20, 581, 41));
horizontalLayout = new QHBoxLayout(horizontalLayoutWidget);
horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout"));
horizontalLayout->setContentsMargins(0, 0, 0, 0);
horizontalLayoutWidget_2 = new QWidget(Dialog2);
horizontalLayoutWidget_2->setObjectName(QString::fromUtf8("horizontalLayoutWidget_2"));
horizontalLayoutWidget_2->setGeometry(QRect(390, 90, 221, 31));
horizontalLayout_2 = new QHBoxLayout(horizontalLayoutWidget_2);
horizontalLayout_2->setObjectName(QString::fromUtf8("horizontalLayout_2"));
horizontalLayout_2->setContentsMargins(0, 0, 0, 0);
label = new QLabel(Dialog2);
label->setObjectName(QString::fromUtf8("label"));
label->setGeometry(QRect(10, 5, 171, 16));
label_2 = new QLabel(Dialog2);
label_2->setObjectName(QString::fromUtf8("label_2"));
label_2->setGeometry(QRect(10, 130, 591, 16));
label_3 = new QLabel(Dialog2);
label_3->setObjectName(QString::fromUtf8("label_3"));
label_3->setGeometry(QRect(10, 145, 591, 16));
groupBox_2 = new QGroupBox(Dialog2);
groupBox_2->setObjectName(QString::fromUtf8("groupBox_2"));
groupBox_2->setGeometry(QRect(10, 160, 601, 221));
listView = new QListView(groupBox_2);
listView->setObjectName(QString::fromUtf8("listView"));
Page 2 of 4
transformation.h
29/04/2010 00:12
listView->setGeometry(QRect(10, 30, 581, 181));
horizontalLayoutWidget_4 = new QWidget(Dialog2);
horizontalLayoutWidget_4->setObjectName(QString::fromUtf8("horizontalLayoutWidget_4"));
horizontalLayoutWidget_4->setGeometry(QRect(290, 390, 311, 31));
horizontalLayout_4 = new QHBoxLayout(horizontalLayoutWidget_4);
horizontalLayout_4->setObjectName(QString::fromUtf8("horizontalLayout_4"));
horizontalLayout_4->setContentsMargins(0, 0, 0, 0);
retranslateUi(Dialog2);
QMetaObject::connectSlotsByName(Dialog2);
} // setupUi
void retranslateUi(QDialog *Dialog2)
{
Dialog2->setWindowTitle(QApplication::translate("Dialog2", "Initialise Register", 0, QApplication::
UnicodeUTF8));
groupBox->setTitle(QApplication::translate("Dialog2", "Initialised Qubit States", 0, QApplication::
UnicodeUTF8));
label->setText(QApplication::translate("Dialog2", "Initialise to classical state:", 0, QApplication
::UnicodeUTF8));
label_2->setText(QApplication::translate("Dialog2", "OR, Initialise to superposition of bases
vectors. Select the vector bases below that you wish", 0, QApplication::UnicodeUTF8));
label_3->setText(QApplication::translate("Dialog2", "to place in superposition (minimum of 2 parts
must be selected)", 0, QApplication::UnicodeUTF8));
groupBox_2->setTitle(QApplication::translate("Dialog2", "Initialised Qubit States", 0, QApplication
::UnicodeUTF8));
} // retranslateUi
};
namespace Ui {
class Dialog2: public Ui_Dialog2 {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_INITIALISEREGISTER_H
Page 3 of 4
transformation.h
29/04/2010 00:12
Page 4 of 4
transformation.h
29/04/2010 00:13
/********************************************************************************
** Form generated from reading UI file 'mainwindow.ui'
**
** Created: Mon Apr 26 17:58:41 2010
**
by: Qt User Interface Compiler version 4.6.1
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef UI_MAINWINDOW_H
#define UI_MAINWINDOW_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
<QtCore/QVariant>
<QtGui/QAction>
<QtGui/QApplication>
<QtGui/QButtonGroup>
<QtGui/QGroupBox>
<QtGui/QHBoxLayout>
<QtGui/QHeaderView>
<QtGui/QLabel>
<QtGui/QMainWindow>
<QtGui/QMenu>
<QtGui/QMenuBar>
<QtGui/QStatusBar>
<QtGui/QTextBrowser>
<QtGui/QToolBar>
<QtGui/QVBoxLayout>
<QtGui/QWidget>
QT_BEGIN_NAMESPACE
class Ui_MainWindow
{
public:
QAction *actionOpen;
QAction *actionOpen_2;
QAction *actionSave_As;
QAction *actionSave;
Page 1 of 9
transformation.h
29/04/2010 00:13
QAction *actionClear_Circuit;
QAction *actionExit;
QAction *actionDocumentation;
QAction *actionInitialise_register;
QAction *actionAbout_this_simulation;
QAction *actionClear_Workspace;
QWidget *centralWidget;
QGroupBox *groupBox_2;
QTextBrowser *textBrowser;
QGroupBox *groupBox_4;
QTextBrowser *workspace;
QGroupBox *groupBox;
QTextBrowser *quantumRegisterDisplay;
QGroupBox *groupBox_5;
QWidget *widget_2;
QVBoxLayout *verticalLayout_3;
QLabel *measurementLabel_2;
QLabel *CNOTlabel_2;
QLabel *pauliYlabel_2;
QLabel *label_2;
QLabel *hadamardLabel_2;
QLabel *pauliZlabel_2;
QLabel *pauliXlabel_2;
QLabel *label;
QGroupBox *groupBox_6;
QWidget *horizontalLayoutWidget;
QHBoxLayout *horizontalLayout;
QMenuBar *menuBar;
QMenu *menuFile;
QMenu *menuHelp;
QMenu *menuAbout;
QMenu *menuEdit;
QToolBar *mainToolBar;
QStatusBar *statusBar;
void setupUi(QMainWindow *MainWindow)
{
if (MainWindow->objectName().isEmpty())
Page 2 of 9
transformation.h
29/04/2010 00:13
MainWindow->setObjectName(QString::fromUtf8("MainWindow"));
MainWindow->resize(1002, 605);
actionOpen = new QAction(MainWindow);
actionOpen->setObjectName(QString::fromUtf8("actionOpen"));
actionOpen_2 = new QAction(MainWindow);
actionOpen_2->setObjectName(QString::fromUtf8("actionOpen_2"));
actionSave_As = new QAction(MainWindow);
actionSave_As->setObjectName(QString::fromUtf8("actionSave_As"));
actionSave = new QAction(MainWindow);
actionSave->setObjectName(QString::fromUtf8("actionSave"));
actionClear_Circuit = new QAction(MainWindow);
actionClear_Circuit->setObjectName(QString::fromUtf8("actionClear_Circuit"));
actionExit = new QAction(MainWindow);
actionExit->setObjectName(QString::fromUtf8("actionExit"));
actionDocumentation = new QAction(MainWindow);
actionDocumentation->setObjectName(QString::fromUtf8("actionDocumentation"));
actionInitialise_register = new QAction(MainWindow);
actionInitialise_register->setObjectName(QString::fromUtf8("actionInitialise_register"));
actionAbout_this_simulation = new QAction(MainWindow);
actionAbout_this_simulation->setObjectName(QString::fromUtf8("actionAbout_this_simulation"));
actionClear_Workspace = new QAction(MainWindow);
actionClear_Workspace->setObjectName(QString::fromUtf8("actionClear_Workspace"));
centralWidget = new QWidget(MainWindow);
centralWidget->setObjectName(QString::fromUtf8("centralWidget"));
groupBox_2 = new QGroupBox(centralWidget);
groupBox_2->setObjectName(QString::fromUtf8("groupBox_2"));
groupBox_2->setGeometry(QRect(740, 0, 251, 551));
textBrowser = new QTextBrowser(groupBox_2);
textBrowser->setObjectName(QString::fromUtf8("textBrowser"));
textBrowser->setGeometry(QRect(10, 30, 231, 511));
groupBox_4 = new QGroupBox(centralWidget);
groupBox_4->setObjectName(QString::fromUtf8("groupBox_4"));
groupBox_4->setGeometry(QRect(240, 0, 491, 331));
workspace = new QTextBrowser(groupBox_4);
workspace->setObjectName(QString::fromUtf8("workspace"));
workspace->setGeometry(QRect(10, 30, 471, 291));
workspace->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
workspace->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
Page 3 of 9
transformation.h
29/04/2010 00:13
workspace->setLineWrapMode(QTextEdit::NoWrap);
groupBox = new QGroupBox(centralWidget);
groupBox->setObjectName(QString::fromUtf8("groupBox"));
groupBox->setGeometry(QRect(240, 330, 491, 221));
quantumRegisterDisplay = new QTextBrowser(groupBox);
quantumRegisterDisplay->setObjectName(QString::fromUtf8("quantumRegisterDisplay"));
quantumRegisterDisplay->setGeometry(QRect(10, 30, 471, 181));
quantumRegisterDisplay->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
quantumRegisterDisplay->setLineWrapMode(QTextEdit::NoWrap);
groupBox_5 = new QGroupBox(centralWidget);
groupBox_5->setObjectName(QString::fromUtf8("groupBox_5"));
groupBox_5->setGeometry(QRect(10, 0, 221, 451));
widget_2 = new QWidget(groupBox_5);
widget_2->setObjectName(QString::fromUtf8("widget_2"));
widget_2->setGeometry(QRect(130, 20, 85, 421));
verticalLayout_3 = new QVBoxLayout(widget_2);
verticalLayout_3->setSpacing(6);
verticalLayout_3->setContentsMargins(11, 11, 11, 11);
verticalLayout_3->setObjectName(QString::fromUtf8("verticalLayout_3"));
measurementLabel_2 = new QLabel(groupBox_5);
measurementLabel_2->setObjectName(QString::fromUtf8("measurementLabel_2"));
measurementLabel_2->setGeometry(QRect(10, 40, 87, 33));
CNOTlabel_2 = new QLabel(groupBox_5);
CNOTlabel_2->setObjectName(QString::fromUtf8("CNOTlabel_2"));
CNOTlabel_2->setGeometry(QRect(10, 240, 87, 33));
pauliYlabel_2 = new QLabel(groupBox_5);
pauliYlabel_2->setObjectName(QString::fromUtf8("pauliYlabel_2"));
pauliYlabel_2->setGeometry(QRect(10, 140, 87, 33));
label_2 = new QLabel(groupBox_5);
label_2->setObjectName(QString::fromUtf8("label_2"));
label_2->setGeometry(QRect(10, 340, 87, 33));
hadamardLabel_2 = new QLabel(groupBox_5);
hadamardLabel_2->setObjectName(QString::fromUtf8("hadamardLabel_2"));
hadamardLabel_2->setGeometry(QRect(10, 290, 87, 32));
pauliZlabel_2 = new QLabel(groupBox_5);
pauliZlabel_2->setObjectName(QString::fromUtf8("pauliZlabel_2"));
pauliZlabel_2->setGeometry(QRect(10, 190, 87, 33));
pauliXlabel_2 = new QLabel(groupBox_5);
Page 4 of 9
transformation.h
29/04/2010 00:13
pauliXlabel_2->setObjectName(QString::fromUtf8("pauliXlabel_2"));
pauliXlabel_2->setGeometry(QRect(10, 90, 87, 32));
label = new QLabel(groupBox_5);
label->setObjectName(QString::fromUtf8("label"));
label->setGeometry(QRect(10, 390, 61, 16));
groupBox_6 = new QGroupBox(centralWidget);
groupBox_6->setObjectName(QString::fromUtf8("groupBox_6"));
groupBox_6->setGeometry(QRect(10, 450, 221, 101));
horizontalLayoutWidget = new QWidget(groupBox_6);
horizontalLayoutWidget->setObjectName(QString::fromUtf8("horizontalLayoutWidget"));
horizontalLayoutWidget->setGeometry(QRect(0, 20, 221, 80));
horizontalLayout = new QHBoxLayout(horizontalLayoutWidget);
horizontalLayout->setSpacing(6);
horizontalLayout->setContentsMargins(11, 11, 11, 11);
horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout"));
horizontalLayout->setContentsMargins(0, 0, 0, 0);
MainWindow->setCentralWidget(centralWidget);
menuBar = new QMenuBar(MainWindow);
menuBar->setObjectName(QString::fromUtf8("menuBar"));
menuBar->setGeometry(QRect(0, 0, 1002, 22));
menuFile = new QMenu(menuBar);
menuFile->setObjectName(QString::fromUtf8("menuFile"));
menuHelp = new QMenu(menuBar);
menuHelp->setObjectName(QString::fromUtf8("menuHelp"));
menuAbout = new QMenu(menuBar);
menuAbout->setObjectName(QString::fromUtf8("menuAbout"));
menuEdit = new QMenu(menuBar);
menuEdit->setObjectName(QString::fromUtf8("menuEdit"));
MainWindow->setMenuBar(menuBar);
mainToolBar = new QToolBar(MainWindow);
mainToolBar->setObjectName(QString::fromUtf8("mainToolBar"));
MainWindow->addToolBar(Qt::TopToolBarArea, mainToolBar);
statusBar = new QStatusBar(MainWindow);
statusBar->setObjectName(QString::fromUtf8("statusBar"));
MainWindow->setStatusBar(statusBar);
menuBar->addAction(menuFile->menuAction());
menuBar->addAction(menuEdit->menuAction());
Page 5 of 9
transformation.h
29/04/2010 00:13
menuBar->addAction(menuHelp->menuAction());
menuBar->addAction(menuAbout->menuAction());
menuFile->addAction(actionOpen_2);
menuFile->addSeparator();
menuFile->addAction(actionSave_As);
menuFile->addSeparator();
menuFile->addSeparator();
menuFile->addAction(actionExit);
menuHelp->addAction(actionDocumentation);
menuAbout->addAction(actionAbout_this_simulation);
menuEdit->addAction(actionInitialise_register);
menuEdit->addAction(actionClear_Workspace);
retranslateUi(MainWindow);
QMetaObject::connectSlotsByName(MainWindow);
} // setupUi
void retranslateUi(QMainWindow *MainWindow)
{
MainWindow->setWindowTitle(QApplication::translate("MainWindow", "Quantum Computer Simulator by
Chris Fuller", 0, QApplication::UnicodeUTF8));
actionOpen->setText(QApplication::translate("MainWindow", "New", 0, QApplication::UnicodeUTF8));
actionOpen_2->setText(QApplication::translate("MainWindow", "Open...", 0, QApplication::UnicodeUTF8)
);
actionSave_As->setText(QApplication::translate("MainWindow", "Save...", 0, QApplication::UnicodeUTF8
));
actionSave->setText(QApplication::translate("MainWindow", "Save", 0, QApplication::UnicodeUTF8));
actionClear_Circuit->setText(QApplication::translate("MainWindow", "Clear Circuit", 0, QApplication
::UnicodeUTF8));
actionExit->setText(QApplication::translate("MainWindow", "Exit", 0, QApplication::UnicodeUTF8));
actionDocumentation->setText(QApplication::translate("MainWindow", "Documentation", 0, QApplication
::UnicodeUTF8));
actionInitialise_register->setText(QApplication::translate("MainWindow", "Initialise register", 0,
QApplication::UnicodeUTF8));
actionAbout_this_simulation->setText(QApplication::translate("MainWindow", "About this simulation",
0, QApplication::UnicodeUTF8));
actionClear_Workspace->setText(QApplication::translate("MainWindow", "Clear Workspace", 0,
Page 6 of 9
transformation.h
29/04/2010 00:13
QApplication::UnicodeUTF8));
groupBox_2->setTitle(QApplication::translate("MainWindow", "Learning Panel", 0, QApplication::
UnicodeUTF8));
textBrowser->setHtml(QApplication::translate("MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML
4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><
style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:'Lucida
Grande'; font-size:13pt; font-weight:400; fontstyle:normal;\">\n"
"<p style=\" margin-top:0px; margin-bottom:0px; marginleft:0px; margin-right:0px; -qt-block-indent:0;
text-indent:0px;\">Welcome to the quantum circuit
simulation.</p>\n"
"<p style=\"-qt-paragraph-type:empty; margin-top:0px;
margin-bottom:0px; margin-left:0px; margin-right:0p
x; -qt-block-indent:0; text-indent:0px;\"></p>\n"
"<p style=\" margin-top:0px; margin-bottom:0px; marginleft:0px; margin-right:0px; -qt-block-indent:0;
text-indent:0px;\">This is the learning panel.</p>\
n"
"<p style=\"-qt-paragraph-type:empty; margin-top:0px;
margin-bottom:0px; margin-left:0px; margin-right:0p
x; -qt-block-indent:0; text-indent:0px;\"></p>\n"
"<p style=\" margin-top:0px; margin-bottom:0px"
"; margin-left:0px; margin-right:0px; -qt-block-indent:
0; text-indent:0px;\">It will fill will information
about different quantum gates when you select them
from the quantum gate panel on the left</p>\n"
"<p style=\"-qt-paragraph-type:empty; margin-top:0px;
margin-bottom:0px; margin-left:0px; margin-right:0p
x; -qt-block-indent:0; text-indent:0px;\"></p>\n"
"<p style=\"-qt-paragraph-type:empty; margin-top:0px;
margin-bottom:0px; margin-left:0px; margin-right:0p
x; -qt-block-indent:0; text-indent:0px;\"></p></
body></html>", 0, QApplication::UnicodeUTF8));
groupBox_4->setTitle(QApplication::translate("MainWindow", "Work Space", 0, QApplication::
Page 7 of 9
transformation.h
29/04/2010 00:13
UnicodeUTF8));
workspace->setHtml(QApplication::translate("MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML
4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><
style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:'Lucida Grande
'; font-size:13pt; font-weight:400; font-style:normal
;\">\n"
"<p style=\" margin-top:0px; margin-bottom:0px; marginleft:0px; margin-right:0px; -qt-block-indent:0; textindent:0px;\">This is the work space, it will update
itself as you build your circuit</p>\n"
"<p style=\"-qt-paragraph-type:empty; margin-top:0px;
margin-bottom:0px; margin-left:0px; margin-right:0px;
-qt-block-indent:0; text-indent:0px;\"></p></body></
html>", 0, QApplication::UnicodeUTF8));
groupBox->setTitle(QApplication::translate("MainWindow", "Quantum Register", 0, QApplication::
UnicodeUTF8));
groupBox_5->setTitle(QApplication::translate("MainWindow", "Quantum Gates", 0, QApplication::
UnicodeUTF8));
measurementLabel_2->setText(QApplication::translate("MainWindow", "Measurement:", 0, QApplication::
UnicodeUTF8));
CNOTlabel_2->setText(QApplication::translate("MainWindow", "CNOT:", 0, QApplication::UnicodeUTF8));
pauliYlabel_2->setText(QApplication::translate("MainWindow", "Pauli-Y:", 0, QApplication::
UnicodeUTF8));
label_2->setText(QApplication::translate("MainWindow", "Toffoli", 0, QApplication::UnicodeUTF8));
hadamardLabel_2->setText(QApplication::translate("MainWindow", "Hadamard:", 0, QApplication::
UnicodeUTF8));
pauliZlabel_2->setText(QApplication::translate("MainWindow", "Pauli-Z:", 0, QApplication::
UnicodeUTF8));
pauliXlabel_2->setText(QApplication::translate("MainWindow", "Pauli-X:", 0, QApplication::
UnicodeUTF8));
label->setText(QApplication::translate("MainWindow", "New..", 0, QApplication::UnicodeUTF8));
groupBox_6->setTitle(QApplication::translate("MainWindow", "Controls", 0, QApplication::UnicodeUTF8)
);
menuFile->setTitle(QApplication::translate("MainWindow", "File", 0, QApplication::UnicodeUTF8));
menuHelp->setTitle(QApplication::translate("MainWindow", "Help", 0, QApplication::UnicodeUTF8));
Page 8 of 9
transformation.h
29/04/2010 00:13
menuAbout->setTitle(QApplication::translate("MainWindow", "About", 0, QApplication::UnicodeUTF8));
menuEdit->setTitle(QApplication::translate("MainWindow", "Edit", 0, QApplication::UnicodeUTF8));
} // retranslateUi
};
namespace Ui {
class MainWindow: public Ui_MainWindow {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_MAINWINDOW_H
Page 9 of 9
transformation.h
29/04/2010 00:14
/********************************************************************************
** Form generated from reading UI file 'qubitSelection.ui'
**
** Created: Mon Apr 26 17:58:41 2010
**
by: Qt User Interface Compiler version 4.6.1
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef UI_QUBITSELECTION_H
#define UI_QUBITSELECTION_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
<QtCore/QVariant>
<QtGui/QAction>
<QtGui/QApplication>
<QtGui/QButtonGroup>
<QtGui/QDialog>
<QtGui/QGroupBox>
<QtGui/QHBoxLayout>
<QtGui/QHeaderView>
<QtGui/QTextBrowser>
<QtGui/QVBoxLayout>
<QtGui/QWidget>
QT_BEGIN_NAMESPACE
class Ui_qubitInput
{
public:
QGroupBox *groupBox;
QWidget *verticalLayoutWidget;
QVBoxLayout *verticalLayout;
QTextBrowser *textBrowser;
QWidget *horizontalLayoutWidget;
QHBoxLayout *horizontalLayout;
void setupUi(QDialog *qubitInput)
{
Page 1 of 3
transformation.h
29/04/2010 00:14
if (qubitInput->objectName().isEmpty())
qubitInput->setObjectName(QString::fromUtf8("qubitInput"));
qubitInput->resize(310, 237);
groupBox = new QGroupBox(qubitInput);
groupBox->setObjectName(QString::fromUtf8("groupBox"));
groupBox->setGeometry(QRect(10, 0, 291, 191));
verticalLayoutWidget = new QWidget(groupBox);
verticalLayoutWidget->setObjectName(QString::fromUtf8("verticalLayoutWidget"));
verticalLayoutWidget->setGeometry(QRect(130, 30, 151, 151));
verticalLayout = new QVBoxLayout(verticalLayoutWidget);
verticalLayout->setObjectName(QString::fromUtf8("verticalLayout"));
verticalLayout->setContentsMargins(0, 0, 0, 0);
textBrowser = new QTextBrowser(groupBox);
textBrowser->setObjectName(QString::fromUtf8("textBrowser"));
textBrowser->setGeometry(QRect(10, 30, 111, 151));
horizontalLayoutWidget = new QWidget(qubitInput);
horizontalLayoutWidget->setObjectName(QString::fromUtf8("horizontalLayoutWidget"));
horizontalLayoutWidget->setGeometry(QRect(130, 200, 171, 32));
horizontalLayout = new QHBoxLayout(horizontalLayoutWidget);
horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout"));
horizontalLayout->setContentsMargins(0, 0, 0, 0);
retranslateUi(qubitInput);
QMetaObject::connectSlotsByName(qubitInput);
} // setupUi
void retranslateUi(QDialog *qubitInput)
{
qubitInput->setWindowTitle(QApplication::translate("qubitInput", "Qubit Selection", 0, QApplication
::UnicodeUTF8));
groupBox->setTitle(QApplication::translate("qubitInput", "Qubit Selection", 0, QApplication::
UnicodeUTF8));
textBrowser->setHtml(QApplication::translate("qubitInput", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML
4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><
style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
Page 2 of 3
transformation.h
29/04/2010 00:14
"</style></head><body style=\" font-family:'Lucida
Grande'; font-size:13pt; font-weight:400; fontstyle:normal;\">\n"
"<p style=\" margin-top:0px; margin-bottom:0px; marginleft:0px; margin-right:0px; -qt-block-indent:0;
text-indent:0px;\">Enter Target qubit in the first
box followed by the Control qubit(s) in the lower
boxes:</p></body></html>", 0, QApplication::
UnicodeUTF8));
} // retranslateUi
};
namespace Ui {
class qubitInput: public Ui_qubitInput {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_QUBITSELECTION_H
Page 3 of 3
transformation.h
29/04/2010 00:11
/********************************************************************************
** Form generated from reading UI file 'unitaryMatrixInputWindow.ui'
**
** Created: Wed Apr 28 17:15:02 2010
**
by: Qt User Interface Compiler version 4.6.1
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef UI_UNITARYMATRIXINPUTWINDOW_H
#define UI_UNITARYMATRIXINPUTWINDOW_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
<QtCore/QVariant>
<QtGui/QAction>
<QtGui/QApplication>
<QtGui/QButtonGroup>
<QtGui/QDialog>
<QtGui/QGridLayout>
<QtGui/QGroupBox>
<QtGui/QHBoxLayout>
<QtGui/QHeaderView>
<QtGui/QTextBrowser>
<QtGui/QWidget>
QT_BEGIN_NAMESPACE
class Ui_Dialog
{
public:
QGroupBox *groupBox;
QWidget *gridLayoutWidget;
QGridLayout *gridLayout;
QGroupBox *groupBox_3;
QWidget *horizontalLayoutWidget;
QHBoxLayout *horizontalLayout;
QTextBrowser *textBrowser;
void setupUi(QDialog *Dialog)
Page 1 of 5
transformation.h
29/04/2010 00:11
{
if (Dialog->objectName().isEmpty())
Dialog->setObjectName(QString::fromUtf8("Dialog"));
Dialog->resize(1118, 671);
groupBox = new QGroupBox(Dialog);
groupBox->setObjectName(QString::fromUtf8("groupBox"));
groupBox->setGeometry(QRect(10, 0, 821, 661));
gridLayoutWidget = new QWidget(groupBox);
gridLayoutWidget->setObjectName(QString::fromUtf8("gridLayoutWidget"));
gridLayoutWidget->setGeometry(QRect(10, 30, 801, 621));
gridLayout = new QGridLayout(gridLayoutWidget);
gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
gridLayout->setContentsMargins(0, 0, 0, 0);
groupBox_3 = new QGroupBox(Dialog);
groupBox_3->setObjectName(QString::fromUtf8("groupBox_3"));
groupBox_3->setGeometry(QRect(840, 10, 271, 651));
horizontalLayoutWidget = new QWidget(groupBox_3);
horizontalLayoutWidget->setObjectName(QString::fromUtf8("horizontalLayoutWidget"));
horizontalLayoutWidget->setGeometry(QRect(10, 610, 251, 31));
horizontalLayout = new QHBoxLayout(horizontalLayoutWidget);
horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout"));
horizontalLayout->setContentsMargins(0, 0, 0, 0);
textBrowser = new QTextBrowser(groupBox_3);
textBrowser->setObjectName(QString::fromUtf8("textBrowser"));
textBrowser->setGeometry(QRect(10, 30, 251, 571));
retranslateUi(Dialog);
QMetaObject::connectSlotsByName(Dialog);
} // setupUi
void retranslateUi(QDialog *Dialog)
{
Dialog->setWindowTitle(QApplication::translate("Dialog", "New Quantum Gate", 0, QApplication::
UnicodeUTF8));
groupBox->setTitle(QApplication::translate("Dialog", "Input Matrix", 0, QApplication::UnicodeUTF8));
groupBox_3->setTitle(QApplication::translate("Dialog", "Learning Panel", 0, QApplication::
UnicodeUTF8));
Page 2 of 5
transformation.h
29/04/2010 00:11
textBrowser->setHtml(QApplication::translate("Dialog", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0
//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><
style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:'Lucida
Grande'; font-size:13pt; font-weight:400; fontstyle:normal;\">\n"
"<p style=\" margin-top:0px; margin-bottom:0px; marginleft:0px; margin-right:0px; -qt-block-indent:0;
text-indent:0px;\">Enter a custom matrix into the
text boxes on the left side. </p>\n"
"<p style=\"-qt-paragraph-type:empty; margin-top:0px;
margin-bottom:0px; margin-left:0px; margin-right:0p
x; -qt-block-indent:0; text-indent:0px;\"></p>\n"
"<p style=\" margin-top:0px; margin-bottom:0px; marginleft:0px; margin-right:0px; -qt-block-indent:0;
text-indent:0px;\">This matrix will be a new
quantum gate that you will be asked to place
somewhere in the circuit once OK has been pressed
and the matrix has been checked for validity.</p>\
n"
"<p style=\"-qt-paragraph-type:empty; margi"
"n-top:0px; margin-bottom:0px; margin-left:0px; marginright:0px; -qt-block-indent:0; text-indent:0px;\"><
/p>\n"
"<p style=\" margin-top:0px; margin-bottom:0px; marginleft:0px; margin-right:0px; -qt-block-indent:0;
text-indent:0px;\">You must enter a matrix that is
unitary because all quantum gates must be unitary.
A matrix is defined to be unitary as follows:</p>\
n"
"<p style=\"-qt-paragraph-type:empty; margin-top:0px;
margin-bottom:0px; margin-left:0px; margin-right:0p
x; -qt-block-indent:0; text-indent:0px;\"></p>\n"
"<p style=\" margin-top:0px; margin-bottom:0px; marginleft:0px; margin-right:0px; -qt-block-indent:0;
text-indent:0px;\">A square matrix is unitary if:</
Page 3 of 5
transformation.h
29/04/2010 00:11
p>\n"
"<p style=\"-qt-paragraph-type:empty; margin-top:0px;
margin-bottom:0px; margin-left:0px; margin-right:0p
x; -qt-block-indent:0; text-indent:0px;\"></p>\n"
"<p style=\" margin-top:0px; margin-bottom:0px; marginleft:0px; margin-right:0px; -qt-block-indent:0;
text-indent:0px;\"><img src=\"./LearningPanelImages
/unitaryEqn.gif\" /> where <im"
"g src=\"./LearningPanelImages/unitaryEqn2.gif\" />
denotes the conjugate transpose and <img src=\"./
LearningPanelImages/unitaryEqn3.gif\" />is the
inverse matrix.</p>\n"
"<p style=\"-qt-paragraph-type:empty; margin-top:0px;
margin-bottom:0px; margin-left:0px; margin-right:0p
x; -qt-block-indent:0; text-indent:0px;\"></p>\n"
"<p style=\" margin-top:0px; margin-bottom:0px; marginleft:0px; margin-right:0px; -qt-block-indent:0;
text-indent:0px;\">The harder way of checking
whether a matrix is unitary is to use Gauss-Jordan
elimination to find the matrix inverse and then
compare it to the conjugate transpose.</p>\n"
"<p style=\"-qt-paragraph-type:empty; margin-top:0px;
margin-bottom:0px; margin-left:0px; margin-right:0p
x; -qt-block-indent:0; text-indent:0px;\"></p>\n"
"<p style=\" margin-top:0px; margin-bottom:0px; marginleft:0px; margin-right:0px; -qt-block-indent:0;
text-indent:0px;\">The easier way comes from the
fact that the definition above guarantees that <img
src=\"./LearningPanelImages/unitaryEqn4.gif\" "
"/> where I is the identity matrix</p>\n"
"<p style=\"-qt-paragraph-type:empty; margin-top:0px;
margin-bottom:0px; margin-left:0px; margin-right:0p
x; -qt-block-indent:0; text-indent:0px;\"></p>\n"
"<p style=\" margin-top:0px; margin-bottom:0px; marginleft:0px; margin-right:0px; -qt-block-indent:0;
text-indent:0px;\">These definitions and equations
came from </p>\n"
"<p style=\"-qt-paragraph-type:empty; margin-top:0px;
Page 4 of 5
transformation.h
29/04/2010 00:11
margin-bottom:0px; margin-left:0px; margin-right:0p
x; -qt-block-indent:0; text-indent:0px;\"></p>\n"
"<p style=\" margin-top:0px; margin-bottom:0px; marginleft:0px; margin-right:0px; -qt-block-indent:0;
text-indent:0px;\"><a href=\"http://mathworld.
wolfram.com/UnitaryMatrix.html\"><span style=\"
text-decoration: underline; color:#0000ff;\">http:/
/mathworld.wolfram.com/UnitaryMatrix.html</span></a
></p></body></html>", 0, QApplication::UnicodeUTF8)
);
} // retranslateUi
};
namespace Ui {
class Dialog: public Ui_Dialog {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_UNITARYMATRIXINPUTWINDOW_H
Page 5 of 5
F.4
Learning Panel Files
210
controlledNotSource.html
29/04/2010 01:13
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1transitional.dtd">
<head>
<title></title>
</head>
<body>
<b><u>The Controlled-NOT Gate</u></b>
<br><br>
<b>Matrix representation:</b>
<table border="1" bordercolor="#000066" style="background-color:#FFFFFF" width="200" cellpadding="3"
cellspacing="3">
<tr>
<td>1</td>
<td>0</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>0</td>
<td>1</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>0</td>
<td>0</td>
<td>0</td>
<td>1</td>
</tr>
<tr>
<td>0</td>
<td>0</td>
<td>1</td>
<td>0</td>
Page 1 of 3
controlledNotSource.html
29/04/2010 01:13
</tr>
</table>
<br><br>
<b>Summary:</b>
<br>
The controlled-NOT can be used to implement the controlled operation: <i>`If A is true then do B'</i>. It
is a 2-qubit gate that flips the target qubit if the control qubit is equal to 1, otherwise it leaves
the target qubit alone.
<br><br>
<b>Its operation:</b>
<table border="1" bordercolor="#000066" style="background-color:#FFFFFF" width="200" cellpadding="3"
cellspacing="3">
<tr>
<th colspan="2">Before</th>
<th colspan="2">After</th>
</tr>
<tr>
<th>Ctrl</th>
<th>Targt</th>
<th>Ctrl</th>
<th>Targt</th>
</tr>
<tr align="center">
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
</tr>
<tr align="center">
<td>0</td>
<td>1</td>
<td>0</td>
<td>1</td>
</tr>
<tr align="center">
<td>1</td>
<td>0</td>
<td>1</td>
Page 2 of 3
controlledNotSource.html
29/04/2010 01:13
<td>1</td>
</tr>
<tr align="center">
<td>1</td>
<td>1</td>
<td>1</td>
<td>0</td>
</tr>
</table>
</html>
Page 3 of 3
controlledNotSource.html
29/04/2010 01:14
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1transitional.dtd">
<head>
<title></title>
</head>
<body>
<b><u>The Hadamard Gate</u></b>
<br><br>
<b>Matrix representation:</b><br><br>
<img src="../LearningPanelImages/hadamardPicLW.png" />
<br><br>
<b>Summary:</b>
<br>
It transforms |0> halfway between |0> and |1> and transforms |1> halfway between |1> and |0>. Applying the
Hadamard gate twice would leave the input unchanged.
<br><br>
With an input of |0> we would get:
<br><br>
<img src="../LearningPanelImages/hadamardPic0.png" />
<br><br>
With an input of |1> we would get:
<br><br>
<img src="../LearningPanelImages/hadamardPic1.png" />
</html>
Page 1 of 1
controlledNotSource.html
29/04/2010 01:14
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1transitional.dtd">
<head>
<title></title>
</head>
<body>
<b><u>The Measurement Gate</u></b>
<br><br>
<b>Summary:</b>
<br>
The measurement gate is the interface between the quantum world and the classical world. A measurement is
the quantum states collapsing down into classical information. This collapse is destructive, you cannot
convert this classical result back into a quantum state.
<br><br>
It is common for a quantum measurement to be an intermediate step in a quantum circuit. The result of a
measurement can be used as a condition to determine how the rest of the circuit executes.
<br><br>
As quantum measurement is destructive, running the circuit over a measurement gate followed by moving
backwards over it and finally over the measurement gate again will result in a new measurement with
possibly a different result from before.
</html>
Page 1 of 1
controlledNotSource.html
29/04/2010 01:15
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1transitional.dtd">
<head>
<title></title>
</head>
<body>
<b><u>The Pauli-X Gate</u></b>
<br><br>
<b>Matrix representation:</b>
<table border="1" bordercolor="#000066" style="background-color:#FFFFFF" cellpadding="3" cellspacing="3">
<tr>
<td>0</td>
<td>1</td>
</tr>
<tr>
<td>1</td>
<td>0</td>
</tr>
</table>
<br><br>
<b>Summary:</b>
<br>
The Pauli-X quantum gate works on 1-qubit and is the quantum equivalent to the classical NOT gate. It flips
a qubit |0> to |1> and a qubit |1> to |0>. Pauli gates are important because they cannot be decomposed
into simpler matrices.
</html>
Page 1 of 1
controlledNotSource.html
29/04/2010 01:16
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1transitional.dtd">
<head>
<title></title>
</head>
<body>
<b><u>The Pauli-Y Gate</u></b>
<br><br>
<b>Matrix representation:</b>
<table border="1" bordercolor="#000066" style="background-color:#FFFFFF" cellpadding="3" cellspacing="3">
<tr>
<td>0</td>
<td>-i</td>
</tr>
<tr>
<td>i</td>
<td>0</td>
</tr>
</table>
<br><br>
<b>Summary:</b>
<br>
The Pauli-Y quantum gate works on 1-qubit. It is the product of the Pauli-Z and Pauli-X matrices. The
symbol, <i>i</i> is known as the imaginary unit with <i>i^2</i>=-1. A complex number is written in the
form <i>a+bi</i> with <i>a</i> and <i>b</i> being real numbers. Pauli gates are important because they
cannot be decomposed into simpler matrices.
</html>
Page 1 of 1
controlledNotSource.html
29/04/2010 01:16
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1transitional.dtd">
<head>
<title></title>
</head>
<body>
<b><u>The Pauli-Z Gate</u></b>
<br><br>
<b>Matrix representation:</b>
<table border="1" bordercolor="#000066" style="background-color:#FFFFFF" cellpadding="3" cellspacing="3">
<tr>
<td>1</td>
<td>0</td>
</tr>
<tr>
<td>0</td>
<td>-1</td>
</tr>
</table>
<br><br>
<b>Summary:</b>
<br>
The Pauli-Z quantum gate works on 1-qubit. It flips a qubit |1> to -|1> and leaves |0> unchanged.
gates are important because they cannot be decomposed into simpler matrices.
</html>
Pauli
Page 1 of 1
controlledNotSource.html
29/04/2010 01:17
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1transitional.dtd">
<head>
<title></title>
</head>
<body>
<b><u>The Toffoli Gate</u></b>
<br><br>
<b>Matrix representation:</b>
<table border="1" bordercolor="#000066" style="background-color:#FFFFFF" width="50" cellpadding="2"
cellspacing="2">
<tr>
<td>1</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>0</td>
<td>1</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>0</td>
<td>0</td>
Page 1 of 5
controlledNotSource.html
29/04/2010 01:17
<td>1</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>0</td>
<td>0</td>
<td>0</td>
<td>1</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>1</td>
<td>0</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>1</td>
<td>0</td>
</tr>
<tr>
Page 2 of 5
controlledNotSource.html
29/04/2010 01:17
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>1</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>1</td>
</tr>
</table>
<br><br>
<b>Summary:</b>
<br>
Another name for the Toffoli gate is the controlled-controlled-not gate. The Toffili gate acts on 3 qubits.
This gate negates the third qubit if the first two qubits are both set to the |1> state.
<br><br>
Without this quantum gate, there would be no quantum equivalent of the classical AND gate because the AND
gate is not a unitary transformation. When the third qubit is set to |0> we effectively get a quantum
AND gate and when the third qubit is set to |1> we get a NAND gate. We know that NAND gates are
important from classical computation because any logical circuit can be made entirely from NANDs.
<br><br>
<b>Its operation:</b>
<table border="1" bordercolor="#000066" style="background-color:#FFFFFF" width="200" cellpadding="2"
cellspacing="2">
<tr>
<th colspan="3">Input</th>
<th colspan="3">Output</th>
Page 3 of 5
controlledNotSource.html
29/04/2010 01:17
</tr>
<tr align="center">
<td>&#160;0&#160;</td>
<td>&#160;0&#160;</td>
<td>&#160;0&#160;</td>
<td>&#160;0&#160;</td>
<td>&#160;0&#160;</td>
<td>&#160;0&#160;</td>
</tr>
<tr align="center">
<td>0</td>
<td>0</td>
<td>1</td>
<td>0</td>
<td>0</td>
<td>1</td>
</tr>
<tr align="center">
<td>0</td>
<td>1</td>
<td>0</td>
<td>0</td>
<td>1</td>
<td>0</td>
</tr>
<tr align="center">
<td>0</td>
<td>1</td>
<td>1</td>
<td>0</td>
<td>1</td>
<td>1</td>
</tr>
<tr align="center">
<td>1</td>
<td>0</td>
<td>0</td>
<td>1</td>
Page 4 of 5
controlledNotSource.html
29/04/2010 01:17
<td>0</td>
<td>0</td>
</tr>
<tr align="center">
<td>1</td>
<td>0</td>
<td>1</td>
<td>1</td>
<td>0</td>
<td>1</td>
</tr>
<tr align="center">
<td>1</td>
<td>1</td>
<td>0</td>
<td>1</td>
<td>1</td>
<td>1</td>
</tr>
<tr align="center">
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>0</td>
</tr>
</table>
</html>
Page 5 of 5
Bibliography
[1] Kitaev A. Classical and quantum computation. American Mathematical Society, Providence, Rhode Island, USA, 2002.
[2] Steane A. Multiple particle interference and quantum error correction. Proceedings of The
Royal Society of London A, 1996.
[3] Yao A. Quantum circuit complexity. Proceedings of the 34th Annual Symposium on Foundations of Computer Science, pages 352–361, 1993.
[4] Clegg B. The God Effect: Quantum Entanglement, Science’s Strangest Phenomenon. St.
Martin’s Press, New York, USA, June 2006.
[5] Lu C, Browne D Yang T, and Pan J. Demonstration of a compiled version of shor’s
quantum factoring algorithm using photonic qubits. Physical Review Letters, December
2007.
[6] Monroe C, Meekhof D, King B, Itano W, and Wineland D. Demonstration of a fundamental
quantum logic gate. Physical Review Letters, December 1995.
[7] Bacon D. Decoherence, Control, and Symmetry in Quantum Computers. PhD thesis, The
University of California, Berkeley, California, USA, 2001.
[8] Deutsch D. Quantum theory, the church-turing principle and the universal quantum computer. Proceedings of the Royal Society of London A 400:97-117, 1985.
[9] Deutsch D and Jozsa R. Rapid solutions of problems by quantum computation. Proceedings
of The Royal Society of London A 439:553-558, 1992.
[10] Harel D. Algorithmics: The Spirit of Computing. Pearson Education Limited, Edinburgh,
UK, April 2004.
[11] Mermin D. Quantum Computer Science: An Introduction. Cambridge University Press,
Cambridge, UK, August 2007.
[12] D-Wave. Quantum computing 1 [online]. December 2009. Available from: http://dwave.
wordpress.com/2008/12/19/.
[13] Rieffel E and Polak W. Quantum computing for non-physicists. ACM Computing Surveys,
September 1998.
[14] Weisstein E. Hilbert space [online]. October 2009. Available from: http://mathworld.
wolfram.com/HilbertSpace.html.
221
[15] Weisstein E. Orthonormal basis [online]. February 2009.
//mathworld.wolfram.com/OrthonormalBasis.html.
Available from: http:
[16] Weisstein E. Unitary matrix [online]. December 2009. Available from: http://mathworld.
wolfram.com/UnitaryMatrix.html.
[17] Golub G. Matrix Computations. The Johns Hopkins University Press, Maryland, USA,
third edition, October 1996.
[18] Stix G. Best-kept secrets. Scientific American, 292:78–83, January 2005.
[19] Papadimitriou C & Lewis H. Elements of the Theory Of Computation. Prentice Hall, New
Jersey, USA, second edition, 1997.
[20] Rogers I, Sharp H, and Preece J. Interaction Design. John Wiley & Sons, Inc, West Sussex,
UK, second edition, December 2007.
[21] Sommerville I. Software Engineering. Addison Wesley, Essex, UK, eighth edition, 2007.
[22] IBM.
Ibm-led team unveils most-advanced quantum computer [online].
August
2000. Available from: http://domino.research.ibm.com/comm/pr.nsf/pages/news.
20000815_quantum.html.
[23] IBM. Quantum computing 1 [online]. December 2009. Available from: http://domino.
research.ibm.com/comm/pr.nsf/pages/rscd.quantum-pica.html.
[24] Intel. Moore’s law made real by intel innovation [online]. December 2009. Available from:
http://www.intel.com/technology/mooreslaw/index.htm.
[25] Bell J. Bertlmann’s socks and the nature of reality. Journal de Physique Colloques, June
1980.
[26] Bulnes J, Sarthour R, Azevedo E, Bonk F, Freitas J, Guimaraes A, Bonagamba T, and
Oliveira I. Separability of very noisy mixed states and implications for nmr quantum
computing. Revision of Physical Review Letters, 2004.
[27] Gruska J. Quantum Computing. McGraw-Hill Publishing Company, Berkshire, UK, 1999.
[28] McEvoy J and Zarate O. Introducing Quantum Theory: A Graphic Guide to Science’s
Most Puzzling Discovery. Icon Books Ltd, Cambridge, UK, 2007.
[29] Watrous J. Quantum teleportation; deutsch’s algorithm. University of Waterloo, January
2006.
[30] Greene K. Scaling up a quantum computer [online]. 2009. Available from: http://www.
technologyreview.com/computing/23137/?a=f.
[31] Vandersypen L, Steffen M, Breyta G, Yannoni C, Sherwood M, and Chuang I. Experimental
realization of shor’s quantum factoring algorithm using nuclear magnetic resonance. Letters
to Nature, 2001.
[32] Linden and Popescu. Good dynamics versus bad kinematics. is entanglement needed for
quantum computation? Physical Review Letters, 87:047901, 2001.
222
[33] De Vos M. Project handbook. The University of Bath, August 2010.
[34] Marquit M. First use of deutsch’s algorithm in a cluster state quantum computer [online].
April 2007. Available from: www.physorg.com/news96107220.html.
[35] Nakahara M, Kondo Y, Hata K, and Tanimura S. Demonstrating quantum algorithm
acceleration with nmr quantum computer. Physical Review Letters, 70:052319, 2004.
[36] Nielsen M and Chuang I. Quantum Computation and Quantum Information. Cambridge
University Press, Cambridge, UK, 2000.
[37] Bohr N.
Quotes museum [online].
April 2010.
quotes-museum.com/quote/8800 [cited 18/04/2010].
Available from:
http://www.
[38] Comstock P. The strange world of quantum entanglement [online]. March 2007. Available
from: http://calitreview.com/51.
[39] Feynman P. Simulating physics with computers. International Journal of Theoretical
Physics, 21:467–488, 1982.
[40] Shor P. Algorithms for quantum computation: discrete logarithms and factoring. Proceedings of the 35th Annual IEEE Symposium on Foundations of Computer Science, pages
124–134, 1994.
[41] Shor P. Scheme for reducing decoherence in quantum computer memory. Physics Letters
A, 52, October 1995.
[42] Walther P, Resch J, Rudolph T, Schenck E, Weinfurter, Vedral V, Aspelmeyer M, and
Zeilinger A. Experimental one-way quantum computing. Nature, 434:169–176, 2005.
[43] Cleve R, Ekbert A, Macchiavello, and Mosca M. Quantum algorithms revisited. Proceedings
of The Royal Society of London A, 454(1969):339–354, January 1997.
[44] Dix A Finlay J Abowd D Beale R. Human-Computer Interation. Pearson Education
Limited, Essex, UK, third edition, 1993.
[45] Hughes R. Quantum computatin roadmap [online]. November 2009. Available from:
http://qist.lanl.gov/qcomp_map.shtml.
[46] Laflamme R. Perfect quantum error correcting code. Physical Review Letters, 77(1):198–
201, July 1996.
[47] Aaronson S. The limits of quantum computers. Scientific American, 298, March 2008.
[48] Braunstein S. Quantum error correction for communication with linear optics. Letters to
Nature, 394:47–49, April 1998.
[49] Kasivajhula S. Quantum computing: A survey. In Proceedings of the 44th annual Southeast
regional conference, pages 249–253, New York, USA, 2006. ACM.
[50] Robinson S. Still guarding secrets after years of attacks, rsa earns accolades for its founders.
from SIAM News, 36(5), 2003.
[51] Swaminarayan S, Bergen B, Turner J, Lang M, Kelley T, and Mohd-Yusof J. Roadrunner
- computing in the fast lane. Los Alamos Science and Technology Magazine, May 2008.
223
[52] Tame S, Prevedel R, Paternostro M, Bohi P, Kim S, and Zeilinger A. Experimental realization of deutsch’s algorithm in a one-way quantum computer. Physical Review Letters,
98, April 2007.
[53] Tomonaga S. The story of spin. University of Chicago Press, March 1998.
[54] Reenskaug T. Mvc xerox parc 1978-79 [online]. March 2010. Available from: http:
//heim.ifi.uio.no/~trygver/themes/mvc/mvc-index.html.
[55] Simonite T. Flat ‘ion trap’ holds quantum computing promise. New Scientist, July 2006.
[56] Jamroz W, Kruzelecky R, and Haddad E. Applied Micophotonics. CRC Press, Florida,
USA, 2006.
224