def test_1234_fusion():
    __location__ = os.path.realpath(
        os.path.join(os.getcwd(), os.path.dirname(__file__)))
    with open(os.path.join(__location__, "spec-1234.json")) as f:
        d = json.loads(f.read())
    spec = CombinatorialSpecification.from_dict(d)
    assert isinstance(spec, CombinatorialSpecification)
    assert not any("NOTIMPLEMENTED" in str(eq.rhs)
                   for eq in spec.get_equations())
    assert [spec.count_objects_of_size(i) for i in range(15)] == [
        1,
        1,
        2,
        6,
        23,
        103,
        513,
        2761,
        15767,
        94359,
        586590,
        3763290,
        24792705,
        167078577,
        1148208090,
    ]
    av = Av([Perm((0, 1, 2, 3))])
    for i in range(10):
        assert set(av.of_length(i)) == set(
            gp.patt for gp in spec.generate_objects_of_size(i))
        assert spec.random_sample_object_of_size(i).patt in av
def test_132_genf():
    searcher = TileScope([Perm((0, 2, 1))], point_placements)
    spec = searcher.auto_search(smallest=True)
    spec = spec.expand_verified()
    av = Av([Perm((0, 2, 1))])
    for i in range(10):
        assert set(av.of_length(i)) == set(
            gp.patt for gp in spec.generate_objects_of_size(i))
        assert spec.random_sample_object_of_size(i).patt in av
    gf = spec.get_genf()
    gf = sympy.series(spec.get_genf(), n=15)
    x = sympy.Symbol("x")
    assert [gf.coeff(x, n) for n in range(13)] == [
        1,
        1,
        2,
        5,
        14,
        42,
        132,
        429,
        1430,
        4862,
        16796,
        58786,
        208012,
    ]
def test_123_positive_fusions():
    pack = TileScopePack.insertion_row_and_col_placements(
        row_only=True).make_fusion(tracked=True, apply_first=True)
    css = TileScope("123", pack)
    spec = css.auto_search(status_update=30)
    spec = spec.expand_verified()
    print(spec)
    assert isinstance(spec, CombinatorialSpecification)
    assert [spec.count_objects_of_size(i) for i in range(20)] == [
        1,
        1,
        2,
        5,
        14,
        42,
        132,
        429,
        1430,
        4862,
        16796,
        58786,
        208012,
        742900,
        2674440,
        9694845,
        35357670,
        129644790,
        477638700,
        1767263190,
    ]
    av = Av([Perm((0, 1, 2))])
    for i in range(10):
        assert set(av.of_length(i)) == set(
            gp.patt for gp in spec.generate_objects_of_size(i))
        assert spec.random_sample_object_of_size(i).patt in av
Example #4
0
 def get_permclass(self):
     if self.is_empty():
         return Av(Perm((0, )))
     elif self.is_point():
         return PermSet(1)
     elif self.is_anything():
         return PermSet()
     elif self.is_avoiding() and not self.is_containing():
         return Av(self.obstructions)
     else:
         return MockAvCoPatts(self.obstructions, self.requirements)
Example #5
0
    def __init__(self, av_patts, co_patts):
        self.base_perm_set = Av(av_patts)

        if isinstance(co_patts, (Perm, MeshPatt)):
            self.filter = lambda perm: perm.contains(co_patts)
        elif all(isinstance(patt, (Perm, MeshPatt)) for patt in co_patts):
            self.filter = lambda perm: any(
                perm.contains(patt) for patt in co_patts)
        else:
            raise ValueError("Variable 'co_patts' not as expected: "
                             "'{}'".format(co_patts))
Example #6
0
 def verified(self, comb_class: Tiling) -> bool:
     if not comb_class.dimensions == (1, 1):
         return False
     if not self.basis:
         return True
     tiling_class = Av([ob.patt for ob in comb_class.obstructions])
     sym_classes = (Av(sym) for sym in self.symmetries)
     is_strict_subclass = any(
         tiling_class.is_subclass(cls) and cls != tiling_class for cls in sym_classes
     )
     return is_strict_subclass or any(
         isinstance(ass, ComponentAssumption) for ass in comb_class.assumptions
     )
