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"{table_code}
idYearDateTimeNameNotes
")) - 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"{table_code}
idDateTimeSampleNameValue
")) - 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"{table_code}
ObjectParameter{name1}{name2}
")) + 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",