Repository navigation
Conversation
ReductionStrategy reduces a set of cells whose crossing obstructions each have one point in it, seen only along its row or its column: the cells become increasing (or decreasing), their points in each row and column in that order, and the tiling of the set's own obstructions and requirements goes beside the reduced tiling. ReductionConstructor counts the rule as the Hadamard product of the two children in the variables counting the points in the cells, at 1, and generates and samples objects through the sorting. ReductionFactory tries the sets of a region: single cells (the default, the cell reduction), rows, columns, every set in one row or column, or any set, of at most max_cells cells. CellReductionFactory and CellReductionStrategy are the single-cell case, with their names and encodings; the kitchen sink pack uses ReductionFactory. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Its own tiling would be Tiling(), with only the empty permutation; develop's cell reduction factory offered such a cell. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… not see left out, and cells it sees as one tracked once A crossing obstruction may now see its point of the set along a row or column the set has other cells in, when the set's own obstructions already put those cells in the order of the reduction: the sorting then leaves that row's order as it is, and the own tiling has the same obstructions. This makes the threshold reduction of Av(2143) (the cell left of the maximum, after its lowest inversion top is placed) a reduction of five cells. The reduced tiling now keeps only what the rest of the tiling sees of the set. It leaves out the cells whose row and column have no cell outside the set and that no crossing obstruction or requirement touches, which the own tiling counts, and keeps one cell for each group of cells in a row (or column) the rest cannot tell apart, tracked once in both children. The count is the Hadamard product in the groups' sizes and the product in the size of the cells left out. The maps are built from the column words, row words and cell permutations. minimal=False keeps every cell, each tracked, as before; a strategy encoded without the key decodes so, and keeps the children it had. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he rest of the tiling sees Henning: "I don't think we really need to be able to read the old specs. They were mostly made for testing purposes. We should rather care about the cleanlyness of the code". So minimal goes from ReductionStrategy, ReductionFactory, the cell reduction's classes, reduction_plan and reduction_children, and the constructor takes the plan. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The region "cut" offers, for each line between two adjacent columns or two adjacent rows, the active cells on each side of it: left and right of it, below and above it. These are the sets a threshold reduction reduces, the cells left of a placed point, as in Av(2143)'s tree, where every reduction is of the cells left of a column (five or seven of them), which "any" reaches only with a bound of seven cells and very many more sets. At most twice the number of columns and rows; max_cells bounds them as it bounds "any". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nts touches A tracking assumption on a gridded permutation of two or more points counts the occurrences of a pattern, and the sorting of the set's share keeps the number of points in each cell but not those occurrences: reducing a cell of such a pattern gave wrong counts or raised ValueError (the review of the pull request, round 1, finding 1). The condition now refuses such a set, as it refuses one with a component assumption, and the tracked cells the plan keeps apart are every cell of the assumptions' gridded permutations. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t cells Mutation testing of reduction.py (the review of the pull request, round 1, finding 2) left mutants of monotone_obstructions, _seen_alike, _moved, _left_out and _runs alive under the tests. New tests: the exact monotone obstructions of a set with two cells in a row and two in a column, in each direction; two cells of a row the rest sees alike (one group) and two it does not (two groups); a cell kept only because an obstruction touches it, beside a cell left out; a requirement list with a point in the set and one outside it; a direction a set is not reducible in; the maps for the new fixtures and the threshold; and a seeded sanity check of every reduction the factory offers on 30 random tilings, to size 4 (7 seconds). Each of the eleven mutants the review named now fails a test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… tilings/algorithms/reduction.py The module had 1203 lines, over Tilings' max-module-lines of 1000, with a new too-many-lines disable (the review of the pull request, round 1, finding 3). As fusion has its algorithm in tilings/algorithms, the reduction's pure functions move there: the condition (is_reducible, is_rigid, monotone_obstructions), the plan (reduction_plan, with ReductionPlan, a named tuple of the groups and the cells left out), the children (reduction_children, own_is_tracked) and the words the maps are built from, with the maps themselves as reduce_gridded_perm and combine_gridded_perms; it takes Tiling for type checking only, as the other algorithm modules do, and builds tilings with the tiling's class. tilings/strategies/reduction.py keeps the argument, the constructor, the strategy and the factory, 682 lines, and drops the disable. The strategy's new public methods reduced_gp and parent_gp are now reduce_gridded_perm(comb_class, gridded_perm) and combine_gridded_perms( comb_class, reduced_gridded_perm, own_gridded_perm), with no abbreviation (finding 4). _runs and _canonical_words take their direction as a keyword, and _layout's cache says why it is there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Following the review of the pull request (round 1, its suggestions): full names in the new code (gridded_perm, obstruction, requirement, pattern, and strategy in the tests); is_reducible takes the cells once, so an iterator serves both directions; the own tiling's own maps (its RowColMap) in place of compression, which goes; the strategy's extra parameters passed to the constructor; one generator of the matching pairs for get_terms and get_sub_objects; the sampling choices as a named tuple, enumerated as the group sizes of sum at most the size (with the sizes the parent fixes) rather than all of (n + 1)^groups; equiv comparing where the children's parameters are, not only how many; the constructor's symbols from the strategy's; the factory's region sets in helpers, its docstring on tracked=False and on what "any" costs, without the claim that the reduced tiling is never larger (a requirement inside the set goes to the own tiling, and then the reduced tiling can have the empty permutation); from_dict popping and checking its keys; ranks by Perm.to_standard. The eleven mutants the review named still fail a test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The review of the pull request (round 1, finding 5): the changes to CellReductionConstructor, CellReductionStrategy's formal step and its reduced tiling (now simplified, so a specification saved with the old strategy may not rebuild its children identically: on 300 random tilings, 16 of 538 cell reductions differ, all in the reduced tiling's unsimplified obstructions; none could have counted, as the old constructor raised NotImplementedError), and the removed helpers of CellReductionFactory, are now in the CHANGELOG, whose Added bullet is shorter. test_specification asserts a reduction of three cells, as the description says. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… row a column sees apart The review's round 2 found two mutants that broke counts and passed every test, round 1's mutations at the other copy of a line that occurs twice: - in _left_out, the cells a requirement list with points outside the set touches (round 1's tests covered the obstructions' copy). In the top row of row_above_a_cell with a point required in B or below it, B is kept though its row and column have no cell outside the set, and A is left out; - in _runs, the place of a cell along a row (the copy in _canonical_words was covered). In the same row without the requirement, B and C are two groups, as C's column has a cell outside the set. The same mutation of _canonical_words, along a row when decreasing, broke only the forward map: unlike_row's complement, reduced decreasing with its two cells kept, is added to test_maps for it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
7dafe8f's message says is_reducible takes the cells once, so that an iterator serves both directions, but the code was not changed: with no direction, it passed the cells to the increasing call and then to the decreasing one, so an iterator was used up by the first, and a set reducible decreasing only was not reducible (the review's round 2). The cells are now made a set first. test_reducible_from_an_iterator passes an iterator of the cells of alike_row's complement, which is reducible decreasing only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…2 suggestions - The condition, and the argument why the reduction holds, are in the docstring of tilings.algorithms.reduction, where the code is, which defines the own tiling once; the strategy module's says what its constructor counts. - One selection of what the rest of the tiling sees the set through: _seen_gridded_perms reads the view, for is_reducible and _left_out alike. - ReductionConstructor(parent, children, plan, parent_to_reduced): the cells, never read, and the fallback for a missing map, which the strategy always passes, are gone, as the CHANGELOG says. - ReductionFactory._lines uses Tiling.cells_in_row and cells_in_col, from_dict pops its keys without defaults, and is_finite_cell, strategy and the constructor's symbol methods have docstrings; _own_tiling says why it is not Tiling.sub_tiling. - _monotone_ranks uses Perm.identity and Perm.monotone_decreasing; the constructor's helpers take parent_size, and the tests a random_generator. - test_equiv; test_tracked_pattern's docstring gives the reason. - The CHANGELOG's code span is on one line. On 10,400 random tilings, every set of up to four cells has the same reducibility in each direction and the same plan as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tation of a requirement list The review's round 3: every requirement in the tests was a single point, so the branch of _seen_gridded_perms that selects a requirement's gridded permutation with a point in the set and a point outside it was never taken (any( and all( agree on a single point), and any( changed to all( passed every test. - seen_through_a_21 is the review's tiling: A = (0, 1), in a column and a row with no cell outside the set, is seen only through the 21 from A down to C = (1, 0) of the list [a point in D = (2, 0), that 21]. Its plan, the "row" region offering the set, both directions' sanity checks to size 5, and test_maps. - left_out_beside_a_21 is row_above_a_cell with [a 21 from A down to D, a 12 in D] required: A is kept through the 21 and B left out, test_left_out_beside_kept with a requirement for the obstruction. Both lists have a second gridded permutation, as Tiling splits a lone 21 between two cells that share no row or column into a point in each. - test_requirement_with_two_points_in_the_set: a 12 from A to B in a list with a point in C makes alike_row's two cells not reducible increasing. With any( as all(, 8 of these tests fail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…me again 2082857 made is_reducible build the whole view (the lines with cells outside the set, the tracked cells and every crossing obstruction) before its first check, where fd37016 stopped at the first gridded permutation not allowed. On every set of at most three cells of 12 tilings of 10 and 11 active cells, grown by point placements, it was 1.4 to 1.7 times slower (the review's round 3, question 7(b)). Now _crossing_obstructions and _crossing_requirements are generators, and _seen_gridded_perms(tiling, cell_set) chains them for is_reducible. _view builds its tuples, and the cells of the set that a seen gridded permutation touches, from the same three, so the selection is still made in one place. _View has the set and the touched cells, and _left_out takes the view alone (the review's suggestion 2). On those sets: the same answers as fd37016 and 2082857, and as fast as fd37016 after warm-up. On 10,400 random tilings (61,570 sets of up to four cells), the same reducibility in each direction, the same answer for an iterator and the same plans as 2082857. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ocstrings - test_equiv: pairs that differ only in leaving a cell out, only in the place of the parent's parameter, or only in the place of the group's parameter in the reduced tiling, none equivalent; equivalent pairs of one group and of two; and one group each, with a cell left out in one. equiv no longer compares the number of groups: reduced_group_indices has an entry for each. The constructor's groups are a local name, as nothing else read them. - test_candidate_sets: the sets each region tries on an L of three cells, the "line" region's single cells among them. - The strategies module's docstring says when the own tiling tracks the groups, and _bounded_compositions' docstring is reworded. - The condition that each cell of the set lie in an obstruction of the set's own is stricter than its reason, since a requirement of the set's own would keep the cell active in the own tiling too. The docstrings say so; the condition is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…turn None of these changes a count, so no test that compares counts saw them: - test_degenerate_sets: the empty set, a set with an empty cell and a set with a cell off the tiling are not reducible; the cell of a one-cell tiling is. - test_reducible_with_no_direction, which test_reducible_from_an_iterator becomes: a set reducible increasing only, and one reducible decreasing only, are reducible with no direction given, from a list and from an iterator. - test_encoding: ReductionStrategy and CellReductionStrategy decode to themselves in each direction, tracked or not. One combination of each was round-tripped, so a from_dict that dropped or swapped increasing and tracked went unseen. - test_rigid: two cells of a column, in no fixed order and in each fixed order, and two cells of a row in a fixed order, the second of which is not monotone. Only cells of a row were tested, so the column branch, and the skip of reversed pairs taken as a break, went unseen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ecification there reduces three cells auto_search looks for a specification as its timing allows and extracts one at random, the smallest of the random proof trees it builds within a time limit. Av(1234, 1342, 2413) also has specifications without any reduction, one of 20 rules at the fifth level. So the specification found there reduced no set of three cells in one of 20 runs of the test, and in one mutation run whose mutant could not change a search, and the test failed. On Av(1243, 2314, 2413), with the same pack, the fourth level is the first with a specification. Without the rules of reductions of three cells, no specification is left there: pruning the rules without them leaves no root, under three hash seeds. So the specification extracted reduces three cells in every run, and it counts the class to length 8. The test passed under 16 hash seeds, in about 7 seconds each. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…h, the strategy's cells and the sampling's compositions - test_requirement_with_two_points_in_the_set also takes a lone 231 across A, B and C: two points in the set and one outside it, which only is_reducible's selection of a requirement's gridded permutations decides. - test_factory_skips: a single finite cell, though reducible and not rigid, and a set the rest of the tiling sees nothing of are not offered. - test_requirement_list asserts the plans. A point required in A or in C keeps A and B apart; a point required in A, in B or in C sees them alike. - test_strategy_cells: a strategy's cells are sorted and without repeats. - test_bounded_compositions: the compositions the random sampling goes through, against their number. - equiv says why it compares the own tiling's tracking and the places of its groups' parameters, which follow from the rest; test_equiv's fifth pair differs in two ways, as its comment now says. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the factory's tracking, defaults and finite cells Each of these went unseen by the tests: - test_maps: unlike_column and unlike_column_decreasing, the inverses of unlike_row and unlike_row_decreasing, in which the reduction keeps the two cells of a column; test_groups_along_a_column asserts their plans. No case kept two cells of one column, so column words put in the wrong order went unseen. - Two cells of a row that are two groups: seen_through_requirement's A and B, which the rest sees alike one way only, and split_by_first_column, the reverse of split_by_column, whose first cell of the row joins no group, as its column has a cell outside the set. Their plans are asserted, and test_sanity_check runs both in each direction: checking one way only, or starting a group at a cell that does not join, made each one group. - test_crossing_in_a_column: a cell of the set alone in its column, which a crossing there touches, is reducible. Its column, 0, differs from its row, 1, as in no other test of a crossing in a column, so reading the set's rows as its columns went unseen. - test_not_tracked: the strategies of ReductionFactory and CellReductionFactory are tracked as the factory is. - test_factory_defaults: a factory is tracked, of the region "cell" and without a bound unless told otherwise. - test_factory_skips: a cell whose basis has an increasing pattern only, or a decreasing one only, is not finite, and is offered alone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t the children, the factories' names and can_be_equivalent - test_rigid's column is in rows 1 and 2 of column 0. In rows 0 and 1, the first cell's row equals the second cell's column, so is_rigid comparing those two passed test_rigid, and only test_specification failed. - test_parent_assumptions calls extra_parameters without the children, which it then computes; comb_spec_searcher always passes them. - test_regions checks the names of the factories of the regions "row", "column", "line" and "any", with a bound and without. - test_children checks that the rule is never an equivalence. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Generalizes the cell reduction (
CellReductionFactory, #428) from one cell to any set of cells, and gives it a counting function, object generation and random sampling, which it did not have: its constructor raisedNotImplementedError. The strategy, its constructor and its factory,ReductionStrategy,ReductionConstructorandReductionFactory, are intilings/strategies/reduction.py; the condition, the plan, the two children and the words the maps are built from are intilings/algorithms/reduction.py, whose docstring has the condition and why the reduction holds, as fusion has its algorithm intilings/algorithms.CellReductionFactoryandCellReductionStrategystay, as the reduction of single cells, with their names and encodings.The rule. A set X of active cells of a tiling is reducible, in a direction (increasing or decreasing), if every obstruction with points both in X and outside it has exactly one point in X, in a cell c say, and
and every requirement list lies in X or has, in each of its gridded permutations, no point in X or one point as above; every cell of X lies in an obstruction that lies in X, which keeps it active in the tiling of X (a requirement that lies in X would too, but the condition asks for an obstruction); and no assumption on X is a component assumption or tracks a gridded permutation of two or more points (the sorting below keeps the number of points in each cell, but not the occurrences of a pattern). For a single cell this is the cell reduction's condition.
Why it holds. A gridded permutation is the same as three things chosen independently: for each column, the word of the cells of its points from left to right; for each row, the word of the cells of its points from bottom to top; and the permutation in each cell. The share of X in these is the order of the points of X among themselves in each column and in each row, and the permutations in the cells of X; the rest is the places of X's points among the other points of each column and row, and the other cells' permutations. An obstruction with one point in X sees that point only through its cell and its place among the other points of its column or of its row, never both. Which of the places of X's points in that row are the cell's is fixed by the rest when c is X's only cell there, and also when X's own obstructions fix the order of X's cells there, as the sorting leaves that order as it is. So sorting the share of X into the canonical one, every cell of X increasing (or decreasing) and the points of the cells of X in each row and each column in that order, is a bijection
where v is the number of points in each cell of X, T_X is the tiling of the obstructions and requirements of X (every other cell empty) and T_reduced is the tiling with those replaced by the monotone obstructions. Going back, T_X has the obstructions that fix the order, so its share agrees with the canonical one there.
The children, and what the reduced tiling keeps. The children are, in this order as before, the reduced tiling and the tiling of X. The reduced tiling keeps only what the rest of the tiling sees of X:
Each group seen as one is tracked once, by a tracking assumption in each child (in T_X unless there is one group and nothing left out, when its size is the group's points). The count is the Hadamard product of the two in the variables counting the points in the groups, at 1, and the product in the size of the cells left out:
printed with ⊙ (
a ↣ b ⊙ c). The parent's assumptions go to the reduced tiling, and a tracked cell of the parent is never left out or grouped. The object maps are the sorting and its inverse, built from the words above (reduce_gridded_permandcombine_gridded_perms, with the own tiling's ownRowColMapfor its cells): the backward map takes the rest from the reduced tiling's gridded permutation and the share of X, the cells left out and the split of each group included, from T_X's.get_sub_objectspairs the children's objects with the same w and sizes that add up, and random sampling picks w and m by their weight first. There is no sympy equation (get_equationraisesNotImplementedError, as for interleaving factors): a Hadamard product keeps D-finite series D-finite, but not algebraic ones.The factory.
ReductionFactory(tracked=True, region="cell", max_cells=None), exported fromtilings.strategiesbesideCellReductionFactory. The region says which sets it tries:"cell": every single cell, the current setup (CellReductionFactoryis this);"row": the active cells of each row;"column": the active cells of each column;"line": every set of cells in one row or in one column, so the single cells and the whole rows and columns too;"cut": the active cells on one side of a line between two adjacent columns or two adjacent rows (left or right of it, below or above it), at most twice the number of columns and rows. The cells left of a placed point are such a set, and these are the sets a threshold reduction reduces: in the specification of Av(2143) built by hand with the reduction, every reduction is of the cells left of a column, five or seven of them, which"any"reaches only withmax_cellsat least 7 and very many more sets;"any": every set of cells (the number of sets grows exponentially with the number of active cells).With
max_cells, the sets of"cut"and"any"have at most that many cells.A set is offered, in each direction it is reducible in, if it is not all of the active cells, is not rigid (every cell monotone and the points of any two of its cells in a row or a column in a fixed order, where reducing would change nothing or reverse the cells), is not a single finite cell, and the rest of the tiling sees one of its cells (otherwise it is a factor).
The cell reduction.
CellReductionFactory(tracked)isReductionFactory(tracked, "cell"), yieldingCellReductionStrategy. On 400 random tilings it gives the reductions develop's factory gives, except those of cells that are factors on their own (30 of 1052), which the factor strategy separates. Three kinds of cells are no longer reduced: a cell with no obstruction of its own, whose own tiling, without a requirement of its own either, would beTiling(), with only the empty permutation, so that the count would be wrong; a cell in a component assumption, where develop's constructor raisedNotImplementedError; and a cell in a tracked gridded permutation of two or more points. The kitchen sink pack usesReductionFactory(tracked). What else changes in the public API, as the CHANGELOG says:CellReductionStrategy.formal_stepnames the direction: "reducing cell (0, 0) to increasing", where it was "reducing cell (0, 0)".Tiling's defaults (simplified, empty rows and columns removed), where develop built it withsimplify=False,derive_empty=Falseandremove_empty_rows_and_cols=False. A specification saved with develop'sCellReductionStrategymay then not rebuild its children identically: on 300 random tilings, 16 of 538 cell reductions have a different reduced tiling, only in develop's unsimplified obstructions, and the same own tiling. None of those specifications could have been counted, as develop's constructor raisedNotImplementedError.CellReductionConstructorisReductionConstructor, which takes the parent, the children, the plan and the map of the parent's parameters to the reduced tiling's; develop'sCellReductionConstructor(parameter)counted nothing.CellReductionFactory.reducible_cells,can_reduce_cell_with_requirements_and_assumptionsandgp_in_row_and_colare removed: the condition istilings.algorithms.reduction.is_reducible.Examples.
With the first version, TileScope with point placements, or row and column placements, with fusion and the factory, on the 56 symmetry classes of two patterns of length 4 and the 317 of three, found specifications that reduce sets of two to five cells for 119 classes, every one counting correctly to length 10; with row and column placements, Av(1234, 2431) and Av(1243, 2431) got specifications with the reduction and none without it in the same time.
Tests (
tests/strategies/test_reduction.py, and the encoding tests):"cut"'s being the sides of the lines between columns and between rows, each among the sets"any"offers, with and withoutmax_cells; and the sets each region tries on an L of three cells; the factories' names;StrategyDoesNotApply;is_reduciblewith no direction: a set reducible increasing only, and one reducible decreasing only, are reducible; its cells are read once, so that an iterator serves for both directions;equiv), and constructors that differ only in leaving cells out, or only in the place of the groups' or of the parent's parameters, are not;"cell"and no bound;extra_parameters, given no children, computes them;CellReductionFactoryis the region"cell", with its old encoding;"any"(at most three cells), level by level. After the fourth level, the first with a specification, every specification of the class reduces a set of three cells, so the one extracted does, and it has the right counts (about 7 seconds). Level by level, so that the result does not depend onauto_search's timing or on the random choice of a specification it extracts.Beside these: on 400 random tilings of up to 3 × 3 cells, every one of the 2838 sets of up to four cells reducible before is reducible now in both directions, 13 more sets are reducible now, and all 3817 reductions the factory offers pass their sanity check to size 5 (1012 of them leave cells out, 308 have a group of two or more cells); the cell reduction gives develop's 1052 single-cell reductions but 30, all of cells that are factors on their own; and on tilings grown from 14 classes by point placements, row and column placements and requirement placements, every one of the 791 reductions offered passes its sanity check to size 6. Those 791 tracked 2486 cells in the first version and track 1343 groups now; 661 leave cells out, 5 have a group of two or more cells, and 28 were not reducible before.
CI's mypy, pylint and
test_positive_reverse_fusionfail on develop too, at the same lines; #531 fixes them. This pull request's own tests pass in every test job. It changes the CHANGELOG's Unreleased section, as #530 does.Reviewed before submission, over six rounds, by an automated reviewer. It ran:
developbranches of all three libraries. The one failure isdevelop'stest_positive_reverse_fusion, which Fix CI: the newest mypy and pylint, and test_positive_reverse_fusion #531 fixes.develop's encodings decoded, and its cell reductions compared (810, identical).developand on this branch: the same classes found, in about the same time.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.