def test_reverse_equiv():
    """A specification that should use reverse equivalence."""
    pack = TileScopePack(
        initial_strats=[
            strat.FactorFactory(),
            strat.RequirementCorroborationFactory(),
            strat.RequirementPlacementFactory(partial=False),
        ],
        inferral_strats=[strat.RowColumnSeparationStrategy()],
        expansion_strats=[[strat.CellInsertionFactory()]],
        ver_strats=[strat.BasicVerificationStrategy()],
        iterative=False,
        name="test pack",
    )
    basis = (Perm((0, 1, 3, 2)), Perm((0, 2, 3, 1)), Perm((1, 0, 3, 2)))
    # From https://oeis.org/A033321
    expected_enum = [
        1, 1, 2, 6, 21, 79, 311, 1265, 5275, 22431, 96900, 424068, 1876143
    ]
    x, f = sympy.symbols("x f")
    expected_min_poly = sympy.sympify("-4*f^2*x^2 + 8*f^2*x - 4*f*x - 4*f + 4")
    searcher = TileScope(basis, pack)
    spec = searcher.auto_search(smallest=True)
    assert [spec.count_objects_of_size(i) for i in range(13)] == expected_enum
    genf = spec.get_genf()
    assert sympy.simplify(expected_min_poly.subs(f, genf)) == 0
    assert taylor_expand(genf, 12) == expected_enum
    # In order to avoid ReccursionError we go incrementally
    for i in range(0, 100):
        spec.count_objects_of_size(i)
    assert spec.count_objects_of_size(50) == 86055297645519796258217673160170
    assert (
        spec.count_objects_of_size(100) ==
        2733073112795720153237297124938915907723365837935699807314396095313)
    len4_perms = tuple(spec.generate_objects_of_size(4))
    assert len(len4_perms) == 21
    assert all(p not in len4_perms for p in basis)
    len8_perms = tuple(spec.generate_objects_of_size(8))
    assert len(len8_perms) == 5275
    assert len(set(len8_perms)) == 5275
    for _ in range(10):
        gp = spec.random_sample_object_of_size(10)
        print(gp)
        assert gp.patt.avoids(*basis)

    av = Av(basis)
    for i in range(10):
        assert set(av.of_length(i)) == set(
            gp.patt for gp in spec.generate_objects_of_size(i))
        assert spec.random_sample_object_of_size(i).patt in av
 def __str__(self) -> str:
     if self.maxreqlen == 1:
         return "point insertion"
     if self.extra_basis:
         perm_class = Av(self.extra_basis)
         return f"cell insertion from {perm_class} up to length {self.maxreqlen}"
     return f"cell insertion up to length {self.maxreqlen}"
Example #9
0
 def __str__(self) -> str:
     if self.extra_basis:
         perm_class = Av(self.extra_basis)
         return "requirement extension from {} up to " "length {}".format(
             perm_class, self.maxreqlen)
     return "requirement extension insertion up to " "length {}".format(
         self.maxreqlen)
Example #10
0
 def req_lists_to_insert(self, tiling: Tiling) -> Iterator[ListRequirement]:
     active = tiling.active_cells
     bdict = tiling.cell_basis()
     for cell, length in product(active, range(1, self.maxreqlen + 1)):
         basis = bdict[cell][0] + self.extra_basis
         yield from ((GriddedPerm.single_cell(patt, cell), )
                     for patt in Av(basis).of_length(length)
                     if not any(patt in perm for perm in bdict[cell][1]))
Example #11
0
 def __str__(self) -> str:
     if self.maxreqlen == 1:
         return "point insertion"
     if self.extra_basis:
         perm_class = Av(self.extra_basis)
         return "cell insertion from {} up to " "length {}".format(
             perm_class, self.maxreqlen)
     return "cell insertion up to length {}".format(self.maxreqlen)
 def __str__(self) -> str:
     if not self.extra_basis:
         s = f"root insertion up to length {self.maxreqlen}"
     else:
         perm_class = Av(self.extra_basis)
         s = f"root insertion from {perm_class} up to length {self.maxreqlen}"
     if self.max_num_req is not None:
         s += f" (up to {self.max_num_req} requirements)"
     return s
Example #13
0
 def __str__(self) -> str:
     if not self.extra_basis:
         s = "root insertion up to length {}".format(self.maxreqlen)
     else:
         perm_class = Av(self.extra_basis)
         s = "root insertion from {} up to length {}".format(
             perm_class, self.maxreqlen)
     if self.max_num_req is not None:
         s += " (up to {} requirements)".format(self.max_num_req)
     return s
