def combine_weights(balanced_config,
                    imbalanced_config,
                    balanced_zhu,
                    imbalanced_zhu,
                    balanced_rand,
                    imbalanced_rand,
                    spec_weight,
                    config_weight,
                    zhu_weight):
    """
    Combine config weights, Zhu-Nakamura weights, and random
    weights to get the final weights for each geom.
    Args:
        balanced_config (torch.Tensor): config weights with
                species balancing
        imbalanced_config (torch.Tensor): config weights without
                species balancing
        balanced_zhu (torch.Tensor): Zhu weights with
                species balancing
        imbalanced_zhu (torch.Tensor): Zhu weights without
                species balancing
        balanced_rand (torch.Tensor): equal weights with
                species balancing
        imbalanced_rand (torch.Tensor): equal weights without
                species balancing
        spec_weight (float): weight given to equal species balancing.
                If equal to 1, then p(A) = p(B) for all species. If equal
                to 0, species are not considered at all for balancing.
                Intermediate values reflect the extent to which you care
                about balancing species during sampling.
        config_weight (float): the weight given to balance among
                configurations. Must be <= 1.
        zhu_weight (float): the weight given to sampling high-hopping rate.
                geoms. Must be <= 1 and satisfy `config_weight` + `zhu_weight`
                <= 1. Thedifference, 1 - config_weight - zhu_weight, is the
                weight given to purely random sampling.
    Returns:
        final_weights (torch.Tensor): final weights for all geoms, normalized
                to 1.
    """

    # combination of zhu weights that are balanced and imbalanced with respect
    # to species

    weighted_zhu = (balanced_zhu * zhu_weight * spec_weight
                    + imbalanced_zhu * zhu_weight * (1 - spec_weight))

    # combination of config weights that are balanced and imbalanced with
    # respect to species
    weighted_config = (balanced_config * config_weight * spec_weight
                       + imbalanced_config * config_weight * (1 - spec_weight))

    # combination of random weights that are balanced and imbalanced with
    # respect to species

    rand_weight = (1 - zhu_weight - config_weight)
    weighted_rand = (balanced_rand * rand_weight * spec_weight
                     + imbalanced_rand * rand_weight * (1 - spec_weight))

    # final weights

    final_weights = weighted_zhu + weighted_config + weighted_rand

    return final_weights