!pip install -U -r resources/requirements.txt

from IPython.display import clear_output
clear_output()

from qiskit import QuantumCircuit

mycircuit = QuantumCircuit(1)
mycircuit.draw('mpl')

from qiskit.quantum_info import Statevector

sv = Statevector.from_label('0')

sv

sv.data

new_sv = sv.evolve(mycircuit)

new_sv

from qiskit.quantum_info import state_fidelity

state_fidelity(sv, new_sv)

from qiskit.visualization import plot_state_qsphere

plot_state_qsphere(sv.data)

mycircuit = QuantumCircuit(1)
mycircuit.x(0)

mycircuit.draw('mpl')

sv = Statevector.from_label('0')
new_sv = sv.evolve(mycircuit)
new_sv

state_fidelity(new_sv, sv)

plot_state_qsphere(new_sv.data)

sv = Statevector.from_label('0')
mycircuit = QuantumCircuit(1)
mycircuit.h(0)
mycircuit.draw('mpl')

new_sv = sv.evolve(mycircuit)
print(new_sv)
plot_state_qsphere(new_sv.data)

sv = Statevector.from_label('1')
mycircuit = QuantumCircuit(1)
mycircuit.h(0)

new_sv = sv.evolve(mycircuit)
print(new_sv)
plot_state_qsphere(new_sv.data)

from resources.qiskit_textbook.widgets import gate_demo
gate_demo(qsphere=True)

sv = Statevector.from_label('00')
plot_state_qsphere(sv.data)

mycircuit = QuantumCircuit(2)
mycircuit.h(0)
mycircuit.cx(0,1)
mycircuit.draw('mpl')

new_sv = sv.evolve(mycircuit)
print(new_sv)
plot_state_qsphere(new_sv.data)

counts = new_sv.sample_counts(shots=1000)

from qiskit.visualization import plot_histogram
plot_histogram(counts)

Tri3=QuantumCircuit(2,2)
Tri3.x(1)
Tri3.h(0)
Tri3.cx(0, 1)
Tri3.draw()

tri3_sv = sv.evolve(Tri3)
print(tri3_sv)
plot_state_qsphere(tri3_sv.data)

counts1 = tri3_sv.sample_counts(shots=1000)

from qiskit.visualization import plot_histogram
plot_histogram(counts1)

#create the above bell state
Sing = QuantumCircuit(2, 2)
#make the gates
Sing.x(1) 
Sing.h(0) 
Sing.z(0) 
Sing.z(1) 
Sing.cx(0,1)
Sing.draw()

#print out the statevector
sing_sv = sv.evolve(Sing)
print(sing_sv)
#plot the statevector on qshere
plot_state_qsphere(sing_sv.data)


mycircuit = QuantumCircuit(2, 2)
mycircuit.h(0)
mycircuit.cx(0,1)
mycircuit.measure([0,1], [0,1])
mycircuit.draw('mpl')

from qiskit import Aer, execute
simulator = Aer.get_backend('qasm_simulator')
result = execute(mycircuit, simulator, shots=10000).result()
counts = result.get_counts(mycircuit)
plot_histogram(counts)

def initialize_qubit(given_circuit, qubit_index):
    
    import numpy as np
    ### WRITE YOUR CODE BETWEEN THESE LINES - START
    initial_state = [np.sqrt(0.70)+0.j,np.sqrt(0.30)+0.j]
    
    ### WRITE YOUR CODE BETWEEN THESE LINES - END
    given_circuit.initialize(initial_state, 0)
    return given_circuit



def entangle_qubits(given_circuit, qubit_Alice, qubit_Bob):
    
    ### WRITE YOUR CODE BETWEEN THESE LINES - START
    given_circuit.h(qubit_Alice)
    given_circuit.cx(qubit_Alice,qubit_Bob)
    
    ### WRITE YOUR CODE BETWEEN THESE LINES - END
    
    return given_circuit

def bell_meas_Alice_qubits(given_circuit, qubit1_Alice, qubit2_Alice, clbit1_Alice, clbit2_Alice):
    
    ### WRITE YOUR CODE BETWEEN THESE LINES - START
    given_circuit.cx(qubit1_Alice,qubit2_Alice)
    given_circuit.h(qubit1_Alice)
    given_circuit.measure(qubit1_Alice,clbit1_Alice)
    given_circuit.measure(qubit2_Alice,clbit2_Alice)

    ### WRITE YOUR CODE BETWEEN THESE LINES - END

    return given_circuit

def controlled_ops_Bob_qubit(given_circuit, qubit_Bob, clbit1_Alice, clbit2_Alice):
    
    ### WRITE YOUR CODE BETWEEN THESE LINES - START
    given_circuit.x(qubit_Bob).c_if(clbit2_Alice, 1)
    given_circuit.z(qubit_Bob).c_if(clbit1_Alice, 1)

    ### WRITE YOUR CODE BETWEEN THESE LINES - END
    
    return given_circuit

### imports
from qiskit import QuantumRegister, ClassicalRegister

### set up the qubits and classical bits
all_qubits_Alice = QuantumRegister(2)
all_qubits_Bob = QuantumRegister(1)
creg1_Alice = ClassicalRegister(1)
creg2_Alice = ClassicalRegister(1)

### quantum teleportation circuit here
# Initialize
mycircuit = QuantumCircuit(all_qubits_Alice, all_qubits_Bob, creg1_Alice, creg2_Alice)
initialize_qubit(mycircuit, 0)
mycircuit.barrier()
# Entangle
entangle_qubits(mycircuit, 1, 2)
mycircuit.barrier()
# Do a Bell measurement
bell_meas_Alice_qubits(mycircuit, all_qubits_Alice[0], all_qubits_Alice[1], creg1_Alice, creg2_Alice)
mycircuit.barrier()
# Apply classically controlled quantum gates
controlled_ops_Bob_qubit(mycircuit, all_qubits_Bob[0], creg1_Alice, creg2_Alice)

### Look at the complete circuit
mycircuit.draw()