Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use actual gate name in backend monitor #5546

Merged
merged 15 commits into from
Jan 6, 2021
93 changes: 47 additions & 46 deletions qiskit/tools/jupyter/backend_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,11 +245,13 @@ def qubits_tab(backend):
Returns:
VBox: A VBox widget.
"""
props = backend.properties().to_dict()
props = backend.properties()

header_html = "<div><font style='font-weight:bold'>{key}</font>: {value}</div>"
update_date = props.last_update_date.strftime("%a %d %B %Y at %H:%M %Z")
header_html = header_html.format(key='last_update_date',
value=props['last_update_date'])
value=update_date)

update_date_widget = widgets.HTML(value=header_html)

qubit_html = "<table>"
Expand All @@ -268,43 +270,42 @@ def qubits_tab(backend):
</style>"""

qubit_html += "<tr><th></th><th>Frequency</th><th>T1</th><th>T2</th>"
qubit_html += "<th>U1 gate error</th><th>U2 gate error</th><th>U3 gate error</th>"
qubit_html += "<th>Readout error</th></tr>"
qubit_footer = "</table>"

for qub in range(len(props['qubits'])):
name = 'Q%s' % qub
qubit_data = props['qubits'][qub]
gate_data = [g for g in props['gates'] if g['qubits'] == [qub]]
t1_info = qubit_data[0]
t2_info = qubit_data[1]
freq_info = qubit_data[2]
readout_info = qubit_data[3]

freq = str(round(freq_info['value'], 5))+' '+freq_info['unit']
T1 = str(round(t1_info['value'],
5))+' ' + t1_info['unit']
T2 = str(round(t2_info['value'],
5))+' ' + t2_info['unit']
gate_error_title = ""

for gd in gate_data:
if gd['gate'] == 'u1':
U1 = str(round(gd['parameters'][0]['value'], 5))
break
for index, qubit_data in enumerate(props.qubits):
name = 'Q%s' % index
gate_data = [gate for gate in props.gates if gate.qubits == [index]]

cal_data = dict.fromkeys(['T1', 'T2', 'frequency', 'readout_error'], 'Unknown')
for nduv in qubit_data:
if nduv.name in cal_data.keys():
cal_data[nduv.name] = str(round(nduv.value, 5)) + ' ' + nduv.unit

gate_names = []
gate_error = []
for gd in gate_data:
if gd['gate'] == 'u2':
U2 = str(round(gd['parameters'][0]['value'], 5))
break
for gd in gate_data:
if gd['gate'] == 'u3':
U3 = str(round(gd['parameters'][0]['value'], 5))
break

readout_error = round(readout_info['value'], 5)
qubit_html += "<tr><td><font style='font-weight:bold'>%s</font></td><td>%s</td>"
qubit_html += "<td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>"
qubit_html = qubit_html % (name, freq, T1, T2, U1, U2, U3, readout_error)
if gd.gate in ['id']:
continue
try:
gate_error.append(str(round(props.gate_error(gd.gate, index), 5)))
gate_names.append(gd.gate.upper())
except QiskitError:
pass

if not gate_error_title:
for gname in gate_names:
gate_error_title += f"<th>{gname}</th>"
qubit_html += gate_error_title + "<th>Readout error</th></tr>"

qubit_html += f"<tr><td><font style='font-weight:bold'>{name}</font></td>"
qubit_html += f"<td>{cal_data['frequency']}</td>" \
f"<td>{cal_data['T1']}</td><td>{cal_data['T2']}</td>"
for gerror in gate_error:
qubit_html += f"<td>{gerror}</td>"
qubit_html += f"<td>{cal_data['readout_error']}</td>"

qubit_html += qubit_footer

