Save
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user