Repository navigation
Keep the final-template prune on in grammars with partial rules wherever no partial word can be involved - #644
johnml1135 wants to merge 8 commits into
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #644 +/- ##
==========================================
+ Coverage 75.30% 75.58% +0.27%
==========================================
Files 454 456 +2
Lines 38527 38892 +365
Branches 5339 5423 +84
==========================================
+ Hits 29013 29395 +382
+ Misses 8376 8360 -16
+ Partials 1138 1137 -1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
…ver no partial word can be involved Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ects the tests found The tests parse 19 adversarial grammars at degree 1 and the default degree and compare the allomorph sets with pure master, bound the work on three grammars, and guard the set of output action types the look-ahead knows. They exposed two defects. With final-template state tracking off, a compounding rule set the state and the template rule then owed a partial nobody cleared (grammar g21). The look-ahead unified against unfrozen feature structures from several threads and lost parses at the default degree, so it unifies against frozen copies. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tial-rule look-ahead, and test the shapes the look-ahead reads A compounding subrule whose output was head, non-head, head was classed as a contiguous run of the input, so the prune dropped a parse master finds (cx1b). A non-head copy after a head copy now counts as an insertion between head copies. New grammars cx1b and cx4 to cx8 cover that compound, ModifyFromInput, InsertSimpleContext, an infix with a copied part, a non-head-first compound and a head part copied twice; cx2 makes the flagged and unflagged word differ only in NeedsPartial so removing it from Word equality or the merge key fails; cx3 pins that a lexical family in a partial-rule grammar returns each analysis once where master returns it twice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… caveat and merge-key doc Root guessing now skips analyses that owe a partial rule, as lexical lookup does, since a guessed root is never partial. The IsFinalTemplatePrunable comment says that in a grammar with both partial rules and lexical families only a duplicate analysis can be lost, which master returns and the prune does not. docs/review/hermitcrab.md lists NeedsPartial among the merge-key fields. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sing skip its real reason Grammar cx9b modifies an unbounded part, which analysis widens without rebuilding it, so a look-ahead that reads ModifyFromInput as a copy loses lopkutr; the test fails with the switch-off removed. The root-guessing comment now says a partial root takes no template, so the slot rule a flagged analysis owes is never applied. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
f7e1e88 to
71ce0fe
Compare
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| /// </summary> | ||
| public bool PartialRuleMayUnapply(Word input) | ||
| { | ||
| if (!_material.TryGetValue(input.Stratum, out StratumMaterial material) || material == null) |
There was a problem hiding this comment.
FYI: F10. A flagged analysis that reaches a stratum deeper than every partial rule is still fully unapplied there. That stratum has no _material entry, so this returns true and OwesImpossiblePartial never fires. Only a non-template partial rule clears NeedsPartial, so every such analysis is dropped at synthesis anyway. Return false for a stratum with no partial rule in it or below it (lang.Strata[0] is the deepest). Unverified: I did not measure the cost.
This comment has been minimized.
This comment has been minimized.
… template, and ignore slot and clitic partial rules in reachability An analysis dropped because it still owes a partial rule now leaves a TemplateAnalysisOutput trace node with FailureReason.OwedPartialCannotUnapply, the owing final template as source and the grammar's partial rules as FailureObject, as UnreachableRequiredSlot does in #575 (EndUnapplyTemplate gains the failureObj parameter, Trace gains FailureObject). Final-template state and the look-ahead are enabled only when the grammar has a final template that can be pruned. Reachability seeds only from non-template, non-clitic partial rules, the ones synthesis marks partial, so a grammar whose only partial rules sit in slots or are clitics prunes like one without partial rules. New grammars cx10 to cx12 and tests for the trace, the tracking flag and the work bound. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
||
| void BeginUnapplyTemplate(AffixTemplate template, Word input); | ||
| void EndUnapplyTemplate(AffixTemplate template, Word output, bool unapplied, FailureReason reason); | ||
| void EndUnapplyTemplate( |
There was a problem hiding this comment.
Major: F11. This breaks FieldWorks: a fifth parameter on the public ITraceManager.EndUnapplyTemplate means FieldWorks' FwXmlTraceManager (Src/LexText/ParserCore/FwXmlTraceManager.cs:72), which implements the four-parameter version, no longer compiles against this package. Keep the four-parameter signature and trace the drop with FailureReason.OwedPartialCannotUnapply alone, or add the failure object without changing the interface.
|
Verdict: request changes. Most important: F11 ( Counts: Critical 1 (F11), Important 0, Low 1 open (F10). Ran: Not verified: I did not build FieldWorks against this branch. The break comes from reading its source. F10's cost is still not measured. API and parity: public API changed. Findings: F1 addressed (c65a0b1). F2 addressed (2db0929). F3 addressed (2db0929). F4 addressed (2db0929). F5 addressed (f7e1e88). F6 addressed (71ce0fe). F7 addressed (f6c0b84). F8 addressed (f6c0b84). F9 addressed (f6c0b84). F10 open, unverified. F11 new. Reviewed at 2db0929 |
Start here: the final-template prune (#491) stays on in grammars that have partial rules, which is what Mbugwe
chaanjiyɛneeds to finish (#643). A prune that fires only where no partial word can be involved gives the same analyses as before and a fraction of the work.On
master,Morpher.HasPartialRulesturns the prune off grammar-wide when any rule is partial. The change has four parts:None, so what it licenses after a final template survives.FinalTemplatePartialReachabilitycomputes at load which final templates a partial word can reach (a part-of-speech closure over every rule, across strata). Any other final template is pruned as before.Word.NeedsPartialis set when a final template is unapplied right after a non-template rule, and cleared when a partial rule is unapplied. It is part ofWordequality, its hash andAnalysisMergeKey. An analysis that still owes one when it reaches lexical lookup or root guessing is dropped.TemplateAnalysisOutputtrace node with the newFailureReason.OwedPartialCannotUnapply, the owing final template as source and the grammar's partial rules asTrace.FailureObject, so Try a Word shows the drop. It uses theEndUnapplyTemplate(..., object failureObj)signature that Prune affix template partials whose required slots cannot find their material, in order and at the word edges #575 adds. State tracking and the look-ahead are on only when the grammar has a final template that can be pruned, and reachability seeds only from the partial rules that synthesis marks partial (not slot or clitic rules).PartialRuleLookAheaddrops an owing analysis early when its shape shows no partial rule can still be unapplied. It is on only for a stratum whose rules use nothing but copy and insert-segments actions; otherwise it says "possible".Result on the reference grammars (this branch against
master, one thread, rule-selector calls): zero changed analyses on every compared word, and Aweti, Sena and Mbugwe do 60 to 92 % less work. In the unit tests, 31 adversarial grammars give the same analyses asmasterat degree 1 and at the default degree.Caveats.
CheckBlockingandChooseInflectionalStemreturn a freshWordfor a family member that drops the pending rule list. In a grammar with both partial rules and lexical families,masternever prunes, so it returns duplicate analyses (same morphemes and shape) that this branch no longer returns. Only a duplicate is lost, never a distinct analysis: grammarcx3returnskamdtrandkamdtrttwice each onmasterand once each here.PartialRulePruneTestspins that. FieldWorks never writesFamily. I did not add a "no lexical families" condition.g7rise 31 % and oncx225 % (degree 1). I found no cheap way to keep the split only where the prune can fire. The reference grammars do not show it.Next: review. Landing order: the suite PR sillsdev/fieldworks-parser-conformance#42 (fixtures, rows identical on
masterand this branch) can land first; nothing here pins it, becausemasterhas no conformance runner until #615 lands.Closes #643. Related: #606, #590, #553, #551, #491. #607 holds the remaining Mbugwe cost.
Results: master against this branch
hcharness with a rule-selector counter, degree 1, puremaster(511fecc) dlls against this branch'sSIL.Machine.Morphology.HermitCrab.dll(rebased on it). "Compared" excludes words the loader skips (letters not in the table) and words that hit the cap on a side. Work is the sum of selector calls over the compared words; allocated bytes areGC.GetTotalAllocatedBytes, the repeatable measure on this loaded machine. Both sides were rerun for every row at head 2db0929.The Mbugwe sample is the first 100 words of the earlier list, 13 later ones and a random 60 from index 400 on.
masterneeds about 90 s per capped word. Five of them hit the cap onmasterand finish on this branch (nyaanjiyɛ,nyanjiyɛ,wāanjiyɛ,woomiyɛ,yaanja); they are not in the compared column. Before the rebase, 377 Mbugwe words were compared (369 with both answers, 345 with parses, 88.0 % less work) with 0 changes.All 31 test grammars (
g*andcx*; 62 runs, degree 1 and default, 758 words) were parsed through thehcharness on both dlls at this head: 0 differences in the distinct analysis sets. Raw multiplicities differ only oncx3(documented) and ong13bandg21, wheremasteritself varies between runs. Work on the test grammars (degree 1):cx1117.6 % andcx1223.5 % less,cx10equal (nothing to prune),g730.7 % more (see caveats).Conformance suite (rerun at this head) at
origin/mainplus the five new fixtures (sillsdev/fieldworks-parser-conformance#42), run with the #615 runner onmaster+ #615 and on this branch + #615: every signature of every word dumped and diffed (with--include-pathological): 1,494 rows for the conformance run and 791 for the stress run, 0 differences. Both engines pass 152 of 153 runs and fail the same one (infix-split-root-allomorph-environment, which needs an engine fix not onmaster). Stress fixtures: 16 of 16 on both.Tests
PartialRulePruneTests(77 tests) intests/SIL.Machine.Morphology.HermitCrab.Tests:g6,g6b,g7,g8,g10tog21,cx1b,cx2tocx12) with their words, each parsed at degree 1 and at the default degree. The.expectedfiles hold the distinct allomorph sets thatmasterreturns, so a lost, extra or changed analysis fails.cxgrammars cover how the look-ahead reads each rule shape:cx1ba compound whose output is head, non-head, head;cx4ModifyFromInputon a bounded part andcx9bon an unbounded one;cx5InsertSimpleContext;cx6an infix plus a copied part;cx7a non-head-first compound;cx8a head part copied twice around the non-head.cx2makes a flagged and an unflagged word differ only inNeedsPartial.cx3has a lexical family and a partial rule.cx10has partial rules and no final template,cx11a partial rule only in a template slot andcx12only a clitic partial rule.cx3duplicate loss (each word once here, twice onmaster).g8), and a shape with no room for partial material, by the contiguous test (g6) and by the existence test (g12).ParseWord_OwedPartialDropped_IsTraced(g6,g6b,cx1b, both degrees) checks the trace node's type, source, null output and non-empty rule list.TracksFinalTemplateState_...pins thatcx10tracks no state and thatcx1b,cx11andcx12do. Two work-bound tests (cx11,cx12) count selector calls to show the prune stays on.MorphologicalOutputActionsubtype appears, because the look-ahead only knows the four that exist.Does each test fail without the mechanism? Mutations of the branch, each run against the whole class (new mutations run on the final head):
cx1bfix removed)cx1bfails at both degreesNeedsPartialout ofWordequality and hashcx2fails at both degreesNeedsPartialout ofAnalysisMergeKeyonlycx2fails at both degreescx1b,cx6,g12,g15failModifyFromInputlet into the look-ahead (its switch-off removed)cx9bfails at both degrees: a modify of an unbounded part widens a node without rebuilding it, so the switch-off is requiredInsertSimpleContextlet into the look-aheadGenerateShapedrops, likeInsertSegments, so the look-ahead stays sound (by reading)TraceOwedPartialDroppedOwedPartialDropped_IsTracedcases failcx10tracking case failscx11andcx12work-bound tests and thecx11tracking case failg13cfails); every final template unreachable (32 tests fail); a partial rule leaves the state atNonTemplate(26 fail); state never tracked (the 3 work-bound tests fail);master(the 3 work-bound tests fail in 6 of 6 runs, the results tests pass, as they must)Two defects the first round of tests found, both fixed here: with state tracking off, a compounding rule set
NonTemplateand the template rule then owed a partial nobody cleared (g21); and the look-ahead unified against unfrozen feature structures from several threads and lost parses at the default degree (g13b,g18). A review then found a third, fixed in the last two commits: a compounding rule that puts the non-head between two head parts was read as a contiguous run, solopkmootr(cx1b) was lost.The whole HermitCrab test project (rebased on master 511fecc): 261 passed. The class (77 tests, both degrees) passes 10 of 10 runs.
masteritself returns a varying number of identical analyses, and a varying morph order under truncation, in the test host, so the comparison uses distinct, ordered allomorph sets.Not done or not run
./local_check.shstops at the solution build:SIL.Machine.Tokenization.SentencePiecerunscmakeand fails in this environment. The HermitCrab project and its tests build and pass,dotnet csharpier checkon both is clean, and./local_check.sh --agent-strictcomment hygiene is clean after two shortenings.FwXmlTraceManager,HcXmlTraceManagerand the two trace XSLs need a case for the new reason, shaped like FieldWorks #1247 for Prune affix template partials whose required slots cannot find their material, in order and at the word edges #575; not written.cx3has lexical families, and it pins the lost duplicate; no FieldWorks project, no PanGloss run.masterdoes not finish its heavy words:chaanjiyɛhits the cap onmasterand finishes on this branch (issue HermitCrab: one partial rule switches off the final-template prune for the whole grammar; Mbugwe chaanjiyɛ never finishes #643).🤖 Generated with Claude Code
This change is