Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Predicates #353

Open
wants to merge 7 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions comb_spec_searcher/comb_spec_searcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -551,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),
)
Expand Down Expand Up @@ -623,10 +631,15 @@ def get_specification(
"""
if not self.ruledb.has_specification():
raise SpecificationNotFound
kwargs = {
"minimization_time_limit": minimization_time_limit,
"smallest": smallest,
}
rules = self.ruledb.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)

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
)
19 changes: 19 additions & 0 deletions comb_spec_searcher/combinatorial_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,25 @@ def minimum_size_of_object(self) -> int:
"'minimum_size_of_object' must be implemented."
)

def min_size(self) -> int:
"""
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.

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'
object. If you are having memory issues then implement this function
Expand Down
9 changes: 9 additions & 0 deletions comb_spec_searcher/rule_db/forest.py
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,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(
Expand Down
9 changes: 3 additions & 6 deletions comb_spec_searcher/strategies/constructor/cartesian.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,9 @@ 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
)
self.min_child_sizes = tuple({"n": child.min_size()} 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": child.min_size()} if child.is_atom() else {} for child in children
)
self.parent_parameters = ("n",) + parent.extra_parameters

Expand Down Expand Up @@ -397,7 +394,7 @@ 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(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
Expand Down