from qiskit import *
from qiskit.compiler import *
from qiskit.tools.jupyter import *
from qiskit.visualization import *
import matplotlib.pyplot as plotter
import numpy as np
from IPython.display import display, Math, Latex
%matplotlib inline
# Loading your IBM Q account(s)
provider = IBMQ.load_account()

qc1=QuantumCircuit(2)
qc1.h(0)
qc1.h(1)
qc1.barrier() #The part between the barriers is our oracle
qc1.cz(0,1)
#We are using a controlled-Z gate which flips the sign of the second qubit when both qubits are set to '1'
qc1.barrier()
qc1.draw('mpl')

def final_vector(qc):
    backend = Aer.get_backend('statevector_simulator')
    job = execute(qc, backend)
    result = job.result()
    outputstate = result.get_statevector(qc, decimals=3)
    return outputstate
print(final_vector(qc1)) #We can see that the desired state has been obtained


qc2=QuantumCircuit(3)

qc2.h(0)
qc2.h(1)
qc2.h(2)
qc2.barrier() 
#The part between the barriers is our oracle
qc2.x(0)
qc2.x(2)

#We are just using the ccz gate which we have defined later
qc2.h(1)
qc2.ccx(0,2,1)
qc2.h(1)

qc2.x(2)
qc2.x(0)

qc2.barrier()
qc2.draw('mpl')

#print the final vector
print(final_vector(qc2))
#The negative sign has been applied only to |010> in the equal superposition of states

def ccz_gate(qc,a,b,c):
    qc.h(c)
    qc.ccx(a,b,c)
    qc.h(c)
    
    

#Let's create an oracle which will mark the states 101 and 110
#(This particular oracle won't be using ancilla qubits)
def phase_oracle(circuit):
    circuit.cz(0, 2)
    circuit.cz(0, 1)
n=3
qc2=QuantumCircuit(n,n)
for i in range(0,n):
    qc2.h(i)
qc2.barrier([0,1,2])
#This creates a superposition of all states

#We will now perform the Grover iteration
phase_oracle(qc2)
qc2.barrier([0,1,2])
for i in range(0,n):
    qc2.h(i)
    
#Performing a conditional phase shift
qc2.x(0)
qc2.x(1)
qc2.x(2)
ccz_gate(qc2,0,1,2)
qc2.x(0)
qc2.x(1)
qc2.x(2)
for i in range(0,n):
    qc2.h(i)
#The Grover iteration is now complete

qc2.barrier([0,1,2])
qc2.draw('mpl')


qc2.measure(0,0)
qc2.measure(1,1)
qc2.measure(2,2)
qc2.draw('mpl')

def counts_circ(circ):
    backend_sim = Aer.get_backend('qasm_simulator')
    job_sim = execute(circ, backend_sim, shots=2000)
    result_sim = job_sim.result()
    counts = result_sim.get_counts(circ)
    return(counts)
plot_histogram(counts_circ(qc2))


qc_mct=QuantumCircuit(5,5)
for i in range(0,4):
    qc_mct.x(i)
qc_mct.mct([0,1,2,3],4)
qc_mct.draw('mpl')

qc_mct.measure(0,0)
qc_mct.measure(1,1)
qc_mct.measure(2,2)
qc_mct.measure(3,3)
qc_mct.measure(4,4)
plot_histogram(counts_circ(qc_mct))

def cccz_gate(qc,a,b,c,d):
    #Suppose qubit d is the target qubit
    qc.h(d)
    qc.mct([a,b,c],d)
    qc.h(d)

#Let's now define the operation for the conditional phase shift (i.e., on |0000>)
def zero_oracle(qc):
    qc.x([0,1,2,3])
    cccz_gate(qc,0,1,2,3)
    qc.x([0,1,2,3])



n=4
qc3=QuantumCircuit(n,n)
for i in range(0,n):
    qc3.h(i)
qc3.barrier([0,1,2,3])

#Finally the oracle for marking the solution states

qc3.x(1)
ccz_gate(qc3,0,1,2)
ccz_gate(qc3,0,1,3)
qc3.x(1)
#The above portion just marked states '1001' and '1010'

qc3.x(1) 
qc3.x(3) 
ccz_gate(qc3,1,3,0)
ccz_gate(qc3,1,3,2)
qc3.x(3) 
qc3.x(1)
#This portion marked states '1000' and '0010'
#The oracle ends


qc3.barrier([0,1,2,3])
for i in range(0,n):
    qc3.h(i)

zero_oracle(qc3)

for i in range(0,n):
    qc3.h(i)
#The Grover iteration is now complete

qc3.barrier([0,1,2,3])
qc3.draw('mpl')   

qc3.measure([0,1,2,3],[0,1,2,3])
plot_histogram(counts_circ(qc3))