Repository: PermutaTriangle/Tilings

Issue:
NoMoreClassesToExpandError
This should replicate (not sure how long it takes, will update later)
```python
from tilings.tilescope import TileScope, TileScopePack
from comb_spec_searcher.rule_db import LimitedStrategyRuleDB
from tilings.strategies.fusion import FusionStrategy

basis = '0123_1230'
pack = TileScopePack.insertion_row_and_col_placements(row_only=True).make_fusion(apply_first=True)
css = TileScope(basis, pack)
spec = css.auto_search()
```

Full traceback:
```
[E 200625 19:12:30 surveyor:211] 0123_1230
    insertion_row_placements_fusion
    Looking for recursive combinatorial specification with the strategies:
    Inferral: row and column separation, obstruction transitivity
    Initial: tracked fusion, add assumptions, splitting the assumptions, factor, requirement corroboration, point insertion
    Verification: verify atoms, insertion encoding verified, one by one verification, locally factorable verification
    Set 1: row placement

    Traceback (most recent call last):
      File "/users/personnel/jay/atrap/repos/comb_spec_searcher/comb_spec_searcher/class_queue.py", line 228, in do_level
        yield next(self)
      File "/users/personnel/jay/atrap/repos/comb_spec_searcher/comb_spec_searcher/class_queue.py", line 217, in __next__
        self._populate_staging()
      File "/users/personnel/jay/atrap/repos/comb_spec_searcher/comb_spec_searcher/class_queue.py", line 169, in _populate_staging
        self._change_level()
      File "/users/personnel/jay/atrap/repos/comb_spec_searcher/comb_spec_searcher/class_queue.py", line 182, in _change_level
        raise StopIteration
    StopIteration

    During handling of the above exception, another exception occurred:

    Traceback (most recent call last):
      File "/users/personnel/jay/atrap/repos/comb_spec_searcher/comb_spec_searcher/specification.py", line 159, in _expand_verified_comb_classes
        css.do_level()
      File "/users/personnel/jay/atrap/repos/comb_spec_searcher/comb_spec_searcher/comb_spec_searcher.py", line 406, in do_level
        for label, strategies, inferral in self.classqueue.do_level():
      File "/users/personnel/jay/atrap/repos/comb_spec_searcher/comb_spec_searcher/class_queue.py", line 231, in do_level
        raise NoMoreClassesToExpandError
    comb_spec_searcher.exception.NoMoreClassesToExpandError

    During handling of the above exception, another exception occurred:

    Traceback (most recent call last):
      File "/users/personnel/jay/atrap/repos/handy-scripts/jay/surveyor/surveyor.py", line 104, in run_work_packet
        spec = css.auto_search(max_time=time_to_try)
      File "/users/personnel/jay/atrap/repos/comb_spec_searcher/comb_spec_searcher/comb_spec_searcher.py", line 613, in auto_search
        minimization_time_limit=0.01 * (time.time() - auto_search_start),
      File "/users/personnel/jay/atrap/repos/comb_spec_searcher/comb_spec_searcher/utils.py", line 30, in inner
        res = func(css, *args, **kwargs)
      File "/users/personnel/jay/atrap/repos/comb_spec_searcher/comb_spec_searcher/comb_spec_searcher.py", line 676, in get_specification
        expand_verified=expand_verified,
      File "/users/personnel/jay/atrap/repos/comb_spec_searcher/comb_spec_searcher/specification.py", line 75, in __init__
        self._populate_rules_dict(strategies, equivalence_paths, expand_verified)
      File "/users/personnel/jay/atrap/repos/comb_spec_searcher/comb_spec_searcher/specification.py", line 123, in _populate_rules_dict
        self._expand_verified_comb_classes(verification_packs)
      File "/users/personnel/jay/atrap/repos/comb_spec_searcher/comb_spec_searcher/specification.py", line 163, in _expand_verified_comb_classes
        css.start_label
      File "/users/personnel/jay/atrap/repos/comb_spec_searcher/comb_spec_searcher/rule_db/base.py", line 256, in get_smallest_specification
        raise SpecificationNotFound("No specification for label {}".format(label))
    comb_spec_searcher.exception.SpecificationNotFound: No specification for label 0
```

Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5c14f31..54d0f2d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -28,6 +28,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
   any factor strategy in the pack to allow interleaving. The default setting is
   for tracked, and so the assumption strategies are also added. This can be
   turned off with the flag `tracked=False`.
+- `InsertionEncodingVerificationStrategy` was added to verification expansion
+  packs.
+
+### Changed
+- The definition of a local `TrackingAssumption` in `LocalEnumeration` now says
+  it is local if every gp in it is local (before it was they all used the same
+  single cell).
+- the default in `LocalVerificationStrategy` is now `no_factors=False`.
 
 ### Fixed
 - untracked fusion packs don't add assumption strategies
diff --git a/tilings/algorithms/enumeration.py b/tilings/algorithms/enumeration.py
index 9272b7b..bbf465f 100644
--- a/tilings/algorithms/enumeration.py
+++ b/tilings/algorithms/enumeration.py
@@ -67,7 +67,10 @@ class LocalEnumeration(Enumeration):
             all(gp.is_single_cell() for gp in self.tiling.obstructions)
             and all(self._req_is_single_cell(req) for req in self.tiling.requirements)
             and all(
-                self._req_is_single_cell(ass.gps) for ass in self.tiling.assumptions
+                gp.is_single_cell()
+                for gp in chain.from_iterable(
+                    ass.gps for ass in self.tiling.assumptions
+                )
             )
         )
 