qubit_widget = widgets.HTML(value=qubit_html)
Expand All @@ -324,13 +325,13 @@ def gates_tab(backend):
Returns:
VBox: A VBox widget.
"""
props = backend.properties().to_dict()
props = backend.properties()

multi_qubit_gates = [g for g in props['gates'] if len(g['qubits']) > 1]
multi_qubit_gates = [g for g in props.gates if len(g.qubits) > 1]

header_html = "<div><font style='font-weight:bold'>{key}</font>: {value}</div>"
header_html = header_html.format(key='last_update_date',
value=props['last_update_date'])
value=props.last_update_date)

update_date_widget = widgets.HTML(value=header_html,
layout=widgets.Layout(grid_area='top'))
Expand Down Expand Up @@ -361,9 +362,9 @@ def gates_tab(backend):

for qub in range(left_num):
gate = multi_qubit_gates[qub]
qubits = gate['qubits']
ttype = gate['gate']
error = round(gate['parameters'][0]['value'], 5)
qubits = gate.qubits
ttype = gate.gate
error = round(props.gate_error(gate.gate, qubits), 5)

left_table += "<tr><td><font style='font-weight:bold'>%s</font>"
left_table += "</td><td>%s</td><td>%s</td></tr>"
Expand All @@ -375,9 +376,9 @@ def gates_tab(backend):

for qub in range(left_num, left_num+mid_num):
gate = multi_qubit_gates[qub]
qubits = gate['qubits']
ttype = gate['gate']
error = round(gate['parameters'][0]['value'], 5)
qubits = gate.qubits
ttype = gate.gate
error = round(props.gate_error(gate.gate, qubits), 5)

middle_table += "<tr><td><font style='font-weight:bold'>%s</font>"
middle_table += "</td><td>%s</td><td>%s</td></tr>"
Expand All @@ -389,9 +390,9 @@ def gates_tab(backend):

for qub in range(left_num+mid_num, len(multi_qubit_gates)):
gate = multi_qubit_gates[qub]
qubits = gate['qubits']
ttype = gate['gate']
error = round(gate['parameters'][0]['value'], 5)
qubits = gate.qubits
ttype = gate.gate
error = round(props.gate_error(gate.gate, qubits), 5)

right_table += "<tr><td><font style='font-weight:bold'>%s</font>"
right_table += "</td><td>%s</td><td>%s</td></tr>"
Expand Down
79 changes: 39 additions & 40 deletions qiskit/tools/monitor/overview.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,6 @@ def backend_monitor(backend):
config = backend.configuration().to_dict()
status = backend.status().to_dict()
config_dict = {**status, **config}
if not config['simulator']:
props = backend.properties().to_dict()

print(backend.name())
print('='*len(backend.name()))
Expand All @@ -96,55 +94,56 @@ def backend_monitor(backend):
return

print()
qubit_header = 'Qubits [Name / Freq / T1 / T2 / U1 err / U2 err / U3 err / Readout err]'
print(qubit_header)
print('-'*len(qubit_header))

props = backend.properties()
qubit_header = None
sep = ' / '
for qub in range(len(props['qubits'])):
name = 'Q%s' % qub
qubit_data = props['qubits'][qub]
gate_data = [g for g in props['gates'] if g['qubits'] == [qub]]
t1_info = qubit_data[0]
t2_info = qubit_data[1]
freq_info = qubit_data[2]
readout_info = qubit_data[3]

freq = str(round(freq_info['value'], 5))+' '+freq_info['unit']
T1 = str(round(t1_info['value'],
5))+' ' + t1_info['unit']
T2 = str(round(t2_info['value'],
5))+' ' + t2_info['unit']
for gd in gate_data:
if gd['gate'] == 'u1':
U1 = str(round(gd['parameters'][0]['value'], 5))
break

for gd in gate_data:
if gd['gate'] == 'u2':
U2 = str(round(gd['parameters'][0]['value'], 5))
break
for gd in gate_data:
if gd['gate'] == 'u3':
U3 = str(round(gd['parameters'][0]['value'], 5))
break
for index, qubit_data in enumerate(props.qubits):
taalexander marked this conversation as resolved.
Show resolved Hide resolved
name = 'Q%s' % index
gate_data = [gate for gate in props.gates if gate.qubits == [index]]

readout_error = str(round(readout_info['value'], 5))
cal_data = dict.fromkeys(['T1', 'T2', 'frequency', 'readout_error'], 'Unknown')
for nduv in qubit_data:
if nduv.name in cal_data.keys():
cal_data[nduv.name] = format(nduv.value, '.5f') + ' ' + nduv.unit

gate_names = []
gate_error = []
for gd in gate_data:
if gd.gate in ['id']:
continue
try:
gate_error.append(format(props.gate_error(gd.gate, index), '.5f'))
gate_names.append(gd.gate.upper() + ' err')
except QiskitError:
pass

if not qubit_header:
qubit_header = 'Qubits [Name / Freq / T1 / T2' + sep.join(['']+gate_names) + \
' / Readout err]'
print(qubit_header)
print('-'*len(qubit_header))

qstr = sep.join([name, cal_data['frequency'], cal_data['T1'], cal_data['T2']] +
gate_error +
[cal_data['readout_error']])

qstr = sep.join([name, freq, T1, T2, U1, U2, U3, readout_error])
print(offset+qstr)

print()
multi_qubit_gates = [g for g in props['gates'] if len(g['qubits']) > 1]
multi_qubit_gates = [g for g in props.gates if len(g.qubits) > 1]
multi_header = 'Multi-Qubit Gates [Name / Type / Gate Error]'
print(multi_header)
print('-'*len(multi_header))

for qub, gate in enumerate(multi_qubit_gates):
gate = multi_qubit_gates[qub]
qubits = gate['qubits']
ttype = gate['gate']
error = round(gate['parameters'][0]['value'], 5)
for gate in multi_qubit_gates:
qubits = gate.qubits
ttype = gate.gate
error = "Unknown"
try:
error = format(props.gate_error(gate.gate, qubits), '.5f')
except QiskitError:
pass
mstr = sep.join(["{}{}_{}".format(ttype, qubits[0], qubits[1]), ttype, str(error)])
print(offset+mstr)

Expand Down
6 changes: 6 additions & 0 deletions releasenotes/notes/jupyter-gates-4940e03b3e4b6e12.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
fixes:
- |
Fixes the issue wherein using Jupyter backend widget or
:meth:`qiskit.tools.backend_monitor` would fail if the
backend's basis gates do not include the traditional u1, u2, and u3.
16 changes: 9 additions & 7 deletions test/python/providers/test_backendproperties.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ def setUp(self):
self.provider = FakeProvider()
self.backend = self.provider.get_backend('fake_ourense')
self.properties = self.backend.properties()
self.ref_gate = next(g for g in self.backend.configuration().basis_gates
if g not in ['id', 'rz'])

def test_gate_property(self):
"""Test for getting the gate properties."""
Expand All @@ -40,14 +42,14 @@ def test_gate_property(self):
self.properties._gates['cx'])

with self.assertRaises(BackendPropertyError):
self.properties.gate_property('u1', None, 'gate_error')
self.properties.gate_property(self.ref_gate, None, 'gate_error')

def test_gate_error(self):
"""Test for getting the gate errors."""
self.assertEqual(self.properties.gate_error('u1', 1),
self.properties._gates['u1'][(1,)]['gate_error'][0])
self.assertEqual(self.properties.gate_error('u1', [2, ]),
self.properties._gates['u1'][(2,)]['gate_error'][0])
self.assertEqual(self.properties.gate_error(self.ref_gate, 1),
self.properties._gates[self.ref_gate][(1,)]['gate_error'][0])
self.assertEqual(self.properties.gate_error(self.ref_gate, [2, ]),
self.properties._gates[self.ref_gate][(2,)]['gate_error'][0])
self.assertEqual(self.properties.gate_error('cx', [0, 1]),
self.properties._gates['cx'][(0, 1)]['gate_error'][0])

Expand All @@ -56,8 +58,8 @@ def test_gate_error(self):

def test_gate_length(self):
"""Test for getting the gate duration."""
self.assertEqual(self.properties.gate_length('u1', 1),
self.properties._gates['u1'][(1,)]['gate_length'][0])
self.assertEqual(self.properties.gate_length(self.ref_gate, 1),
self.properties._gates[self.ref_gate][(1,)]['gate_length'][0])
self.assertEqual(self.properties.gate_length('cx', [4, 3]),
self.properties._gates['cx'][(4, 3)]['gate_length'][0])

Expand Down
7 changes: 5 additions & 2 deletions test/python/tools/monitor/test_backend_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,11 @@ def test_backend_monitor(self, _):

stdout = fake_stdout.getvalue()
self.assertIn('Configuration', stdout)
self.assertIn('Qubits [Name / Freq / T1 / T2 / U1 err / U2 err / U3 err / Readout err]',
stdout)
self.assertIn('Qubits [Name / Freq / T1 / T2 / ', stdout)
jyu00 marked this conversation as resolved.
Show resolved Hide resolved
for gate in backend.properties().gates:
if gate.gate not in ['id'] and len(gate.qubits) == 1:
self.assertIn(gate.gate.upper() + ' err', stdout)
self.assertIn('Readout err', stdout)
self.assertIn('Multi-Qubit Gates [Name / Type / Gate Error]', stdout)


Expand Down
25 changes: 20 additions & 5 deletions test/python/transpiler/test_instruction_durations.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,28 @@ def test_fail_if_invalid_dict_is_supplied_when_construction(self):
InstructionDurations(invalid_dic)

def test_from_backend_for_backend_with_dt(self):
durations = InstructionDurations.from_backend(FakeParis())
backend = FakeParis()
gate = self._find_gate_length_gate(backend)
durations = InstructionDurations.from_backend(backend)
self.assertGreater(durations.dt, 0)
self.assertGreater(durations.get('u2', 0), 0)
self.assertGreater(durations.get(gate, 0), 0)

def test_from_backend_for_backend_without_dt(self):
durations = InstructionDurations.from_backend(FakeTokyo())
backend = FakeTokyo()
gate = self._find_gate_length_gate(backend)
durations = InstructionDurations.from_backend(backend)
self.assertIsNone(durations.dt)
self.assertGreater(durations.get('u2', 0, 's'), 0)
self.assertGreater(durations.get(gate, 0, 's'), 0)
with self.assertRaises(TranspilerError):
durations.get('u2', 0)
durations.get(gate, 0)

def _find_gate_length_gate(self, backend):
"""Find a gate that has gate length."""
props = backend.properties()
for gate in props.gates:
try:
if props.gate_length(gate.gate, 0):
return gate.gate
except Exception: # pylint: disable=broad-except
pass
raise ValueError("Unable to find a gate with gate length.")