diff --git a/.travis.yml b/.travis.yml
index 53f2dbfb..c3556463 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,8 +5,8 @@ language: python
python:
- 3.6
env:
- - CONDA_TYPE=miniconda CONDA_VERS=https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh
- - CONDA_TYPE=miniconda CONDA_VERS=https://repo.continuum.io/miniconda/Miniconda3-4.5.11-Linux-x86_64.sh
+ - CONDA_TYPE=miniconda CONDA_VERS=https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh UPDATE_CONDA="true"
+ - CONDA_TYPE=miniconda CONDA_VERS=https://repo.continuum.io/miniconda/Miniconda3-4.5.11-Linux-x86_64.sh UPDATE_CONDA=""
before_install:
# install git lfs and fetch test data
@@ -32,8 +32,7 @@ install:
- export PATH="$HOME/miniconda/bin:$PATH"
- hash -r
- conda config --set always_yes yes --set changeps1 no
- - conda install -c anaconda setuptools
- - conda update -q conda
+ - if [ $UPDATE_CONDA ]; then conda update -q conda; fi
# Useful for debugging any issues with conda
- conda info -a
diff --git a/QGL/ChannelLibraries.py b/QGL/ChannelLibraries.py
index e0f1f8fa..a781e260 100644
--- a/QGL/ChannelLibraries.py
+++ b/QGL/ChannelLibraries.py
@@ -147,17 +147,6 @@ def ls(self):
table_code += f"
{id} | {y} | {d} | {t} | {label} | {notes} |
"
display(HTML(f"id | Year | Date | Time | Name | Notes |
---|
{table_code}
"))
- def cal_ls(self):
- ''' List of auspex.pulse_calibration results '''
- caldb = bbndb.calibration.Calibration
- c = self.session.query(caldb.sample_id, caldb.name, caldb.value, caldb.date).order_by(-Channels.ChannelDatabase.id).all()
- table_code = ""
- for i, (id, sample_id, name, value, time) in enumerate(c):
- d,t = str(time).split()
- sample = self.session.query(bbndb.calibration.Sample).filter_by(id=sample_id).first()
- table_code += f"{id} | {d} | {t.split('.')[0]} | {sample.name} | {name} | {round(value,9)} |
"
- display(HTML(f"id | Date | Time | Sample | Name | Value |
---|
{table_code}
"))
-
def ent_by_type(self, obj_type, show=False):
q = self.session.query(obj_type).filter(obj_type.channel_db.has(label="working")).order_by(obj_type.label).all()
if show:
@@ -273,6 +262,61 @@ def spike_at(f):
figs.append(Figure(marks=lines+[labels], axes=[ax, ay], title=f"{ss} Frequency Plan"))
return HBox(figs)
+ def diff(self, name1, name2, index1=1, index2=1):
+ '''
+ Compare 2 channel library versions. Print the difference between 2 libraries, including parameter values and channel allocations. It requires both versions to be saved in the same sqlite database.
+ Args
+ name1: name of first version to compare
+ name2: name of second version to compare
+ index1, index2: by default, loading the most recent instances for the given names. Specifying index1/2 = 2 will select the second most recent instance etc."""
+ '''
+ cdb = Channels.ChannelDatabase
+ db1 = self.session.query(cdb).filter(cdb.label==name1).order_by(cdb.time.desc())[-1*index1]
+ db2 = self.session.query(cdb).filter(cdb.label==name2).order_by(cdb.time.desc())[-1*index2]
+ copied_db1 = bbndb.deepcopy_sqla_object(db1)
+ copied_db2 = bbndb.deepcopy_sqla_object(db2)
+ dict_1 = {c.label: c for c in copied_db1.channels + copied_db1.all_instruments()}
+ dict_2 = {c.label: c for c in copied_db2.channels + copied_db2.all_instruments()}
+ def iter_diff(value_iter1, value_iter2, ct, label=''):
+ table_code = ''
+ for key, key2 in zip(value_iter1, value_iter2):
+ if key in ['_sa_instance_state', 'channel_db']:
+ continue
+ if isinstance(value_iter1, dict):
+ cmp1 = value_iter1[key]
+ cmp2 = value_iter2[key]
+ if label in value_iter1:
+ label = value_iter1['label']
+ elif isinstance(value_iter1, list):
+ cmp1 = key
+ cmp2 = key2
+ else:
+ cmp1 = getattr(value_iter1, key)
+ cmp2 = getattr(value_iter2, key)
+ if (cmp1 == None) ^ (cmp2 == None):
+ table_code += f"{label} | {key} | {cmp1} | {cmp2} |
"
+ continue
+ if (cmp1 == None) or (cmp2 == None) or ((isinstance(cmp1, dict) or isinstance(cmp1, list)) and len(cmp1) == 0):
+ continue
+ if isinstance(cmp1, (bbndb.qgl.DatabaseItem, bbndb.qgl.Channel, bbndb.qgl.Instrument)):
+ cmp1 = cmp1.__dict__
+ cmp2 = cmp2.__dict__
+ if isinstance(cmp1, (dict, list, bbndb.qgl.DatabaseItem, bbndb.qgl.Channel, bbndb.qgl.Instrument)):
+ if ct<1: # up to 2 recursion levels for now, to avoid infinite loops for bidirectional relations
+ ct+=1
+ table_code += iter_diff(cmp1, cmp2, ct, label=label)
+ break
+ if cmp1 != cmp2:
+ table_code += f"{label} | {key} | {cmp1} | {cmp2} |
"
+ return table_code
+
+ table_code = ''
+ for chan, value in dict_1.items():
+ this_dict = value.__dict__
+ ct = 0
+ table_code += iter_diff(this_dict, dict_2[chan].__dict__, ct, chan)
+ display(HTML(f"Object | Parameter | {name1} | {name2} |
---|
{table_code}
"))
+
def receivers(self):
return self.ent_by_type(Channels.Receiver)
@@ -285,6 +329,9 @@ def transceivers(self):
def qubits(self):
return self.ent_by_type(Channels.Qubit)
+ def edges(self):
+ return self.ent_by_type(Channels.Edge)
+
def meas(self):
return self.ent_by_type(Channels.Measurement)
diff --git a/QGL/PulseSequencer.py b/QGL/PulseSequencer.py
index d19027f5..d70069b7 100644
--- a/QGL/PulseSequencer.py
+++ b/QGL/PulseSequencer.py
@@ -47,7 +47,11 @@ def __new__(cls, label, channel, shapeParams, amp=1.0, phase=0, frameChange=0, i
for param in requiredParams:
if param not in shapeParams.keys():
raise NameError("shapeParams must include {0}".format(param))
- isTimeAmp = (shapeParams['shape_fun'] == PulseShapes.constant)
+ if isinstance(shapeParams['shape_fun'],str):
+ shape = getattr(PulseShapes, shapeParams['shape_fun'])
+ else:
+ shape = shapeParams['shape_fun']
+ isTimeAmp = (shape == PulseShapes.constant)
isZero = (amp == 0)
return super(cls, Pulse).__new__(cls, label, channel,
shapeParams['length'], amp, phase,
diff --git a/QGL/drivers/APS2Pattern.py b/QGL/drivers/APS2Pattern.py
index d6e3d10c..8b2c1633 100644
--- a/QGL/drivers/APS2Pattern.py
+++ b/QGL/drivers/APS2Pattern.py
@@ -47,8 +47,9 @@
MAX_NUM_INSTRUCTIONS = 2**26
MAX_REPEAT_COUNT = 2**16 - 1
MAX_TRIGGER_COUNT = 2**32 - 1
-
+MAX_VRAM_ADDRESS = 2**(12-2)-1
MODULATION_CLOCK = 300e6
+NUM_NCO = 4
# instruction encodings
WFM = 0x0
@@ -581,13 +582,19 @@ def to_instruction(self, write_flag=True, label=None):
MODULATOR_OP_OFFSET = 44
NCO_SELECT_OP_OFFSET = 40
+ nco_select_bits = {1 : 0b0001,
+ 2 : 0b0010,
+ 3 : 0b0100,
+ 4 : 0b1000,
+ 15: 0b1111}[self.nco_select]
+
op_code_map = {"MODULATE": 0x0,
"RESET_PHASE": 0x2,
"SET_FREQ": 0x6,
"SET_PHASE": 0xa,
"UPDATE_FRAME": 0xe}
payload = (op_code_map[self.instruction] << MODULATOR_OP_OFFSET) | (
- self.nco_select << NCO_SELECT_OP_OFFSET)
+ (nco_select_bits) << NCO_SELECT_OP_OFFSET)
if self.instruction == "MODULATE":
#zero-indexed quad count
payload |= np.uint32(self.length / ADDRESS_UNIT - 1)
@@ -615,9 +622,9 @@ def inject_modulation_cmds(seqs):
for ct,seq in enumerate(seqs):
#check whether we have modulation commands
freqs = np.unique([entry.frequency for entry in filter(lambda s: isinstance(s,Compiler.Waveform), seq)])
- if len(freqs) > 2:
- raise Exception("Max 2 frequencies on the same channel allowed.")
- no_freq_cmds = np.all(np.less(np.abs(freqs), 1e-8))
+ if len(freqs) > NUM_NCO:
+ raise Exception("Max {} frequencies on the same channel allowed.".format(NUM_NCO))
+ no_freq_cmds = np.allclose(freqs, 0)
phases = [entry.phase for entry in filter(lambda s: isinstance(s,Compiler.Waveform), seq)]
no_phase_cmds = np.all(np.less(np.abs(phases), 1e-8))
frame_changes = [entry.frameChange for entry in filter(lambda s: isinstance(s,Compiler.Waveform), seq)]
@@ -641,7 +648,7 @@ def inject_modulation_cmds(seqs):
#heuristic to insert phase reset before trigger if we have modulation commands
if isinstance(entry, ControlFlow.Wait):
if not ( no_modulation_cmds and (cur_freq == 0) and (cur_phase == 0)):
- mod_seq.append(ModulationCommand("RESET_PHASE", 0x3))
+ mod_seq.append(ModulationCommand("RESET_PHASE", 0xF))
for nco_ind, freq in enumerate(freqs):
mod_seq.append( ModulationCommand("SET_FREQ", nco_ind + 1, frequency = -freq) )
elif isinstance(entry, ControlFlow.Return):
@@ -1139,8 +1146,6 @@ def start_new_seq():
wf_len = struct.unpack('= 0.1
+bbndb >= 2019.2
numpy >= 1.11.1
scipy >= 0.17.1
networkx >= 1.11
diff --git a/setup.py b/setup.py
index 8f8829dc..8aa67efe 100644
--- a/setup.py
+++ b/setup.py
@@ -1,13 +1,13 @@
from setuptools import setup, find_packages
setup(name='QGL',
- version='2019.1',
+ version='2019.2',
packages=find_packages(exclude=["tests"]),
url='https://github.com/BBN-Q/QGL',
download_url='https://github.com/BBN-Q/QGL',
license="Apache 2.0 License",
install_requires=[
- "bbndb >= 2019.1",
+ "bbndb >= 2019.2",
"numpy >= 1.11.1",
"scipy >= 0.17.1",
"networkx >= 1.11",