import numpy as np
zero_state = np.array([[1],[0]])
one_state = np.array([[0],[1]])

print("The |0> is \n", zero_state)
print("The |1> is \n", one_state)

print("The shape of the Vector |0> is",zero_state.shape)
print("The shape of the Vector |1> is",one_state.shape)

#Getting the user input int values for two numbers
num1 = int(input("Enter a value for Number One! \n")) 
num2 = int(input("Enter a value for Number Two! \n")) 

num1, num2 = num2, num1 #Swapping

print("The value of Number 1 after swapping: ",num1)
print("The value of Number 2 after swapping: ",num2)

#Getting the user input int values for two numbers
num1 = int(input("Enter a value for Number One! \n")) 
num2 = int(input("Enter a value for Number Two! \n")) 

def cvtb(num):
  binnum = [int(i) for i in list('{0:0b}'.format(num))]
  return binnum

'{0:0b}'.format(4)

list('{0:0b}'.format(4))

[int(i) for i in list('{0:0b}'.format(4))]

#Calling the method "cvtb" and getting the binary equivalents of num1 and num2
num1_b = cvtb(num1)
num2_b = cvtb(num2)

#Getting the length of each list
num1_l = len(num1_b)
num2_l = len(num2_b)

#Adjusting the length of two lists 
if num1_l==num2_l:
  pass
elif num1_l < num2_l:
  diff = num2_l - num1_l #Getting the difference in the lengths
  for ind in range(diff):
    num1_b.insert(ind,0)#Adding zeroes to the left 
elif num2_l < num1_l:
  diff = num1_l - num2_l
  for ind in range(diff):
    num2_b.insert(ind,0)


print(num1_b)

print(num2_b)

#In this block, we check for the indices with the value 1 in the lists num1_b,
#num2_b, and store the indices in the corresponding list
indices_num1 = []
indices_num2 = []
for i in range(len(num2_b)):
  if num1_b[i]==1:
    indices_num1.append(i)
  if num2_b[i]==1:
    indices_num2.append(i)

#In this block, we check for the indices for which the values
#differ in both the lists
indices = []
for i in range(len(num2_b)):
  if num1_b[i]!=num2_b[i]:
    indices.append(i)

!pip install qiskit #Install qiskit on colab
!pip install pylatexenc #Required for matplotlib support to render the images of circuit
from IPython.display import clear_output #Clear the output after installation
clear_output()

from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit, Aer, execute

n_qubits = len(num2_b)#Number of required qubits 
                      #equals to the length of num2_b or num1_b list
n_q1 = QuantumRegister(n_qubits,name='num1')
print(n_q1)
n_b1 = ClassicalRegister(n_qubits)
print(n_b1)

qnum1 = QuantumCircuit(n_q1, n_b1) #Initializing the Quantum Circuit
#For every index with a value one, we appply a NOT Gate 
#that transforms state |0> to |1>
for i in indices_num1:
  qnum1.x(i)

qnum1.barrier() #We will add a barrier for visual discrimination between the initial
                #encoding part and the transformation part
qnum1.draw('mpl') #Visualizing the Circuit qnum1

n_q2 = QuantumRegister(n_qubits,name='num2')
n_b2 = ClassicalRegister(n_qubits)

qnum2 = QuantumCircuit(n_q2,n_b2)
for i in indices_num2:
  qnum2.x(i)

qnum2.barrier()
qnum2.draw('mpl')

for i in indices:
  qnum1.x(i)
  qnum2.x(i)

#Using barriers to distinguish transformation part from output extraction
qnum1.barrier()
qnum2.barrier()

qnum1.draw('mpl')

qnum2.draw('mpl')

for i in range(3):
  qnum1.measure(i,i)
  qnum2.measure(i,i)

qnum1.draw('mpl')

#Using qasm_simulator, we can simulate our circuit on an actual quantum device
simulator = Aer.get_backend('qasm_simulator')

#Get the results for each simulation
result_num1 = execute(qnum1,backend=simulator).result().get_counts()

#Visualizing the results through a histogram
from qiskit.visualization import plot_histogram
plot_histogram(result_num1)

qnum2.draw('mpl')

simulator = Aer.get_backend('qasm_simulator')
result_num2 = execute(qnum2,backend=simulator).result().get_counts()
plot_histogram(result_num2)