Get started with IBM Quantum Experience & Supercomputing Virtual Forum Demo

cahyati sangaji (cahya)
20 min readJul 1, 2020

--

Cahyati Supriyati Sangaji (My Note)

Preparation

link : https://quantum-computing.ibm.com/

Login with IBMid

Use Jupyter notebook (Anaconda) → for windows

Python programming with Jupyter Notebooks

Install qiskit → pip install qiskit

Get started (Code your first quantum circuit)

Import packages

The import lines import the basic elements (packages and functions) needed for your program. The following imports are the default imports for any new Jupyter Notebook in Anaconda, so they do no appear in the code snippet.

%matplotlib inline
import numpy as np
#!pip install qiskit
from qiskit import ClassicalRegister, QuantumRegister
# Importing standard Qiskit libraries and configuring account
from qiskit import QuantumCircuit, execute, Aer, IBMQ
from qiskit.compiler import transpile, assemble
from qiskit.tools.jupyter import *
from qiskit.visualization import *
from qiskit.providers.ibmq import least_busy
from qiskit import providers

The imports used in the rest of the code example are

  • QuantumCircuit: Holds all your quantum operations; the instructions for the quantum system
  • execute: Runs your circuit
  • Aer: Handles simulator backends
  • qiskit.visualization: Enables data visualization, such as plot_histogram

Qiskit Aer: Simulators

qc = QuantumCircuit(2,2)qc.h(0)
qc.cx(0,1)
qc.measure([0,1], [0,1])
backend = Aer.get_backend('qasm_simulator')
job_sim = execute(qc, backend)
sim_result = job_sim.result()
sim_result.get_counts(qc)

Output:

{'00': 539, '11': 485}

Learn to code your first quantum circuit without downloading anything to your computer, by using Jupyter Notebooks. While you can benefit from having some familiarity with Python and quantum computing, you can get a sense of the big picture without those prerequisites.

Overview

To code any quantum circuit with Jupyter, you follow three high-level steps:

> Build: Design a quantum circuit that represents the problem you are considering.

> Execute: Run experiments on different backends, either systems or simulators.

> Analyze: Calculate summary statistics and visualize the results of experiments.

Run code in a Jupyter Notebook

  1. Go to IBM Quantum Experience.
  2. Sign in or Create an IBMid account.
  3. Copy Code Snippet 1 (below) and paste it in an empty code block cell in your new Jupyter Notebook.
  4. Click the Run button.

Code Snippet 1

# Build
#------
# Create a Quantum Circuit acting on the q register
circuit = QuantumCircuit(2, 2)
# Add a H gate on qubit 0
circuit.h(0)
# Add a CX (CNOT) gate on control qubit 0 and target qubit 1
circuit.cx(0, 1)
# Map the quantum measurement to the classical bits
circuit.measure([0,1], [0,1])
# Execute
#--------
# Use Aer's qasm_simulator
simulator = Aer.get_backend('qasm_simulator')
# Execute the circuit on the qasm simulator
job = execute(circuit, simulator, shots=1000)
# Grab results from the job
result = job.result()
# Return counts
counts = result.get_counts(circuit)
print("\nTotal count for 00 and 11 are:",counts)
# Analyze
#--------
# Draw the circuit
circuit.draw()

Plot a histogram

  1. To see a visualization of the results, copy and paste Code Snippet 2 into the next empty cell in your notebook.
  2. Run the cell by holding the Shift key and then pressing the Enter/Return key on your keyboard.
