@@ -397,6 +397,53 @@ def build_substrate_bigram(vocab_size: int) -> torch.Tensor:
397397_SUBSTRATE_BIGRAM_ALPHA = 1.0 / (_PHI_FOR_SAMPLING ** math .pi ) # ~0.221
398398
399399
400+ def substrate_subject_threading (sequence : list , vocab : list ,
401+ probs : torch .Tensor ,
402+ is_sentence_start : bool ) -> torch .Tensor :
403+ """Cross-sentence dependency: at sentence-start positions, boost
404+ tokens that appeared at past sentence-starts (likely subjects).
405+
406+ Maintains a substrate-canonical memory: the last F(5)=8 sentence-
407+ starts. Each contributes a boost F(k)/phi^(pi*k) where k = how
408+ many sentences ago. Most-recent subject boosted full F(0)=1;
409+ older subjects decay by phi^pi per sentence.
410+
411+ Substrate "topic threading" across paragraph scale.
412+ """
413+ if not is_sentence_start or not vocab :
414+ return probs
415+ # Find tokens at sentence-start positions in the sequence.
416+ sentence_starts = []
417+ for i , tok_id in enumerate (sequence ):
418+ tok = vocab [tok_id ] if tok_id < len (vocab ) else ''
419+ # A token is a sentence-start if it follows .!?, newline,
420+ # OR is at position 0.
421+ if i == 0 :
422+ sentence_starts .append (tok_id )
423+ continue
424+ prev = vocab [sequence [i - 1 ]] if sequence [i - 1 ] < len (vocab ) else ''
425+ if prev in ('.' , '!' , '?' , '\n ' ):
426+ # The current token is the subject of a new sentence.
427+ sentence_starts .append (tok_id )
428+ if not sentence_starts :
429+ return probs
430+ # Keep last F(5)=8 sentence-starts.
431+ sentence_starts = sentence_starts [- 8 :]
432+ n = len (sentence_starts )
433+ phi_pi = _PHI_FOR_SAMPLING ** math .pi
434+ boost = torch .zeros_like (probs )
435+ for i , tok_id in enumerate (reversed (sentence_starts )):
436+ # i=0 = most recent sentence-start
437+ k_tier = min (i , len (_FIB_NUMS_FOR_BIGRAM ) - 1 )
438+ weight = (_FIB_NUMS_FOR_BIGRAM [k_tier ]
439+ / (phi_pi ** k_tier ))
440+ boost [tok_id ] += weight
441+ # Apply boost multiplicatively (substrate-canonical log-boost).
442+ boost_factor = 1.0 + boost * (math .pi * math .log (_PHI_FOR_SAMPLING ))
443+ out = probs * boost_factor
444+ return out / (out .sum () + 1e-8 )
445+
446+
400447def substrate_sentence_boundary_boost (prev_token : int , vocab : list ,
401448 probs : torch .Tensor ) -> torch .Tensor :
402449 """Substrate sentence-boundary primitive.
@@ -612,6 +659,16 @@ def autoregressive_generate(model, prompt: torch.Tensor, n_new: int,
612659 probs [0 ] = substrate_syntax_blend (
613660 int (seq [0 , - 1 ]), bigram_prior , probs [0 ],
614661 context_tokens = ctx_back , vocab = vocab )
662+ # Cross-sentence subject threading at sentence-starts.
663+ if vocab is not None and seq .shape [1 ] >= 1 :
664+ prev_tok_id = int (seq [0 , - 1 ])
665+ prev_str = (vocab [prev_tok_id ]
666+ if prev_tok_id < len (vocab ) else '' )
667+ if prev_str in ('.' , '!' , '?' , '\n ' ):
668+ seq_list = seq [0 ].tolist ()
669+ probs [0 ] = substrate_subject_threading (
670+ seq_list , vocab , probs [0 ],
671+ is_sentence_start = True )
615672 # Substrate anti-stagnation on the full window.
616673 history_aw = seq [0 , - 21 :]
617674 probs [0 ] = substrate_anti_stagnation (history_aw , probs [0 ],
@@ -678,6 +735,16 @@ def _single_stage_refine(model, draft, vocab_size, scorer, mode: str,
678735 pos_probs = substrate_syntax_blend (
679736 int (new [0 , t_draft - 1 ]), bigram_prior , pos_probs ,
680737 context_tokens = ctx_back , vocab = vocab )
738+ # Cross-sentence subject threading at sentence-starts.
739+ if vocab is not None and t_draft >= 1 :
740+ prev_tok_id = int (new [0 , t_draft - 1 ])
741+ prev_str = (vocab [prev_tok_id ]
742+ if prev_tok_id < len (vocab ) else '' )
743+ if prev_str in ('.' , '!' , '?' , '\n ' ):
744+ seq_list = new [0 , :t_draft ].tolist ()
745+ pos_probs = substrate_subject_threading (
746+ seq_list , vocab , pos_probs ,
747+ is_sentence_start = True )
681748 # Anti-stagnation on full prior context.
682749 aw_start = max (0 , t_draft - 21 )
683750 history_aw = new [0 , aw_start :t_draft ]
0 commit comments