import numpy as np
zero_ket = np.array([[1], [0]])
print("|0> ket:\n", zero_ket)
print("<0| bra:\n", zero_ket.T.conj())

zero_ket.T.conj() @ zero_ket

one_ket = np.array([[0], [1]])
zero_ket.T.conj() @ one_ket

zero_ket @ zero_ket.T.conj()

ψ = np.array([[1], [0]])/np.sqrt(2)
Π_0 = zero_ket @ zero_ket.T.conj()
ψ.T.conj() @ Π_0 @ ψ

from qiskit import QuantumCircuit, execute,QuantumCircuit, ClassicalRegister, QuantumRegister, Aer
from math import pi
import numpy as np
from qiskit.visualization import plot_bloch_multivector, plot_histogram
%matplotlib inline

q = QuantumRegister(1)
c = ClassicalRegister(1)
circuit = QuantumCircuit(q, c)
# Apply H-gate to each qubit:
circuit.h(q[0])
circuit.measure(q, c)
circuit.draw('mpl')

# Let's see the result:
backend = Aer.get_backend('qasm_simulator')
results = execute(circuit,backend, shots=1000).result()
counts  = results.get_counts(circuit)
print(counts)

plot_histogram(counts)

ψ = np.array([[np.sqrt(2)/2], [np.sqrt(2)/2]])
Π_0 = zero_ket @ zero_ket.T.conj()
probability_0 = ψ.T.conj() @ Π_0 @ ψ
Π_0 @ ψ/np.sqrt(probability_0)

backend = Aer.get_backend('qasm_simulator')
q1 = QuantumRegister(1)
c1 = ClassicalRegister(2)
circuit1 = QuantumCircuit(q1, c1)
circuit1.h(q1[0])
circuit1.measure(q1[0], c1[0])
circuit1.measure(q1[0], c1[1])
circuit1.draw('mpl')

results = execute(circuit1,backend, shots=1000).result()
counts1  = results.get_counts(circuit1)
print(counts1)

plot_histogram(counts1)

q = QuantumRegister(2)
c = ClassicalRegister(2)
circuit = QuantumCircuit(q, c)
circuit.h(q[0])
circuit.measure(q, c)
job = execute(circuit, backend, shots=1000)
plot_histogram(job.result().get_counts(circuit))

q = QuantumRegister(2)
c = ClassicalRegister(2)
circuit = QuantumCircuit(q, c)
circuit.h(q[0])
circuit.cx(q[0], q[1])
circuit.measure(q, c)
circuit.draw('mpl')


job = execute(circuit, backend, shots=1000)
plot_histogram(job.result().get_counts(circuit))

ψ = np.array([[1], [1]])/np.sqrt(2)
ρ = ψ @ ψ.T.conj()
Π_0 = zero_ket @ zero_ket.T.conj()
np.trace(Π_0 @ ρ)

probability_0 = np.trace(Π_0 @ ρ)
Π_0 @ ρ @ Π_0/probability_0

zero_ket = np.array([[1], [0]])
one_ket = np.array([[0], [1]])
ψ = (zero_ket + one_ket)/np.sqrt(2)
print("Density matrix of the equal superposition")
print(ψ @ ψ.T.conj())
print("Density matrix of the equally mixed state of |0><0| and |1><1|")
print((zero_ket @ zero_ket.T.conj()+one_ket @ one_ket.T.conj())/2)