Skip to content

Commit f88a0f6

Browse files
AriJordanAri Jordan 80055203Takishima
authored
Add histogram plotting feature for simulator (#362)
* Add histogram plotting function for Simulator * Apply suggestion to projectq/libs/__init__.py * Apply suggestion to projectq/libs/hist/__init__.py * Update _histogram.py * Apply suggestion to projectq/libs/hist/_histogram.py * Apply suggestion to projectq/libs/hist/_histogram.py * Add docstrings * All suggestions applied. * Minor fixes for _histogram.py * Minor modifications to _histogram_test.py * Check that some message was printed in case of too many qubits * Update __init__.py Trigger Travis-CI * Add print_function for Python 2.7 * Remove unsupported 'flush' keyword for Python 2.7 * Update bellpair example with histogram plot of probabilities * Add support for other backends * Update IBM examples with histogram plots * Fix error in conf.py * Increase test coverage Co-authored-by: Ari Jordan 80055203 <ari.jordan@huawei.com> Co-authored-by: Damien Nguyen <damien1@huawei.com>
1 parent dfaf725 commit f88a0f6

8 files changed

Lines changed: 333 additions & 32 deletions

File tree

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
#!/usr/bin/env python3
23
# -*- coding: utf-8 -*-
34
#
@@ -28,7 +29,6 @@
2829
import projectq.setups.default
2930
import projectq.setups.grid
3031
import projectq.setups.ibm
31-
import projectq.setups.ibm16
3232
import projectq.setups.linear
3333
import projectq.setups.restrictedgateset
3434
import projectq.setups.decompositions

examples/bellpair_circuit.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
1+
import matplotlib.pyplot as plt
2+
13
from projectq import MainEngine
24
from projectq.backends import CircuitDrawer
5+
from projectq.setups.default import get_engine_list
6+
from projectq.libs.hist import histogram
37

48
from teleport import create_bell_pair
59

610
# create a main compiler engine
711
drawing_engine = CircuitDrawer()
8-
eng = MainEngine(drawing_engine)
12+
eng = MainEngine(engine_list = get_engine_list() + [drawing_engine])
913

10-
create_bell_pair(eng)
14+
qb0, qb1 = create_bell_pair(eng)
1115

1216
eng.flush()
1317
print(drawing_engine.get_latex())
18+
19+
histogram(eng.backend, [qb0, qb1])
20+
plt.show()

examples/ibm.py

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
import projectq.setups.ibm
1+
import matplotlib.pyplot as plt
2+
import getpass
3+
4+
from projectq import MainEngine
25
from projectq.backends import IBMBackend
6+
from projectq.libs.hist import histogram
37
from projectq.ops import Measure, Entangle, All
4-
from projectq import MainEngine
5-
import getpass
8+
import projectq.setups.ibm
69

710

811
def run_entangle(eng, num_qubits=3):
@@ -29,21 +32,24 @@ def run_entangle(eng, num_qubits=3):
2932
eng.flush()
3033

3134
# access the probabilities via the back-end:
32-
results = eng.backend.get_probabilities(qureg)
33-
for state in results:
34-
print("Measured {} with p = {}.".format(state, results[state]))
35+
# results = eng.backend.get_probabilities(qureg)
36+
# for state in results:
37+
# print("Measured {} with p = {}.".format(state, results[state]))
38+
# or plot them directly:
39+
histogram(eng.backend, qureg)
40+
plt.show()
3541

3642
# return one (random) measurement outcome.
3743
return [int(q) for q in qureg]
3844

3945

4046
if __name__ == "__main__":
4147
#devices commonly available :
42-
#ibmq_16_melbourne (15 qubit)
43-
#ibmq_essex (5 qubit)
44-
#ibmq_qasm_simulator (32 qubits)
45-
device = None #replace by the IBM device name you want to use
46-
token = None #replace by the token given by IBMQ
48+
# ibmq_16_melbourne (15 qubit)
49+
# ibmq_essex (5 qubit)
50+
# ibmq_qasm_simulator (32 qubits)
51+
device = None # replace by the IBM device name you want to use
52+
token = None # replace by the token given by IBMQ
4753
if token is None:
4854
token = getpass.getpass(prompt='IBM Q token > ')
4955
if device is None:

examples/ibmq_tutorial.ipynb

Lines changed: 72 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,18 @@
22
"cells": [
33
{
44
"cell_type": "markdown",
5-
"metadata": {},
5+
"metadata": {
6+
"collapsed": false
7+
},
68
"source": [
79
"# Running ProjectQ code on IBM Q devices"
810
]
911
},
1012
{
1113
"cell_type": "markdown",
12-
"metadata": {},
14+
"metadata": {
15+
"collapsed": false
16+
},
1317
"source": [
1418
"In this tutorial, we will see how to run code on IBM Q devices directly from within ProjectQ. All that is needed is an IBM Q Experience user account. To sign up, visit https://quantumexperience.ng.bluemix.net/.\n",
1519
"\n",
@@ -19,10 +23,24 @@
1923
"First, we import all necessary operations (`Entangle`, measurement), the back-end (`IBMBackend`), and the main compiler engine (`MainEngine`). The Entangle operation is defined as a Hadamard gate on the first qubit (creates an equal superposition of |0> and |1>), followed by controlled NOT gates acting on all other qubits controlled on the first."
2024
]
2125
},
26+
{
27+
"cell_type": "code",
28+
"execution_count": null,
29+
"metadata": {
30+
"collapsed": false
31+
},
32+
"outputs": [],
33+
"source": [
34+
"%matplotlib inline\n",
35+
"import matplotlib.pyplot as plt"
36+
]
37+
},
2238
{
2339
"cell_type": "code",
2440
"execution_count": 1,
25-
"metadata": {},
41+
"metadata": {
42+
"collapsed": false
43+
},
2644
"outputs": [],
2745
"source": [
2846
"import projectq.setups.ibm\n",
@@ -33,15 +51,19 @@
3351
},
3452
{
3553
"cell_type": "markdown",
36-
"metadata": {},
54+
"metadata": {
55+
"collapsed": false
56+
},
3757
"source": [
3858
"Next, we instantiate a main compiler engine using the IBM Q back-end and the predefined compiler engines which take care of the qubit placement, translation of operations, etc.:"
3959
]
4060
},
4161
{
4262
"cell_type": "code",
4363
"execution_count": 2,
44-
"metadata": {},
64+
"metadata": {
65+
"collapsed": false
66+
},
4567
"outputs": [],
4668
"source": [
4769
"eng = MainEngine(IBMBackend(use_hardware=True, num_runs=1024,\n",
@@ -51,7 +73,9 @@
5173
},
5274
{
5375
"cell_type": "markdown",
54-
"metadata": {},
76+
"metadata": {
77+
"collapsed": false
78+
},
5579
"source": [
5680
"If `use_hardware` is set to `False`, it will use the IBM Q simulator instead. `num_runs` specifies the number of samples to collect for statistics, `verbose=True` would output additional information which may be helpful for debugging, and the device parameter lets users choose between the two devices (\"ibmqx4\" and \"ibmqx5\").\n",
5781
"\n",
@@ -61,7 +85,9 @@
6185
{
6286
"cell_type": "code",
6387
"execution_count": 3,
64-
"metadata": {},
88+
"metadata": {
89+
"collapsed": false
90+
},
6591
"outputs": [
6692
{
6793
"name": "stdout",
@@ -105,9 +131,12 @@
105131
" eng.flush()\n",
106132
"\n",
107133
" # access the probabilities via the back-end:\n",
108-
" results = eng.backend.get_probabilities(qureg)\n",
109-
" for state in results:\n",
110-
" print(\"Measured {} with p = {}.\".format(state, results[state]))\n",
134+
" # results = eng.backend.get_probabilities(qureg)\n",
135+
" # for state in results:\n",
136+
" # print(\"Measured {} with p = {}.\".format(state, results[state]))\n",
137+
" # or plot them directly:\n",
138+
" histogram(eng.backend, qureg)\n",
139+
" plt.show()\n",
111140
"\n",
112141
" # return one (random) measurement outcome.\n",
113142
" return [int(q) for q in qureg]\n",
@@ -117,23 +146,29 @@
117146
},
118147
{
119148
"cell_type": "markdown",
120-
"metadata": {},
149+
"metadata": {
150+
"collapsed": false
151+
},
121152
"source": [
122153
"## Retrieving a timed-out execution\n",
123154
"Sometimes, the queue is very long and the waiting times may exceed the limit of 5 minutes. In this case, ProjectQ will raise an exception which contains the job ID, as could be seen above, where the job ID was `5b557df2306393003b746da2`."
124155
]
125156
},
126157
{
127158
"cell_type": "markdown",
128-
"metadata": {},
159+
"metadata": {
160+
"collapsed": false
161+
},
129162
"source": [
130163
"In order to still retrieve all results at a later point in time, one can simply re-run the entire program using a slightly modified back-end:"
131164
]
132165
},
133166
{
134167
"cell_type": "code",
135168
"execution_count": 4,
136-
"metadata": {},
169+
"metadata": {
170+
"collapsed": false
171+
},
137172
"outputs": [
138173
{
139174
"name": "stdout",
@@ -193,7 +228,9 @@
193228
},
194229
{
195230
"cell_type": "markdown",
196-
"metadata": {},
231+
"metadata": {
232+
"collapsed": false
233+
},
197234
"source": [
198235
"## Entangling more qubits: Using ibmqx5\n",
199236
"\n",
@@ -209,7 +246,9 @@
209246
{
210247
"cell_type": "code",
211248
"execution_count": 5,
212-
"metadata": {},
249+
"metadata": {
250+
"collapsed": false
251+
},
213252
"outputs": [],
214253
"source": [
215254
"import projectq.setups.ibm16 # import setup which contains the grid mapper\n",
@@ -220,15 +259,19 @@
220259
},
221260
{
222261
"cell_type": "markdown",
223-
"metadata": {},
262+
"metadata": {
263+
"collapsed": false
264+
},
224265
"source": [
225266
"and then re-run the example from before via `run_entangle(eng, num_qubits)`. If an execution times out, it can also be retrieved at a later point by providing the additional `retrieve_execution=\"execution_id\"` parameter to the IBMBackend (but this time with `device='ibmqx5'`)."
226267
]
227268
},
228269
{
229270
"cell_type": "code",
230271
"execution_count": 6,
231-
"metadata": {},
272+
"metadata": {
273+
"collapsed": false
274+
},
232275
"outputs": [
233276
{
234277
"name": "stdout",
@@ -488,8 +531,18 @@
488531
],
489532
"metadata": {
490533
"kernelspec": {
534+
"argv": [
535+
"python",
536+
"-m",
537+
"ipykernel_launcher",
538+
"-f",
539+
"{connection_file}"
540+
],
491541
"display_name": "Python 3",
542+
"env": null,
543+
"interrupt_mode": "signal",
492544
"language": "python",
545+
"metadata": null,
493546
"name": "python3"
494547
},
495548
"language_info": {
@@ -503,7 +556,8 @@
503556
"nbconvert_exporter": "python",
504557
"pygments_lexer": "ipython3",
505558
"version": "3.6.5"
506-
}
559+
},
560+
"name": "ibmq_tutorial.ipynb"
507561
},
508562
"nbformat": 4,
509563
"nbformat_minor": 2

projectq/libs/hist/__init__.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Copyright 2020 ProjectQ-Framework (www.projectq.ch)
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""
16+
contains a function to plot measurement outcome probabilities
17+
as a histogram for the simulator
18+
"""
19+
20+
from ._histogram import histogram

projectq/libs/hist/_histogram.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Copyright 2020 ProjectQ-Framework (www.projectq.ch)
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from __future__ import print_function
16+
import matplotlib.pyplot as plt
17+
18+
from projectq.backends import Simulator
19+
20+
21+
def histogram(backend, qureg):
22+
"""
23+
Make a measurement outcome probability histogram for the given qubits.
24+
25+
Args:
26+
backend (BasicEngine): A ProjectQ backend
27+
qureg (list of qubits and/or quregs): The qubits,
28+
for which to make the histogram
29+
30+
Returns:
31+
A tuple (fig, axes, probabilities), where:
32+
fig: The histogram as figure
33+
axes: The axes of the histogram
34+
probabilities (dict): A dictionary mapping outcomes as string
35+
to their probabilities
36+
37+
Note:
38+
Don't forget to call eng.flush() before using this function.
39+
"""
40+
qubit_list = []
41+
for q in qureg:
42+
if isinstance(q, list):
43+
qubit_list.extend(q)
44+
else:
45+
qubit_list.append(q)
46+
47+
if len(qubit_list) > 5:
48+
print('Warning: For {0} qubits there are 2^{0} different outcomes'.
49+
format(len(qubit_list)))
50+
print("The resulting histogram may look bad and/or take too long.")
51+
print("Consider calling histogram() with a sublist of the qubits.")
52+
53+
if hasattr(backend, 'get_probabilities'):
54+
probabilities = backend.get_probabilities(qureg)
55+
elif isinstance(backend, Simulator):
56+
outcome = [0] * len(qubit_list)
57+
n_outcomes = (1 << len(qubit_list))
58+
probabilities = {}
59+
for i in range(n_outcomes):
60+
for pos in range(len(qubit_list)):
61+
if (1 << pos) & i:
62+
outcome[pos] = 1
63+
else:
64+
outcome[pos] = 0
65+
probabilities[''.join([str(bit) for bit in outcome
66+
])] = backend.get_probability(
67+
outcome, qubit_list)
68+
else:
69+
raise RuntimeError('Unable to retrieve probabilities from backend')
70+
71+
# Empirical figure size for up to 5 qubits
72+
fig, axes = plt.subplots(figsize=(min(21.2, 2
73+
+ 0.6 * (1 << len(qubit_list))), 7))
74+
names = list(probabilities.keys())
75+
values = list(probabilities.values())
76+
axes.bar(names, values)
77+
fig.suptitle('Measurement Probabilities')
78+
return (fig, axes, probabilities)

0 commit comments

Comments
 (0)