2

Summary

I'm writing a program to simulate an ideal quantum computer in python 3.

Right now, I'm working on adding two-qubit functionality, and I finally got it to the point where I could actually run it (and then I got promptly hit by a bug). Now, I've worked out a lot of kinks but the program isn't giving the right answer for one of the qubits.

Problem

In a nutshell, the program isn't performing any operations on the second qubit, it's only doing stuff to the first, which makes me think there's a problem with the way the program is looping through everything, but I've stared at it for a while and can't find anything wrong.

Running the MWE, the output should be

your result is [ 0.70710678+0.j -0.70710678+0.j] qubit # 1
probability of |0> state is 0.5
probability of |1> state is 0.5

your result is [0 1] qubit # 2
probability of |0> state is 0
probability of |1> state is 1
=> None

The output should have the second qubit's result and probabilities the same as the first state. Also note that for both qubits, their original state is [0 1] - in other words, the second qubit's state isn't being changed at all.

MWE

import numpy as np
import cmath

qubits = 2
done = "n"
qstats = {key:np.array([0,1]) for key in range(1,qubits+1)}

def hadop(qstat):
    matrix = (1/cmath.sqrt(2))*np.array([[1,1],[1,-1]])
    return np.dot(matrix, qstat)

def probability(qstat, n):
    if n == 0:
        return np.abs((qstat[0]))**2
    elif n == 1:
        return np.abs((qstat[1]))**2

singates = {"Hadamard":hadop}

commands = {1:["Hadamard"],2:["Hadamard"]}
qubitnum=1
while qubitnum <= qubits:
    for index,gate in enumerate(commands[qubitnum]):
        qstat = qstats[index+1]
        qstat = singates[gate](qstat)
        qstats[index+1] = qstat
        if index+1 == len(commands[qubitnum]):
            print(" ")
            print("your result is", qstats[qubitnum], "qubit #", qubitnum)
            print("probability of |0> state is", probability(qstats[qubitnum],0))
            print("probability of |1> state is", probability(qstats[qubitnum],1))
    qubitnum+=1

The Full Code

main-file.py:

import numpy as np
from random import randint
import cmath
import math
from function import *

qubits = int(input("How many qubits would you like to use? (Currently, only supports 1): "))
done = "n"
qstatask = input("Would you like your initial qubits to be in the |0> state or |1> state? 0 or 1: ")
if qstatask == "0":
    qstats = {key:np.array([0,1]) for key in range(1,qubits+1)}
elif qstatask == "1":
    qstats = {key:np.array([1,0]) for key in range(1,qubits+1)}
else:
    print("I'm sorry, that is not a valid input. State set to zero.")
    qstats = {key:np.array([0,1]) for key in range(1,qubits+1)}

singates = {"Hadamard":hadop, "X":xop, "Z":zop, "Y":yop, "sqrtX":sqrtxop,"phase shift":phaseshiftop,"measurement":measurement,"custom":customop, "control":control, "target":target}
twgates = ["cNOT", "swap"]
thrgates = ["Toffoli"]

print(singates.keys())
print(twgates)
print(thrgates)

while done == "n":
    if qubits == 1:
        fstgat = input("what gate would you like to use? use the list of single gates at the top: ")
        if fstgat in singates:
            qstat = qstats[1]
            qstat = singates[fstgat](qstat)
            qstats[1] = qstat
            done = input("Done with your circuit? y or n: ")
        else:
            print("sorry, that gate is not yet implemented. maybe try custom gate.")
            done = "y"
    elif qubits >= 2:
        commands = {}
        for i in range(1,qubits+1):
            commands[i] = []
        qubitnum=1
        while qubitnum <= qubits:
            while done == "n":
                fstgat = input("what gate would you like to use for " + str(qubitnum) + " qubit? Use the list of single qubits at the top, plus control or target: ")
                commands[qubitnum].append(fstgat)
                done = input("Done with your " + str(qubitnum) + " qubit? y or n: ")
            qubitnum+=1
            done = "n"
        qubitnum=1
        while qubitnum <= qubits:
            for index,gate in enumerate(commands[qubitnum]):
                if gate in singates:
                    if gate != "target" or (gate == "target" and mem1 in globals()):
                        qstat = qstats[index+1]
                        qstat = singates[gate](qstat)
                        qstats[index+1] = qstat
                        print("done with a calculation")
                        if index+1 == len(commands[qubitnum]):
                            print(" ")
                            print("your result is", qstats[qubitnum], "qubit #", qubitnum)
                            print("probability of |0> state is", probability(qstats[qubitnum],0))
                            print("probability of |1> state is", probability(qstats[qubitnum],1))
                    else:
                        print("checking for information")
                else:
                    print(gate, " has not yet been implemented. Maybe try the custom gate?")
                    break
            qubitnum+=1
        print("Program complete.")
        done = "y"
    else:
        print("sorry, that functionality is not yet implemented")
        done = "y"

function.py:

import cmath
import numpy as np
import math
from random import randint

def hadop(qstat):
    matrix = (1/cmath.sqrt(2))*np.array([[1,1],[1,-1]])
    return np.dot(matrix, qstat)

def xop(qstat):
    matrix = np.array([[0,1],[1,0]])
    return np.dot(matrix,qstat)

def zop(qstat):
    matrix = np.array([[1,0],[0,-1]])
    return np.dot(matrix,qstat)

def yop(qstat):
    matrix = np.array([[0, cmath.sqrt(-1)],[-1*cmath.sqrt(-1),0]])
    return np.dot(matrix,qstat)

