# qiskit packages
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit import Aer, IBMQ, execute

# visualization packages
from qiskit.tools.visualization import plot_histogram, qx_color_scheme, plot_state_city, plot_bloch_multivector, plot_state_paulivec, plot_state_hinton, plot_state_qsphere

backend = Aer.get_backend('qasm_simulator') # select the qasm simulator

# to use a real processor uncomment the following lines:
#IBMQ.load_accounts()
#from qiskit.providers.ibmq import least_busy
#backend = least_busy(IBMQ.backends(simulator=False))
#print("the best backend is " + backend.name())

# Create the registers
q2 = QuantumRegister(2)
c2 = ClassicalRegister(2)

# Create the Bell's State
bell = QuantumCircuit(q2, c2)
bell.h(q2[0])
bell.cx(q2[0], q2[1])

# Measure the qubits in the standard base (Z)
measureZZ = QuantumCircuit(q2, c2)
measureZZ.measure(q2[0], c2[0])
measureZZ.measure(q2[1], c2[1])
bellZZ = bell+measureZZ

# Measure the qubits in the superposition base (X)
measureXX = QuantumCircuit(q2, c2)
measureXX.h(q2)
measureXX.measure(q2, c2)
bellXX = bell+measureXX

bellZZ.draw(output='mpl')

circuits = [bellZZ,bellXX]
job = execute(circuits, backend)
result = job.result()

#plot_histogram(result.get_counts(bellZZ))
legend = ['bellZZ', 'bellXX']
plot_histogram([result.get_counts(bellZZ), result.get_counts(bellXX)], legend=legend, sort='desc', figsize=(15,12), 
               color=['orange', 'black'], bar_labels=False)

# Create a circuit that measures the qubits in 0 and one that flips and measures them in 1:
mixed1 = QuantumCircuit(q2, c2)
mixed2 = QuantumCircuit(q2, c2)
mixed2.x(q2)
mixed1.measure(q2[0], c2[0])
mixed1.measure(q2[1], c2[1])
mixed2.measure(q2[0], c2[0])
mixed2.measure(q2[1], c2[1])

mixed1.draw(output='mpl')

mixed2.draw(output='mpl')

mixed_state = [mixed1,mixed2]
job = execute(mixed_state, backend)
result = job.result()

counts1 = result.get_counts(mixed_state[0])
counts2 = result.get_counts(mixed_state[1])

from collections import Counter
ground = Counter(counts1)
excited = Counter(counts2)
plot_histogram(ground+excited)

backend = Aer.get_backend('') # select the appropriate backend

# Create registers
q2 = QuantumRegister(2)
c2 = ClassicalRegister(2)

# Create the Bell's State
bell = QuantumCircuit(q2, c2)
bell.h(q2[0])
bell.cx(q2[0], q2[1])

# Run the job to see the matrix that creates the entanglement
circuit = bell
job = execute(circuit, backend)
result = job.result()

print(result.get_unitary(bell, decimals=3))

backend = Aer.get_backend('') # select the appropriate simulator

# Create registers
q2 = QuantumRegister(2)
c2 = ClassicalRegister(2)

# Create the mixed state
mix1 = QuantumCircuit(q2, c2)
mix2 = QuantumCircuit(q2, c2)
mix1.iden(q2)
mix2.x(q2)

# Execute the circuits to obtain the matrices
mixed_state = [mix1,mix2]
job = execute(mixed_state, backend)
result = job.result()

print(result.get_unitary(mixed_state[0], decimals=3),'\n \n',result.get_unitary(mixed_state[1],decimals=3))


backend= Aer.get_backend('qasm_simulator')

q2 = QuantumRegister(2)
c2 = ClassicalRegister(2)

# Create Bell's State
env = QuantumCircuit(q2, c2)
env.h(q2[0])
env.cx(q2[0], q2[1])

# Apply the X gates
env.x(q2[0])
env.iden(q2[1])
env.iden(q2[0])
env.x(q2[1])

meas = QuantumCircuit(q2, c2)
meas.measure(q2[0], c2[0])
meas.measure(q2[1], c2[1])
env = env+meas

env.draw(output='mpl')

circuit = env
job = execute(circuit, backend)
result = job.result()

plot_histogram(result.get_counts(env))