# Analyze
#--------
# Plot a histogram
plot_histogram(counts

Initialize variables

In the next line of code, you initialize two qubits in the zero state, and two classical bits in the zero state, in the quantum circuit called circuit.

circuit = QuantumCircuit(2, 2)

Add gates

The next three lines of code, beginning with circuit., add gates that manipulate the qubits in your circuit.

circuit.h(0)
circuit.cx(0, 1)
circuit.measure([0,1], [0,1])

Output :

<qiskit.circuit.instructionset.InstructionSet at 0x1fbedd485c8>

The code above applies the following gates:

  • QuantumCircuit.h(0): A Hadamard gate on qubit 0, which puts it into a superposition state
  • QuantumCircuit.cx(0, 1): A controlled-NOT operation () on control qubit 0 and target qubit 1, putting the qubits in an entangled state
  • QuantumCircuit.measure([0,1], [0,1]): The first argument indexes the qubits, the second argument indexes the classical bits. The nth qubit’s measurement result will be stored in the nth classical bit.

This particular trio of gates added one-by-one to the circuit forms the Bell state,

In this state, there is a 50 percent chance of finding both qubits to have the value zero and a 50 percent chance of finding both qubits to have the value one.

Simulate the experiment

The next line of code calls a specific simulator framework — in this case, it calls Qiskit Aer, which is a high-performance simulator that provides several backends to achieve different simulation goals.

In this program, you use the qasm_simulator. Each run of this circuit will yield either the bit string '00' or '11'.

simulator = Aer.get_backend('qasm_simulator')
job = execute(circuit, simulator, shots=1000)
result = job.result()
counts = result.get_counts(circuit)
print("\nTotal count for 00 and 11 are:",counts)

Output:

Total count for 00 and 11 are: {'00': 486, '11': 514}

The program specifies the number of times to run the circuit in the shots argument of the execute method (job = execute(circuit, simulator, shots=1000)). The number of shots of the simulation is set to 1000 (the default is 1024).

Once you have a result object, you can access the counts via the method get_counts(circuit). This gives you the aggregate outcomes of your experiment.

As expected, the output bit string is '00' approximately 50 percent of the time. This simulator does not model noise. Any deviation from 50 percent is due to the small sample size.

Visualize the circuit

QuantumCircuit.draw() (called by circuit.draw() in the code) displays your circuit in one of the various styles used in textbooks and research articles.

circuit.draw()

In this circuit, the qubits are ordered with qubit zero at the top and qubit one below it. The circuit is read from left to right, representing the passage of time.

Visualize the results

Qiskit provides many visualizations, including the function plot_histogram, to view your results.

plot_histogram(counts)

The probabilities (relative frequencies) of observing the and states are computed by taking the respective counts and dividing by the total number of shots.

Qiskit IBM Quantum Experience account

The IBM Quantum Experience is accessed through Qiskit via the account interface. This notebook gives an overview of how to use this account to access the systems and simulators available on the IBM Quantum Experience. Additionally, it will detail how to interact with, and retrieve, jobs associated with executing circuits on these backends.

In this tutorial, we will review the core components of Qiskit’s base backend framework, using the IBM Quantum Experience (IQX) account as an example.

The interface has four main components: the account, providers, backends, and jobs:

  • account: Gives access to one or more ‘providers’ based on the account’s permissions.
  • provider: Provides access to quantum devices and simulators, collectively called ‘backends’, and additional services tailored to a specific backend instance.
  • backend: A quantum device or simulator capable of running quantum circuits or pulse schedules.
  • job: A local reference to a collection of quantum circuits or pulse schedules submitted to a given backend.

The Account

The Qiskit IBMQ account object is the local reference for accessing your IBM Quantum Experience account, and all of the providers, backends, etc, that are available to you.

The IBMQ account has functions for handling administrative tasks. The credentials can be saved to disk, or used in a session and never saved.

  • enable_account(TOKEN, HUB, GROUP, PROJECT): Enable your account in the current session and optionally specify a default provider to return.
  • save_account(TOKEN, HUB, GROUP, PROJECT): Save your account to disk for future use and optionally specify a default provider to return when loading your account.
  • load_account(): Load account using stored credentials.
  • disable_account(): Disable your account in the current session.
  • stored_account(): List the account stored to disk.
  • active_account(): List the account currently in the session.
  • delete_account(): Delete the saved account from disk.

A provider offers access to quantum systems, simulators, and additional services. To see all the providers available with your IQX account:

IBMQ.save_account('<your TOKEN>')
IBMQ.load_account() # Load account from disk
IBMQ.providers() # List all available providers

output:

[<AccountProvider for IBMQ(hub='ibm-q', group='open', project='main')>]

where we have assumed that the user has stored their IQX account information locally ahead of time using IBMQ.save_account(TOKEN). TOKEN here is the API token you obtain from your IQX account.

Note: The use of provider instances is the default way of retrieving backends from Qiskit 0.11 onwards - if you have been using earlier versions of Qiskit, check the “Updating from previous versions” section for more detailed instructions on updating and using the different options.

The above example shows two different providers. All IBMQ providers are specified by a hub, group, and project. The provider given by hub='ibm-q', group='open', project='main' is the provider that gives access to the public IBM Quantum devices available to all IQX users. The second is an example of a provider that is only unlocked for a specific set of users. Members of the IBM Q Network may see one or more providers (with names different than those shown above) depending on the access level granted to them.

To access a given provider one should use the get_provider() method of the IBMQ account, filtering by hub, group, or project:

IBMQ.get_provider(hub='ibm-q')

output

<AccountProvider for IBMQ(hub='ibm-q', group='open', project='main')>

Script:

IBMQ.get_provider(group='open')

output

<AccountProvider for IBMQ(hub='ibm-q', group='open', project='main')>

Finally, as a convenience, calling IBMQ.load_account() or IBMQ.enable_account() will return the default public provider instance <AccountProvider for IBMQ(hub='ibm-q', group='open', project='main')>.

The Provider

All providers inherit from qiskit.providers.BaseProvider and implement the methods:

  • backends(): Returns all backend objects known to the provider.
  • get_backend(NAME): Returns the named backend.

Providers associated via your IBMQ account provide access to a collection of different backends, such as those available through the open IBM Quantum Experience or the IBM Q Network.

Using the public provider instance from above:

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

Output :

[<IBMQSimulator('ibmq_qasm_simulator') from IBMQ(hub='ibm-q', group='open', project='main')>,
<IBMQBackend('ibmqx2') from IBMQ(hub='ibm-q', group='open', project='main')>,
<IBMQBackend('ibmq_16_melbourne') from IBMQ(hub='ibm-q', group='open', project='main')>,
<IBMQBackend('ibmq_vigo') from IBMQ(hub='ibm-q', group='open', project='main')>,
<IBMQBackend('ibmq_ourense') from IBMQ(hub='ibm-q', group='open', project='main')>,
<IBMQBackend('ibmq_london') from IBMQ(hub='ibm-q', group='open', project='main')>,
<IBMQBackend('ibmq_burlington') from IBMQ(hub='ibm-q', group='open', project='main')>,
<IBMQBackend('ibmq_essex') from IBMQ(hub='ibm-q', group='open', project='main')>,
<IBMQBackend('ibmq_armonk') from IBMQ(hub='ibm-q', group='open', project='main')>,
<IBMQBackend('ibmq_rome') from IBMQ(hub='ibm-q', group='open', project='main')>]

Selecting a backend is done by name using the get_backend(NAME) method:

backend = provider.get_backend('ibmq_vigo')
backend

Filtering the Backends

You may also optionally filter the set of returned backends, by passing arguments that query the backend’s configuration, status, or properties. The filters are passed by conditions and, for more general filters, you can make advanced functions using a lambda function.

As a first example lets return only those backends that are real quantum devices, and that are currently operational:

provider.backends(simulator=False, operational=True)

Output:

[<IBMQBackend('ibmqx2') from IBMQ(hub='ibm-q', group='open', project='main')>,
<IBMQBackend('ibmq_16_melbourne') from IBMQ(hub='ibm-q', group='open', project='main')>,
<IBMQBackend('ibmq_vigo') from IBMQ(hub='ibm-q', group='open', project='main')>,
<IBMQBackend('ibmq_ourense') from IBMQ(hub='ibm-q', group='open', project='main')>,
<IBMQBackend('ibmq_london') from IBMQ(hub='ibm-q', group='open', project='main')>,
<IBMQBackend('ibmq_burlington') from IBMQ(hub='ibm-q', group='open', project='main')>,
<IBMQBackend('ibmq_essex') from IBMQ(hub='ibm-q', group='open', project='main')>,
<IBMQBackend('ibmq_armonk') from IBMQ(hub='ibm-q', group='open', project='main')>,
<IBMQBackend('ibmq_rome') from IBMQ(hub='ibm-q', group='open', project='main')>]

Or, only those backends that are real devices, have more than 10 qubits, and are operational

provider.backends(filters=lambda x: x.configuration().n_qubits >= 10
and not x.configuration().simulator
and x.status().operational==True)

Output:

[<IBMQBackend('ibmq_16_melbourne') from IBMQ(hub='ibm-q', group='open', project='main')>]

Lastly, show the least busy 5 qubit device (in terms of the number of jobs pending in the queue)

from qiskit.providers.ibmq import least_busysmall_devices = provider.backends(filters=lambda x: x.configuration().n_qubits == 5
and not x.configuration().simulator)
least_busy(small_devices)

The above filters can be combined as desired.

Backends

Backends represent either a simulator or a real quantum computer, and are responsible for running quantum circuits and/or pulse schedules and returning results. They have a run method which takes in a qobj as input, the Qiskit API serialization format, and returns a BaseJob object. This object allows asynchronous running of jobs for retrieving results from a backend when the job is completed.

At a minimum, backends use the following methods, inherited from qiskit.providers.BaseBackend:

  • provider(): Returns the provider of the backend.
  • name(): Returns the name of the backend.
  • status(): Returns the current status of the backend.
  • configuration(): Returns the backend configuration.
  • properties(): Returns the backend properties.
  • run(QOBJ, **kwargs): Runs a qobj on the backend.

The qiskit-ibmq-provider’s implementation of BaseBackend is `IBMQBackend <https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.IBMQBackend.html#qiskit.providers.ibmq.IBMQBackend>`__. It accepts additional parameters to the run() method:

  • job_name: Custom name to be assigned to the job.
  • job_share_level: Allows sharing the job at different level.
  • job_tags: Tags to be assigned to the job.

And supports additional methods:

  • jobs(): Returns a list of previous jobs executed on this backend through the current provider instance.
  • retrieve_job(JOB_ID): Returns a job by its job ID.
  • defaults(): Gives a data structure of typical default parameters, if applicable.
  • job_limit(): Returns the job limit for the backend.
  • remaining_jobs_count(): Returns the number of remaining jobs that could be submitted to the backend.
  • active_jobs(): Returns a list of unfinished jobs.

Refer to the `IBMQBackend <https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.IBMQBackend.html#qiskit.providers.ibmq.IBMQBackend>`__ documentation for a complete list of methods.

Lets load up the least busy backend from the small_devices filtered above:

backend = least_busy(small_devices)

Some examples using the different methods:

backend.provider()

Output :

<AccountProvider for IBMQ(hub='ibm-q', group='open', project='main')>

Script:

backend.name()

Output:

'ibmq_ourense'

Script:

backend.status()

Output :

<qiskit.providers.models.backendstatus.BackendStatus at -0x1fbf025bf48>

Here we see the name of the backend, the software version it is running, along with its operational status, number of jobs pending in the backends queue, and a more detailed status message.

Next we look at the backend configuration and properties:

backend.configuration()

Output:

QasmBackendConfiguration(allow_object_storage=True, allow_q_object=True, backend_name='ibmq_ourense', backend_version='1.0.1', basis_gates=['u1', 'u2', 'u3', 'cx', 'id'], conditional=False, coupling_map=[[0, 1], [1, 0], [1, 2], [1, 3], [2, 1], [3, 1], [3, 4], [4, 3]], credits_required=True, description='5 qubit device Ourense', gates=[GateConfig(id, [], gate id q { U(0,0,0) q; }, [[0], [1], [2], [3], [4]]), GateConfig(u1, ['lambda'], gate u1(lambda) q { U(0,0,lambda) q; }, [[0], [1], [2], [3], [4]]), GateConfig(u2, ['phi', 'lambda'], gate u2(phi,lambda) q { U(pi/2,phi,lambda) q; }, [[0], [1], [2], [3], [4]]), GateConfig(u3, ['theta', 'phi', 'lambda'], gate u3(theta,phi,lambda) q { U(theta,phi,lambda) q; }, [[0], [1], [2], [3], [4]]), GateConfig(cx, [], gate cx q1,q2 { CX q1,q2; }, [[0, 1], [1, 0], [1, 2], [1, 3], [2, 1], [3, 1], [3, 4], [4, 3]])], local=False, max_experiments=75, max_shots=8192, meas_map=[[0, 1, 2, 3, 4]], memory=True, n_qubits=5, n_registers=1, online_date=datetime.datetime(2019, 7, 3, 4, 0, tzinfo=tzutc()), open_pulse=False, quantum_volume=8, sample_name='Giraffe', simulator=False, url='None')

The backend configuration provides some useful information via its attributes, such as basis_gates, coupling_map, max_experiments, max_shots, quantum_volume, and simulator.

The backend properties contain data that was measured and reported. Let’s see what kind of information is reported for qubit 0.

props = backend.properties()def describe_qubit(qubit, properties):
"""Print a string describing some of reported properties of the given qubit."""
# Conversion factors from standard SI units
us = 1e6
ns = 1e9
GHz = 1e-9
print("Qubit {0} has a \n"
" - T1 time of {1} microseconds\n"
" - T2 time of {2} microseconds\n"
" - U2 gate error of {3}\n"
" - U2 gate duration of {4} nanoseconds\n"
" - resonant frequency of {5} GHz".format(
qubit,
properties.t1(qubit) * us,
properties.t2(qubit) * us,
properties.gate_error('u2', qubit),
properties.gate_length('u2', qubit) * ns,
properties.frequency(qubit) * GHz))
describe_qubit(0, props)

Output :

Qubit 0 has a 
- T1 time of 111.13711339452661 microseconds
- T2 time of 62.24520011783602 microseconds
- U2 gate error of 0.00040202749088905256
- U2 gate duration of 35.555555555555564 nanoseconds
- resonant frequency of 4.820294893402858 GHz

To see the last five jobs run on this backend:

ran_job = None
for ran_job in backend.jobs(limit=5):
print(str(ran_job.job_id()) + " " + str(ran_job.status()))

A job can be retrieved using the retrieve_job(JOB_ID) method:

if ran_job is not None:
job = backend.retrieve_job(ran_job.job_id())

Backend Service

qiskit-ibmq-provider version 0.4 (Qiskit version 0.14) introduced a new class `IBMQBackendService <https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.IBMQBackendService.html#qiskit.providers.ibmq.IBMQBackendService>`__. It provides generic backend related services for a provider without requiring a particular backend as input. The main methods it supports are:

  • jobs(): Returns a list of previously submitted jobs through the current provider instance.
  • retrieve_job(JOB_ID): Returns a job by its job ID.

The backend service is defined as the backends attribute of a provider. All of the backends available to this provider are also attributes of the backend service, allowing the backend names to be autocompleted:

provider.backends.ibmq_vigo

To see the last five jobs submitted through this provider, regardless of which backend they ran on:

for ran_job in provider.backends.jobs(limit=5):
print(str(ran_job.job_id()) + " " + str(ran_job.status()))

Output:

5efb4dae0d181a0013f10cbf JobStatus.DONE
5efb4da9bb52a9001379cc24 JobStatus.DONE
5efb4d82bb52a9001379cc1d JobStatus.DONE
5efb4cfa43d20e0012f3da17 JobStatus.DONE
5efb4cf0a229d9001393456b JobStatus.DONE

To retrieve a particular job:

if ran_job is not None:
job = provider.backends.retrieve_job(ran_job.job_id())

Jobs

Job instances can be thought of as the “ticket” for a submitted job. They find out the execution state at a given point in time (for example, if the job is queued, running, or has failed), and also allow control over the job. They have the following methods:

  • status(): Returns the status of the job.
  • backend(): Returns the backend the job was run on.
  • job_id(): Gets the job_id.
  • cancel(): Cancels the job.
  • result(): Gets the results from the circuit run.

Some of the methods that are only available to “IBM Q Job”(`IBMQJob <https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.job.IBMQJob.html#qiskit.providers.ibmq.job.IBMQJob>`__) include:

  • creation_date(): Gives the date at which the job was created.
  • queue_info(): Returns queue information for this job, including queue position, estimated start and end time, and dynamic priorities for the hub, group, and project.
  • error_message(): The error message of failed jobs, if any.
  • name(): Returns the name assigned to this job.
  • properties(): Returns the backend properties for this job.
  • time_per_step(): Returns the time spent for each step (job creation, validation, etc).

Refer to the `IBMQJob <https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.job.IBMQJob.html#qiskit.providers.ibmq.job.IBMQJob>`__ documentation for a complete list of methods.

Now some examples. Let’s start with submitting a job:

from qiskit import *
from qiskit.compiler import transpile, assemble
backend = provider.get_backend('ibmq_qasm_simulator')qr = QuantumRegister(3)
cr = ClassicalRegister(3)
circuit = QuantumCircuit(qr, cr)
circuit.x(qr[0])
circuit.x(qr[1])
circuit.ccx(qr[0], qr[1], qr[2])
circuit.cx(qr[0], qr[1])
circuit.measure(qr, cr)

Output:

<qiskit.circuit.instructionset.InstructionSet at 0x1fbf07eb3c8>

To pass this circuit to the backend, we must first map it onto the backend, package it, and send to the device. This is all done for you by the execute function:

job = execute(circuit, backend)

Alternatively, you can map the circuit yourself using the transpile function, package it using assemble, and then send it from the backend instance itself:

mapped_circuit = transpile(circuit, backend=backend)
qobj = assemble(mapped_circuit, backend=backend, shots=1024)
job = backend.run(qobj)

The status() method returns the job status and a message:

job.status()

Output:

<JobStatus.RUNNING: 'job is actively running'>

To get a backend object from the job, use the backend() method:

backend_temp = job.backend()
backend_temp

To get the job_id use the job_id() method:

job.job_id()

Output:

'5efbe972ade6c400123554a3'

To get the result from the job, use the result() method:

result = job.result()
counts = result.get_counts()
print(counts)

Output:

{'101': 1024}

If you want to check the creation date, use creation_date():

job.creation_date()

Output:

C:\Users\cahya\anaconda3\lib\site-packages\ipykernel_launcher.py:1: UserWarning: The creation date is returned in local time now, rather than UTC.
"""Entry point for launching an IPython kernel.

Out:

datetime.datetime(2020, 7, 1, 8, 40, 2, 910000, tzinfo=tzlocal())

Job Manager

The Job Manager is another convenience function provided by qiskit-ibmq-provider, available in version 0.4 (Qiskit version 0.14) and up. It splits experiments into multiple jobs based on backend restrictions. When the jobs are finished, it collects and presents the results in a unified view.

`IBMQJobManager <https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.managed.IBMQJobManager.html#qiskit.providers.ibmq.managed.IBMQJobManager>`__ has the following methods: - run(): Execute a set of circuits or pulse schedules. - report(): Return a report on the statuses of all jobs managed by this manager. - job_sets(): Return a list of managed job sets matching the specified filtering.

You can run multiple sets of experiments by invoking job_manager.run() multiple times, and each call will return a `ManagedJobSet <https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.managed.ManagedJobSet.html>`__ instance. The ManagedJobSet methods allow you to apply operations on this set of jobs as a whole and are similiar to those of the Job class: - statuses(): Return the status of each job. - cancel(): Cancel all jobs in this set. - results(): Return the results of the jobs. - error_messages(): Provide details about job failures. - jobs(): Return a list of submitted jobs. - report(): Return a report on current job statuses.

Now let’s see some examples. Say you want to submit a bunch of circuits to a backend:

from qiskit.providers.ibmq.managed import IBMQJobManagersim_backend = provider.get_backend('ibmq_qasm_simulator')
circs = transpile([circuit]*20, backend=sim_backend)
# Submit them all to the backend
job_manager = IBMQJobManager()
job_set = job_manager.run(circs, backend=sim_backend, name='foo')

You can use the report() method to inquire the statuses of the jobs:

print(job_set.report())

Output:

Job set name: foo
ID: f545f7f03176421884d45d43853032e6-15935676177214239
tags: []
Summary report:
Total jobs: 1
Successful jobs: 0
Failed jobs: 0
Cancelled jobs: 0
Running jobs: 0
Pending jobs: 1

Detail report:
experiments: 0-19
job index: 0
status: job is being initialized

job_set above is not very interesting, as it only contains a single job. To force multiple jobs without making this tutorial too slow, we can use the max_experiments_per_job parameter:

# Restrict 10 experiments per job.
job_set_multiple = job_manager.run(circs, backend=sim_backend, name='bar', max_experiments_per_job=10)
print(job_set_multiple.report())

Output:

Job set name: bar
ID: a540e8ee46814c60b4fdb102241dcfe2-15935676229420533
tags: []
Summary report:
Total jobs: 2
Successful jobs: 0
Failed jobs: 0
Cancelled jobs: 0
Running jobs: 0
Pending jobs: 2

Detail report:
experiments: 0-9
job index: 0
status: job is being initialized
experiments: 10-19
job index: 1
status: job is being initialized

As you can see, job_set_multiple contains multiple jobs. To collect the results of all jobs, you can use the results() method, which returns a `ManagedResults <https://qiskit.org/documentation/stubs/qiskit.providers.ibmq.managed.ManagedResults.html>`__ instance. ManagedResults supports the same methods as Result, which can be used to retrieve the ouputs of individual experiments:

results = job_set_multiple.results()
print("This is the histogram data for experiment 5: {}".format(results.get_counts(5)))
print("This is the histogram data for experiment 15: {}".format(results.get_counts(15)))

Output:

This is the histogram data for experiment 5: {'101': 1024}
This is the histogram data for experiment 15: {'101': 1024}

Similar to a job, each job set is assigned a unique ID. The job set ID along with the provider object can be used to retrive a previously submitted job set:

job_set_id = job_set_multiple.job_set_id()
retrieved_job_set = job_manager.retrieve_job_set(job_set_id=job_set_id, provider=provider)
print(retrieved_job_set.report())

Output:

Job set name: bar
ID: a540e8ee46814c60b4fdb102241dcfe2-15935676229420533
tags: []
Summary report:
Total jobs: 2
Successful jobs: 2
Failed jobs: 0
Cancelled jobs: 0
Running jobs: 0
Pending jobs: 0

Detail report:
experiments: 0-9
job index: 0
job ID: 5efbe988b8465a0012a25049
name: bar_0_
status: job has successfully run
experiments: 10-19
job index: 1
job ID: 5efbe98ca229d900139355ff
name: bar_1_
status: job has successfully run

If you want to manipulate the jobs within a job set directly, you can use the jobs() method to retrive them. Note that an entry is None if that particular job could not be submitted:

jobs = job_set_multiple.jobs()  # Get a list of all jobs in the set.
job0 = jobs[0]
if job0 is None:
print("Job0 submit failed!")
import qiskit.tools.jupyter
%qiskit_version_table

Supercomputing Virtual Forum (Demo)

Import Qiskit

from qiskit import QuantumCircuit, execute # for creating and executing quantum circuits
from qiskit.visualization import plot_state_qsphere, plot_histogram #for visualization
%config InlineBackend.figure_format = 'svg' #make image look nice
import qiskit.tools.jupyter #handy jupyter notebook tools
%qiskit_version_table # display versions of qiskit and its elements

Create a quantum circuit

qc0 = QuantumCircuit(1) # create a quantum circuit with 1 qubit
qc0.draw('mpl') #Visualize the circuit
from qiskit.providers.aer import StatevectorSimulator
# StatevectorSumulator returns final quantum statevector of the circuit
state0 = execute(qc0, StatevectorSimulator()).result().get_statevector() # exwcute simulatiom
plot_state_qsphere(state0) #visualize statevector in a qsphere

Add quantum gates

qc1 = QuantumCircuit(1)
qc1.x(0) #apply x gate to qubit 0
qc1.draw('mpl')
state1 = execute(qc1, StatevectorSimulator()).result().get_statevector()
plot_state_qsphere(state1)

Create superposition

qc2 = QuantumCircuit(1)
qc2.h(0) #apply Hadamard gate to qubit 0
qc2.draw('mpl')
state2 = execute(qc0, StatevectorSimulator()).result().get_statevector() # exwcute simulatiom
plot_state_qsphere(state2) #visualize statevector in a qsphere

Add measurement operation

qc0.measure_all() #measure all qubits and store the result in classical bits
qc0.draw('mpl')
qc1.measure_all()
qc1.draw('mpl')
qc2.measure_all()
qc2.draw('mpl')
from qiskit.providers.aer import QasmSimulator # QasmSimulator micmic beheaviour of real device#real device require multiple execution (shots, default=1024) to obtain outcome statisticscounts0 = execute(qc0, QasmSimulator(), shots=1000).result().get_counts()
counts1 = execute(qc1, QasmSimulator(), shots=1000).result().get_counts()
counts2 = execute(qc2, QasmSimulator(), shots=1000).result().get_counts()
print(counts0, counts1, counts2)

Output:

{'0': 1000} {'1': 1000} {'0': 484, '1': 516}plot_histogram([counts0, counts1, counts2], legend = ['|0>','|1>','|0>+|1>']) # visualize outcome statistics

Hadamard with 2 qubits

qc3 = QuantumCircuit(2) # create a quntum circuit with 2 quantum bits
qc3.h(0)
qc3.h(1)
qc3.draw('mpl')
state3 = execute(qc3, StatevectorSimulator()).result().get_statevector()
plot_state_qsphere(state3)

Bell state |ø> = 1/√2(|100> + |11>)

qc4 = QuantumCircuit(2) # create a quntum circuit with 2 quantum bits
qc4.h(0)
qc4.cx(0,1) #apply a CNOT gate with qubit 0 as control and qubit 1 as target
qc4.draw('mpl')
state4 = execute(qc4, StatevectorSimulator()).result().get_statevector()
plot_state_qsphere(state4) #plot the cityscape of quantum state
qc4.measure_all()
counts4 = execute(qc4, QasmSimulator()).result().get_counts()
plot_histogram(counts4)
from qiskit.aqua.algorithms import Grover
from qiskit.aqua.components.oracles import TruthTableOracle
from qiskit.providers.basicaer import QasmSimulatorPy
oracle = TruthTableOracle('0010') # implement oracle using truth table
grover = Grover(oracle, num_iterations=1) #initialize Grover's algorithm with oracle and number of iterations
grover.set_backend(QasmSimulatorPy()) #set backend for running thr algorithm
result = grover.run() #run Grover's algorithm
plot_histogram(result['measurement'])
grover.construct_circuit(measurement=True).draw('mpl') #viualize the grover circuit
from qiskit.aqua.algorithms import Grover
from qiskit.aqua.components.oracles import TruthTableOracle
from qiskit.providers.basicaer import QasmSimulatorPy
oracle = TruthTableOracle('00100000') # implement oracle using truth table
grover = Grover(oracle, num_iterations=1) #initialize Grover's algorithm with oracle and number of iterations
grover.set_backend(QasmSimulatorPy()) #set backend for running thr algorithm
result = grover.run() #run Grover's algorithm
plot_histogram(result['measurement'])
grover.construct_circuit(measurement=True).draw('mpl') #viualize the grover circuit
from qiskit.aqua.algorithms import Grover
from qiskit.aqua.components.oracles import TruthTableOracle
from qiskit.providers.basicaer import QasmSimulatorPy
oracle = TruthTableOracle('0010') # implement oracle using truth table
grover = Grover(oracle, num_iterations=3) #initialize Grover's algorithm with oracle and number of iterations
grover.set_backend(QasmSimulatorPy()) #set backend for running thr algorithm
result = grover.run() #run Grover's algorithm
plot_histogram(result['measurement'])
grover.construct_circuit(measurement=True).draw('mpl') #viualize the grover circuit
from qiskit.aqua.algorithms import Grover
from qiskit.aqua.components.oracles import TruthTableOracle
from qiskit.providers.basicaer import QasmSimulatorPy
oracle = TruthTableOracle('00100000') # implement oracle using truth table
grover = Grover(oracle, num_iterations=3) #initialize Grover's algorithm with oracle and number of iterations
grover.set_backend(QasmSimulatorPy()) #set backend for running thr algorithm
result = grover.run() #run Grover's algorithm
plot_histogram(result['measurement'])
grover.construct_circuit(measurement=True).draw('mpl') #viualize the grover circuit

References:

IBM, Code your first quantum circuit”.

IBM, “Qiskit IBM Quantum Experience account

IBM,“(Supercomputing Virtual Forum Singapore)Bringing Quantum to Life

--

--