From 0cc8e39946755bcd6e1bb7493a1c468199b0e09c Mon Sep 17 00:00:00 2001 From: Dimitri Vranken Date: Mon, 16 Jan 2023 18:02:58 +0100 Subject: [PATCH 1/2] Use itertools.combinations generator for subsets_of_size_k --- cscl/cardinality_constraint_encoders.py | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/cscl/cardinality_constraint_encoders.py b/cscl/cardinality_constraint_encoders.py index 46245bb..50c97d0 100644 --- a/cscl/cardinality_constraint_encoders.py +++ b/cscl/cardinality_constraint_encoders.py @@ -8,7 +8,7 @@ import itertools -def subsets_of_size_k(collection, k): +def subsets_of_size_k(collection: list, k: int): """ Computes all subsets of size k. @@ -16,27 +16,8 @@ def subsets_of_size_k(collection, k): :param k: A non-negative integer. :return: A list containing all size-k subsets of collection. """ - # Potential optimization: make this a generator - - assert(k >= 0) - - # Base cases: - if k > len(collection): - return [] - if k == 0: - return [[]] - if k == len(collection): - return [collection] - - next_smaller_subsets = subsets_of_size_k(collection[1:], k-1) - next_subsets = subsets_of_size_k(collection[1:], k) - - def extend_list(lst, item): - lst_copy = lst[:] - lst_copy.append(item) - return lst_copy - - return next_subsets + list(map(lambda x: extend_list(x, collection[0]), next_smaller_subsets)) + + return map(list, itertools.combinations(collection, k)) def encode_at_most_k_constraint_binomial(lit_factory: CNFLiteralFactory, k: int, constrained_lits: list): From 534da82b8d1d24120a2f9aab26506dc5acaed13b Mon Sep 17 00:00:00 2001 From: Dimitri Vranken Date: Mon, 16 Jan 2023 18:07:42 +0100 Subject: [PATCH 2/2] Optimize encode_at_most_k_constraint_binomial Negating the input of subsets_of_size_k is faster than negating the output, as the input is smaller. encode_at_most_k_constraint_binomial is now a generator, so we need to wrap it in list() where needed. --- cscl/cardinality_constraint_encoders.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/cscl/cardinality_constraint_encoders.py b/cscl/cardinality_constraint_encoders.py index 50c97d0..f5ca9f8 100644 --- a/cscl/cardinality_constraint_encoders.py +++ b/cscl/cardinality_constraint_encoders.py @@ -34,10 +34,7 @@ def encode_at_most_k_constraint_binomial(lit_factory: CNFLiteralFactory, k: int, :return: The constraint in CNF clausal form, a list of lists of literals. """ - result = [] - for subset in subsets_of_size_k(constrained_lits, k+1): - result.append(list(map(lambda x: -x, subset))) - return result + return subsets_of_size_k([ -x for x in constrained_lits], k+1) def encode_at_most_k_constraint_ltseq(lit_factory: CNFLiteralFactory, k: int, constrained_lits: list): @@ -189,7 +186,7 @@ def encode_at_most_k_constraint_commander(lit_factory: CNFLiteralFactory, k: int for idx, group in enumerate(groups): group_with_commanders = group + [-c for c in commanders[idx]] group_constraints += encode_exactly_k_constraint(lit_factory, k, group_with_commanders, - encode_at_most_k_constraint_binomial) + list(encode_at_most_k_constraint_binomial)) # Break symmetries by ordering the commander literals: order_commanders = [[-group_commanders[i], group_commanders[i+1]]