# Importando módulos
from qiskit import *
from qiskit.tools.visualization import plot_histogram

# Inicializando o circuito

nQubits = 2
nBits = 2
circuitoQuantico = QuantumCircuit(nQubits, nBits)

# Para aplicar uma porta no circuito devemos seguir o seguinte exemplo onde aplicamos uma Hadamard Gate

circuitoQuantico.h(0)

# Nesse exemplo h() é a função que usamos para aplicar uma Hadamard Gate e o argumento é o índice do qubit
# onde se deseja aplica a porta

# Podemos ver ao chamar draw() que a Hadamard Gate fica no qubit desejado

circuitoQuantico.draw(output = 'mpl')

# Podemos aplicar também portas que envolvem mais de um qubit, como a CNOT(Controlled NOT) Gate

circuitoQuantico.cx(0,1)

# Visualização do circuito após chamar a CNOT Gate

circuitoQuantico.draw(output = 'mpl')

# Agora podemos medir esses qubits após as operações chamando measure()

circuitoQuantico.measure(0,0)
circuitoQuantico.measure(1,1)

# Visualização do circuito após chamar measure()

circuitoQuantico.draw(output = 'mpl')

# Para simular um circuito quântico usamos um elemento do Qiskit chamado Aer, que tem como 
# uma de suas funções a simulação de circuitos

simulador = Aer.get_backend('qasm_simulator')

# Para executar o circuito chamamos execute() que leva como argumento o circuito a ser executado e o 
# backend(aonde o circuito vai ser executado) que nesse caso é no simulador do Aer

resultado = execute(circuitoQuantico, backend = simulador).result()

# Usamos a variável resultado para guardar os dados do resultado

# Para exibir os resultados chamamos plot_histogram()

plot_histogram(resultado.get_counts(circuitoQuantico))

# Antes de tudo é necessário importar o módulo da IBMQ Experience e carregar a sua conta

from qiskit import IBMQ

IBMQ.load_account()

# Agora precisamos inicializar a variável de provider que vai ser responsável por ter o acesso a 
# um dos computadores quanticos da IBM

provedor = IBMQ.get_provider('ibm-q')

# Podemos agora escolher um dos computadores disponíveis da IBM para podermos rodar nosso circuito

computadorQuantico = provedor.get_backend('ibmq_16_melbourne')

# Para simular no nosso próprio computado tivemos que usar
# " execute(circuitoQuantico, backend = simulador) "
# Agora vamos ter que fazer algo similar

executar = execute(circuitoQuantico, backend=computadorQuantico)

# Depois de rodar o comando " execute(circuitoQuantico, backend=computadorQuantico).result() "
# o nosso circuito entra numa fila do computador da IBM que escolhemos roda. Como se fosse uma 
# lista de pedidos num restaurante para o cozinheiro preparar.

# Podemos checar o status do nosso "pedido" chamando o job_monitor

from qiskit.tools.monitor import job_monitor

job_monitor(executar)

# Para pegar o resultado do circuito fazemos o seguinte

resultado = executar.result()

# Da mesma forma como na simulação no próprio computador podemos exibir os resultados num histograma

plot_histogram(resultado.get_counts(circuitoQuantico))