'Since LFADS supports multiple datasets in the same dynamical model,
we have to be careful to use all the data in a single training epoch.  But
since the datasets my have different data dimensionality, we cannot batch
examples from data dictionaries together.  Instead, we generate random
batches within each data dictionary, and then randomize these batches
while holding onto the dataname, so that when it\'s time to feed
the graph, the correct in/out matrices can be selected, per batch.
Args:
datasets: A dict of data dicts.  The dataset dict is simply a
name(string)-> data dictionary mapping (See top of lfads.py).
kind: \'train\' or \'valid\'
Returns:
A flat list, in which each element is a pair (\'name\', indices).'

def shuffle_and_flatten_datasets(self, datasets, kind='train'):

    batch_size = self.hps.batch_size
    ndatasets = len(datasets)
    random_example_idxs = {}
    epoch_idxs = {}
    all_name_example_idx_pairs = []
    kind_data = (kind + '_data')
    for (name, data_dict) in datasets.items():
        (nexamples, ntime, data_dim) = data_dict[kind_data].shape
        epoch_idxs[name] = 0
        (random_example_idxs, _) = self.randomize_example_idxs_mod_batch_size(nexamples, batch_size)
        epoch_size = random_example_idxs.shape[0]
        names = ([name] * epoch_size)
        all_name_example_idx_pairs += zip(names, random_example_idxs)
    np.random.shuffle(all_name_example_idx_pairs)
    return all_name_example_idx_pairs
