<jupyter_start><jupyter_text>Lección 4: Protocolo de codificación densaLos estados entrelazados, como lo hemos visto en las sesiones anteriores, permiten realizar cosas bastante interesantes. La propiedad de entrelazamiento entre un par de partículas dio pie para la proposición de diferentes protocolos cuánticos cuyas posibles aplicaciones se exploran aún en la actualidad.En esta lección analizaremos en detalle el protocolo de codificación densa. Este protocolo es posible gracias a las propiedades del entrelazamiento entre dos partículas. Las fuentes de este tipo de partículas las llamaremos fuentes EPR por los autores del artículo *Can Quantum-Mechanical Description of Physical Reality Be Considered Complete?* publicado por <NAME>, <NAME>, y <NAME> en 1935 en donde se muestra como el formalismos de la mecánica cuántica permite que un par de partículas compartan esta propiedad de entrelazamiento.**SUPER IMPORTANTE:** En este ejemplo intentaremos presentar al lector cómo simular el protocolo cuántico de teleportación en un computador cuántico. Esta sesiónes está disponible en nuestro servidor de MyBinder.​        Como de costumbre realizamos las importaciones necesarias para neustro circuito.<jupyter_code>from qiskit import QuantumRegister, ClassicalRegister
from qiskit import QuantumCircuit, execute, Aer
from qiskit.visualization import plot_histogram,state_visualization
from qiskit.quantum_info.operators import Operator
import matplotlib.pyplot as plt
import numpy as np<jupyter_output><empty_output><jupyter_text>Para realizar este protocolo primero tenemos que definir lo que se conoce como un *alfabeto*, esto es, a ciertos estados cuánticos, les vamos a asignar cierta información. En este caso presentaremos el protocolo para enviar un mensaje de 2 bits. entonces la asignación que definimos va a ser.$$ 00 \longrightarrow |\Phi^+\rangle_{AB} = \frac{1}{\sqrt{2}}\left(|00 \rangle + |11\rangle\right)$$$$ 01 \longrightarrow |\Psi^+\rangle_{AB} = \frac{1}{\sqrt{2}}\left(|01 \rangle + |10\rangle\right)$$$$ 10 \longrightarrow |\Phi^-\rangle_{AB} = \frac{1}{\sqrt{2}}\left(|00 \rangle - |11\rangle\right)$$$$ 11 \longrightarrow |\Psi^-\rangle_{AB} = \frac{1}{\sqrt{2}}\left(|01 \rangle - |10\rangle\right)$$El protocolo se puede ilustrar en la siquiente imagen.- Paso 1: Una fuente EPR, la cual es una fuente de partículas entrelazadas, entrega un par de partículas entrelazadas a Alice y Bob. A la partícula de Alice la llamamos $A$ y a la partícula de Bob la llamamos $B$. Estas partículas deben estar entrelazadas en un estado de Bell, en este ejemplo partícular elegimos el estado de la forma $|\Phi^{+}\rangle_{AB} = \frac{1}{\sqrt{2}}|00\rangle + \frac{1}{\sqrt{2}} |11\rangle$.- Paso 2: Bob realiza una operación unitaria sobre su qubit dependiendo de el mensaje que el desea enviar, las posibilidades que el tiene son:$$I_B |\Phi^+\rangle\rightarrow |\Phi^+\rangle \rightarrow 00$$$$X_B |\Phi^+\rangle\rightarrow |\Psi^+\rangle \rightarrow 01$$$$Z_B |\Phi^+\rangle\rightarrow |\Phi^-\rangle \rightarrow 10$$$$X_B Z_B |\Phi^+\rangle\rightarrow |\Psi^-\rangle \rightarrow 11\hspace{1.1em}$$   Por ejemplo si el quisiera enviar el mensaje $01$, entonces debe aplicar una compuerta NOT sobre su qubit para formar este mensaje.- Paso 3: Luego de que Bob realiza la operación unitaria sobre su qubit, el se lo envía a Alice para que ella realiza una medición del estado de Bell (BSM) entre los dos qubits y de acuerdo a su resultado ella sabrá que mensaje le quiso enviar Bob.Para realizar el protocolo definimos la una función que es la que va a entrelazar los dos qubits en el estado deseado.<jupyter_code>def entangle_qubits(circuit, q_Alice, q_Bob):
    
    ## Entrelazamos un par de qubits en un estado de Bell
    circuit.h(q_Alice)                 ## Hadamard sobre el qubit de Alice
    circuit.cx(q_Alice,q_Bob)          ## CNOT para entrelazar los qubits de Alice y Bob
     
    
    return circuit<jupyter_output><empty_output><jupyter_text>Luego definimos una función que, de acuerdo con el mensaje que desea enviar Bob se realiza una operación unitaria<jupyter_code>def Bob_transformation (circuit, q_Bob, message):
    
    ## Si el mensaje es '00' No se realiza ninguna operación
    if (message == '00'):
        return circuit
    
    ## Si el mensaje es '01' se niega el qubit de bob
    elif (message == '01'):
        circuit.x(q_Bob)
        return circuit
    
    ## Si el mensaje es '10' se agrega una fase relativa de pi al qubit de Bob
    elif (message == '10'):
        circuit.z(q_Bob)
        return circuit
    
    ## Si el mensaje es '11' se niega y se agrega una fase relativa de pi al qubit de bob
    elif (message == '11'):
        circuit.z(q_Bob)
        circuit.x(q_Bob)
        return circuit<jupyter_output><empty_output><jupyter_text>Ahora definimos una función que nos permite realizar una medición de un estado de Bell entre dos qubits.<jupyter_code>def bell_measurement(circuit, q_Alice, q_Bob, c_Alice, c_Bob):
    
    ## Acá Alice realiza la medición del estado de Bell para esto lleva los estados a dicha base y realiza la medición
    circuit.cx(q_Alice, q_Bob)
    circuit.h(q_Alice)
    
    ## Los resultados que obtenga Alice indicarán El mensaje que le quiso enviar Bob
    circuit.barrier()
    circuit.measure(q_Alice, c_Alice)
    circuit.measure(q_Bob, c_Bob)

    return circuit<jupyter_output><empty_output><jupyter_text>Ahora iniciamos un circuito y ejecutamos el protocolo<jupyter_code>## Inicializamos todo el circuito 
