%run init.ipynb

from qiskit import *

def Uf_c(n):
    qr = QuantumRegister(n+1); qc = QuantumCircuit(qr, name = 'Uf_c')
    qc.x(qr[n])
    return qc
qc = Uf_c(3); qc.draw()

def Uf_b(n):
    qr = QuantumRegister(n+1); qc = QuantumCircuit(qr, name = 'Uf_b')
    qc.cx(qr[n-1],qr[n])
    return qc
qc = Uf_b(3); qc.draw()

def deutsch_jozsa(n, typ):
    qr = QuantumRegister(n+1); cr = ClassicalRegister(n); qc = QuantumCircuit(qr,cr)
    qc.x(qr[n])
    for j in range(0,n+1):
        qc.h(qr[j])
    qc.barrier()
    qrs = []
    for j in range(0,n+1):
        qrs.append(qr[j])
    if typ == 'c':
        qc_uf = Uf_c(n); qc.append(qc_uf, qrs)
    elif typ == 'b':
        qc_uf = Uf_b(n); qc.append(qc_uf, qrs)
    qc.barrier()
    for j in range(0,n):
        qc.h(qr[j])
    for j in range(0,n):
        qc.measure(qr[j], cr[j])
    return qc

qc = deutsch_jozsa(3, 'c'); qc.draw() # exemplo pra funcao constante

simulator = Aer.get_backend('qasm_simulator')
nshots = 8192
result = execute(qc, backend = simulator, shots = nshots).result()
from qiskit.tools.visualization import plot_histogram
plot_histogram(result.get_counts(qc))

qiskit.IBMQ.load_account()
provider = qiskit.IBMQ.get_provider(hub='ibm-q', group='open', project='main')
device = provider.get_backend('ibmq_belem')
from qiskit.tools.monitor import backend_overview, backend_monitor
job = execute(qc, backend = device, shots = nshots)
from qiskit.tools.monitor import job_monitor
job_monitor(job)

result = job.result(); plot_histogram(result.get_counts(qc))

qc = deutsch_jozsa(3, 'b'); qc.draw() # exemplo de funcao balanceada

result = execute(qc, backend = simulator, shots = nshots).result()
plot_histogram(result.get_counts(qc))

job = execute(qc, backend = device, shots = nshots)
job_monitor(job)

result = job.result(); plot_histogram(result.get_counts(qc))