Example #14
0
 def req_lists_to_insert(self, tiling: Tiling) -> Iterator[ListRequirement]:
     bdict = tiling.cell_basis()
     cell_with_req = ((cell, obs, reqlist[0])
                      for cell, (obs, reqlist) in bdict.items()
                      if len(reqlist) == 1)
     for cell, obs, curr_req in cell_with_req:
         for length in range(len(curr_req) + 1, self.maxreqlen + 1):
             for patt in Av(obs + self.extra_basis).of_length(length):
                 if curr_req in patt:
                     yield (GriddedPerm.single_cell(patt, cell), )
Example #15
0
def simples_avoiding(basis):
    """
    Yield all simple permutations that avoid basis.

    You may wish to use the 'Av' class from permuta for iterating over
    permutations that avoid a given basis.
    A naive approach to know when to terminate is to use the fact that every
    length n simple contains a simple of length n - 1 or length n - 2.
    """
    av = Av(basis)
    longest = 4
    length = 4
    while True:
        if length - 2 > longest:
            break
        for perm in av.of_length(length):
            if perm.is_simple():
                yield perm
                longest = length
        length += 1
    def test_get_elmnts_of_size_Av21_cell(self):
        mt = MeshTiling({
            (0, 0): Cell(frozenset({Perm((1, 0))}), frozenset()),
            (1, 1): MeshTiling.point_cell
        })

        for size in range(1, 5):
            expected_perms = set(Av([Perm((1, 0))]).of_length(size))
            mt_perms = mt.get_elmnts(of_size=size)
            assert (len(set(mt_perms)) == len(list(mt_perms)))
            assert (set(mt_perms) == expected_perms)
Example #17
0
def all_cell_insertions(tiling, **kwargs):
    """
    The cell insertion strategy.

    The cell insertion strategy is a batch strategy that considers each active
    cells, excluding positive cells. For each of these cells, the strategy
    considers all patterns (up to some maximum length given by maxreqlen, and
    some maximum number given by maxreqnum) and returns two tilings; one which
    requires the pattern in the cell and one where the pattern is obstructed.

    TODO:
        - Have a flag to insert into positive cells that contain the maximal
        intersections
    """
    maxreqlen = kwargs.get('maxreqlen')
    if not maxreqlen:
        maxreqlen = 1
    ignore_parent = kwargs.get('ignore_parent', False)
    extra_basis = kwargs.get('extra_basis')
    if extra_basis is None:
        extra_basis = []
    if (not isinstance(extra_basis, list)
            or not all(isinstance(p, Perm) for p in extra_basis)):
        raise TypeError("'extra_basis' flag should be a list of Perm to avoid")
    maxreqnum = kwargs.get('maxreqnum')
    if not maxreqnum:
        maxreqnum = 1

    active = tiling.active_cells
    bdict = tiling.cell_basis()
    for cell in active:
        if len(bdict[cell][1]) >= maxreqnum:
            continue
        for length in range(1, maxreqlen + 1):
            for patt in Av(bdict[cell][0] + extra_basis).of_length(length):
                if not any(patt in perm for perm in bdict[cell][1]):
                    if (tiling.dimensions != (1, 1)
                            or all(patt > perm for perm in bdict[cell][1])):
                        yield Rule(
                            formal_step=("Insert {} into cell {}.|{}|{}|{}|"
                                         "".format(
                                             patt, cell, cell[0], cell[1],
                                             "".join(str(i) for i in patt))),
                            comb_classes=cell_insertion(tiling, patt, cell),
                            ignore_parent=ignore_parent,
                            inferable=[True for _ in range(2)],
                            possibly_empty=[True for _ in range(2)],
                            workable=[True for _ in range(2)],
                            constructor='disjoint')
Example #18
0
class MockAvCoPatts:
    def __init__(self, av_patts, co_patts):
        self.base_perm_set = Av(av_patts)

        if isinstance(co_patts, (Perm, MeshPatt)):
            self.filter = lambda perm: perm.contains(co_patts)
        elif all(isinstance(patt, (Perm, MeshPatt)) for patt in co_patts):
            self.filter = lambda perm: any(
                perm.contains(patt) for patt in co_patts)
        else:
            raise ValueError("Variable 'co_patts' not as expected: "
                             "'{}'".format(co_patts))

    def of_length(self, size):
        return filter(self.filter, self.base_perm_set.of_length(size))
    def req_lists_to_insert(self, tiling: Tiling) -> Iterator[ListRequirement]:
        if self.one_cell_only:
            assert self.maxreqlen == 1 and self.ignore_parent
            cells = sorted(
                frozenset(tiling.active_cells) - frozenset(tiling.positive_cells)
            )
            if cells:
                yield (GriddedPerm.single_cell((0,), cells[0]),)
            return

        active = tiling.active_cells
        bdict = tiling.cell_basis()
        for cell, length in product(active, range(1, self.maxreqlen + 1)):
            basis = bdict[cell][0] + self.extra_basis
            patterns = Av(basis).of_length(length) if basis else Perm.of_length(length)
            yield from (
                (GriddedPerm.single_cell(patt, cell),)
                for patt in patterns
                if not any(patt in perm for perm in bdict[cell][1])
            )
