Skip to content

Add RSK, evacuation and Knuth-closure tests (permuta.permutils.robinson_schensted) - #211

Open
ulfarsson wants to merge 5 commits into
developfrom
rsk
Open

ulfarsson wants to merge 5 commits into
developfrom
rsk

Conversation

@ulfarsson

Copy link
Copy Markdown
Member

Adds permuta.permutils.robinson_schensted: the Robinson–Schensted correspondence on words of distinct letters, Schützenberger's evacuation, and two tests on sets of patterns, whether their avoiders are closed under Knuth equivalence and whether they are determined by the RSK shape. They are about permutations, not tilings, so they belong here: Tilings' Knuth slide (PermutaTriangle/Tilings#532) will import them from Permuta, once a Permuta release has them.

What it adds

  • rsk(word) gives the insertion and recording tableaux of a word of distinct letters, by row insertion, with the recording tableau of the steps 1, 2, …; rsk_inverse(insertion_tableau, recording_tableau) gives the word back, and raises ValueError for tableaux of different shapes.
  • evacuation(tableau) is Schützenberger's evacuation of a standard Young tableau, by jeu de taquin. It keeps the shape and is an involution, and the recording tableau of a permutation's reverse-complement is the evacuation of the permutation's.
  • evacuate_recording_tableau(word) is the word with the same insertion tableau and the evacuated recording tableau. It is Knuth equivalent to the word, it is an involution, and each run of consecutive letters at the mirrored positions has the RSK shape of the corresponding run of the word. This is what lets Tilings' Knuth slide reverse a block of cells.
  • is_knuth_closed(basis) tells whether the permutations avoiding the patterns, given as any iterable of them, are closed under Knuth equivalence. It is decided locally: an occurrence that a Knuth move destroys uses both letters the move exchanges, so with the letter that allows the move it lies in a permutation at most one entry longer than the pattern. It checks the Knuth moves of each pattern and of its one-point extensions (Perm.coveredby), and caches the answers by set of patterns.
  • is_shape_closed(basis) tells whether avoiding the patterns depends only on the RSK shape. That holds exactly when the permutations avoiding the patterns, and those avoiding their inverses, are both closed under Knuth equivalence, as for monotone patterns.

All six are exported from permuta.permutils. The module is named for its topic, so that the function rsk does not hide it. The docstrings say what is not checked: a word with a repeated letter, a tableau that is not standard, and a single Perm given as the basis.

Changed

The BiSC properties yt_perm_avoids_22 and yt_perm_avoids_32 take their insertion tableau from rsk in place of a private insertion of their own, which is removed; its test moves to the new tests, unchanged in what it checks. Their answers are the same, and they are faster: on all permutations to length 9, about half the time on CPython and 0.84 of it on PyPy.

Who will use it

Tilings' Knuth slide, Permuta's BiSC properties, and anyone who needs RSK or evacuation on permutations.

Tests

In tests/permutils/test_robinson_schensted.py, on every permutation up to length 7:

  • RSK and its inverse, on permutations and on words of other letters, the empty word and a single letter among them; tableaux given as tuples, and left unchanged; tableaux of different shapes refused, in each way two shapes can differ;
  • evacuation as a shape-preserving involution, and as the recording tableau of the reverse-complement;
  • the evacuated word: the same insertion tableau, the mirrored shapes, an involution;
  • Knuth's theorem, that two permutations have the same insertion tableau exactly when Knuth moves join them, with the moves written from their definition;
  • the closure tests against brute force: every set of patterns of length 3, random sets with patterns of length 4, unions of whole Knuth classes, and 45 bases for the shape; patterns of length at most 2 and the empty permutation; the patterns in any order, repeated, redundant, and given as six kinds of iterable;
  • the insertion tableaux of the BiSC properties' former test: as many of each size as the involutions, and ten examples.

In tests/bisc/test_perm_properties.py, the two BiSC properties against Greene's theorem on every permutation up to length 7.

How it was checked

Before submission, by an automated reviewer, against develop:

  • flake8, mypy, pylint and black pass, and on CPython 3.14 and PyPy 3.11 all 655 tests pass; Tilings' tests pass with this Permuta;
  • the functions agree with those Tilings#532 was reviewed with, on every permutation to length 8 and on 2,064 sets of patterns;
  • the closure tests agree with an independent brute force on more than 3,000 sets of patterns of lengths 1 to 5;
  • the BiSC properties give the same answers before and after on all 409,114 permutations to length 9;
  • mutation testing of the new module and the two properties: every surviving mutant is equivalent.

AI assistance: written with Claude Code (Opus 5.5) as the TileScope agent, and reviewed before submission by Claude Code (Opus 5.5) as an automated reviewer; Henning Ulfarsson checked and opened it.

ulfarsson and others added 5 commits October 25, 2026 22:18
The Robinson-Schensted correspondence on words of distinct letters (rsk,
rsk_inverse), Schutzenberger's evacuation of standard Young tableaux
(evacuation), the word with the same insertion tableau and the evacuated
recording tableau (evacuate_recording_tableau), and whether the avoiders of
some patterns are closed under Knuth equivalence (is_knuth_closed) or
determined by their RSK shape (is_shape_closed), all exported from
permuta.permutils. Tilings' Knuth slide (PermutaTriangle/Tilings#532) is
built on them; they are about permutations, so they are Permuta's.

The BiSC properties yt_perm_avoids_22 and yt_perm_avoids_32 take their
insertion tableau from rsk; the private _perm_to_yt goes, and its test
moves to tests/permutils/test_rsk.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, and more

The review's tests reader wrote tests for what the moved tests do not
reach, each failing on a fault that passed the tests before:

- the closure tests on six kinds of iterable, in any order and with
  repeats, and on bases with redundant patterns;
- is_shape_closed against brute force on 45 bases, which caught a check
  of the inverses alone;
- the empty word and a single letter; words of letters other than 0, 1,
  ...; tableaux given as tuples and left as they were; patterns of length
  at most 2, the empty permutation among them;
- the BiSC properties of the shape against Greene's theorem, with the
  BiSC tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The review's question 2: permutils exports the function rsk, which hid the
module permuta.permutils.rsk, so importing the module gave the function,
and monkeypatching it by name failed. Henning chose to name the module for
its topic, robinson_schensted, before a release makes the name public; the
functions keep their names, and its tests are
tests/permutils/test_robinson_schensted.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…oops commented

The review's suggestions 3 to 5:

- rsk_inverse raises ValueError for tableaux of different shapes, where it
  dropped letters or raised a bare KeyError or IndexError; a test checks it.
  The module's docstring, and each function's, say what is not checked: a
  word with a repeated letter, a tableau that is not standard, a single
  Perm for a basis.
- The loops a reader must stop at are commented: rsk's for ... else,
  rsk_inverse's reverse bump, and the closure test's generator.
  evacuation's locals say what they hold, and its branches are ordered so
  that the assert for mypy goes.
- evacuate_recording_tableau's docstring says it returns a word and
  defines P, Q and the positions; is_shape_closed's says what is closed
  under what; the cache's size is explained, and the docstring says that
  answers are cached.
- The BiSC properties unpack the insertion tableau; a test comment names
  the Knuth class of 1243 rather than a person.
- The CHANGELOG's Added entry is a list, and its Changed entry says that
  the BiSC properties answer as before, and faster (0.043 s against 0.064 s
  for 9,000 permutations of lengths 8 to 60 on PyPy, the same tableaux).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…wordings

- rsk_inverse's refusal of tableaux of different shapes is tested on the
  other ways two shapes can differ: rows of other lengths in the same
  number of rows, the same first row, the same size, and an empty tableau
  against a non-empty one (the review's ten cases); a check of the number
  of rows alone passed before. Its message is matched, anchored.
- is_shape_closed's docstring said it holds when "the set of the patterns
  and the set of their inverses are both Knuth closed", which reads as the
  sets being closed under Knuth moves, and that is not enough: the four
  permutations of shape (2, 2) are such a set, and the shape class (3, 1, 1)
  of length 5 splits, 01432 avoiding them and 14203 not. It now says the
  avoiders are closed, exactly.
- The cache's comment compared it with Permuta's others, wrongly, as
  pin_words has unbounded ones; it says what it keeps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant