Search code examples
pythonpython-3.xquantum-computing

Logic error - incorrect answer given


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.


Solution

  • 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]