def get_class_weights(label_map, stype="linear", maxw=float('inf'), minw=0.0, norm=True, invmax=False):
    """Returns a map of label weights that may be adjusted based on a given rebalancing strategy.

    Args:
        label_map: map of index lists or sample counts tied to class labels.
        stype: weighting strategy ('uniform', 'linear', or 'rootX'). Using 'uniform' will provide a uniform
            map of weights. Using 'linear' will return the actual weights, unmodified. Using 'rootX' will
            rebalance the weights according to factor 'X'. See :class:`thelper.data.samplers.WeightedSubsetRandomSampler`
            for more information on these strategies.
        maxw: maximum allowed weight value (applied after invmax, if required).
        minw: minimum allowed weight value (applied after invmax, if required).
        norm: specifies whether the returned weights should be normalized (default=True, i.e. normalized).
        invmax: specifies whether to max-invert the weight vector (thus creating cost factors) or not. Not
            compatible with ``norm`` (it would return weights again instead of factors).

    Returns:
        Map of weights tied to class labels.

    .. seealso::
        | :class:`thelper.data.samplers.WeightedSubsetRandomSampler`
    """
    assert isinstance(label_map, dict) and all([isinstance(val, (list, int)) for val in label_map.values()]), \
        "unexpected label map type"
    assert stype in ["uniform", "linear"] or "root" in stype, "unknown label weighting strategy"
    if stype == "uniform":
        label_weights = {label: 1.0 / len(label_map) for label in label_map}
    else:  # if stype == "linear" or "root" in stype:
        if stype == "root" or stype == "linear":
            rpow = 1.0
        else:
            rpow = 1.0 / float(stype.split("root", 1)[1])
        label_sizes = {label: len(v) if isinstance(v, list) else v for label, v in label_map.items()}
        label_weights = {label: (lsize / sum(label_sizes.values())) ** rpow for label, lsize in label_sizes.items()}
    if invmax:
        label_weights = {label: max(label_weights.values()) / max(weight, 1e-6) for label, weight in label_weights.items()}
    label_weights = {label: min(max(weight, minw), maxw) for label, weight in label_weights.items()}
    if norm:
        assert not invmax, "if computing factors, normalizing is useless (you would get weights back again)"
        tot_weight = sum([w for w in label_weights.values()])
        label_weights = {label: weight / tot_weight for label, weight in label_weights.items()}
    return label_weights