%matplotlib inline
# Importing standard Qiskit libraries and configuring account
from qiskit import *
from qiskit.visualization import *
import numpy as np

# Create a quantum register with 2 qubits
q = QuantumRegister(2,'q')
# Form a quantum circuit
# Note that the circuit name is optional
qc = QuantumCircuit(q,name="first_qc")
# Display the quantum circuit
qc.draw()

# Add a Hadamard gate on qubit 0, putting this in superposition.
qc.h(0)
# Add a CX (CNOT) gate on control qubit 0 
# and target qubit 1 to create an entangled state.
qc.cx(0, 1)
qc.draw()

# Create a classical register with 2 bits
c = ClassicalRegister(2,'c')

meas = QuantumCircuit(q,c,name="first_m")
meas.barrier(q)
meas.measure(q, c)

meas.draw()

# Quantum circuits can be added with + operations
# Add two pre-defined circuits
qc_all=qc+meas
qc_all.draw()

# Draw the quantum circuit in a different (slightly better) format
qc_all.draw(output='mpl')

# Create the quantum circuit with the measurement in one go.
qc_all = QuantumCircuit(q,c,name="2q_all")
qc_all.h(0)
qc_all.cx(0,1)
qc_all.barrier()
qc_all.measure(0,0)
qc_all.measure(1,1)
qc_all.draw(output='mpl')

# Use Aer's qasm_simulator
backend_q = Aer.get_backend('qasm_simulator')

# Execute the circuit on the qasm simulator.
job_sim1 = execute(qc_all, backend_q, shots=4096)

job_sim1.status()

# Grab the results from the job.
result_sim1 = job_sim1.result()
result_sim1

result_sim1.get_counts(qc_all)

plot_histogram(result_sim1.get_counts(qc_all))

# Use Aer's statevector_simulator
backend_sv = Aer.get_backend('statevector_simulator')

# Execute the circuit on the statevector simulator.
# It is important to note that the measurement has been excluded
job_sim2 = execute(qc, backend_sv)

# Grab the results from the job.
result_sim2 = job_sim2.result()
# Output the entire result
result_sim2

# See output state as a vector
outputstate = result_sim2.get_statevector(qc, decimals=5)
print(outputstate)

# Visualize density matrix
plot_state_city(outputstate)

# Create the quantum circuit with the measurement in one go.
qc_3 = QuantumCircuit(3,3,name="qc_bloch")
qc_3.x(1)
qc_3.h(2)
qc_3.barrier()
qc_3.draw(output='mpl')

# Execute the circuit on the statevector simulator.
# It is important to note that the measurement has been excluded
job_sim_bloch = execute(qc_3, backend_sv)

# Grab the results from the job.
result_sim_bloch = job_sim_bloch.result()

# See output state as a vector
output_bloch = result_sim_bloch.get_statevector(qc_3, decimals=5)

# Draw on the Bloch sphere
plot_bloch_multivector(output_bloch)

# Use Aer's unitary_simulator
backend_u = Aer.get_backend('unitary_simulator')

# Execute the circuit on the unitary simulator.
job_usim = execute(qc, backend_u)

# Grab the results from the job.
result_usim = job_usim.result()
result_usim

# Output the unitary matrix
unitary = result_usim.get_unitary(qc)
print('%s\n' % unitary)

# Create the quantum circuit with the measurement in one go.
qc_ex1 = QuantumCircuit(q,c,name="ex1")

# Put the first qubit in equal superposition
qc_ex1.h(0)

# Rest of the circuit
qc_ex1.x(1)
qc_ex1.cx(0,1)
qc_ex1.barrier()
qc_ex1.measure(0,0)
qc_ex1.measure(1,1)
qc_ex1.draw(output='mpl')

# Execute the circuit on the qasm simulator.
job_ex1 = execute(qc_ex1, backend_q, shots=4096)

job_ex1.status()

# Grab the results from the job.
result_ex1 = job_ex1.result()
result_ex1.get_counts(qc_ex1)

plot_histogram(result_ex1.get_counts(qc_ex1))

# Or get the histogram in one go
plot_histogram(job_ex1.result().get_counts(qc_ex1))

# Create a quantum register with 3 qubits
q3 = QuantumRegister(3,'q')
# Create a classical register with 3 qubits
c3 = ClassicalRegister(3,'c')

