Example #1
0
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
Example #2
0
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
Example #3
0
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
Example #4
0
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
Example #5
0
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
Example #6
0
 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
Example #7
0
 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
Example #8
0
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
Example #9
0
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
Example #10
0
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