qubit_Alice = QuantumRegister(1)
qubit_Bob = QuantumRegister(1)
cr_Alice = ClassicalRegister(1)
cr_Bob = ClassicalRegister(1)

## Acá ejecutamos el protocolo, primero inicializamos nuestro circuito
qc = QuantumCircuit(qubit_Alice, qubit_Bob, cr_Alice, cr_Bob)

## Paso 1: Entregamos a Bob y a Alice un par de partículas enrtelazadas
entangle_qubits(qc, qubit_Alice, qubit_Bob)
qc.barrier()

## Paso 2: Bob realiza una una operación de acuerdo al mensaje que desea enviar
message = '10'
Bob_transformation(qc,  qubit_Bob, message)
qc.barrier()

## Paso 3: Alice realiza una medición del estado de Bell con el qubit de Bob para ver el mensaje
bell_measurement(qc, qubit_Alice, qubit_Bob, cr_Alice, cr_Bob)


## El circuito toma la forma
qc.draw(output='mpl')<jupyter_output><empty_output><jupyter_text>Ahora mostramos el histograma de las mediciones que obtuvo Alice.<jupyter_code>## Simulamos el circuito
backend = Aer.get_backend('qasm_simulator')
counts = execute(qc,backend,shots=10000).result().get_counts()


## Mostramos el histograma para el qubit de Bob
plot_histogram(counts)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.08173729452571256, 'fraction_numerical': 0.013723420298597496, 'mean_word_length': 4.61082910321489, 'pattern_counts': {'":': 0, '<': 28, '<?xml version=': 0, '>': 28, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '215943', 'license': 'MIT', 'n_tokens_mistral': 2237, 'n_tokens_neox': 2097, 'n_words': 789, 'path': 'Lec_4_Dense_coding/Lec_4_Dense_Coding.ipynb', 'repo_name': 'QC-FEM/QC-CrashCourse', 'size': '6654'}