# Create the quantum circuit with the measurement in one go.
qc_ex2 = QuantumCircuit(q3,c3,name="ex1")

qc_ex2.ry(2*np.pi/3,0)
qc_ex2.cx(0,1)
qc_ex2.cx(1,2)
qc_ex2.barrier()
qc_ex2.measure(q3,c3)
qc_ex2.draw(output='mpl')

# Execute the circuit on the qasm simulator.
job_ex2 = execute(qc_ex2, backend_q, shots=4096)

# Grab the results from the job.
result_ex2 = job_ex2.result()
plot_histogram(result_ex2.get_counts(qc_ex2))

# Create a quantum register with 3 qubits
q3 = QuantumRegister(3,'q')
# Create a classical register with 3 qubits
c3 = ClassicalRegister(3,'c')

# Create the quantum circuit without a Toffoli gate
qc_toff = QuantumCircuit(q3,c3,name="ex1")

qc_toff.ry(2*np.pi/3,0)
qc_toff.h(1)
qc_toff.h(2)
qc_toff.barrier()
qc_toff.measure(q3,c3)
qc_toff.draw(output='mpl')

# Execute the circuit on the qasm simulator.
job_toff = execute(qc_toff, backend_q, shots=4096)

# Grab the results from the job.
result_toff = job_toff.result()
plot_histogram(result_toff.get_counts(qc_toff))

# Now, add a Toffoli gate
qc_toff = QuantumCircuit(q3,c3,name="ex1")

qc_toff.ry(2*np.pi/3,0)
qc_toff.h(1)
qc_toff.h(2)
qc_toff.ccx(1,2,0)
qc_toff.barrier()
qc_toff.measure(q3,c3)
qc_toff.draw(output='mpl')

# Execute the circuit on the qasm simulator.
job_toff = execute(qc_toff, backend_q, shots=4096)

# Grab the results from the job.
result_toff = job_toff.result()
plot_histogram(result_toff.get_counts(qc_toff))

IBMQ.disable_account()
provider = IBMQ.enable_account('IBM_TOKEN')

# provider = IBMQ.get_provider(hub='ibm-q-research')

provider.backends()

from qiskit.tools.monitor import backend_overview, backend_monitor, job_monitor
from qiskit.tools.visualization import plot_gate_map, plot_error_map

# Retrieve IBM Quantum device information
backend_overview()

# Let's get two quantum devices as an example
backend_qx2 = provider.get_backend('ibmqx2')
backend_vigo = provider.get_backend('ibmq_vigo')

backend_monitor(backend_qx2)

plot_error_map(backend_qx2)

backend_monitor(backend_vigo)

plot_error_map(backend_vigo)

![sdc2](jupyter_img/superdensecoding2.png)# Create a 5-qubit GHZ state (i.e. (|00000> + |11111>)/sqrt(2))
q5 = QuantumRegister(5,'q')
c5 = ClassicalRegister(5,'c')
ghz5= QuantumCircuit(q5,c5)

ghz5.h(0)
for i in range(1,5):
    ghz5.cx(0,i)

ghz5.barrier()
ghz5.measure(q5,c5)
ghz5.draw(output='mpl')

# Run the 5-qubit GHZ experiment on a 5-qubit device (try vigo)
job_exp1 = execute(ghz5, backend=backend_vigo, shots=4096)
job_monitor(job_exp1)

# Grab experimental results
result_vigo = job_exp1.result()
counts_vigo = result_vigo.get_counts(ghz5)

# Let's also try the same experiment on the 14-qubit device.
job_exp2 = execute(ghz5, backend=provider.get_backend('ibmq_16_melbourne'), shots=4096)
job_monitor(job_exp2)

# Grab experimental results
result_mel = job_exp2.result()
counts_mel = result_mel.get_counts(ghz5)

# Now, compare to theory by running it on qasm_simulator
job_qasm = execute(ghz5,backend=backend_q)
result_qasm = job_qasm.result()
counts_qasm = result_qasm.get_counts(ghz5)

# Plot both experimental and ideal results
plot_histogram([counts_qasm,counts_vigo,counts_mel],
               color=['black','green','blue'],
               legend=['QASM','Vigo','Melbourne'],figsize = [20,8])

