From 6f2a8d25875a45e05747837fa1d17d6b63ffa555 Mon Sep 17 00:00:00 2001 From: Graham Rowlands Date: Thu, 2 May 2019 09:40:07 -0400 Subject: [PATCH 1/4] Added bqplot graph plot of channel connectivity using show() method --- QGL/ChannelLibraries.py | 80 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/QGL/ChannelLibraries.py b/QGL/ChannelLibraries.py index f15816eb..aa3a0df5 100644 --- a/QGL/ChannelLibraries.py +++ b/QGL/ChannelLibraries.py @@ -37,7 +37,8 @@ import datetime import importlib import inspect -from functools import wraps +import operator +from functools import wraps, reduce import itertools import numpy as np import networkx as nx @@ -45,6 +46,10 @@ import bbndb +from bqplot import Figure, LinearScale +from bqplot.marks import Graph, Lines, Label +from ipywidgets import Layout + from . import config from . import Channels from . import PulseShapes @@ -150,6 +155,79 @@ def ent_by_type(self, obj_type, show=False): else: return q + def show(self, qubits=[]): + # nodes = list(dgraph.nodes()) + edges = [] + qub_objs = qubits if not qubits == [] else self.qubits() + for q in qub_objs: + edges.append((q, q.measure_chan)) + edges.append((q.measure_chan, q.measure_chan.phys_chan)) + edges.append((q.measure_chan.phys_chan,q.measure_chan.phys_chan.transmitter)) + edges.append((q, q.phys_chan)) + edges.append((q.phys_chan, q.phys_chan.transmitter)) + + #Generators + if q.measure_chan.phys_chan.generator: + edges.append((q.measure_chan.phys_chan, q.measure_chan.phys_chan.generator)) + if q.phys_chan.generator: + edges.append((q.phys_chan, q.phys_chan.generator)) + + graph = nx.digraph.DiGraph() + graph.add_edges_from(edges) + + indices = {n: i for i, n in enumerate(graph.nodes())} + node_data = [{'label': str(n)} for n in graph.nodes()] + link_data = [{'source': indices[s], 'target': indices[t]} for s, t in graph.edges()] + + qub_objs.sort(key=lambda x: x.label) + qubit_names = [q.label for q in qub_objs] + + loc = {} + def next_level(nodes, iteration=0, offset=0, accum=[]): + if len(accum) == 0: + loc[nodes[0]] = {'x': 0, 'y': 0} + accum = [nodes] + next_gen_nodes = list(reduce(operator.add, [list(graph.successors(n)) for n in nodes])) + l = len(next_gen_nodes) + if l > 0: + for k,n in enumerate(next_gen_nodes): + loc[n] = {'x': k, 'y': -(iteration+1)} + accum.append(next_gen_nodes) + return next_level(next_gen_nodes, iteration=iteration+1, offset=2.5*l, accum=accum) + else: + return accum + + hierarchy = [next_level([q]) for q in qub_objs] + widest = [max([len(row) for row in qh]) for qh in hierarchy] + for i in range(1, len(qub_objs)): + offset = sum(widest[:i]) + loc[qub_objs[i]]['x'] += offset*3 + for n in nx.descendants(graph, qub_objs[i]): + loc[n]['x'] += offset*3 + + x = [loc[n]['x'] for n in graph.nodes()] + y = [loc[n]['y'] for n in graph.nodes()] + xs = LinearScale(min=min(x)-0.5, max=max(x)+0.6) + ys = LinearScale(min=min(y)-0.5, max=max(y)+0.6) + fig_layout = Layout(width='960px', height='500px') + bq_graph = Graph(node_data=node_data, link_data=link_data, x=x, y=y, scales={'x': xs, 'y': ys}, + link_type='line', colors=['orange'] * len(node_data), directed=False) + bgs_lines = [] + middles = [] + for i in range(len(qub_objs)): + if i==0: + start = -0.4 + end = widest[0]-0.6 + elif i == len(qub_objs): + start = sum(widest)-0.4 + end = max(x)+0.4 + else: + start = sum(widest[:i])-0.4 + end = sum(widest[:i+1])-0.6 + + fig = Figure(marks=[bq_graph], layout=fig_layout) + return fig + def receivers(self): return self.ent_by_type(Channels.Receiver) From 1653ebb659ca25e12fc6c8d3363481f597e2b5ab Mon Sep 17 00:00:00 2001 From: Graham Rowlands Date: Thu, 2 May 2019 14:23:50 -0400 Subject: [PATCH 2/4] Add additional info to connectivity plot --- QGL/ChannelLibraries.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/QGL/ChannelLibraries.py b/QGL/ChannelLibraries.py index aa3a0df5..dca7c38b 100644 --- a/QGL/ChannelLibraries.py +++ b/QGL/ChannelLibraries.py @@ -172,11 +172,16 @@ def show(self, qubits=[]): if q.phys_chan.generator: edges.append((q.phys_chan, q.phys_chan.generator)) + # Triggers + if q.measure_chan.trig_chan: + edges.append((q.measure_chan, q.measure_chan.trig_chan)) + + graph = nx.digraph.DiGraph() graph.add_edges_from(edges) indices = {n: i for i, n in enumerate(graph.nodes())} - node_data = [{'label': str(n)} for n in graph.nodes()] + node_data = [{'label': str(n).replace('(','\r\n(')} for n in graph.nodes()] link_data = [{'source': indices[s], 'target': indices[t]} for s, t in graph.edges()] qub_objs.sort(key=lambda x: x.label) From 6c1424196e20cc6fef99481356a055882c6e990f Mon Sep 17 00:00:00 2001 From: Graham Rowlands Date: Thu, 2 May 2019 14:24:04 -0400 Subject: [PATCH 3/4] Add show_frequency_plan method --- QGL/ChannelLibraries.py | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/QGL/ChannelLibraries.py b/QGL/ChannelLibraries.py index dca7c38b..3b4b818c 100644 --- a/QGL/ChannelLibraries.py +++ b/QGL/ChannelLibraries.py @@ -46,9 +46,9 @@ import bbndb -from bqplot import Figure, LinearScale +from bqplot import Figure, LinearScale, Axis, Lines, Figure from bqplot.marks import Graph, Lines, Label -from ipywidgets import Layout +from ipywidgets import Layout, VBox, HBox from . import config from . import Channels @@ -233,6 +233,35 @@ def next_level(nodes, iteration=0, offset=0, accum=[]): fig = Figure(marks=[bq_graph], layout=fig_layout) return fig + def show_frequency_plan(self): + c_freqs = {} + m_freqs = {} + for qubit in self.qubits(): + c_freqs[qubit.label] = qubit.frequency*1e-9 + if qubit.phys_chan.generator: + c_freqs[qubit.label] += qubit.phys_chan.generator.frequency*1e-9 + + m_freqs[qubit.label] = qubit.measure_chan.frequency*1e-9 + if qubit.measure_chan.phys_chan.generator: + m_freqs[qubit.label] += qubit.measure_chan.phys_chan.generator.frequency*1e-9 + def spike_at(f): + fs = np.linspace(f-0.02,f+0.02,50) + return fs, np.exp(-(fs-f)**2/0.01**2) + figs = [] + for freqs, ss in zip([c_freqs, m_freqs],["Control","Measure"]): + sx = LinearScale() + sy = LinearScale() + ax = Axis(scale=sx, label="Frequency (GHz)") + ay = Axis(scale=sy, orientation='vertical') + lines = [] + for k,f in freqs.items(): + fs, a = spike_at(f) + lines.append(Lines(x=fs, y=a, scales={'x': sx, 'y': sy})) + labels = Label(x=list(freqs.values()), y=[1.1 for f in freqs], text=list(freqs.keys()), align='middle', scales= {'x': sx, 'y': sy}, + default_size=14, font_weight='bolder', colors=['#4f6367']) + figs.append(Figure(marks=lines+[labels], axes=[ax, ay], title=f"{ss} Frequency Plan")) + return HBox(figs) + def receivers(self): return self.ent_by_type(Channels.Receiver) From 175f397589a851a406425d898753abf1c67301b1 Mon Sep 17 00:00:00 2001 From: Graham Rowlands Date: Wed, 22 May 2019 21:21:52 -0400 Subject: [PATCH 4/4] Fix channel lib setup for unit tests --- tests/helpers.py | 2 +- tests/test_Compiler.py | 2 ++ tests/test_Sequences.py | 10 +++++----- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/helpers.py b/tests/helpers.py index df558eed..1f663643 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -2,7 +2,7 @@ def setup_test_lib(): cl = ChannelLibrary(db_resource_name=":memory:") - + cl.clear() q1 = cl.new_qubit(label='q1') q2 = cl.new_qubit(label='q2') q3 = cl.new_qubit(label='q3') diff --git a/tests/test_Compiler.py b/tests/test_Compiler.py index 7754b72a..0482b3e2 100644 --- a/tests/test_Compiler.py +++ b/tests/test_Compiler.py @@ -6,7 +6,9 @@ class CompileUtils(unittest.TestCase): def setUp(self): + print("Running setup") self.cl = ChannelLibrary(db_resource_name=":memory:") + self.cl.clear() self.q1gate = Channels.LogicalMarkerChannel(label='q1-gate', channel_db=self.cl.channelDatabase) self.q1gate = Channels.LogicalMarkerChannel(label='q1-gate', channel_db=self.cl.channelDatabase) self.q1phys = Channels.PhysicalChannel(label='q1-phys', sampling_rate=1.2e9, channel_db=self.cl.channelDatabase) diff --git a/tests/test_Sequences.py b/tests/test_Sequences.py index d9eb1ee8..923b6add 100644 --- a/tests/test_Sequences.py +++ b/tests/test_Sequences.py @@ -454,7 +454,7 @@ def setUp(self): AWGTestHelper.__init__(self, APS2Pattern) for name in ['APS1', 'APS2', 'APS3', 'APS4', 'APS5', 'APS6']: channelName = name + '-1' - channel = PhysicalQuadratureChannel(label=channelName) + channel = PhysicalQuadratureChannel(label=channelName, channel=0) channel.sampling_rate = 1.2e9 channel.instrument = name channel.translator = 'APS2Pattern' @@ -462,7 +462,7 @@ def setUp(self): for m in range(1, 5): channelName = "{0}-m{1}".format(name, m) - channel = PhysicalMarkerChannel(label=channelName) + channel = PhysicalMarkerChannel(label=channelName, channel=m-1) channel.sampling_rate = 1.2e9 channel.instrument = name channel.translator = 'APS2Pattern' @@ -509,9 +509,9 @@ class TestAPS1(unittest.TestCase, AWGTestHelper, TestSequences): def setUp(self): AWGTestHelper.__init__(self, APSPattern) for name in ['APS1', 'APS2', 'APS3']: - for ch in ['12', '34']: + for i, ch in enumerate(['12', '34']): channelName = name + '-' + ch - channel = PhysicalQuadratureChannel(label=channelName) + channel = PhysicalQuadratureChannel(label=channelName, channel=i) channel.sampling_rate = 1.2e9 channel.instrument = name channel.translator = 'APSPattern' @@ -519,7 +519,7 @@ def setUp(self): for m in range(1, 5): channelName = "{0}-{1}m1".format(name, m) - channel = PhysicalMarkerChannel(label=channelName) + channel = PhysicalMarkerChannel(label=channelName, channel=m-1) channel.sampling_rate = 1.2e9 channel.instrument = name channel.translator = 'APSPattern'