def align(label, pulse, blockLength, alignment, cutoff=12): # check for composite pulses if hasattr(pulse, 'pulses'): entries = [LLWaveform(p) for p in pulse.pulses] entries[0].label = label shapes = [p.shape for p in pulse.pulses] else: entries = [LLWaveform(pulse, label)] shapes = [pulse.shape] padLength = blockLength - pulse.length if padLength == 0: # no padding element required return shapes, entries if (padLength < cutoff) and (alignment == "left" or alignment == "right"): # pad the first/last shape on one side if alignment == "left": shapes[-1] = np.hstack((shapes[-1], np.zeros(padLength))) entries[-1].key = PatternUtils.hash_pulse(shapes[-1]) else: #right alignment shapes[0] = np.hstack((np.zeros(padLength), shapes[0])) entries[0].key = PatternUtils.hash_pulse(shapes[0]) elif (padLength < 2 * cutoff and alignment == "center"): # pad the both sides of the shape(s) if len(shapes) == 1: shapes[0] = np.hstack( (np.zeros(np.floor(padLength / 2)), shapes[0], np.zeros(np.ceil(padLength / 2)))) entries[0].key = PatternUtils.hash_pulse(shapes[0]) else: shapes[0] = np.hstack( (np.zeros(np.floor(padLength / 2)), shapes[0])) shapes[-1] = np.hstack( (np.zeroes(np.ceil(padLength / 2)), shapes[-1])) entries[0].key = PatternUtils.hash_pulse(shapes[0]) entries[-1].key = PatternUtils.hash_pulse(shapes[-1]) elif padLength == blockLength: #Here we have a zero-length sequence which just needs to be expanded entries[0].key = PatternUtils.TAZKey entries[0].length = blockLength shapes = [np.zeros(1, dtype=np.complex)] else: #split the entry into the shape and one or more TAZ if alignment == "left": padEntry = create_padding_LL(padLength) entries = entries + [padEntry] elif alignment == "right": padEntry = create_padding_LL(padLength) entries = [padEntry] + entries else: padEntry1 = create_padding_LL(np.floor(padLength / 2)) padEntry2 = create_padding_LL(np.ceil(padLength / 2)) entries = [padEntry1] + entries + [padEntry2] return shapes, entries
def align(label, pulse, blockLength, alignment, cutoff=12): # check for composite pulses if hasattr(pulse, 'pulses'): entries = [LLWaveform(p) for p in pulse.pulses] entries[0].label = label shapes = [p.shape for p in pulse.pulses] else: entries = [LLWaveform(pulse, label)] shapes = [pulse.shape] padLength = blockLength - pulse.length if padLength == 0: # no padding element required return shapes, entries if (padLength < cutoff) and (alignment == "left" or alignment == "right"): # pad the first/last shape on one side if alignment == "left": shapes[-1] = np.hstack((shapes[-1], np.zeros(padLength))) entries[-1].key = PatternUtils.hash_pulse(shapes[-1]) else: #right alignment shapes[0] = np.hstack((np.zeros(padLength), shapes[0])) entries[0].key = PatternUtils.hash_pulse(shapes[0]) elif (padLength < 2*cutoff and alignment == "center"): # pad the both sides of the shape(s) if len(shapes) == 1: shapes[0] = np.hstack(( np.zeros(np.floor(padLength/2)), shapes[0], np.zeros(np.ceil(padLength/2)) )) entries[0].key = PatternUtils.hash_pulse(shapes[0]) else: shapes[0] = np.hstack(( np.zeros(np.floor(padLength/2)), shapes[0])) shapes[-1] = np.hstack(( np.zeroes(np.ceil(padLength/2)), shapes[-1])) entries[0].key = PatternUtils.hash_pulse(shapes[0]) entries[-1].key = PatternUtils.hash_pulse(shapes[-1]) elif padLength == blockLength: #Here we have a zero-length sequence which just needs to be expanded entries[0].key = PatternUtils.TAZKey entries[0].length = blockLength shapes = [np.zeros(1, dtype=np.complex)] else: #split the entry into the shape and one or more TAZ if alignment == "left": padEntry = create_padding_LL(padLength) entries = entries + [padEntry] elif alignment == "right": padEntry = create_padding_LL(padLength) entries = [padEntry] + entries else: padEntry1 = create_padding_LL(np.floor(padLength/2)) padEntry2 = create_padding_LL(np.ceil(padLength/2)) entries = [padEntry1] + entries + [padEntry2] return shapes, entries
def merge_channels(linkLists, wfLib, channels): chan = channels[0] newLinkList = [[] for _ in range(len(linkLists[chan]))] newWfLib = {} for ct, segment in enumerate(newLinkList): entryIterators = [iter(linkLists[ch][ct]) for ch in channels] while True: try: entries = [e.next() for e in entryIterators] # control flow on any channel should pass thru if any(isinstance(e, ControlFlow.ControlInstruction) for e in entries): # for the moment require uniform control flow so that we # can pull from the first channel assert all(e == entries[0] for e in entries), "Non-uniform control flow" segment.append(entries[0]) continue # at this point we have at least one waveform instruction blocklength = pull_uniform_entries(entries, entryIterators, wfLib, channels) newentry = copy(entries[0]) newentry.length = blocklength # sum waveforms wfnew = reduce(operator.add, [wfLib[channel][e.key] for channel, e in zip(channels, entries)]) newentry.key = PatternUtils.hash_pulse(wfnew) newWfLib[newentry.key] = wfnew segment.append(newentry) except StopIteration: break return newLinkList, newWfLib
def merge_channels(linkLists, wfLib, channels): chan = channels[0] newLinkList = [[] for _ in range(len(linkLists[chan]))] newWfLib = {} for ct, segment in enumerate(newLinkList): entryIterators = [iter(linkLists[ch][ct]) for ch in channels] while True: try: entries = [e.next() for e in entryIterators] # control flow on any channel should pass thru if any( isinstance(e, ControlFlow.ControlInstruction) for e in entries): # for the moment require uniform control flow so that we # can pull from the first channel assert all(e == entries[0] for e in entries), "Non-uniform control flow" segment.append(entries[0]) continue # at this point we have at least one waveform instruction blocklength = pull_uniform_entries(entries, entryIterators, wfLib, channels) newentry = copy(entries[0]) newentry.length = blocklength # sum waveforms wfnew = reduce(operator.add, [ wfLib[channel][e.key] for channel, e in zip(channels, entries) ]) newentry.key = PatternUtils.hash_pulse(wfnew) newWfLib[newentry.key] = wfnew segment.append(newentry) except StopIteration: break return newLinkList, newWfLib
def concatenate_entries(entry1, entry2, wfLib): newentry = copy(entry1) # TA waveforms with the same amplitude can be merged with a just length update # otherwise, need to concatenate the pulse shapes if not (entry1.isTimeAmp and entry2.isTimeAmp and entry1.key == entry2.key and entry1.phase == entry2.phase and entry1.frameChange == 0): # otherwise, need to expand pulses and stack them wf = np.hstack((np.resize(wfLib[entry1.key], len(entry1)), np.resize(wfLib[entry2.key], len(entry2)))) newentry.isTimeAmp = False newentry.key = PatternUtils.hash_pulse(wf) newentry.frameChange += entry2.frameChange wfLib[newentry.key] = wf newentry.repeat = 1 newentry.length = len(entry1) + len(entry2) return newentry
def __init__(self, pulse=None, label=None): self.repeat = 1 self.label = label if pulse is None: self.key = None self.length = 0 self.phase = 0 self.frameChange = 0 self.isTimeAmp = False self.repeat = 1 else: self.key = PatternUtils.hash_pulse(pulse.shape) self.length = pulse.length self.phase = pulse.phase self.frameChange = pulse.frameChange self.isTimeAmp = pulse.isTimeAmp
def compile_sequence(seq, wfLib={}, channels=None): ''' Converts a single sequence into a miniLL and waveform library. Returns a single-entry list of a miniLL and the updated wfLib ''' #Find the set of logical channels used here and initialize them if not channels: channels = find_unique_channels(seq) logicalLLs = {} for chan in channels: logicalLLs[chan] = [] if chan not in wfLib: if isinstance(chan, Channels.LogicalMarkerChannel): wfLib[chan] = markerWFLib else: wfLib[chan] = {PatternUtils.TAZKey: np.zeros(1, dtype=np.complex)} carriedPhase = {ch: 0 for ch in channels} for block in normalize(flatten(seq), channels): # control flow instructions just need to broadcast to all channels if isinstance(block, ControlFlow.ControlInstruction): for chan in channels: logicalLLs[chan] += [copy(block)] continue # Align the block # drop length 0 blocks but push frame change onto next non-zero entry if len(block) == 0: carriedPhase = {ch: carriedPhase[ch]+block.pulses[ch].frameChange for ch in channels} continue for chan in channels: # add aligned LL entry(ies) (if the block contains a composite pulse, may get back multiple waveforms and LL entries) wfs, LLentries = align(block.label, block.pulses[chan], len(block), block.alignment) for wf in wfs: if isinstance(chan, Channels.LogicalMarkerChannel): wf = wf.astype(np.bool) if PatternUtils.hash_pulse(wf) not in wfLib: wfLib[chan][PatternUtils.hash_pulse(wf)] = wf # Frame changes are then propagated through logicalLLs[chan] += propagate_frame(LLentries, carriedPhase[chan]) carriedPhase = {ch: 0 for ch in channels} # loop through again to find phases, frame changes, and SSB modulation for quadrature channels for chan in channels: if not isinstance(chan, (Channels.Qubit, Channels.Measurement)): continue curFrame = 0 for entry in logicalLLs[chan]: if isinstance(entry, ControlFlow.ControlInstruction): continue # frame update shape = np.copy(wfLib[chan][entry.key]) # See if we can turn into a TA pair # fragile: if you buffer a square pulse it will not be constant valued if np.all(shape == shape[0]): entry.isTimeAmp = True shape = shape[:1] # convert near zeros to PatternUtils.TAZKey if abs(shape[0]) < 1e-6: entry.key = PatternUtils.TAZKey #Rotate for phase and frame change (don't rotate zeros...) if entry.key != PatternUtils.TAZKey: shape *= np.exp(1j*(entry.phase+curFrame)) shapeHash = PatternUtils.hash_pulse(shape) if shapeHash not in wfLib[chan]: wfLib[chan][shapeHash] = shape entry.key = shapeHash curFrame += entry.frameChange return logicalLLs, wfLib
def compile_sequence(seq, wfLib={}, channels=None): ''' Converts a single sequence into a miniLL and waveform library. Returns a single-entry list of a miniLL and the updated wfLib ''' #Find the set of logical channels used here and initialize them if not channels: channels = find_unique_channels(seq) logicalLLs = {} for chan in channels: logicalLLs[chan] = [] if chan not in wfLib: if isinstance(chan, Channels.LogicalMarkerChannel): wfLib[chan] = markerWFLib else: wfLib[chan] = { PatternUtils.TAZKey: np.zeros(1, dtype=np.complex) } carriedPhase = {ch: 0 for ch in channels} for block in normalize(flatten(seq), channels): # control flow instructions just need to broadcast to all channels if isinstance(block, ControlFlow.ControlInstruction): for chan in channels: logicalLLs[chan] += [copy(block)] continue # Align the block # drop length 0 blocks but push frame change onto next non-zero entry if len(block) == 0: carriedPhase = { ch: carriedPhase[ch] + block.pulses[ch].frameChange for ch in channels } continue for chan in channels: # add aligned LL entry(ies) (if the block contains a composite pulse, may get back multiple waveforms and LL entries) wfs, LLentries = align(block.label, block.pulses[chan], len(block), block.alignment) for wf in wfs: if isinstance(chan, Channels.LogicalMarkerChannel): wf = wf.astype(np.bool) if PatternUtils.hash_pulse(wf) not in wfLib: wfLib[chan][PatternUtils.hash_pulse(wf)] = wf # Frame changes are then propagated through logicalLLs[chan] += propagate_frame(LLentries, carriedPhase[chan]) carriedPhase = {ch: 0 for ch in channels} # loop through again to find phases, frame changes, and SSB modulation for quadrature channels for chan in channels: if not isinstance(chan, (Channels.Qubit, Channels.Measurement)): continue curFrame = 0 for entry in logicalLLs[chan]: if isinstance(entry, ControlFlow.ControlInstruction): continue # frame update shape = np.copy(wfLib[chan][entry.key]) # See if we can turn into a TA pair # fragile: if you buffer a square pulse it will not be constant valued if np.all(shape == shape[0]): entry.isTimeAmp = True shape = shape[:1] # convert near zeros to PatternUtils.TAZKey if abs(shape[0]) < 1e-6: entry.key = PatternUtils.TAZKey #Rotate for phase and frame change (don't rotate zeros...) if entry.key != PatternUtils.TAZKey: shape *= np.exp(1j * (entry.phase + curFrame)) shapeHash = PatternUtils.hash_pulse(shape) if shapeHash not in wfLib[chan]: wfLib[chan][shapeHash] = shape entry.key = shapeHash curFrame += entry.frameChange return logicalLLs, wfLib