def combinations_for_sum(values, target):
    if target < 0 or any(x <= 0 for x in values):
        raise ValueError('target must be non-negative and values positive')
    values = sorted(values)
    answer, path = [], []

    def search(start, remaining):
        if remaining == 0:
            answer.append(path.copy())
            return
        for i in range(start, len(values)):
            if i > start and values[i] == values[i - 1]:
                continue
            if values[i] > remaining:
                break
            path.append(values[i])
            search(i + 1, remaining - values[i])
            path.pop()

    search(0, target)
    return answer


if __name__ == '__main__':
    print(combinations_for_sum([1, 1, 2, 3], 4))
