Repository: PermutaTriangle/Tilings

Issue:
Specification that can't count
[bugged_5x6.txt](https://github.com/PermutaTriangle/Tilings/files/5968177/bugged_5x6.txt)

On `develop` on CSS and `both-reverse-fusion` on Tilings.

To replicate:
```py
import json
from comb_spec_searcher.specification import CombinatorialSpecification
spec = CombinatorialSpecification.from_dict(json.loads(open("bugged_5x6.spec", "r").read()))
spec.count_objects_of_size(10)
```

Traceback:
```py
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-10-e8e30b3bca8a> in <module>
----> 1 spec.count_objects_of_size(10)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/specification.py in count_objects_of_size(self, n, **parameters)
    400         limit = n * self.number_of_rules()
    401         with RecursionLimit(limit):
--> 402             return self.root_rule.count_objects_of_size(n, **parameters)
    403
    404     def get_terms(self, n: int) -> Terms:

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in count_objects_of_size(self, n, **parameters)
    210         result is cached.
    211         """
--> 212         terms = self.get_terms(n)
    213         params_tuple = tuple(parameters[k] for k in self.comb_class.extra_parameters)
    214         return terms[params_tuple]

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in get_terms(self, n)
    202         Return the terms for the given n.
    203         """
--> 204         self._ensure_level(n)
    205         return self.terms_cache[n]
    206

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in _ensure_level(self, n)
    417         while n >= len(self.terms_cache):
    418             terms = self.constructor.get_terms(
--> 419                 self.get_terms, self.subterms, len(self.terms_cache)
    420             )
    421             self.terms_cache.append(terms)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/constructor/disjoint.py in get_terms(self, parent_terms, subterms, n)
    108         new_terms: Terms = Counter()
    109         for child_terms, param_map in zip(subterms, self._children_param_maps):
--> 110             for param, value in child_terms(n).items():
    111                 new_terms[param_map(param)] += value
    112         return new_terms

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in get_terms(self, n)
    202         Return the terms for the given n.
    203         """
--> 204         self._ensure_level(n)
    205         return self.terms_cache[n]
    206

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in _ensure_level(self, n)
    417         while n >= len(self.terms_cache):
    418             terms = self.constructor.get_terms(
--> 419                 self.get_terms, self.subterms, len(self.terms_cache)
    420             )
    421             self.terms_cache.append(terms)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/constructor/cartesian.py in get_terms(self, parent_terms, subterms, n)
    268         for sizes in size_compositions:
    269             for param_value_pairs in self.params_value_pairs_combinations(
--> 270                 sizes, subterms
    271             ):
    272                 new_param = self._new_param(*(p for p, _ in param_value_pairs))

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/constructor/cartesian.py in params_value_pairs_combinations(sizes, sub_getters)
    291         assert len(sizes) == len(sub_getters), sub_getters
    292         children_values = (sg(s) for sg, s in zip(sub_getters, sizes))
--> 293         return product(*(c.items() for c in children_values))
    294
    295     def get_sub_objects(

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/constructor/cartesian.py in <genexpr>(.0)
    291         assert len(sizes) == len(sub_getters), sub_getters
    292         children_values = (sg(s) for sg, s in zip(sub_getters, sizes))
--> 293         return product(*(c.items() for c in children_values))
    294
    295     def get_sub_objects(

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/constructor/cartesian.py in <genexpr>(.0)
    290     ) -> Iterator[Tuple[Tuple[Parameters, T], ...]]:
    291         assert len(sizes) == len(sub_getters), sub_getters
--> 292         children_values = (sg(s) for sg, s in zip(sub_getters, sizes))
    293         return product(*(c.items() for c in children_values))
    294

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in get_terms(self, n)
    202         Return the terms for the given n.
    203         """
--> 204         self._ensure_level(n)
    205         return self.terms_cache[n]
    206

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in _ensure_level(self, n)
    417         while n >= len(self.terms_cache):
    418             terms = self.constructor.get_terms(
--> 419                 self.get_terms, self.subterms, len(self.terms_cache)
    420             )
    421             self.terms_cache.append(terms)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/constructor/disjoint.py in get_terms(self, parent_terms, subterms, n)
    108         new_terms: Terms = Counter()
    109         for child_terms, param_map in zip(subterms, self._children_param_maps):
--> 110             for param, value in child_terms(n).items():
    111                 new_terms[param_map(param)] += value
    112         return new_terms

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in get_terms(self, n)
    202         Return the terms for the given n.
    203         """
--> 204         self._ensure_level(n)
    205         return self.terms_cache[n]
    206

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in _ensure_level(self, n)
    417         while n >= len(self.terms_cache):
    418             terms = self.constructor.get_terms(
--> 419                 self.get_terms, self.subterms, len(self.terms_cache)
    420             )
    421             self.terms_cache.append(terms)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/Tilings/tilings/strategies/assumption_insertion.py in get_terms(self, parent_terms, subterms, n)
     63     ) -> Terms:
     64         assert len(subterms) == 1
---> 65         return self._push_add_assumption(n, subterms[0], self._child_param_map)
     66
     67     @staticmethod

~/Dropbox/Research/Active/2017-44-ATRAP/repos/Tilings/tilings/strategies/assumption_insertion.py in _push_add_assumption(n, child_terms, child_param_map)
     72     ) -> Terms:
     73         new_terms: Terms = Counter()
---> 74         for param, value in child_terms(n).items():
     75             new_terms[child_param_map(param)] += value
     76         return new_terms

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in get_terms(self, n)
    202         Return the terms for the given n.
    203         """
--> 204         self._ensure_level(n)
    205         return self.terms_cache[n]
    206

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in _ensure_level(self, n)
    417         while n >= len(self.terms_cache):
    418             terms = self.constructor.get_terms(
--> 419                 self.get_terms, self.subterms, len(self.terms_cache)
    420             )
    421             self.terms_cache.append(terms)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/constructor/cartesian.py in get_terms(self, parent_terms, subterms, n)
    268         for sizes in size_compositions:
    269             for param_value_pairs in self.params_value_pairs_combinations(
--> 270                 sizes, subterms
    271             ):
    272                 new_param = self._new_param(*(p for p, _ in param_value_pairs))

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/constructor/cartesian.py in params_value_pairs_combinations(sizes, sub_getters)
    291         assert len(sizes) == len(sub_getters), sub_getters
    292         children_values = (sg(s) for sg, s in zip(sub_getters, sizes))
--> 293         return product(*(c.items() for c in children_values))
    294
    295     def get_sub_objects(

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/constructor/cartesian.py in <genexpr>(.0)
    291         assert len(sizes) == len(sub_getters), sub_getters
    292         children_values = (sg(s) for sg, s in zip(sub_getters, sizes))
--> 293         return product(*(c.items() for c in children_values))
    294
    295     def get_sub_objects(

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/constructor/cartesian.py in <genexpr>(.0)
    290     ) -> Iterator[Tuple[Tuple[Parameters, T], ...]]:
    291         assert len(sizes) == len(sub_getters), sub_getters
--> 292         children_values = (sg(s) for sg, s in zip(sub_getters, sizes))
    293         return product(*(c.items() for c in children_values))
    294

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in get_terms(self, n)
    202         Return the terms for the given n.
    203         """
--> 204         self._ensure_level(n)
    205         return self.terms_cache[n]
    206

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in _ensure_level(self, n)
    417         while n >= len(self.terms_cache):
    418             terms = self.constructor.get_terms(
--> 419                 self.get_terms, self.subterms, len(self.terms_cache)
    420             )
    421             self.terms_cache.append(terms)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/constructor/disjoint.py in get_terms(self, parent_terms, subterms, n)
    108         new_terms: Terms = Counter()
    109         for child_terms, param_map in zip(subterms, self._children_param_maps):
--> 110             for param, value in child_terms(n).items():
    111                 new_terms[param_map(param)] += value
    112         return new_terms

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in get_terms(self, n)
    202         Return the terms for the given n.
    203         """
--> 204         self._ensure_level(n)
    205         return self.terms_cache[n]
    206

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in _ensure_level(self, n)
    417         while n >= len(self.terms_cache):
    418             terms = self.constructor.get_terms(
--> 419                 self.get_terms, self.subterms, len(self.terms_cache)
    420             )
    421             self.terms_cache.append(terms)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/Tilings/tilings/strategies/assumption_insertion.py in get_terms(self, parent_terms, subterms, n)
     63     ) -> Terms:
     64         assert len(subterms) == 1
---> 65         return self._push_add_assumption(n, subterms[0], self._child_param_map)
     66
     67     @staticmethod

~/Dropbox/Research/Active/2017-44-ATRAP/repos/Tilings/tilings/strategies/assumption_insertion.py in _push_add_assumption(n, child_terms, child_param_map)
     72     ) -> Terms:
     73         new_terms: Terms = Counter()
---> 74         for param, value in child_terms(n).items():
     75             new_terms[child_param_map(param)] += value
     76         return new_terms

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in get_terms(self, n)
    202         Return the terms for the given n.
    203         """
--> 204         self._ensure_level(n)
    205         return self.terms_cache[n]
    206

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in _ensure_level(self, n)
    417         while n >= len(self.terms_cache):
    418             terms = self.constructor.get_terms(
--> 419                 self.get_terms, self.subterms, len(self.terms_cache)
    420             )
    421             self.terms_cache.append(terms)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/Tilings/tilings/strategies/fusion/constructor.py in get_terms(self, parent_terms, subterms, n)
    716     ) -> Terms:
    717         terms: Terms = Counter()
--> 718         child_terms = subterms[0](n)
    719         for param, value in child_terms.items():
    720             new_param = self.forward_map(param)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in get_terms(self, n)
    202         Return the terms for the given n.
    203         """
--> 204         self._ensure_level(n)
    205         return self.terms_cache[n]
    206

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in _ensure_level(self, n)
    417         while n >= len(self.terms_cache):
    418             terms = self.constructor.get_terms(
--> 419                 self.get_terms, self.subterms, len(self.terms_cache)
    420             )
    421             self.terms_cache.append(terms)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/Tilings/tilings/strategies/fusion/constructor.py in get_terms(self, parent_terms, subterms, n)
    716     ) -> Terms:
    717         terms: Terms = Counter()
--> 718         child_terms = subterms[0](n)
    719         for param, value in child_terms.items():
    720             new_param = self.forward_map(param)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in get_terms(self, n)
    202         Return the terms for the given n.
    203         """
--> 204         self._ensure_level(n)
    205         return self.terms_cache[n]
    206

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in _ensure_level(self, n)
    417         while n >= len(self.terms_cache):
    418             terms = self.constructor.get_terms(
--> 419                 self.get_terms, self.subterms, len(self.terms_cache)
    420             )
    421             self.terms_cache.append(terms)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/constructor/cartesian.py in get_terms(self, parent_terms, subterms, n)
    268         for sizes in size_compositions:
    269             for param_value_pairs in self.params_value_pairs_combinations(
--> 270                 sizes, subterms
    271             ):
    272                 new_param = self._new_param(*(p for p, _ in param_value_pairs))

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/constructor/cartesian.py in params_value_pairs_combinations(sizes, sub_getters)
    291         assert len(sizes) == len(sub_getters), sub_getters
    292         children_values = (sg(s) for sg, s in zip(sub_getters, sizes))
--> 293         return product(*(c.items() for c in children_values))
    294
    295     def get_sub_objects(

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/constructor/cartesian.py in <genexpr>(.0)
    291         assert len(sizes) == len(sub_getters), sub_getters
    292         children_values = (sg(s) for sg, s in zip(sub_getters, sizes))
--> 293         return product(*(c.items() for c in children_values))
    294
    295     def get_sub_objects(

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/constructor/cartesian.py in <genexpr>(.0)
    290     ) -> Iterator[Tuple[Tuple[Parameters, T], ...]]:
    291         assert len(sizes) == len(sub_getters), sub_getters
--> 292         children_values = (sg(s) for sg, s in zip(sub_getters, sizes))
    293         return product(*(c.items() for c in children_values))
    294

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in get_terms(self, n)
    202         Return the terms for the given n.
    203         """
--> 204         self._ensure_level(n)
    205         return self.terms_cache[n]
    206

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in _ensure_level(self, n)
    417         while n >= len(self.terms_cache):
    418             terms = self.constructor.get_terms(
--> 419                 self.get_terms, self.subterms, len(self.terms_cache)
    420             )
    421             self.terms_cache.append(terms)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/Tilings/tilings/strategies/fusion/constructor.py in get_terms(self, parent_terms, subterms, n)
    276                 new_terms[tuple(params)] += value
    277
--> 278         for param, value in subterms[0](n).items():
    279             fuse_region_points = param[self.fuse_parameter_index]
    280             new_params = list(self.children_param_map(param))

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in get_terms(self, n)
    202         Return the terms for the given n.
    203         """
--> 204         self._ensure_level(n)
    205         return self.terms_cache[n]
    206

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in _ensure_level(self, n)
    417         while n >= len(self.terms_cache):
    418             terms = self.constructor.get_terms(
--> 419                 self.get_terms, self.subterms, len(self.terms_cache)
    420             )
    421             self.terms_cache.append(terms)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/Tilings/tilings/strategies/fusion/constructor.py in get_terms(self, parent_terms, subterms, n)
    276                 new_terms[tuple(params)] += value
    277
--> 278         for param, value in subterms[0](n).items():
    279             fuse_region_points = param[self.fuse_parameter_index]
    280             new_params = list(self.children_param_map(param))

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in get_terms(self, n)
    202         Return the terms for the given n.
    203         """
--> 204         self._ensure_level(n)
    205         return self.terms_cache[n]
    206

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in _ensure_level(self, n)
    417         while n >= len(self.terms_cache):
    418             terms = self.constructor.get_terms(
--> 419                 self.get_terms, self.subterms, len(self.terms_cache)
    420             )
    421             self.terms_cache.append(terms)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/Tilings/tilings/strategies/rearrange_assumption.py in get_terms(self, parent_terms, subterms, n)
    190     ) -> Terms:
    191         terms: Terms = Counter()
--> 192         for param, value in subterms[0](n).items():
    193             new_param = self.child_to_parent_param_map(param)
    194             terms[new_param] += value

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in get_terms(self, n)
    202         Return the terms for the given n.
    203         """
--> 204         self._ensure_level(n)
    205         return self.terms_cache[n]
    206

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in _ensure_level(self, n)
    417         while n >= len(self.terms_cache):
    418             terms = self.constructor.get_terms(
--> 419                 self.get_terms, self.subterms, len(self.terms_cache)
    420             )
    421             self.terms_cache.append(terms)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/Tilings/tilings/strategies/rearrange_assumption.py in get_terms(self, parent_terms, subterms, n)
    190     ) -> Terms:
    191         terms: Terms = Counter()
--> 192         for param, value in subterms[0](n).items():
    193             new_param = self.child_to_parent_param_map(param)
    194             terms[new_param] += value

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in get_terms(self, n)
    202         Return the terms for the given n.
    203         """
--> 204         self._ensure_level(n)
    205         return self.terms_cache[n]
    206

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in _ensure_level(self, n)
    417         while n >= len(self.terms_cache):
    418             terms = self.constructor.get_terms(
--> 419                 self.get_terms, self.subterms, len(self.terms_cache)
    420             )
    421             self.terms_cache.append(terms)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/constructor/disjoint.py in get_terms(self, parent_terms, subterms, n)
    108         new_terms: Terms = Counter()
    109         for child_terms, param_map in zip(subterms, self._children_param_maps):
--> 110             for param, value in child_terms(n).items():
    111                 new_terms[param_map(param)] += value
    112         return new_terms

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in get_terms(self, n)
    202         Return the terms for the given n.
    203         """
--> 204         self._ensure_level(n)
    205         return self.terms_cache[n]
    206

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in _ensure_level(self, n)
    417         while n >= len(self.terms_cache):
    418             terms = self.constructor.get_terms(
--> 419                 self.get_terms, self.subterms, len(self.terms_cache)
    420             )
    421             self.terms_cache.append(terms)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/Tilings/tilings/strategies/assumption_insertion.py in get_terms(self, parent_terms, subterms, n)
     63     ) -> Terms:
     64         assert len(subterms) == 1
---> 65         return self._push_add_assumption(n, subterms[0], self._child_param_map)
     66
     67     @staticmethod

~/Dropbox/Research/Active/2017-44-ATRAP/repos/Tilings/tilings/strategies/assumption_insertion.py in _push_add_assumption(n, child_terms, child_param_map)
     72     ) -> Terms:
     73         new_terms: Terms = Counter()
---> 74         for param, value in child_terms(n).items():
     75             new_terms[child_param_map(param)] += value
     76         return new_terms

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in get_terms(self, n)
    202         Return the terms for the given n.
    203         """
--> 204         self._ensure_level(n)
    205         return self.terms_cache[n]
    206

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in _ensure_level(self, n)
    417         while n >= len(self.terms_cache):
    418             terms = self.constructor.get_terms(
--> 419                 self.get_terms, self.subterms, len(self.terms_cache)
    420             )
    421             self.terms_cache.append(terms)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/Tilings/tilings/strategies/assumption_insertion.py in get_terms(self, parent_terms, subterms, n)
     63     ) -> Terms:
     64         assert len(subterms) == 1
---> 65         return self._push_add_assumption(n, subterms[0], self._child_param_map)
     66
     67     @staticmethod

~/Dropbox/Research/Active/2017-44-ATRAP/repos/Tilings/tilings/strategies/assumption_insertion.py in _push_add_assumption(n, child_terms, child_param_map)
     72     ) -> Terms:
     73         new_terms: Terms = Counter()
---> 74         for param, value in child_terms(n).items():
     75             new_terms[child_param_map(param)] += value
     76         return new_terms

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in get_terms(self, n)
    202         Return the terms for the given n.
    203         """
--> 204         self._ensure_level(n)
    205         return self.terms_cache[n]
    206

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in _ensure_level(self, n)
    417         while n >= len(self.terms_cache):
    418             terms = self.constructor.get_terms(
--> 419                 self.get_terms, self.subterms, len(self.terms_cache)
    420             )
    421             self.terms_cache.append(terms)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/Tilings/tilings/strategies/rearrange_assumption.py in get_terms(self, parent_terms, subterms, n)
    190     ) -> Terms:
    191         terms: Terms = Counter()
--> 192         for param, value in subterms[0](n).items():
    193             new_param = self.child_to_parent_param_map(param)
    194             terms[new_param] += value

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in get_terms(self, n)
    202         Return the terms for the given n.
    203         """
--> 204         self._ensure_level(n)
    205         return self.terms_cache[n]
    206

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in _ensure_level(self, n)
    417         while n >= len(self.terms_cache):
    418             terms = self.constructor.get_terms(
--> 419                 self.get_terms, self.subterms, len(self.terms_cache)
    420             )
    421             self.terms_cache.append(terms)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/Tilings/tilings/strategies/fusion/constructor.py in get_terms(self, parent_terms, subterms, n)
    716     ) -> Terms:
    717         terms: Terms = Counter()
--> 718         child_terms = subterms[0](n)
    719         for param, value in child_terms.items():
    720             new_param = self.forward_map(param)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in get_terms(self, n)
    202         Return the terms for the given n.
    203         """
--> 204         self._ensure_level(n)
    205         return self.terms_cache[n]
    206

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in _ensure_level(self, n)
    417         while n >= len(self.terms_cache):
    418             terms = self.constructor.get_terms(
--> 419                 self.get_terms, self.subterms, len(self.terms_cache)
    420             )
    421             self.terms_cache.append(terms)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/constructor/cartesian.py in get_terms(self, parent_terms, subterms, n)
    268         for sizes in size_compositions:
    269             for param_value_pairs in self.params_value_pairs_combinations(
--> 270                 sizes, subterms
    271             ):
    272                 new_param = self._new_param(*(p for p, _ in param_value_pairs))

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/constructor/cartesian.py in params_value_pairs_combinations(sizes, sub_getters)
    291         assert len(sizes) == len(sub_getters), sub_getters
    292         children_values = (sg(s) for sg, s in zip(sub_getters, sizes))
--> 293         return product(*(c.items() for c in children_values))
    294
    295     def get_sub_objects(

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/constructor/cartesian.py in <genexpr>(.0)
    291         assert len(sizes) == len(sub_getters), sub_getters
    292         children_values = (sg(s) for sg, s in zip(sub_getters, sizes))
--> 293         return product(*(c.items() for c in children_values))
    294
    295     def get_sub_objects(

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/constructor/cartesian.py in <genexpr>(.0)
    290     ) -> Iterator[Tuple[Tuple[Parameters, T], ...]]:
    291         assert len(sizes) == len(sub_getters), sub_getters
--> 292         children_values = (sg(s) for sg, s in zip(sub_getters, sizes))
    293         return product(*(c.items() for c in children_values))
    294

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in get_terms(self, n)
    202         Return the terms for the given n.
    203         """
--> 204         self._ensure_level(n)
    205         return self.terms_cache[n]
    206

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in _ensure_level(self, n)
    417         while n >= len(self.terms_cache):
    418             terms = self.constructor.get_terms(
--> 419                 self.get_terms, self.subterms, len(self.terms_cache)
    420             )
    421             self.terms_cache.append(terms)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/Tilings/tilings/strategies/rearrange_assumption.py in get_terms(self, parent_terms, subterms, n)
    190     ) -> Terms:
    191         terms: Terms = Counter()
--> 192         for param, value in subterms[0](n).items():
    193             new_param = self.child_to_parent_param_map(param)
    194             terms[new_param] += value

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in get_terms(self, n)
    202         Return the terms for the given n.
    203         """
--> 204         self._ensure_level(n)
    205         return self.terms_cache[n]
    206

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in _ensure_level(self, n)
    417         while n >= len(self.terms_cache):
    418             terms = self.constructor.get_terms(
--> 419                 self.get_terms, self.subterms, len(self.terms_cache)
    420             )
    421             self.terms_cache.append(terms)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/Tilings/tilings/strategies/rearrange_assumption.py in get_terms(self, parent_terms, subterms, n)
    190     ) -> Terms:
    191         terms: Terms = Counter()
--> 192         for param, value in subterms[0](n).items():
    193             new_param = self.child_to_parent_param_map(param)
    194             terms[new_param] += value

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in get_terms(self, n)
    202         Return the terms for the given n.
    203         """
--> 204         self._ensure_level(n)
    205         return self.terms_cache[n]
    206

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in _ensure_level(self, n)
    417         while n >= len(self.terms_cache):
    418             terms = self.constructor.get_terms(
--> 419                 self.get_terms, self.subterms, len(self.terms_cache)
    420             )
    421             self.terms_cache.append(terms)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/Tilings/tilings/strategies/fusion/constructor.py in get_terms(self, parent_terms, subterms, n)
    276                 new_terms[tuple(params)] += value
    277
--> 278         for param, value in subterms[0](n).items():
    279             fuse_region_points = param[self.fuse_parameter_index]
    280             new_params = list(self.children_param_map(param))

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in get_terms(self, n)
    202         Return the terms for the given n.
    203         """
--> 204         self._ensure_level(n)
    205         return self.terms_cache[n]
    206

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in _ensure_level(self, n)
    417         while n >= len(self.terms_cache):
    418             terms = self.constructor.get_terms(
--> 419                 self.get_terms, self.subterms, len(self.terms_cache)
    420             )
    421             self.terms_cache.append(terms)

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/constructor/disjoint.py in get_terms(self, parent_terms, subterms, n)
    108         new_terms: Terms = Counter()
    109         for child_terms, param_map in zip(subterms, self._children_param_maps):
--> 110             for param, value in child_terms(n).items():
    111                 new_terms[param_map(param)] += value
    112         return new_terms

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in get_terms(self, n)
    202         Return the terms for the given n.
    203         """
--> 204         self._ensure_level(n)
    205         return self.terms_cache[n]
    206

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in _ensure_level(self, n)
    416             raise RuntimeError("set_subrecs must be set first")
    417         while n >= len(self.terms_cache):
--> 418             terms = self.constructor.get_terms(
    419                 self.get_terms, self.subterms, len(self.terms_cache)
    420             )

~/Dropbox/Research/Active/2017-44-ATRAP/repos/Tilings/tilings/strategies/fusion/fusion.py in constructor(self)
     26     @property
     27     def constructor(self) -> FusionConstructor:
---> 28         return cast(FusionConstructor, super().constructor)
     29
     30     @staticmethod

~/Dropbox/Research/Active/2017-44-ATRAP/repos/comb_spec_searcher/comb_spec_searcher/strategies/rule.py in constructor(self)
    365         if self._constructor is None:
    366             self._constructor = self.strategy.constructor(
--> 367                 self.comb_class, self.children
    368             )
    369             if self._constructor is None:

~/Dropbox/Research/Active/2017-44-ATRAP/repos/Tilings/tilings/strategies/fusion/fusion.py in constructor(self, comb_class, children)
    186             *self.left_right_both_sided_parameters(comb_class),
    187             min_left,
--> 188             min_right,
    189         )
    190

~/Dropbox/Research/Active/2017-44-ATRAP/repos/Tilings/tilings/strategies/fusion/constructor.py in __init__(self, parent, child, fuse_parameter, extra_parameters, left_sided_parameters, right_sided_parameters, both_sided_parameters, min_left, min_right)
     92         self.both_sided_parameters = frozenset(both_sided_parameters)
     93
---> 94         self._init_checked()
     95
     96         self.parent_fusion_parameters = self.reversed_extra_parameters[

~/Dropbox/Research/Active/2017-44-ATRAP/repos/Tilings/tilings/strategies/fusion/constructor.py in _init_checked(self)
    159                 )
    160             )
--> 161             for val in self.reversed_extra_parameters.values()
    162         )
    163         assert all(

AssertionError:
```

Discussion:

Patch:
diff --git a/tilings/strategies/fusion/constructor.py b/tilings/strategies/fusion/constructor.py
index 6f645fa..e3e3c06 100644
--- a/tilings/strategies/fusion/constructor.py
+++ b/tilings/strategies/fusion/constructor.py
@@ -139,27 +139,14 @@ class FusionConstructor(Constructor[Tiling, GriddedPerm]):
 
     def _init_checked(self):
         """
-        The lists in reversed_extra_parameters can have size at most two (in
-        which case one of the two variables is a subset of the other), unless,
-        they are contained entirely within the fused region, in which case it
-        can have up to 3, namely left, right and both. This is checked in the
-        first assertion.
+        The lists in reversed_extra_parameters can have size at most three.
+        This is checked in the first assertion.
 
         Moreover, if two parent assumptions map to the same assumption, then one
         of them is one sided, and the other covers both sides, OR they are all
         contained fully in fuse region. This is checked in the second assertion.
         """
-        assert all(
-            len(val) <= 2
-            or (
-                len(val) == 3
-                and all(
-                    self.extra_parameters[parent_var] == self.fuse_parameter
-                    for parent_var in val
-                )
-            )
-            for val in self.reversed_extra_parameters.values()
-        )
+        assert all(len(val) <= 3 for val in self.reversed_extra_parameters.values())
         assert all(
             (
                 any(


Test patch:
diff --git a/tests/strategies/test_sanity_check.py b/tests/strategies/test_sanity_check.py
index 6c65b19..10f4edb 100644
--- a/tests/strategies/test_sanity_check.py
+++ b/tests/strategies/test_sanity_check.py
@@ -368,6 +368,37 @@ rules_to_check = [
             ),
         )
     ),
+    FusionStrategy(row_idx=1, col_idx=None, tracked=True)(
+        Tiling(
+            obstructions=(
+                GriddedPerm((0, 1), ((0, 0), (0, 0))),
+                GriddedPerm((0, 1, 2), ((0, 0), (0, 1), (0, 1))),
+                GriddedPerm((0, 1, 2), ((0, 0), (0, 1), (0, 2))),
+                GriddedPerm((0, 1, 2), ((0, 0), (0, 2), (0, 2))),
+                GriddedPerm((0, 1, 2), ((0, 1), (0, 1), (0, 1))),
+                GriddedPerm((0, 1, 2), ((0, 1), (0, 1), (0, 2))),
+                GriddedPerm((0, 1, 2), ((0, 1), (0, 2), (0, 2))),
+                GriddedPerm((0, 1, 2), ((0, 2), (0, 2), (0, 2))),
+            ),
+            assumptions=(
+                TrackingAssumption((GriddedPerm((0,), ((0, 0),)),)),
+                TrackingAssumption(
+                    (GriddedPerm((0,), ((0, 0),)), GriddedPerm((0,), ((0, 1),)))
+                ),
+                TrackingAssumption(
+                    (
+                        GriddedPerm((0,), ((0, 0),)),
+                        GriddedPerm((0,), ((0, 1),)),
+                        GriddedPerm((0,), ((0, 2),)),
+                    )
+                ),
+                TrackingAssumption(
+                    (GriddedPerm((0,), ((0, 0),)), GriddedPerm((0,), ((0, 2),)))
+                ),
+                TrackingAssumption((GriddedPerm((0,), ((0, 2),)),)),
+            ),
+        )
+    ),
 ]