def sqrtxop(qstat):
    const1 = 1+cmath.sqrt(1)
    const2 = 1-cmath.sqrt(1)
    matrix = np.array([[const1/2,const2/2],[const2/2,const1/2]])
    return np.dot(matrix,qstat)

def phaseshiftop(qstat):
    phasepos = [math.pi/4, math.pi/2]
    print(phasepos)
    x = input("Please pick one of the two phase shifts, 0 for the first, 1 for the second: ")
    if x == "0":
        y = phasepos[0]
    elif x == "1":
        y = phasepos[1]
    const1 = cmath.sqrt(-1)*y
    matrix = np.array([[1,0],[0,math.e**const1]])
    return np.dot(matrix,qstat)

def customop(qstat):
    num1 = float(input("Please input a number (no pi, e, etc) for the first number in your matrix (row 1 column 1): "))
    num2 = float(input("Number for matrix - row 1 column 2: "))
    num3 = float(input("Number for matrix - row 2 column 1: "))
    num4 = float(input("Number for matrix - row 2 column 2: "))
    matrix = np.array([[num1,num3],[num2,num4]])
    matrix2 = matrix.conj().T
    result = np.dot(matrix, matrix2)
    identity = np.identity(2)
    if np.array_equal(result, identity) == True:
        return np.dot(matrix, qstat)
    else:
        print("matrix not unitary, pretending no gate was applied")
        return qstat

def probability(qstat, n):
    if n == 0:
        return np.abs((qstat[0]))**2
    elif n == 1:
        return np.abs((qstat[1]))**2

def measurement(qstat):
    prob1 = probability(qstat,0)
    prob2 = probability(qstat,1)
    random = randint(0,1)
    if random <= prob1:
        qstat = np.array([0,1])
        return qstat
    elif prob1 < random:
        qstat = np.array([1,0])
        return qstat

def control(qstat):
    typegat = input("Which gate is this the control qubit for? See list of two qubit gates at the top.")
    if typegat == "cNOT":
        global mem1
        mem1 = qstat
    elif typegat == "swap":
        mem1 = qstat
    else:
        print("other gates not yet implemented")
    return qstat

def target(qstat):
    typegat2 = input("Which gate is this target qubit for? See list of two qubit gates at the top.")
    if typegat2 == "cNOT":
        if np.array_equal(mem1, [0,1]) == True:
            return qstat
        elif np.array_equal(mem1, [1,0]) == True:
            return np.dot(qstat,mem1)
        else:
            print("superposition...not implemented")
            return qstat
    elif typegat2 == "swap":
        return mem1
    else:
        print("other gates not yet implemented")
        return qstat

If you decide to run the full code given here, to reproduce the problem, input 2 (in answer to the question of how many qubits), 0 or 1 (note that this sets the qubits to [0,1] and [1,0] respectively; either answer here is fine) and then Hadamard, X, or what have you, then y, then Hadamard, X, or whatever, and then y. At that point it should output the result. I would suggest using the Hadamard gate on both to see the problem. This is only applicable if you run the full program; otherwise you don't need to input anything.

Note: I know there's a lot of variables and other madness, so if anyone wants a description of what a variable is for, I'd be glad to provide it. I tried to make the variables fairly self-explanatory.

Auden Young
  • 1,147
  • 2
  • 18
  • 39
  • 2
    TL;DR. Please mention the [Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve) – Moinuddin Quadri Dec 18 '16 at 18:28
  • Isn't it offered @MoinuddinQuadri? The code is there and the steps required to reproduce it are supplied. What I'm trying to say is, I don't know if it could be more minimal than this due to the context of the subject (simulating an ideal quantum computer). – Dimitris Fasarakis Hilliard Dec 18 '16 at 18:31
  • @JimFasarakis-Hilliard: But it is too long. As per the definition of minimal in document *"Minimal – Use as little code as possible that still produces the same problem"* – Moinuddin Quadri Dec 18 '16 at 18:32
  • PyCharm has a pretty useful debugger... – OneCricketeer Dec 18 '16 at 18:33
  • I generally agree @MoinuddinQuadri, I'm just not sure how easily this could be "minimized" while still being reproducible. – Dimitris Fasarakis Hilliard Dec 18 '16 at 18:34
  • I tried to debug it. But I was not sure where to check. Debugging this will take a plenty of time, and I am sure others will feel the same. So for the best interest of all (including OP for more response), I feel it is worthy if it could be shortened. – Moinuddin Quadri Dec 18 '16 at 18:37
  • @MoinuddinQuadri, fwiw, I tried to give an idea of where the bug probably was in my question; in the way it loops through the lists of user-inputted commands. – Auden Young Dec 18 '16 at 18:43
  • 2
    This could definitely be trimmed down a lot. Most of the user input code and the operations not used in the failing code path could be stripped out. – user2357112 Dec 18 '16 at 22:05
  • What does "MWE" stand for? – das-g Dec 18 '16 at 22:17
  • @das-g, minimal working example – Auden Young Dec 18 '16 at 22:18
  • 2
    Re "I'm just not sure how easily this could be "minimized" while still being reproducible." Well if you do the minimization in small steps and at one point the bug stops being reproducible when you do that, the last thing you removed will be a strong hint on where the bug might have been. So that'd be a **good thing**. – das-g Dec 18 '16 at 22:21
  • @das-g, I have shortened it further – Auden Young Dec 18 '16 at 22:25

1 Answers1

3

I'm not completely sure what you mean to be doing with index. However, it looks to me like your line

qstat = qstats[index+1]

should really read

qstat = qstats[qubitnum]
E.P.
  • 342
  • 4
  • 13