# Imports from Qiskit Terra
from qiskit.circuit import QuantumCircuit
from qiskit.visualization import plot_bloch_vector, plot_bloch_multivector, plot_state_qsphere, plot_histogram, visualize_transition
from qiskit.quantum_info import Pauli, PauliList, Statevector

# Imports from Qiskit Aer
from qiskit import Aer, execute

# Creation of multi-qubit circuit
q_multi = QuantumCircuit()    # Mention multi-quantum and classical bits in args

# Display circuit
q_multi.draw()

cx_circ = QuantumCircuit()    # Mention number of quantum and classical bits in args

# Apply CX gate to the qubits [0 - Control qubit; 1 - Target qubit]

# Draw the circuit
cx_circ.draw()

# Bloch Sphere visualization
state = Statevector(cx_circ)    # Statevector of the circuit
plot_bloch_multivector(state)

# Let's measaure the multi-qubit circuit
cx_circ.measure()    # Add measurement gate with appropriate args

# Draw the circuit
cx_circ.draw()

# Import the backend
backend = Aer.get_backend('qasm_simulator')

# Creating a job and extracting results
job = execute(cx_circ, backend = backend, shots = 1024)
result = job.result()
counts = result.get_counts()

# Plotting the counts
plot_histogram(counts)

# Do you know some of the quantum gates are reversible? 
# Can you verify what happens when you apply these gates twice?

reverse_gate_circ = QuantumCircuit(2, 2)

# Apply 2 CX gates on the same qubits
## APPLY GATE 1 HERE ##
## APPLY GATE 2 HERE ##

# Draw circuit
reverse_gate_circ.draw()

# Send the circuit to a simulator to check the results!

# Your blank canvas to apply the Toffoli gate!

# Let us contruct the circuit for the first Bell state |phi+>
entangled_circ = QuantumCircuit(2, 2)

# Apply H gate follwoed by a CX gate on the qubits [0 - Control qubit; 1 - Target qubit]

# Draw the circuit
entangled_circ.draw()

# Let's measaure the multi-qubit circuit
entangled_circ.measure([0, 1], [0, 1])    # Add measurement gate with appropriate args

# Draw the circuit
entangled_circ.draw()

# Import the backend
backend = Aer.get_backend('qasm_simulator')

# Creating a job and extracting results
job = execute(entangled_circ, backend = backend, shots = 1024)
result = job.result()
counts = result.get_counts()

# Plotting the counts
plot_histogram(counts)    # Don't forget Qiskit uses a little-endian notation !

# Do you know there are 4 different Bell States? Can you build a circuit for the rest 3 Bell States?