* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Download A WYSIWYG Simulation Tool for Investigating the Circuit Model of
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
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
Quantum machine learning wikipedia , lookup
Hidden variable theory wikipedia , lookup
Quantum state wikipedia , lookup
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> 0 </td> <td> 0 </td> <td> 0 </td> <td> 0 </td> <td> 0 </td> <td> 0 </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