def con(i, now): if len(now) == len(patt): yield now elif i < len(perm): nxt = now + [perm[i]] if Permutation.to_standard(nxt) == Permutation.to_standard(patt[:len(nxt)]): for res in con(i+1, nxt): yield res for res in con(i+1, now): yield res
def _assure_length(self, l): if l in self.permutations: return if l == 0: self.permutations[0] = [Permutation()] else: self._assure_length(l - 1) here = set() for p in self.permutations[l - 1]: for i in range(l): q = p[:i] + (l, ) + p[i:] if Permutation(q).avoids(*self.avoid): here.add(q) self.permutations[l] = list(here)
def sub_mesh_pattern(self, indices): """Return the mesh pattern induced by indices. Args: self: A mesh pattern. indices: <collections.Iterable> of <numbers.Integral> A list of unique indices of elements in self. Returns: permuta.MeshPattern A mesh pattern where the pattern is the permutation induced by the indices and a region is shaded if and only if the corresponding region of self is fully shaded. """ indices = sorted(indices) if not indices: return MeshPattern() pattern = Permutation.to_standard(self.pattern[index] for index in indices) vertical = [0] vertical.extend(index + 1 for index in indices) vertical.append(len(self) + 1) horizontal = [0] horizontal.extend(sorted(self.pattern[index] for index in indices)) horizontal.append(len(self) + 1) shading = frozenset((x, y) for x in range(len(pattern) + 1) for y in range(len(pattern) + 1) if self.is_shaded((vertical[x], horizontal[y]), (vertical[x+1] - 1, horizontal[y+1] - 1))) return MeshPattern(pattern, shading)
def test_direct_sum(self): p1 = Permutation(1243) p2 = Permutation(15324) p3 = Permutation(312) p4 = Permutation(1) p5 = Permutation() # All together result = p1.direct_sum(p2, p3, p4, p5) expected = Permutation((1,2,4,3,5,9,7,6,8,12,10,11,13)) self.assertEqual(result, expected) # Two result = p1.direct_sum(p3) expected = Permutation((1,2,4,3,7,5,6)) self.assertEqual(result, expected) # None self.assertEqual(p1.direct_sum(), p1)
def test_skew_sum(self): p1 = Permutation(1243) p2 = Permutation(15324) p3 = Permutation(312) p4 = Permutation(1) p5 = Permutation() # All together result = p1.skew_sum(p2, p3, p4, p5) expected = Permutation((10,11,13,12,5,9,7,6,8,4,2,3,1)) self.assertEqual(result, expected) # Two result = p1.skew_sum(p3) expected = Permutation((4,5,7,6,3,1,2)) self.assertEqual(result, expected) # None self.assertEqual(p1.skew_sum(), p1)
def occurrences_in(self, perm): """Find all indices of occurrences of self in perm. Args: self: The mesh pattern whose occurrences are to be found. perm: permuta.Permutation The permutation to search for occurrences in. Yields: [int] The indices of the occurrences of self in perm. Each yielded element l is a list of integer indices of the permutation perm such that self.pattern == permuta.Permutation.to_standard([perm[i] for i in l]) and that no element not in the occurrence falls within self.shading. """ # TODO: Implement all nice indices = list(range(len(perm))) for candidate_indices in itertools.combinations(indices, len(self)): candidate = [perm[index] for index in candidate_indices] if Permutation.to_standard(candidate) != self.pattern: continue x = 0 for element in perm: if element in candidate: x += 1 continue y = sum(1 for candidate_element in candidate if candidate_element < element) if (x, y) in self.shading: break else: # No unused point fell within shading yield list(candidate_indices)
def add_rule(self, rule): self.total_rules += 1 bs = 0 curcnt = 0 empty = True for l in range(self.settings.perm_bound+1): curlevel = [] for perm in rule.generate_of_length(l, self.settings.sinput.permutations): if not self.settings.sinput.contains(perm): # the rule generated something that doesn't satisfy perm_prop self.death_by_perm_prop += 1 return RuleDeath.PERM_PROP curlevel.append(perm) cur = sorted(curlevel) for a,b in zip(cur, cur[1:]): if a == b: # the rule generated something more than once (i.e. there is overlap) self.death_by_overlap += 1 return RuleDeath.OVERLAP i = 0 j = 0 while i < len(cur) and j < len(self.permset[l]): if self.permset[l][j] < Permutation(cur[i]): j += 1 curcnt += 1 elif Permutation(cur[i]) == self.permset[l][j]: bs |= 1 << curcnt i += 1 j += 1 curcnt += 1 empty = False else: assert False assert i == len(cur) curcnt += len(self.permset[l]) - j if empty: assert False self.rules.setdefault(bs, []) self.rules[bs].append(rule) return RuleDeath.ALIVE
def _assure_length(self, l): if l in self.permutations: return if l == 0: self.permutations[0] = [] maybe = Permutation([]) if maybe.avoids(*self.avoidance): self.permutations[0].append(maybe) else: self._assure_length(l-1) here = set() for p in self.permutations[l-1]: for i in range(l): q = Permutation(p[:i] + (l,) + p[i:]) if q.avoids(*self.avoidance): here.add(q) self.permutations[l] = list(here)
def test_to_standard(self): def gen(perm): res = list(perm) add = 0 for i in perm.inverse(): add += random.randint(0,10) res[i-1] += add return Permutation(res) for i in range(100): perm = Permutations(random.randint(0,20)).random_element() self.assertEqual(perm, Permutation.to_standard(perm)) self.assertEqual(perm, Permutation.to_standard(gen(perm))) self.assertEqual(Permutation.to_standard(range(10)), Permutation((1,2,3,4,5,6,7,8,9,10))) self.assertEqual(Permutation.to_standard(10 - x for x in range(5)), Permutation((5,4,3,2,1)))
def _assure_length(self, l): if l in self.permutations: return if l == 0: self.permutations[0] = [] maybe = Permutation([]) if maybe.avoids(*self.avoidance): self.permutations[0].append(maybe) else: self._assure_length(l - 1) here = set() for p in self.permutations[l - 1]: for i in range(l): q = Permutation(p[:i] + (l, ) + p[i:]) if q.avoids(*self.avoidance): here.add(q) self.permutations[l] = here
def taylor_dag(settings, max_len_patt=None, upper_bound=None, remove=False, remove_finite=True, subpattern_type=SubPatternType.EVERY): assert settings.sinput.avoidance is not None, "Tayloring is only supported for avoidance" patterns = settings.sinput.avoidance started = datetime.datetime.now() settings.logger.log('Tayloring DAG') elems = [] if len(patterns) > 0: if max_len_patt is None: max_len_patt = max( len(p) for p in patterns ) n = max( len(p) for p in patterns ) sub = [ set([]) for _ in range(len(patterns)) ] for i,p in enumerate(patterns): last = set([ p ]) if len(p) <= max_len_patt: sub[i] |= last for l in range(len(p)-1, 1, -1): nxt = set([]) for q in last: for j in range(len(q)): qp = Permutation([ x-1 if x>q[j] else x for x in q[:j] + q[j+1:] ]) nxt.add(qp) if l <= max_len_patt: sub[i] |= nxt last = nxt valid = set() for i,p in enumerate(patterns): if subpattern_type == SubPatternType.RECTANGULAR: for l in range(len(p)): for r in range(l,len(p)): here = sorted(p.perm[l:r+1]) for x in range(len(here)): want = set() for y in range(x,len(here)): want.add(here[y]) cur = [] for j in range(l,r+1): if p.perm[j] in want: cur.append(p.perm[j]) if len(cur) <= max_len_patt: valid.add(Permutation.to_standard(cur)) elif subpattern_type == SubPatternType.CONSECUTIVE: for l in range(len(p)): for r in range(l,len(p)): if r - l + 1 > max_len_patt: break here = p.perm[l:r+1] if max(here) - min(here) + 1 == len(here): valid.add(Permutation.to_standard(here)) if subpattern_type != SubPatternType.EVERY: for i,p in enumerate(patterns): sub[i] &= valid def can_add(add, picked): for p in picked: if len(p) > len(add) and p.contains(add): return False if len(add) > len(p) and add.contains(p): return False return True def bt(at,picked,seen): if upper_bound is not None and len(picked) > upper_bound: pass elif picked == set(patterns): pass elif at == len(patterns): yield picked else: for s in subsets(list(sub[at] - picked - seen)): npicked = set(picked) ok = True for add in set(s): if not can_add(add, npicked): ok = False break npicked.add(add) if not ok: continue found = False for q in npicked: if patterns[at].contains(q): found = True break if not found: continue for res in bt(at+1,npicked,seen | sub[at]): yield res for ps in bt(0,set(),set()): # if remove_av_incr_decr: # if any( p.is_increasing() for p in ps ) and any( p.is_decreasing() for p in ps ): # continue s = AvoiderPermutationSet(ps) s._assure_length(settings.perm_bound) here = set() finite = False for l in range(settings.perm_bound+1): found = False for p in s.generate_of_length(l, {}): here.add(Permutation(list(p))) found = True if not found: finite = True if finite and remove_finite and settings.sinput.is_classical: break if finite and remove_finite and settings.sinput.is_classical: continue here = { Permutation(list(p)) for l in range(settings.perm_bound+1) for p in s.generate_of_length(l, {}) } elems.append((s, here, None)) input = settings.sinput.get_permutation_set() elems.append((InputPermutationSet(settings), input, None)) elems.append((N, set([ Permutation([]) ]), None)) elems.append((P, set([ Permutation([1]) ]), None)) res = DAG() if remove: for ps,here,descr in elems: rem = set() rems = [] for qs,other,odescr in elems: if other and other < here: rems.append(qs) rem |= other if not here-rem: continue if rems: res.add_element(SubtractPermutationSet(ps, rems, alone_ok=type(ps) is not InputPermutationSet)) else: res.add_element(ps) else: for ps,here,descr in elems: res.add_element(ps) for ps,here,descr in elems: for qs,other,odescr in elems: if other and other < here: res.put_below(qs,ps) ended = datetime.datetime.now() settings.logger.log('Finished in %.3fs' % (ended - started).total_seconds()) return res
def decr(n): return SimpleGeneratingRule(Permutation([2, 1]), [X, P], description='decreasing').to_static(n, empty)
from permuta.misc import ordered_set_partitions, flatten from permstruct.permutation_sets import PermutationSet, StaticPermutationSet, PointPermutationSet, InputPermutationSet from permstruct import X, N, P, empty, generate_all_of_length from permuta import Permutation, Permutations from permstruct.permutation_sets import SimpleGeneratingRule, OverlayGeneratingRule from itertools import product from copy import deepcopy incr = SimpleGeneratingRule(Permutation([1, 2]), [X, P], description='increasing').to_static(8, empty) decr = SimpleGeneratingRule(Permutation([2, 1]), [X, P], description='decreasing').to_static(8, empty) def at_most_one_descent(p): found = False for i in range(1, len(p)): if p[i - 1] > p[i]: if found: return False found = True return True av123 = set([ tuple(p) for l in range(8) for p in Permutations(l) if p.avoids([1, 2, 3]) ]) # print(sorted(av123))
def construct_rule(perm_prop, perm_bound, dag, max_rule_size, max_nonempty, max_rules, ignore_first=1, allow_overlap_in_first=True): """Tries to construct a set of generating rules that together generate the given permutation set. INPUT: - ``perm_prop`` - the permutation set expressed as a boolean predicate: perm_prop(p) should return True iff the permutation p is a part of the permutation set. - ``perm_bound`` - consider only permutations of length up to perm_bound, inclusive. - ``max_rule_size`` - a tuple (n, m) specifying that we should consider generating rules with at most n rows and at most m columns. - ``max_nonempty`` - the maximum number of non-empty boxes in the resulting generating rule. - ``max_rules`` - the maximum number of generating rules to match together. - ``dag`` - a list of tuples (f, g), where g is a generating rule and f is a boolean predicate: f(p) should return True iff the permutation p can be produced by g. These generating rules are possible candidates for boxes in the resulting generating rules. - ``ignore_first`` - ignore the smallest ``ignore_first`` permutations when doing the generating rule matching. So even if a set of generating rules don't produce a certain small permutation, they will still be considered. - ``allow_overlap_in_first`` - whether to allow overlap (that is, the same permutation being produced multiple times) in the ``ignore_first`` permutations. Note that if performance is an issue, the parameters ``perm_bound``, ``max_rule_size``, ``max_nonempty``, ``max_rules`` and ``dag`` can be tweaked for better performance, at the cost of lower number of results. This function currently doesn't return anything meaningful, but it does display its results to stdout. """ main_perms = [] for perm in Permutations(perm_bound): if perm_prop(perm): main_perms.append(tuple(perm)) # pick the main permutation to work with, currently just chooses one of the # largest ones randomly # TODO: be more smart about picking the permutations to learn from (or use all of them) random.shuffle(main_perms) main_perms = main_perms[:50] # main_perm = [ Permutation([1,2,3,4,5,6]) ] rules = RuleSet(perm_prop, perm_bound) tried_rules = set() for n in range(1, max_rule_size[0] + 1): for m in range(1, max_rule_size[1] + 1): for xsep in choose(perm_bound - 1, n - 1): for ysep in choose(perm_bound - 1, m - 1): for main_perm in main_perms: arr = [[[] for j in range(m)] for i in range(n)] nonempty_cnt = 0 ok = True for i in range(n): for j in range(m): for k in range( 0 if j == 0 else ysep[j - 1] + 1, (perm_bound - 1 if j == m - 1 else ysep[j]) + 1): if (0 if i == 0 else xsep[i - 1] + 1 ) <= perm_bound - main_perm[k] <= ( perm_bound - 1 if i == n - 1 else xsep[i]): arr[i][j].append(main_perm[k]) if arr[i][j]: nonempty_cnt += 1 if nonempty_cnt > max_nonempty: ok = False break if not ok: break if not ok: continue nonempty = [] for i in range(n): for j in range(m): if arr[i][j]: arr[i][j] = Permutation.to_standard( arr[i][j]) cur = [] # for inp_prop, inp in dag.elements: for inp in dag.elements: if inp is None: continue if inp.contains(arr[i][j]): cur.append((i, j, inp)) nonempty.append(cur) for poss in product(*nonempty): rule = GeneratingRule({(i, j): inp for i, j, inp in poss}) if rule in tried_rules: continue # print(rule) tried_rules.add(rule) rules.add_rule(rule) print('Found %d rules, %d of which are valid, %d of which are distinct' % ( len(tried_rules), sum(len(v) for k, v in rules.rules.items()), len(rules.rules), )) return rules.exact_cover( max_rules, ignore_first, allow_overlap_in_first, )
from permuta import Permutation from permstruct import * from permstruct.dag import * patts = [ Permutation([1,3,2]) ] # patts = [ Permutation([1,3,2]), Permutation([4,3,1,2]) ] # patts = [ Permutation([]), Permutation([]) ] # patts = [Permutation([1,4,3,2]), Permutation([4,2,3,1])] # patts = [Permutation([1,3,2,4])] # patts = [Permutation([1, 4, 2, 3]), Permutation([2, 1, 4, 3]), Permutation([2, 4, 3, 1]), Permutation([3, 1, 4, 2]), Permutation([3, 2, 1, 4]), Permutation([3, 2, 4, 1]), Permutation([3, 4, 1, 2]), Permutation([4, 1, 2, 3]), Permutation([4, 2, 1, 3]), Permutation([4, 2, 3, 1]), Permutation([4, 3, 2, 1])] # patts = [Permutation([3,2,1]), Permutation([2,1,4,3])] # patts = [ Permutation([1,2,3]) ] # patts = [ Permutation([1,3,2,4]) ] perm_bound = 7 settings = StructSettings( perm_bound=perm_bound, verify_bound=7, max_rule_size=(3,3), max_non_empty=3, verbosity=StructLogger.INFO) # settings.set_input(StructInput.from_avoidance(settings, patts)) settings.set_input(AvoiderInput(settings, patts)) # settings.set_dag(taylor_dag(settings, max_len_patt=3, remove=True, upper_bound=3)) # settings.set_dag(taylor_dag(settings, remove=False)) # el = taylor_dag(settings, remove=True, max_len_patt=2, upper_bound=1).elements # print(el) # print(len(el)) dag = taylor_dag(settings, remove=False, subpattern_type=SubPatternType.EVERY)
def construct_rule(perm_prop, perm_bound, dag, max_rule_size, max_nonempty, max_rules, ignore_first=1, allow_overlap_in_first=True): """Tries to construct a set of generating rules that together generate the given permutation set. INPUT: - ``perm_prop`` - the permutation set expressed as a boolean predicate: perm_prop(p) should return True iff the permutation p is a part of the permutation set. - ``perm_bound`` - consider only permutations of length up to perm_bound, inclusive. - ``max_rule_size`` - a tuple (n, m) specifying that we should consider generating rules with at most n rows and at most m columns. - ``max_nonempty`` - the maximum number of non-empty boxes in the resulting generating rule. - ``max_rules`` - the maximum number of generating rules to match together. - ``dag`` - a list of tuples (f, g), where g is a generating rule and f is a boolean predicate: f(p) should return True iff the permutation p can be produced by g. These generating rules are possible candidates for boxes in the resulting generating rules. - ``ignore_first`` - ignore the smallest ``ignore_first`` permutations when doing the generating rule matching. So even if a set of generating rules don't produce a certain small permutation, they will still be considered. - ``allow_overlap_in_first`` - whether to allow overlap (that is, the same permutation being produced multiple times) in the ``ignore_first`` permutations. Note that if performance is an issue, the parameters ``perm_bound``, ``max_rule_size``, ``max_nonempty``, ``max_rules`` and ``dag`` can be tweaked for better performance, at the cost of lower number of results. This function currently doesn't return anything meaningful, but it does display its results to stdout. """ main_perms = [] for perm in Permutations(perm_bound): if perm_prop(perm): main_perms.append(tuple(perm)) # pick the main permutation to work with, currently just chooses one of the # largest ones randomly # TODO: be more smart about picking the permutations to learn from (or use all of them) random.shuffle(main_perms) main_perms = main_perms[:50] # main_perm = [ Permutation([1,2,3,4,5,6]) ] rules = RuleSet(perm_prop, perm_bound) tried_rules = set() for n in range(1, max_rule_size[0] + 1): for m in range(1, max_rule_size[1] + 1): for xsep in choose(perm_bound - 1, n - 1): for ysep in choose(perm_bound - 1, m - 1): for main_perm in main_perms: arr = [ [ [] for j in range(m) ] for i in range(n) ] nonempty_cnt = 0 ok = True for i in range(n): for j in range(m): for k in range(0 if j == 0 else ysep[j-1] + 1, (perm_bound - 1 if j == m - 1 else ysep[j]) + 1): if (0 if i == 0 else xsep[i-1] + 1) <= perm_bound - main_perm[k] <= (perm_bound - 1 if i == n - 1 else xsep[i]): arr[i][j].append(main_perm[k]) if arr[i][j]: nonempty_cnt += 1 if nonempty_cnt > max_nonempty: ok = False break if not ok: break if not ok: continue nonempty = [] for i in range(n): for j in range(m): if arr[i][j]: arr[i][j] = Permutation.to_standard(arr[i][j]) cur = [] # for inp_prop, inp in dag.elements: for inp in dag.elements: if inp is None: continue if inp.contains(arr[i][j]): cur.append((i, j, inp)) nonempty.append(cur) for poss in product(*nonempty): rule = GeneratingRule({ (i,j): inp for i, j, inp in poss }) if rule in tried_rules: continue # print(rule) tried_rules.add(rule) rules.add_rule(rule) print('Found %d rules, %d of which are valid, %d of which are distinct' % ( len(tried_rules), sum( len(v) for k, v in rules.rules.items() ), len(rules.rules), )) return rules.exact_cover( max_rules, ignore_first, allow_overlap_in_first, )
return not is_polynomial(C) def wrong_is_polynomial(C): overallinterset = set([]) for perm in C: overallinterset = overallinterset.union(wrong_types(perm)) if len(overallinterset) == 10: return True return False def wrong_is_non_polynomial(C): return not wrong_is_polynomial(C) while True: line = sys.stdin.readline() if not line: break line = line.strip() perms = [Permutation(list(map(int, p))) for p in line.split('_')] if is_non_polynomial(perms): print line # Use the stuff below to see what we first missed # winp = wrong_is_non_polynomial(perms) # inp = is_non_polynomial(perms) # if winp != inp: # print line
def generate_of_length(self, n, input): rule = list(self.rule.items()) h = max( k[0] for k,v in rule ) + 1 if rule else 1 w = max( k[1] for k,v in rule ) + 1 if rule else 1 def permute(arr, perm): res = [None] * len(arr) for i in range(len(arr)): res[i] = arr[perm[i] - 1] return res def count_assignments(at, left): if at == len(rule): if left == 0: yield [] elif type(rule[at][1]) is PointPermutationSet: # this doesn't need to be handled separately, # it's just an optimization if left > 0: for ass in count_assignments(at + 1, left - 1): yield [1] + ass else: for cur in range(left+1): for ass in count_assignments(at + 1, left - cur): yield [cur] + ass for count_ass in count_assignments(0, n): for perm_ass in product(*[ s[1].generate_of_length(cnt, input) for cnt, s in zip(count_ass, rule) ]): arr = [ [ [] for j in range(w) ] for i in range(h) ] for i, perm in enumerate(perm_ass): arr[rule[i][0][0]][rule[i][0][1]] = perm rowcnt = [ sum( len(arr[row][col]) for col in range(w) ) for row in range(h) ] colcnt = [ sum( len(arr[row][col]) for row in range(h) ) for col in range(w) ] for colpart in product(*[ ordered_set_partitions(range(colcnt[col]), [ len(arr[row][col]) for row in range(h) ]) for col in range(w) ]): for rowpart in product(*[ ordered_set_partitions(range(rowcnt[row]), [ len(arr[row][col]) for col in range(w) ]) for row in range(h) ]): ok = True for idxs, perm_set in self.overlay: res = [ [None]*colcnt[col] for col in range(w) ] cumul = 1 for row in range(h-1,-1,-1): for col in range(w): if (row,col) in idxs: for idx, val in zip(sorted(colpart[col][row]), permute(sorted(rowpart[row][col]), arr[row][col])): res[col][idx] = cumul + val cumul += rowcnt[row] perm = Permutation.to_standard(flatten(res)) if not perm_set.contains(perm): ok = False break if not ok: continue res = [ [None]*colcnt[col] for col in range(w) ] cumul = 1 for row in range(h-1,-1,-1): for col in range(w): for idx, val in zip(sorted(colpart[col][row]), permute(sorted(rowpart[row][col]), arr[row][col])): res[col][idx] = cumul + val cumul += rowcnt[row] yield Permutation(flatten(res))
def decr_nonempty(n): return SimpleGeneratingRule(Permutation([2, 1]), [X, P], description='decreasing nonempty').to_static( n, {1: [Permutation([1])]})
def taylor_dag(settings, max_len_patt=None, upper_bound=None, remove=False, remove_finite=True, subpattern_type=SubPatternType.EVERY): assert settings.sinput.avoidance is not None, "Tayloring is only supported for avoidance" patterns = settings.sinput.avoidance started = datetime.datetime.now() settings.logger.log('Tayloring DAG') elems = [] if len(patterns) > 0: if max_len_patt is None: max_len_patt = max(len(p) for p in patterns) n = max(len(p) for p in patterns) sub = [set([]) for _ in range(len(patterns))] for i, p in enumerate(patterns): last = set([p]) if len(p) <= max_len_patt: sub[i] |= last for l in range(len(p) - 1, 1, -1): nxt = set([]) for q in last: for j in range(len(q)): qp = Permutation([ x - 1 if x > q[j] else x for x in q[:j] + q[j + 1:] ]) nxt.add(qp) if l <= max_len_patt: sub[i] |= nxt last = nxt valid = set() for i, p in enumerate(patterns): if subpattern_type == SubPatternType.RECTANGULAR: for l in range(len(p)): for r in range(l, len(p)): here = sorted(p.perm[l:r + 1]) for x in range(len(here)): want = set() for y in range(x, len(here)): want.add(here[y]) cur = [] for j in range(l, r + 1): if p.perm[j] in want: cur.append(p.perm[j]) if len(cur) <= max_len_patt: valid.add(Permutation.to_standard(cur)) elif subpattern_type == SubPatternType.CONSECUTIVE: for l in range(len(p)): for r in range(l, len(p)): if r - l + 1 > max_len_patt: break here = p.perm[l:r + 1] if max(here) - min(here) + 1 == len(here): valid.add(Permutation.to_standard(here)) if subpattern_type != SubPatternType.EVERY: for i, p in enumerate(patterns): sub[i] &= valid def can_add(add, picked): for p in picked: if len(p) > len(add) and p.contains(add): return False if len(add) > len(p) and add.contains(p): return False return True def bt(at, picked, seen): if upper_bound is not None and len(picked) > upper_bound: pass elif picked == set(patterns): pass elif at == len(patterns): yield picked else: for s in subsets(list(sub[at] - picked - seen)): npicked = set(picked) ok = True for add in set(s): if not can_add(add, npicked): ok = False break npicked.add(add) if not ok: continue found = False for q in npicked: if patterns[at].contains(q): found = True break if not found: continue for res in bt(at + 1, npicked, seen | sub[at]): yield res for ps in bt(0, set(), set()): # if remove_av_incr_decr: # if any( p.is_increasing() for p in ps ) and any( p.is_decreasing() for p in ps ): # continue s = AvoiderPermutationSet(ps) s._assure_length(settings.perm_bound) here = set() finite = False for l in range(settings.perm_bound + 1): found = False for p in s.generate_of_length(l, {}): here.add(Permutation(list(p))) found = True if not found: finite = True if finite and remove_finite and settings.sinput.is_classical: break if finite and remove_finite and settings.sinput.is_classical: continue here = { Permutation(list(p)) for l in range(settings.perm_bound + 1) for p in s.generate_of_length(l, {}) } elems.append((s, here, None)) input = settings.sinput.get_permutation_set() elems.append((InputPermutationSet(settings), input, None)) elems.append((N, set([Permutation([])]), None)) elems.append((P, set([Permutation([1])]), None)) res = DAG() if remove: for ps, here, descr in elems: rem = set() rems = [] for qs, other, odescr in elems: if other and other < here: rems.append(qs) rem |= other if not here - rem: continue if rems: res.add_element( SubtractPermutationSet(ps, rems, alone_ok=type(ps) is not InputPermutationSet)) else: res.add_element(ps) else: for ps, here, descr in elems: res.add_element(ps) for ps, here, descr in elems: for qs, other, odescr in elems: if other and other < here: res.put_below(qs, ps) ended = datetime.datetime.now() settings.logger.log('Finished in %.3fs' % (ended - started).total_seconds()) return res
# if avoids_231_vinc(p) and p.avoids([1,2,3]): # cnt += 1 # # print(p) # print(l, cnt) # # import sys # sys.exit(0) avoiders_len_3 = [] for p in Permutations(3): avoiders_len_3.append((lambda perm: perm.avoids(p),StaticPermutationSet.from_predicate(lambda x: x.avoids(p), 6, description='Av(%s)' % str(p)))) # avoiders_len_3.append((lambda perm: len(perm) >= 3 and perm.avoids(p),StaticPermutationSet.from_predicate(lambda x: x.avoids(p), 6, description='Av(%s)' % str(p)))) incr = SimpleGeneratingRule(Permutation([1,2]), [X, P], description='increasing').to_static(8, empty) decr = SimpleGeneratingRule(Permutation([2,1]), [X, P], description='decreasing').to_static(8, empty) incr_nonempty = SimpleGeneratingRule(Permutation([1,2]), [X, P], description='increasing nonempty').to_static(8, {1:[Permutation([1])]}) decr_nonempty = SimpleGeneratingRule(Permutation([2,1]), [X, P], description='decreasing nonempty').to_static(8, {1:[Permutation([1])]}) max_len = 6 n_range = (2, 3) # number of rows (min, max) m_range = (2, 3) # numbor of columns (min, max) max_nonempty = 4 max_ec_cnt = 4 # permProp = lambda perm: perm.avoids([1,2]) permProp = lambda perm: perm.avoids([2,3,1]) # permProp = lambda perm: perm.avoids([1,4,2,3])
def incr(n): return SimpleGeneratingRule(Permutation([1, 2]), [X, P], description='increasing').to_static(n, empty)
def contains(self, perm): if type(perm) is not Permutation: perm = Permutation(list(perm)) return perm in self.permutations[len(perm)]
def generate_of_length(self, n, input): rule = list(self.rule.items()) h = max(k[0] for k, v in rule) + 1 if rule else 1 w = max(k[1] for k, v in rule) + 1 if rule else 1 def permute(arr, perm): res = [None] * len(arr) for i in range(len(arr)): res[i] = arr[perm[i] - 1] return res def count_assignments(at, left): if at == len(rule): if left == 0: yield [] elif type(rule[at][1]) is PointPermutationSet: # this doesn't need to be handled separately, # it's just an optimization if left > 0: for ass in count_assignments(at + 1, left - 1): yield [1] + ass else: for cur in range(left + 1): for ass in count_assignments(at + 1, left - cur): yield [cur] + ass for count_ass in count_assignments(0, n): for perm_ass in product(*[ s[1].generate_of_length(cnt, input) for cnt, s in zip(count_ass, rule) ]): arr = [[[] for j in range(w)] for i in range(h)] for i, perm in enumerate(perm_ass): arr[rule[i][0][0]][rule[i][0][1]] = perm rowcnt = [ sum(len(arr[row][col]) for col in range(w)) for row in range(h) ] colcnt = [ sum(len(arr[row][col]) for row in range(h)) for col in range(w) ] for colpart in product(*[ ordered_set_partitions( range(colcnt[col]), [len(arr[row][col]) for row in range(h)]) for col in range(w) ]): for rowpart in product(*[ ordered_set_partitions( range(rowcnt[row]), [len(arr[row][col]) for col in range(w)]) for row in range(h) ]): ok = True for idxs, perm_set in self.overlay: res = [[None] * colcnt[col] for col in range(w)] cumul = 1 for row in range(h - 1, -1, -1): for col in range(w): if (row, col) in idxs: for idx, val in zip( sorted(colpart[col][row]), permute( sorted(rowpart[row][col]), arr[row][col])): res[col][idx] = cumul + val cumul += rowcnt[row] perm = Permutation.to_standard(flatten(res)) if not perm_set.contains(perm): ok = False break if not ok: continue res = [[None] * colcnt[col] for col in range(w)] cumul = 1 for row in range(h - 1, -1, -1): for col in range(w): for idx, val in zip( sorted(colpart[col][row]), permute(sorted(rowpart[row][col]), arr[row][col])): res[col][idx] = cumul + val cumul += rowcnt[row] yield Permutation(flatten(res))
def rotate(perm): n = len(perm) return Permutation([ perm.index(n-i) + 1 for i in range(n)])
def generate_of_length(self, n, input): if n == 1: yield Permutation([1])
def test_taylor(self): settings = StructSettings(perm_bound=7, max_rule_size=(3, 3), max_non_empty=3) patts = [Permutation([1, 2, 3]), Permutation([3, 2, 1])] settings.set_input(StructInput.from_avoidance(settings, patts)) res = taylor_dag(settings, remove=False) self.check([], res) patts = [Permutation([1, 2, 3]), Permutation([3, 2, 1])] settings.set_input(StructInput.from_avoidance(settings, patts)) res = taylor_dag(settings, remove=False, remove_finite=False) self.check([ [Permutation([1, 2]), Permutation([2, 1])], [Permutation([1, 2, 3]), Permutation([2, 1])], [Permutation([1, 2]), Permutation([3, 2, 1])], ], res) patts = [ Permutation([1, 2, 3]), Permutation([3, 2, 1]), ] settings.set_input(StructInput.from_avoidance(settings, patts)) res = taylor_dag(settings, upper_bound=1, remove=False, remove_finite=False) self.check([], res) patts = [ Permutation([1, 2, 3]), Permutation([3, 2, 1]), ] settings.set_input(StructInput.from_avoidance(settings, patts)) res = taylor_dag(settings, max_len_patt=2, remove=False, remove_finite=False) self.check([ [Permutation([1, 2]), Permutation([2, 1])], ], res)