!pip3 install qiskit 
# !pip install pylatexenc

import qiskit as q
import matplotlib.pyplot as plt

qr = q.QuantumRegister(2)
cr = q.ClassicalRegister(2)

circuit = q.QuantumCircuit(qr, cr)
circuit.draw()

circuit.h(qr[0]) # apply hadamard gate on first qubit. 
circuit.h(qr[1]) # apply hadamard gate on second qubit. 
# apply cnot gate. 
circuit.cx(qr[0], qr[1]) # in qiskit cnot-- first bit is set as control bit and second as target bit. 
display(circuit.draw())

#### see the state-vector 
statevec = q.Aer.get_backend('statevector_simulator')
final_state = q.execute(circuit, statevec).result().get_statevector()
q.visualization.plot_bloch_multivector(final_state) # the state doesn't not change after application of the CNOT gate 

circuit.measure(qr, cr)
circuit.draw(scale=2)

#### simulate result on a local computer 

simulator = q.Aer.get_backend(name='qasm_simulator')
results = q.execute(circuit, backend=simulator, ).result()
q.visualization.plot_histogram(results.get_counts(circuit)) 

### try a different circuit where we apply X gate before applying H gate. 

qr1 = q.QuantumRegister(2)
cr1 = q.ClassicalRegister(2)

circuit1 = q.QuantumCircuit(qr1, cr1)
# circuit1.draw()


circuit1.h(qr1[0]) # apply the H gate on q0
circuit1.x(qr1[1]) # apply Not gate on q_1
circuit1.h(qr1[1]) # add H gate on q_1
circuit1.cx(qr1[0], qr1[1]) # apply cx gate with control bit at 0th index 

### draw the circuit
circuit1.draw()

#### plt the state vector 

statevec1 = q.Aer.get_backend('statevector_simulator')
final_state1 = q.execute(circuit1, statevec1).result().get_statevector()
q.visualization.plot_bloch_multivector(final_state1) # the state doesn't not change after application of the CNOT gate 
#### unchanged state as expected 

circuit1.measure(qr1, cr1)
### simulate result on local computer 
simulator1 = q.Aer.get_backend('qasm_simulator')
results1 = q.execute(circuit1, backend=simulator1, ).result()
q.visualization.plot_histogram(results1.get_counts(circuit1)) 

### try a different circuit where we apply X gate before applying H gate. 
### but we do this for first qubit. 

qr2 = q.QuantumRegister(2)
cr2 = q.ClassicalRegister(2)

circuit2 = q.QuantumCircuit(qr2, cr2)
# circuit2.draw()
circuit2.x(qr2[0])
circuit2.h(qr2[0])
circuit2.h(qr2[1])
circuit2.cx(qr2[0], qr2[1])
circuit2.draw()

#### plt the state vector 

statevec2 = q.Aer.get_backend('statevector_simulator')
final_state2 = q.execute(circuit2, statevec2).result().get_statevector()
q.visualization.plot_bloch_multivector(final_state2) 

circuit2.measure(qr2, cr2)
### simulate result on local computer 
simulator2 = q.Aer.get_backend('qasm_simulator')
results2 = q.execute(circuit2, backend=simulator1, ).result()
q.visualization.plot_histogram(results2.get_counts(circuit2)) 

qr3 = q.QuantumRegister(2)
cr3 = q.ClassicalRegister(2)

circuit3 = q.QuantumCircuit(qr3, cr3)
# circuit3.draw()

circuit3.h(qr3[0])
circuit3.h(qr3[1])
## apply hadamard gates to both qubits. 
circuit3.cx(qr3[0], qr3[1])
## till this is first circuit. Now we add one more H gate. 
circuit3.h(qr3[0])
circuit3.draw(scale=2)

### plot the state vector 

statevec3 = q.Aer.get_backend('statevector_simulator')
final_state3 = q.execute(circuit3, statevec3).result().get_statevector()
q.visualization.plot_bloch_multivector(final_state3)  

# let's simulate this on local computer 

circuit3.measure(qr3, cr3)
### simulate result on local computer 
simulator3 = q.Aer.get_backend('qasm_simulator')
results3 = q.execute(circuit3, backend=simulator3, ).result()
q.visualization.plot_histogram(results3.get_counts(circuit3)) 

qr4 = q.QuantumRegister(2)
cr4 = q.ClassicalRegister(2)

circuit4 = q.QuantumCircuit(qr4, cr4)

circuit4.h(qr4[0])
circuit4.h(qr4[1])
## apply hadamard gates to both qubits. 
circuit4.cx(qr4[0], qr4[1])
## till this is first circuit. Now we add one more H gate. 
circuit4.h(qr4[1]) # but now apply the H gate to the second qubit. 
circuit4.draw(scale=2)

### plot the state vector 

statevec4 = q.Aer.get_backend('statevector_simulator')
final_state4 = q.execute(circuit4, statevec4).result().get_statevector()
q.visualization.plot_bloch_multivector(final_state4)  

# let's simulate this on local computer 

circuit4.measure(qr4, cr4)
### simulate result on local computer 
simulator4 = q.Aer.get_backend('qasm_simulator')
results4 = q.execute(circuit4, backend=simulator4, ).result()
q.visualization.plot_histogram(results4.get_counts(circuit4))  ### !!! great !!! as expected 

