This commit is contained in:
khodowany
2026-10-04 15:51:18 -05:00
parent 405066eb43
commit f234dd6d51
54 changed files with 2104 additions and 330 deletions
+39 -1
View File
@@ -4,7 +4,44 @@ from __future__ import annotations
import dataclasses
from fractions import Fraction as F
from generator.solo import drafts, harmonic, types
from generator.solo import drafts, harmonic, types, groups
def join_variants(draft,harmony,library):
"""Recompose both sides of an editable internal join as one complete route.
Keep endpoints and exact span. A provisional held tail can reopen into two
binary attacks; a committed hold or identifying event is never consumed.
Alternatives are returned to the authoritative phrase evaluator.
"""
from generator.solo import routes, policy
fixed=set(draft.protected)|set(draft.structural)|{e for f in draft.features for e in f.events}
produced=0
for join in (t.start for t in draft.transformations[1:]):
inside=tuple(n for n in draft.notes if join-2<=n.start and n.end<=join+2)
if len(inside)<3 or any(n.event_id in fixed or n.role=='quote' for n in inside[1:-1]):continue
if any(t.start<inside[-1].end and t.end>inside[0].start for t in draft.sustained_tails):continue
pattern=tuple((n.start-inside[0].start,n.end-inside[0].start) for n in inside)
if not groups.valid(pattern):continue
alternatives=[inside]
for i,n in enumerate(inside[1:-1],1):
if n.end==join and n.end-n.start>=1 and (n.start*2).denominator==1:
cut=n.end-F(1,2)
alternatives.append((*inside[:i],dataclasses.replace(n,end=cut),
dataclasses.replace(n,start=cut,event_id=n.event_id+':extend'),*inside[i+1:]))
break
for template in alternatives:
for route in routes.candidates(template,{template[-1].event_id},harmony,library,harmony.profile.register,'two-sided join'):
if route.notes==inside:continue
actual=tuple(n for n in draft.notes if n.end<=inside[0].start)+route.notes+tuple(n for n in draft.notes if n.start>=inside[-1].end)
if not drafts.contract_valid(draft,actual)[0] or not harmony.evaluate(actual,until=draft.end,complete=True).valid:continue
transforms=tuple(dataclasses.replace(t,events=tuple(n.event_id for n in actual if t.start<=n.start<t.end),
rhythm=tuple((n.start-t.start,n.end-t.start) for n in actual if t.start<=n.start<t.end)) for t in draft.transformations)
changed=dataclasses.replace(draft,id=draft.id+':join:'+route.id,notes=actual,transformations=transforms)
yield changed,types.DraftEdit('two_sided_join',inside[0].start,inside[-1].end,
tuple(n.event_id for n in inside),tuple(n.event_id for n in route.notes),'complete route over both sides; endpoints and contracts preserved'),route
produced+=1
if produced>=policy.DEFAULT.join_alternatives:return
def fragmentation(notes):
@@ -71,6 +108,7 @@ def revise(draft, harmony, treatments=()):
if len(proposals)>=8: break
valid=[]
for actual in proposals[:8]:
if not groups.valid(tuple((n.start-draft.start,n.end-draft.start) for n in actual)):continue
if fragmentation(actual)>=fragmentation(notes): continue
if not drafts.contract_valid(draft,actual)[0]: continue
if not harmony.evaluate(actual,treatments,until=draft.end,complete=True).valid: continue