'Shuffle the spikes in the temporal dimension.  This is useful to
help the LFADS system avoid overfitting to individual spikes or fast
oscillations found in the data that are irrelevant to behavior. A
pure \'tabula rasa\' approach would avoid this, but LFADS is sensitive
enough to pick up dynamics that you may not want.
Args:
data_bxtxd: numpy array of spike count data to be shuffled.
Returns:
S_bxtxd, a numpy array with the same dimensions and contents as
data_bxtxd, but shuffled appropriately.'

def shuffle_spikes_in_time(self, data_bxtxd):

    (B, T, N) = data_bxtxd.shape
    w = self.hps.temporal_spike_jitter_width
    if (w == 0):
        return data_bxtxd
    max_counts = np.max(data_bxtxd)
    S_bxtxd = np.zeros([B, T, N])
    for mc in range(1, (max_counts + 1)):
        idxs = np.nonzero((data_bxtxd >= mc))
        data_ones = np.zeros_like(data_bxtxd)
        data_ones[(data_bxtxd >= mc)] = 1
        nfound = len(idxs[0])
        shuffles_incrs_in_time = np.random.randint((- w), w, size=nfound)
        shuffle_tidxs = idxs[1].copy()
        shuffle_tidxs += shuffles_incrs_in_time
        shuffle_tidxs[(shuffle_tidxs < 0)] = (- shuffle_tidxs[(shuffle_tidxs < 0)])
        shuffle_tidxs[(shuffle_tidxs > (T - 1))] = ((T - 1) - (shuffle_tidxs[(shuffle_tidxs > (T - 1))] - (T - 1)))
        for iii in zip(idxs[0], shuffle_tidxs, idxs[2]):
            S_bxtxd[iii] += 1
    return S_bxtxd
