A generator which returns all non-empty combinations of ChainMutation objects, respecting residue position i.e. if two residues
       have the same chain and residue ID then we do not return a combination with both residues.
       Note: You need to use ChainMutation objects here as their equality considers the chain id.

def mutation_combinations(mutations):
    '''A generator which returns all non-empty combinations of ChainMutation objects, respecting residue position i.e. if two residues
       have the same chain and residue ID then we do not return a combination with both residues.
       Note: You need to use ChainMutation objects here as their equality considers the chain id.
    '''
    mutations = sorted(mutations)
    combntn = itertools.chain.from_iterable(itertools.combinations(mutations, x) for x in range(len(mutations) + 1))
    for c in combntn:
        if len(c) > 0: # filter out the empty combination
            positions = ['%s%s' % (m.Chain, m.ResidueID.strip()) for m in c]
            if len(positions) == len(set(positions)): # filter out combinations where
                yield c