Example #20
0
def all_requirement_extensions(tiling, **kwargs):
    """Insert longer requirements in to cells which contain a requirement"""
    maxreqlen = kwargs.get('maxreqlen')
    if not maxreqlen:
        maxreqlen = 2
    extra_basis = kwargs.get('extra_basis')
    if extra_basis is None:
        extra_basis = []
    if (not isinstance(extra_basis, list)
            or not all(isinstance(p, Perm) for p in extra_basis)):
        raise TypeError("'extra_basis' flag should be a list of Perm to avoid")

    active = tiling.active_cells
    bdict = tiling.cell_basis()
    for cell in active:
        basis = bdict[cell][0]
        reqs = bdict[cell][1]
        if len(reqs) != 1:
            continue
        curr_req = reqs[0]
        for length in range(len(curr_req) + 1, maxreqlen + 1):
            for patt in Av(bdict[cell][0] + extra_basis).of_length(length):
                if curr_req in patt:
                    yield Rule(
                        formal_step=("Insert {} into cell {}."
                                     "".format(patt, cell)),
                        comb_classes=[
                            tiling.add_single_cell_obstruction(patt, cell),
                            tiling.add_single_cell_requirement(patt, cell)
                        ],
                        ignore_parent=False,
                        possibly_empty=[
                            any(len(r) > 1 for r in tiling.requirements), True
                        ],
                        inferable=[True for _ in range(2)],
                        workable=[True for _ in range(2)],
                        constructor='disjoint')
def subclass_verified(tiling, basis, **kwargs):
    """The subclass verified strategy.

    A tiling is subclass verified if it only generates permutations in a
    proper subclass of Av(basis).
    """
    if tiling.dimensions == (1, 1):
        return None
    else:
        maxlen = kwargs.get('maxpattlen', 4)
        patterns = set(perm for perm in chain(
            *[Av(basis).of_length(i) for i in range(maxlen + 1)]))
        maxlen += tiling.maximum_length_of_minimum_gridded_perm()
        for i in range(maxlen + 1):
            for g in tiling.objects_of_length(i):
                perm = g.patt
                patterns = set(pattern for pattern in patterns
                               if perm.avoids(pattern))
                if not patterns:
                    return None
        return VerificationRule(formal_step=("The tiling belongs to the "
                                             "subclass obtained by adding"
                                             " the patterns {}."
                                             "".format(Basis(patterns))))
Example #22
0
def test_321_1324():
    searcher = TileScope("321_1324", reginsenc)
    spec = searcher.auto_search()
    assert isinstance(spec, CombinatorialSpecification)
    for i in range(20):
        gp = spec.random_sample_object_of_size(i)
        assert all(cell == (0, 0) for cell in gp.pos)
        assert gp.patt.avoids(Perm((2, 1, 0)), Perm((0, 2, 1, 3)))
    av = Av([Perm((2, 1, 0)), Perm((0, 2, 1, 3))])
    for i in range(10):
        assert set(av.of_length(i)) == set(
            gp.patt for gp in spec.generate_objects_of_size(i))
    assert [spec.count_objects_of_size(i) for i in range(50)] == [
        1,
        1,
        2,
        5,
        13,
        32,
        72,
        148,
        281,
        499,
        838,
        1343,
        2069,
        3082,
        4460,
        6294,
        8689,
        11765,
        15658,
        20521,
        26525,
        33860,
        42736,
        53384,
        66057,
        81031,
        98606,
        119107,
        142885,
        170318,
        201812,
        237802,
        278753,
        325161,
        377554,
        436493,
        502573,
        576424,
        658712,
        750140,
        851449,
        963419,
        1086870,
        1222663,
        1371701,
        1534930,
        1713340,
        1907966,
        2119889,
        2350237,
    ]
 def formal_step(self) -> str:
     cls = Av(min(self.symmetries))
     if len(self.symmetries) == 1:
         return f"No cell is {cls}"
     return f"No cell is a symmetry of {cls}"