@@ -33,7 +33,7 @@ public void SetCorpusStatistics(TermCollection termCollection, int totalDocument
3333 public byte CalculateCoverageScore ( string query , string documentText , double lcsSum , out int wordHits )
3434 {
3535 CoverageResult result = CalculateCoverageInternal ( query , documentText , lcsSum , out wordHits ,
36- out _ , out _ , out _ , out _ , out _ , out _ , out _ , out _ , out _ , out _ ) ;
36+ out _ , out _ , out _ , out _ , out _ , out _ , out _ , out _ , out _ , out _ , out _ ) ;
3737 return result . CoverageScore ;
3838 }
3939
@@ -49,7 +49,8 @@ public ushort CalculateRankedScore(string query, string documentText, double lcs
4949 out _ , // suffixPrefixRun
5050 out _ , // phraseSpan
5151 out _ , // precedingStrictCount
52- out _ ) ; // lastTokenHasPrefix
52+ out _ , // lastTokenHasPrefix
53+ out _ ) ; // fusionSignals
5354
5455 return CoverageScorer . CalculateRankedScore (
5556 result ,
@@ -78,7 +79,8 @@ public CoverageFeatures CalculateFeatures(string query, string documentText, dou
7879 out int suffixPrefixRun ,
7980 out int phraseSpan ,
8081 out int precedingStrictCount ,
81- out bool lastTokenHasPrefix ) ;
82+ out bool lastTokenHasPrefix ,
83+ out var fusionSignals ) ;
8284
8385 return new CoverageFeatures (
8486 result . CoverageScore ,
@@ -101,7 +103,8 @@ public CoverageFeatures CalculateFeatures(string query, string documentText, dou
101103 result . LastTermIsTypeAhead ,
102104 result . IdfCoverage ,
103105 result . TotalIdf ,
104- result . MissingIdf ) ;
106+ result . MissingIdf ,
107+ fusionSignals ) ;
105108 }
106109
107110 private CoverageResult CalculateCoverageInternal ( string query , string documentText , double lcsSum ,
@@ -115,7 +118,8 @@ private CoverageResult CalculateCoverageInternal(string query, string documentTe
115118 out int suffixPrefixRun ,
116119 out int phraseSpan ,
117120 out int precedingStrictCount ,
118- out bool lastTokenHasPrefix )
121+ out bool lastTokenHasPrefix ,
122+ out FusionSignals fusionSignals )
119123 {
120124 wordHits = 0 ;
121125 docTokenCount = 0 ;
@@ -128,6 +132,7 @@ private CoverageResult CalculateCoverageInternal(string query, string documentTe
128132 phraseSpan = 0 ;
129133 precedingStrictCount = 0 ;
130134 lastTokenHasPrefix = false ;
135+ fusionSignals = default ;
131136
132137 if ( query . Length == 0 )
133138 return new CoverageResult ( 0 , 0 , - 1 , 0 ) ;
@@ -147,6 +152,7 @@ private CoverageResult CalculateCoverageInternal(string query, string documentTe
147152 if ( qCountRaw == 0 )
148153 {
149154 if ( queryTokenArray != null ) ArrayPool < StringSlice > . Shared . Return ( queryTokenArray ) ;
155+ fusionSignals = default ;
150156 return new CoverageResult ( 0 , 0 , - 1 , 0 ) ;
151157 }
152158
@@ -306,7 +312,7 @@ private CoverageResult CalculateCoverageInternal(string query, string documentTe
306312
307313 wordHits = state . WordHits ;
308314
309- return CoverageScorer . CalculateFinalScore (
315+ CoverageResult coverageResult = CoverageScorer . CalculateFinalScore (
310316 ref state ,
311317 queryLen ,
312318 lcsSum ,
@@ -320,6 +326,42 @@ private CoverageResult CalculateCoverageInternal(string query, string documentTe
320326 out phraseSpan ,
321327 out precedingStrictCount ,
322328 out lastTokenHasPrefix ) ;
329+
330+ // Fusion signals need all tokens (no MinWordSize filtering)
331+ int maxFusionQueryTokens = queryLen / 2 + 1 ;
332+ StringSlice [ ] ? fusionQueryTokenArray = null ;
333+ Span < StringSlice > fusionQueryTokens = maxFusionQueryTokens <= CoverageTokenizer . MaxStackTerms
334+ ? stackalloc StringSlice [ maxFusionQueryTokens ]
335+ : ( fusionQueryTokenArray = ArrayPool < StringSlice > . Shared . Rent ( maxFusionQueryTokens ) ) ;
336+
337+ int fusionQCount = CoverageTokenizer . TokenizeToSpan ( query , fusionQueryTokens , minWordSize : 0 , delimiters ) ;
338+
339+ int maxFusionDocTokens = docLen / 2 + 1 ;
340+ StringSlice [ ] ? fusionDocTokenArray = null ;
341+ Span < StringSlice > fusionDocTokens = maxFusionDocTokens <= CoverageTokenizer . MaxStackTerms
342+ ? stackalloc StringSlice [ maxFusionDocTokens ]
343+ : fusionDocTokenArray = ArrayPool < StringSlice > . Shared . Rent ( maxFusionDocTokens ) ;
344+
345+ int fusionDCount = CoverageTokenizer . TokenizeToSpan ( documentText , fusionDocTokens , minWordSize : 0 , delimiters ) ;
346+
347+ try
348+ {
349+ fusionSignals = FusionSignalComputer . ComputeSignals (
350+ querySpan ,
351+ docSpan ,
352+ fusionQueryTokens [ ..fusionQCount ] ,
353+ fusionDocTokens [ ..fusionDCount ] ,
354+ fusionQCount ,
355+ fusionDCount ,
356+ _setup . MinWordSize ) ;
357+ }
358+ finally
359+ {
360+ if ( fusionQueryTokenArray != null ) ArrayPool < StringSlice > . Shared . Return ( fusionQueryTokenArray ) ;
361+ if ( fusionDocTokenArray != null ) ArrayPool < StringSlice > . Shared . Return ( fusionDocTokenArray ) ;
362+ }
363+
364+ return coverageResult ;
323365 }
324366
325367 /// <summary>
0 commit comments