<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def gather_categories(imap, header, categories=None):
 """ Find the user specified categories in the map and create a dictionary to contain the relevant data for each type within the categories. Multiple categories will have their types combined such that each possible combination will have its own entry in the dictionary. :type imap: dict :param imap: The input mapping file data keyed by SampleID :type header: list :param header: The header line from the input mapping file. This will be searched for the user-specified categories :type categories: list :param categories: The list of user-specified category column name from mapping file :rtype: dict :return: A sorted dictionary keyed on the combinations of all the types found within the user-specified categories. Each entry will contain an empty DataCategory namedtuple. If no categories are specified, a single entry with the key 'default' will be returned """

    # If no categories provided, return all SampleIDs
    if categories is None:
        return {"default": DataCategory(set(imap.keys()), {})}

    cat_ids = [header.index(cat)
               for cat in categories if cat in header and "=" not in cat]

    table = OrderedDict()
    conditions = defaultdict(set)
    for i, cat in enumerate(categories):
        if "=" in cat and cat.split("=")[0] in header:
            cat_name = header[header.index(cat.split("=")[0])]
            conditions[cat_name].add(cat.split("=")[1])

    # If invalid categories or conditions identified, return all SampleIDs
    if not cat_ids and not conditions:
        return {"default": DataCategory(set(imap.keys()), {})}

    #If only category column given, return column-wise SampleIDs
    if cat_ids and not conditions:
        for sid, row in imap.items():
            cat_name = "_".join([row[cid] for cid in cat_ids])
            if cat_name not in table:
                table[cat_name] = DataCategory(set(), {})
            table[cat_name].sids.add(sid)
        return table

    # Collect all condition names
    cond_ids = set()
    for k in conditions:
        try:
            cond_ids.add(header.index(k))
        except ValueError:
            continue
    idx_to_test = set(cat_ids).union(cond_ids)

    # If column name and condition given, return overlapping SampleIDs of column and
    # condition combinations
    for sid, row in imap.items():
        if all([row[header.index(c)] in conditions[c] for c in conditions]):
            key = "_".join([row[idx] for idx in idx_to_test])
            try:
                assert key in table.keys()
            except AssertionError:
                table[key] = DataCategory(set(), {})
            table[key].sids.add(sid)
    try:
        assert len(table) > 0
    except AssertionError:
        return {"default": DataCategory(set(imap.keys()), {})}
    else:
        return table