From 901a0c6806bd14b0c01191553438ecac926ca2a9 Mon Sep 17 00:00:00 2001 From: Christian Bean Date: Wed, 27 Jul 2022 16:57:47 +0000 Subject: [PATCH 1/6] some code for the predicates branch on tilings --- comb_spec_searcher/comb_spec_searcher.py | 8 ++++++++ comb_spec_searcher/rule_db/abstract.py | 4 +++- comb_spec_searcher/rule_db/forest.py | 9 +++++++++ .../strategies/constructor/cartesian.py | 11 ++++++++++- 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/comb_spec_searcher/comb_spec_searcher.py b/comb_spec_searcher/comb_spec_searcher.py index ec05ec275..2165e3f64 100644 --- a/comb_spec_searcher/comb_spec_searcher.py +++ b/comb_spec_searcher/comb_spec_searcher.py @@ -282,6 +282,14 @@ def add_rule( """ for comb_class, child_label in zip(rule.children, end_labels): if not rule.possibly_empty: + if self.debug: + if comb_class.is_empty(): + logger.debug( + "SANITY CHECK FAILURE.\n" + " The folowing combinatorial class " + "is set not empty but is empty!\n%s", + comb_class, + ) self.classdb.set_empty(child_label, empty=False) if self.symmetries and child_label not in self.symmetry_expanded: self._symmetry_expand(comb_class, child_label) diff --git a/comb_spec_searcher/rule_db/abstract.py b/comb_spec_searcher/rule_db/abstract.py index 9388ff427..24d1cd238 100644 --- a/comb_spec_searcher/rule_db/abstract.py +++ b/comb_spec_searcher/rule_db/abstract.py @@ -52,7 +52,9 @@ def classdb(self) -> ClassDB: @property def strategy_pack(self) -> StrategyPack: - return self.searcher.strategy_pack + from tilings.tilescope import OddOrEvenStrategy + + return self.searcher.strategy_pack.add_initial(OddOrEvenStrategy()) @property def root_label(self) -> int: diff --git a/comb_spec_searcher/rule_db/forest.py b/comb_spec_searcher/rule_db/forest.py index d805ea74e..5161044f0 100644 --- a/comb_spec_searcher/rule_db/forest.py +++ b/comb_spec_searcher/rule_db/forest.py @@ -686,6 +686,15 @@ def _add_empty_rule(self, ends: Iterable[int], rule: AbstractRule) -> None: Add empty rule for the children of the rule if needed. """ if not rule.possibly_empty: + if self.searcher.debug: + for child in rule.children: + if child.is_empty(): + logger.debug( + "SANITY CHECK FAILURE.\n" + " The folowing combinatorial class " + "assumed not empty but is empty!\n%s", + child, + ) return for label, comb_class in zip(ends, rule.children): if label not in self._already_empty and self.classdb.is_empty( diff --git a/comb_spec_searcher/strategies/constructor/cartesian.py b/comb_spec_searcher/strategies/constructor/cartesian.py index d994ce8f6..62c27c1a4 100644 --- a/comb_spec_searcher/strategies/constructor/cartesian.py +++ b/comb_spec_searcher/strategies/constructor/cartesian.py @@ -396,7 +396,16 @@ def __init__( self._children_param_maps = CartesianProduct._build_children_param_map( parent, children, self.extra_parameters ) - self._min_sizes = tuple(child.minimum_size_of_object() for child in children) + self._min_sizes = tuple( + len( + next( + child.gridded_perms( + child.maximum_length_of_minimum_gridded_perm() + 4 + ) + ) + ) + for child in children + ) self._max_sizes = tuple( child.minimum_size_of_object() if child.is_atom() else None for child in children From d03f2a55cc942d6ea0abf6b91cca70c8496b1e90 Mon Sep 17 00:00:00 2001 From: Christian Bean Date: Thu, 28 Jul 2022 15:32:59 +0000 Subject: [PATCH 2/6] compute min value in cartesian hard coded --- .../strategies/constructor/cartesian.py | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/comb_spec_searcher/strategies/constructor/cartesian.py b/comb_spec_searcher/strategies/constructor/cartesian.py index 62c27c1a4..03d6969f0 100644 --- a/comb_spec_searcher/strategies/constructor/cartesian.py +++ b/comb_spec_searcher/strategies/constructor/cartesian.py @@ -74,12 +74,22 @@ def __init__( for k in parent.extra_parameters: self.minimum_sizes[k] = parent.get_minimum_value(k) - self.min_child_sizes = tuple( - {"n": child.minimum_size_of_object()} for child in children - ) + def min_size(child): + try: + min_point = len( + next( + child.gridded_perms( + child.maximum_length_of_minimum_gridded_perm() + 4 + ) + ) + ) + except StopIteration: + min_point = child.minimum_size_of_object() + return min_point + + self.min_child_sizes = tuple({"n": min_size(child)} for child in children) self.max_child_sizes = tuple( - {"n": child.minimum_size_of_object()} if child.is_atom() else {} - for child in children + {"n": min_size(child)} if child.is_atom() else {} for child in children ) self.parent_parameters = ("n",) + parent.extra_parameters From a25edacf751f0cd08df034276967f700f5743b26 Mon Sep 17 00:00:00 2001 From: Christian Bean Date: Wed, 22 Mar 2023 11:38:47 +0000 Subject: [PATCH 3/6] move tiling specific things out of here! --- comb_spec_searcher/comb_spec_searcher.py | 11 +++++++++-- comb_spec_searcher/combinatorial_class.py | 9 +++++++++ comb_spec_searcher/rule_db/abstract.py | 4 +--- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/comb_spec_searcher/comb_spec_searcher.py b/comb_spec_searcher/comb_spec_searcher.py index 2165e3f64..35e1e813c 100644 --- a/comb_spec_searcher/comb_spec_searcher.py +++ b/comb_spec_searcher/comb_spec_searcher.py @@ -559,7 +559,7 @@ def _auto_search_rules( logger.debug("Searching for specification.") if self.has_specification(): logger.info("Specification detected.") - return self.ruledb.get_specification_rules( + return self._get_specification_rules( smallest=smallest, minimization_time_limit=0.01 * (time.time() - auto_search_start), ) @@ -635,6 +635,13 @@ def get_specification( "minimization_time_limit": minimization_time_limit, "smallest": smallest, } - rules = self.ruledb.get_specification_rules(**kwargs) + rules = self._get_specification_rules(**kwargs) logger.info("Creating a specification.") return CombinatorialSpecification(self.start_class, rules) + + def _get_specification_rules( + self, smallest: bool = False, minimization_time_limit: float = 10 + ) -> Iterator[AbstractRule]: + return self.ruledb.get_specification_rules( + smallest=smallest, minimization_time_limit=minimization_time_limit + ) diff --git a/comb_spec_searcher/combinatorial_class.py b/comb_spec_searcher/combinatorial_class.py index db8da0a7b..04c2b9404 100644 --- a/comb_spec_searcher/combinatorial_class.py +++ b/comb_spec_searcher/combinatorial_class.py @@ -203,6 +203,15 @@ def minimum_size_of_object(self) -> int: "'minimum_size_of_object' must be implemented." ) + def min_size(self) -> int: + """Return the minimum size of the objects in the combinatorial class. + This is the method used by the Cartesian product constructor. + For productivity reasons, you must at least return 1, if this should be + greater than 0.""" + raise NotImplementedError( + "To use the CartesianProduct constructor, 'min_size' must be implemented." + ) + def to_bytes(self) -> bytes: """Return a compressed version of the class in the form of a 'bytes' object. If you are having memory issues then implement this function diff --git a/comb_spec_searcher/rule_db/abstract.py b/comb_spec_searcher/rule_db/abstract.py index 24d1cd238..9388ff427 100644 --- a/comb_spec_searcher/rule_db/abstract.py +++ b/comb_spec_searcher/rule_db/abstract.py @@ -52,9 +52,7 @@ def classdb(self) -> ClassDB: @property def strategy_pack(self) -> StrategyPack: - from tilings.tilescope import OddOrEvenStrategy - - return self.searcher.strategy_pack.add_initial(OddOrEvenStrategy()) + return self.searcher.strategy_pack @property def root_label(self) -> int: From b65ca333f641f669f6095c26f894a75c9e09bce9 Mon Sep 17 00:00:00 2001 From: Christian Bean Date: Wed, 22 Mar 2023 11:41:57 +0000 Subject: [PATCH 4/6] min size now a method on comb class --- .../strategies/constructor/cartesian.py | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/comb_spec_searcher/strategies/constructor/cartesian.py b/comb_spec_searcher/strategies/constructor/cartesian.py index bc2b641df..76bdf5c06 100644 --- a/comb_spec_searcher/strategies/constructor/cartesian.py +++ b/comb_spec_searcher/strategies/constructor/cartesian.py @@ -74,22 +74,9 @@ def __init__( for k in parent.extra_parameters: self.minimum_sizes[k] = parent.get_minimum_value(k) - def min_size(child): - try: - min_point = len( - next( - child.gridded_perms( - child.maximum_length_of_minimum_gridded_perm() + 4 - ) - ) - ) - except StopIteration: - min_point = child.minimum_size_of_object() - return min_point - - self.min_child_sizes = tuple({"n": min_size(child)} for child in children) + self.min_child_sizes = tuple({"n": child.min_size()} for child in children) self.max_child_sizes = tuple( - {"n": min_size(child)} if child.is_atom() else {} for child in children + {"n": child.min_size()} if child.is_atom() else {} for child in children ) self.parent_parameters = ("n",) + parent.extra_parameters From 2222c740d1b2761cbd182f68343c7ef9e5bb6c81 Mon Sep 17 00:00:00 2001 From: Christian Bean Date: Wed, 22 Mar 2023 12:13:53 +0000 Subject: [PATCH 5/6] add default min size method --- comb_spec_searcher/combinatorial_class.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/comb_spec_searcher/combinatorial_class.py b/comb_spec_searcher/combinatorial_class.py index 04c2b9404..6c1bbc394 100644 --- a/comb_spec_searcher/combinatorial_class.py +++ b/comb_spec_searcher/combinatorial_class.py @@ -204,13 +204,23 @@ def minimum_size_of_object(self) -> int: ) def min_size(self) -> int: - """Return the minimum size of the objects in the combinatorial class. + """ + This is only here for when you are using an is empty method which returns + False on sets which are empty. If you are using an is empty method which + is 100% accurate, you can ignore this method. + + Return the minimum size of the objects in the combinatorial class. This is the method used by the Cartesian product constructor. For productivity reasons, you must at least return 1, if this should be - greater than 0.""" - raise NotImplementedError( - "To use the CartesianProduct constructor, 'min_size' must be implemented." - ) + greater than 0. + + By default, CartesianProductStrategy assumes that all children are + non-empty, and hence this check is redundant so it instead calls the + 'minimum_size_of_object' method. But, if you overwrite the + CartesianProductStrategy to allow for some children to be empty, then + the rules are reversible only if all children are non-empty. + """ + return self.minimum_size_of_object() def to_bytes(self) -> bytes: """Return a compressed version of the class in the form of a 'bytes' From 096862d2130bafe6f797cde7c143e77fe6650946 Mon Sep 17 00:00:00 2001 From: Christian Bean Date: Wed, 22 Mar 2023 12:19:26 +0000 Subject: [PATCH 6/6] tidying up --- comb_spec_searcher/comb_spec_searcher.py | 8 +++----- .../strategies/constructor/cartesian.py | 11 +---------- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/comb_spec_searcher/comb_spec_searcher.py b/comb_spec_searcher/comb_spec_searcher.py index 35e1e813c..8e36f8150 100644 --- a/comb_spec_searcher/comb_spec_searcher.py +++ b/comb_spec_searcher/comb_spec_searcher.py @@ -631,11 +631,9 @@ def get_specification( """ if not self.ruledb.has_specification(): raise SpecificationNotFound - kwargs = { - "minimization_time_limit": minimization_time_limit, - "smallest": smallest, - } - rules = self._get_specification_rules(**kwargs) + rules = self._get_specification_rules( + smallest=smallest, minimization_time_limit=minimization_time_limit + ) logger.info("Creating a specification.") return CombinatorialSpecification(self.start_class, rules) diff --git a/comb_spec_searcher/strategies/constructor/cartesian.py b/comb_spec_searcher/strategies/constructor/cartesian.py index 76bdf5c06..2b8ef8207 100644 --- a/comb_spec_searcher/strategies/constructor/cartesian.py +++ b/comb_spec_searcher/strategies/constructor/cartesian.py @@ -394,16 +394,7 @@ def __init__( self._children_param_maps = CartesianProduct._build_children_param_map( parent, children, self.extra_parameters ) - self._min_sizes = tuple( - len( - next( - child.gridded_perms( - child.maximum_length_of_minimum_gridded_perm() + 4 - ) - ) - ) - for child in children - ) + self._min_sizes = tuple(child.min_size() for child in children) self._max_sizes = tuple( child.minimum_size_of_object() if child.is_atom() else None for child in children