diff --git a/tilings/strategies/verification.py b/tilings/strategies/verification.py
index e861e43..be49a4c 100644
--- a/tilings/strategies/verification.py
+++ b/tilings/strategies/verification.py
@@ -342,6 +342,7 @@ class LocallyFactorableVerificationStrategy(TileScopeVerificationStrategy):
             ver_strats=[
                 BasicVerificationStrategy(),
                 OneByOneVerificationStrategy(),
+                InsertionEncodingVerificationStrategy(),
                 MonotoneTreeVerificationStrategy(no_factors=True),
                 LocalVerificationStrategy(no_factors=True),
             ],
@@ -419,7 +420,7 @@ class LocalVerificationStrategy(TileScopeVerificationStrategy):
     localized, i.e. in a single cell and the tiling is not 1x1.
     """
 
-    def __init__(self, ignore_parent: bool = True, no_factors: bool = True):
+    def __init__(self, ignore_parent: bool = True, no_factors: bool = False):
         self.no_factors = no_factors
         super().__init__(ignore_parent=ignore_parent)
 
@@ -444,6 +445,7 @@ class LocalVerificationStrategy(TileScopeVerificationStrategy):
             ver_strats=[
                 BasicVerificationStrategy(),
                 OneByOneVerificationStrategy(),
+                InsertionEncodingVerificationStrategy(),
                 MonotoneTreeVerificationStrategy(no_factors=True),
                 LocalVerificationStrategy(no_factors=True),
             ],
@@ -609,6 +611,7 @@ class MonotoneTreeVerificationStrategy(TileScopeVerificationStrategy):
             ver_strats=[
                 BasicVerificationStrategy(),
                 OneByOneVerificationStrategy(),
+                InsertionEncodingVerificationStrategy(),
                 MonotoneTreeVerificationStrategy(no_factors=True),
             ],
             name="factor pack",


Test patch:
diff --git a/tests/strategies/test_verification.py b/tests/strategies/test_verification.py
index b505734..7dd326e 100644
--- a/tests/strategies/test_verification.py
+++ b/tests/strategies/test_verification.py
@@ -280,7 +280,59 @@ class TestLocalVerificationStrategy(CommonTest):
                 [GriddedPerm(Perm((0,)), ((1, 0),))],
             ],
         )
-        return [t]
+        t1 = Tiling(
+            obstructions=[
+                GriddedPerm(Perm((0, 1)), [(0, 0), (0, 0)]),
+                GriddedPerm(Perm((0, 1)), [(1, 1), (1, 1)]),
+                GriddedPerm(Perm((0, 1)), [(2, 0), (2, 0)]),
+                GriddedPerm(Perm((1, 0)), [(1, 1), (1, 1)]),
+            ],
+            requirements=[
+                [GriddedPerm(Perm((1, 0)), ((0, 0), (0, 0)))],
+                [GriddedPerm.point_perm((1, 1))],
+                [GriddedPerm.point_perm((2, 0))],
+            ],
+            assumptions=[
+                TrackingAssumption([GriddedPerm.point_perm((0, 0))]),
+                TrackingAssumption([GriddedPerm.point_perm((1, 1))]),
+                TrackingAssumption([GriddedPerm.point_perm((2, 0))]),
+                TrackingAssumption(
+                    [GriddedPerm.point_perm((0, 0)), GriddedPerm.point_perm((2, 0))]
+                ),
+            ],
+        )
+        t2 = Tiling(
+            obstructions=(
+                GriddedPerm(Perm((0,)), ((0, 0),)),
+                GriddedPerm(Perm((0,)), ((1, 1),)),
+                GriddedPerm(Perm((0,)), ((2, 0),)),
+                GriddedPerm(Perm((0, 1)), ((0, 1), (0, 1))),
+                GriddedPerm(Perm((0, 1)), ((1, 0), (1, 0))),
+                GriddedPerm(Perm((0, 1)), ((2, 1), (2, 1))),
+                GriddedPerm(Perm((1, 0)), ((1, 0), (1, 0))),
+            ),
+            requirements=(
+                (GriddedPerm(Perm((0,)), ((1, 0),)),),
+                (GriddedPerm(Perm((1, 0)), ((2, 1), (2, 1))),),
+            ),
+            assumptions=(
+                TrackingAssumption(
+                    (
+                        GriddedPerm(Perm((0,)), ((0, 1),)),
+                        GriddedPerm(Perm((0,)), ((1, 0),)),
+                    )
+                ),
+                TrackingAssumption(
+                    (
+                        GriddedPerm(Perm((0,)), ((0, 1),)),
+                        GriddedPerm(Perm((0,)), ((1, 0),)),
+                        GriddedPerm(Perm((0,)), ((2, 1),)),
+                    )
+                ),
+                TrackingAssumption((GriddedPerm(Perm((0,)), ((2, 1),)),)),
+            ),
+        )
+        return [t, t1, t2]
 
     @pytest.fixture
     def onebyone_enum(self):
@@ -311,6 +363,8 @@ class TestLocalVerificationStrategy(CommonTest):
         ) == TileScopePack.regular_insertion_encoding(3).add_initial(
             SplittingStrategy(ignore_parent=True), apply_first=True
         )
+        assert strategy.pack(enum_verified[1]).name == "factor pack"
+        assert strategy.pack(enum_verified[2]).name == "factor pack"
 
     @pytest.mark.timeout(10)
     def test_get_specification(self, strategy, enum_verified):
@@ -327,6 +381,7 @@ class TestLocalVerificationStrategy(CommonTest):
             )
             == 0
         )
+        # can't the other tilings due to assumptions.
 
     @pytest.fixture
     def enum_crossing_req(self):