@@ -74,3 +74,125 @@ def sudoku_extreme_preprocess_fn(
7474
7575def sudoku_extreme_kaggle_filter_fn (example : Dict [str , Any ]) -> bool :
7676 return example ["source" ] == "puzzles0_kaggle"
77+
78+
79+ # ---------------------------------------------------------------------------
80+ # Hard-tier filters for the Sudoku qualitative study.
81+ #
82+ # Used as ``datamodule.dataset_managers.val.infill_prediction.filter_fn=...`` to
83+ # bias the dump pool toward the long tail of difficulty without dumping the
84+ # whole 422k-puzzle test split. The filters live here (rather than in
85+ # ``doublebackprop``) so that they're discoverable from
86+ # ``xlm.utils.module_loading.get_function`` like the existing ``kaggle`` filter.
87+ # ---------------------------------------------------------------------------
88+
89+ # Strategies above the "single" / "candidate-line" baseline. Any of these
90+ # appearing in ``strategies_used`` means the timvink solver had to do real
91+ # heuristic work; if "Brute Force" is also present the puzzle additionally
92+ # required search/lookahead.
93+ _NON_TRIVIAL_STRATEGIES : frozenset [str ] = frozenset ({
94+ # Advanced
95+ "Naked Pair" , "Naked Pairs" ,
96+ "Naked Triple" , "Naked Triples" ,
97+ "Naked Quad" , "Naked Quads" ,
98+ "Hidden Pair" , "Hidden Pairs" ,
99+ "Hidden Triple" , "Hidden Triples" ,
100+ "Hidden Quad" , "Hidden Quads" ,
101+ # Master
102+ "X-Wing" , "X-Wings" ,
103+ "Swordfish" ,
104+ "Jellyfish" , "Jellyfishes" ,
105+ "Forcing Chain" , "Forcing Chains" ,
106+ })
107+
108+
109+ def _strategies_set (example : Dict [str , Any ]) -> set :
110+ s = example .get ("strategies_used" )
111+ if s is None :
112+ return set ()
113+ try :
114+ return {str (x ).strip () for x in s }
115+ except TypeError :
116+ return set ()
117+
118+
119+ def sudoku_extreme_hard_filter_fn (example : Dict [str , Any ]) -> bool :
120+ """Default 'hard' filter: keep puzzles in the top decile by difficulty.
121+
122+ A puzzle qualifies as hard if any of:
123+
124+ - ``rating >= 50``: timvink solver's tiered difficulty score (p90 of the
125+ test split is ~51, p95 is ~64). Catches the heavy brute-force tail.
126+ - ``num_steps >= 8``: long heuristic chains (p90 of the test split is 7).
127+ - any strategy in ``_NON_TRIVIAL_STRATEGIES``: Advanced or Master tier in
128+ the corrected tier mapping (catches the ~6k Advanced + ~225 Master
129+ puzzles that were silently bucketed as BruteForce in the original sweep).
130+
131+ Together these cover ~13% of the test split (vs. ~1.5% for tier-only and
132+ ~10% for rating-only); good for a dump pool that's small but not trivial.
133+ """
134+ rating = example .get ("rating" )
135+ if rating is not None and rating >= 50 :
136+ return True
137+ num_steps = example .get ("num_steps" )
138+ if num_steps is not None and num_steps >= 8 :
139+ return True
140+ if _strategies_set (example ) & _NON_TRIVIAL_STRATEGIES :
141+ return True
142+ return False
143+
144+
145+ def sudoku_extreme_extreme_filter_fn (example : Dict [str , Any ]) -> bool :
146+ """'Extreme' filter: top ~1% of the test split by rating *or* tier.
147+
148+ A puzzle qualifies as extreme if any of:
149+
150+ - ``rating >= 100``: ~1% of the split (p99 = 100).
151+ - ``num_steps >= 12``: ~1% (p99 = 12).
152+ - any Master-tier strategy (X-Wing / Swordfish / Jellyfish / Forcing Chain).
153+
154+ Designed for a small but pure hard slice when the goal is to localize
155+ where loopholing+BPTT actually starts to separate from StopGrad.
156+ """
157+ _MASTER = frozenset ({
158+ "X-Wing" , "X-Wings" ,
159+ "Swordfish" ,
160+ "Jellyfish" , "Jellyfishes" ,
161+ "Forcing Chain" , "Forcing Chains" ,
162+ })
163+ rating = example .get ("rating" )
164+ if rating is not None and rating >= 100 :
165+ return True
166+ num_steps = example .get ("num_steps" )
167+ if num_steps is not None and num_steps >= 12 :
168+ return True
169+ if _strategies_set (example ) & _MASTER :
170+ return True
171+ return False
172+
173+
174+ def sudoku_extreme_deduction_only_filter_fn (example : Dict [str , Any ]) -> bool :
175+ """'Deduction-only hard' filter: Advanced/Master strategies *and* no Brute Force.
176+
177+ A puzzle qualifies if it satisfies BOTH:
178+
179+ 1. ``"Brute Force"`` is **not** in ``strategies_used`` (excludes the ~358k
180+ BruteForce-tier puzzles entirely; we don't expect a forward-only diffusion
181+ model to do recursive backtracking).
182+ 2. ``strategies_used`` contains at least one Advanced or Master tier strategy
183+ (Naked/Hidden Pairs/Triples/Quads, X-Wing/Swordfish/Jellyfish/Forcing Chain).
184+
185+ This is the "real difficulty axis" cohort: ~6,190 puzzles in the test split
186+ (5,965 Advanced + 225 Master), so a 2,000-puzzle uniform-shuffled slice will
187+ contain ~1,930 Advanced + ~70 Master in expectation -- enough power to put a
188+ tight CI on the BPTT-vs-StopGrad paired delta separately for each tier.
189+
190+ Sister filters (`sudoku_extreme_hard_filter_fn`, `_extreme_filter_fn`) use
191+ OR over rating/num_steps/strategy, which pulls in lots of long-but-easy
192+ BruteForce-tail puzzles. This one uses AND so the cohort is *only* the
193+ deduction-needed puzzles.
194+ """
195+ s = _strategies_set (example )
196+ if "Brute Force" in s :
197+ return False
198+ return bool (s & _NON_TRIVIAL_STRATEGIES )
0 commit comments