# !pip3 install qiskit

import qiskit as q
import matplotlib.pyplot as plt
import numpy as np

def build_circ(num_qbits, num_cbits):
  qr = q.QuantumRegister(num_qbits)
  cr = q.ClassicalRegister(num_cbits)
  final_circ = q.QuantumCircuit(qr, cr)
  return final_circ, qr, cr

def h_gates(qcirc, a, b): # 2 inputs and h gates in parallel
  qcirc.h(a)
  qcirc.h(b)  

hadamard_front, qr, cr = build_circ(2, 2)
h_gates(hadamard_front, qr[0], qr[1])
hadamard_front.draw() 

### define the oracle for state 00

hadamard_front.x(qr[0])
hadamard_front.x(qr[1])
hadamard_front.cz(qr[0], qr[1])
hadamard_front.x(qr[0])
hadamard_front.x(qr[1])
hadamard_front.draw()

### We apply the steps below to create the reflection about the original superposition state
### 1. Apply H to each qubit in the register.
### 2. A conditional phase shift of −1 to every computational basis state except |0⟩. 
### This can be represented by the unitary operation −O_0, as O_0 represents the conditional phase shift to |0⟩ only.
### 3. Apply H to each qubit in the register.

### reflection about state |0> can be thought of as circuit below
### apply z gate to both qubits, then add a cz gate

def reflection_psi(qcirc, a, b):
  h_gates(qcirc, a, b)
  qcirc.z(a)
  qcirc.z(b)
  qcirc.cz(a, b)
  h_gates(qcirc, a, b)

reflection_psi_circ, qr_rf, cr_rf = build_circ(2, 2)
reflection_psi(reflection_psi_circ, qr_rf[0], qr_rf[1])
reflection_psi_circ.draw()


# !pip3 install pylatexenc


complete_circuit = hadamard_front.compose(reflection_psi_circ)

for n in range(2):
  complete_circuit.measure(n, n)

complete_circuit.draw('mpl', filename=path+'Grover_Algo_00.png', scale=1.1)

statevec_sim = q.Aer.get_backend("statevector_simulator")

def statevec_exec(circ):
  statevec = q.execute(circ, backend=statevec_sim).result().get_statevector()
  return statevec

complete_circuit_statevec = statevec_exec(complete_circuit)
q.visualization.plot_bloch_multivector(complete_circuit_statevec)

qasm_sim = q.Aer.get_backend('qasm_simulator')
counts = q.execute(complete_circuit, backend=qasm_sim, shots=1024).result().get_counts()
q.visualization.plot_histogram([counts], legend=['output'])

from qiskit import IBMQ

IBMQ.save_account('find your token')
IBMQ.load_account()


provider = IBMQ.get_provider('ibm-q')
qcomp = provider.get_backend('ibmq_manila') # check which computer has 0 jobs on queue
job = q.execute(complete_circuit, backend=qcomp)
q_result = job.result()

q.visualization.plot_histogram(q_result.get_counts(complete_circuit))

check_circ = q.QuantumCircuit(2)
# check_circ.iswap(0, 1)
check_circ.rz(np.pi/2, 0)
check_circ.rz(np.pi/2, 1)
check_circ.cz(0, 1)
check_circ.rz(np.pi/2, 0)
check_circ.rz(np.pi/2, 1)
qasm_sim = q.Aer.get_backend('unitary_simulator')
# we need to make a copy of the circuit with the 'save_statevector'
# instruction to run on the Aer simulator

job = q.execute(check_circ, qasm_sim)
result = job.result()
print(result.get_unitary(check_circ, decimals=2))

from google.colab import drive
drive.mount('/content/drive')

path = '/content/drive/My Drive/'

### let's use the oracke above to check whether we get 00 state as solution or not 

hadamard_front_check, qr_check, cr_check = build_circ(2, 2)
h_gates(hadamard_front_check, qr_check[0], qr_check[1])

#### oracle with rz and cz gate
hadamard_front_check.rz(np.pi/2, qr_check[0])
hadamard_front_check.rz(np.pi/2, qr_check[1])
hadamard_front_check.cz(qr_check[0], qr_check[1])
hadamard_front_check.rz(np.pi/2, qr_check[0])
hadamard_front_check.rz(np.pi/2, qr_check[1])
####

reflection_psi_circ_check, qr_rf_check, cr_rf_check = build_circ(2, 2)
reflection_psi(reflection_psi_circ_check, qr_rf_check[0], qr_rf_check[1])

complete_circuit_check = hadamard_front_check.compose(reflection_psi_circ_check)

for n in range(2):
  complete_circuit_check.measure(n, n)



style = {'backgroundcolor': 'lavender', 'dpi':200, 'subfontsize':10}


complete_circuit_check.draw('mpl', scale=0.8, style=style, filename=path+'Grover_Algo_RZ_00.png')

qasm_sim = q.Aer.get_backend('qasm_simulator')
counts = q.execute(complete_circuit_check, backend=qasm_sim, shots=1024).result().get_counts()
q.visualization.plot_histogram([counts], legend=['output'])

provider = IBMQ.get_provider('ibm-q')
qcomp = provider.get_backend('ibmq_manila') # check which computer has 0 jobs on queue
job = q.execute(complete_circuit_check, backend=qcomp)
q_result = job.result()

q.visualization.plot_histogram(q_result.get_counts(complete_circuit_check))

