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
+44
View File
@@ -0,0 +1,44 @@
"""Isolated production-role benchmark. No target discovery or audition capture."""
from __future__ import annotations
import argparse
import cProfile
import hashlib
import json
import os
from pathlib import Path
import platform
import pstats
import time
from generator import production, parts, musicxml, vocabulary
def main():
p=argparse.ArgumentParser(description=__doc__)
p.add_argument('--source',type=Path,required=True)
p.add_argument('--data-dir',type=Path,default=Path('data'))
p.add_argument('--role',choices=production.ROLES,required=True)
p.add_argument('--cache',type=Path)
p.add_argument('--output',type=Path,required=True)
p.add_argument('--profile',action='store_true')
args=p.parse_args();args.output.mkdir(parents=True,exist_ok=True)
start=time.monotonic()
source=production.SourceAnalysis.read(parts.prepare_document(musicxml.load_musicxml(args.source)))
analysis_seconds=time.monotonic()-start
profile=cProfile.Profile() if args.profile else None
if profile:profile.enable()
start=time.monotonic()
result=production.generate_role(source,args.role,args.data_dir,cache_dir=args.cache)
seconds=time.monotonic()-start
if profile:
profile.disable();profile.dump_stats(args.output/'role.prof')
with (args.output/'profile.txt').open('w') as out:pstats.Stats(profile,stream=out).sort_stats('cumulative').print_stats(70)
evidence={'source':str(args.source),'canonical_source':source.musical_key,'role':args.role,
'platform':platform.platform(),'processor':platform.processor(),'cpu_count':os.cpu_count(),'workers':1,
'cache_hit':result['cache_hit'],'analysis_seconds':analysis_seconds,'role_seconds':seconds,
'cprofile_enabled':bool(profile),'musical_document_hash':vocabulary.fingerprint(result['document']),
'input_trace':result['trace'],'observed_reads':result.get('observed_reads',[])}
(args.output/'result.json').write_text(json.dumps(result,sort_keys=True,indent=2))
(args.output/'benchmark.json').write_text(json.dumps(evidence,sort_keys=True,indent=2))
print(json.dumps({k:v for k,v in evidence.items() if k!='input_trace'},indent=2))
if __name__=='__main__':main()
+37
View File
@@ -0,0 +1,37 @@
"""Explicit reproducibility exercise with authored synthetic input; no targets needed."""
from __future__ import annotations
import argparse,concurrent.futures,contextlib,copy,json,multiprocessing,tempfile
from pathlib import Path
from generator import production,vocabulary
from tests.test_solo import song
def main():
p=argparse.ArgumentParser(description=__doc__);p.add_argument('--output',type=Path,required=True);a=p.parse_args();a.output.mkdir(parents=True,exist_ok=True)
data=Path('data').resolve();source=production.SourceAnalysis.read(song(count=1,chords=('C7',)))
results={};evidence={'scope':'One-bar independently authored source, real production catalogs, all six roles; not a whole-song musical quality test.','canonical_source':source.musical_key,'cases':{}}
def collect(label,values):
hashes={role:vocabulary.fingerprint(value['document']) for role,value in values.items()}
evidence['cases'][label]=hashes
evidence.setdefault('reads',{})[label]={r:v.get('observed_reads',[]) for r,v in values.items()}
if results:assert hashes==results['base'],label
else:results['base']=hashes
with tempfile.TemporaryDirectory() as temp:
cache=Path(temp)/'cache'
collect('alone_cold',{r:production.generate_role(source,r,data,cache_dir=cache) for r in production.ROLES})
collect('reverse_warm',{r:production.generate_role(source,r,data,cache_dir=cache) for r in reversed(production.ROLES)})
with concurrent.futures.ProcessPoolExecutor(max_workers=2,mp_context=multiprocessing.get_context('spawn')) as pool:
futures={r:pool.submit(production._job,(source,r,data,{},None)) for r in reversed(production.ROLES)}
collect('parallel_cold',{r:f.result() for r,f in futures.items()})
with contextlib.chdir(temp):
refs=Path('build');refs.mkdir()
for name in ('all-of-me','autumn-leaves'):
for i in (1,2):(refs/f'{name}-solo-{i}.xml').write_text('invalid optional content')
collect('targets_present_cold',{r:production.generate_role(source,r,data) for r in production.ROLES})
for path in refs.glob('*.xml'):path.unlink()
collect('targets_absent_cold',{r:production.generate_role(source,r,data) for r in production.ROLES})
production.generate_role(source,'electric_solo',data,{'choice_seed':'different electric only'})
collect('after_electric_setting',{r:production.generate_role(source,r,data,cache_dir=cache) for r in production.ROLES})
evidence['passed']=True
(a.output/'dependency.json').write_text(json.dumps(evidence,indent=2))
print(json.dumps({'passed':True,'hashes':results['base']},indent=2))
if __name__=='__main__':main()
+4 -2
View File
@@ -23,7 +23,8 @@ def region(document, part):
def staged(document, details, stage, tempo):
notes=[]
for phrase in details['phrases']:
for n in phrase['lead_stages'].get(stage,{}).get('notes',[]):
selected=phrase['lead_stages'].get(stage) or phrase['draft']
for n in selected.get('notes',[]):
p=n['pitch']
notes.append(types.Note(F(n['start']),F(n['end']),types.Pitch(p['letter'],F(p['alter']),p['octave']),
tuple(n['sources']),n['role'],continuation=n['continuation'],event_id=n['event_id']))
@@ -86,7 +87,8 @@ def export(assets,baseline,output):
notes_report.append(f"{phrase['id']}: {phrase['start']}–{phrase['end']}; {phrase['ending']}; completed={phrase['ending_completed']}\n")
for n in phrase['draft']['notes']:
p=n['pitch'];tone=types.Pitch(p['letter'],F(p['alter']),p['octave'])
pos=n['position'];notes_report.append(f" {n['start']}–{n['end']} {tone.label()} {n['role']} string {pos[0]} fret {pos[1]}\n")
pos=n['position'];tab=f' string {pos[0]} fret {pos[1]}' if pos else ' (draft pitch; final TAB in XML)'
notes_report.append(f" {n['start']}–{n['end']} {tone.label()} {n['role']}{tab}\n")
back_audio=mix([backing],tempo,output,tone_cache)
for name,document in versions.items():
label=key+'_'+name
+41
View File
@@ -0,0 +1,41 @@
"""Summarize finished production decisions; no composition or reference reading."""
from __future__ import annotations
import argparse,collections,json
from fractions import Fraction as F
from pathlib import Path
from generator import vocabulary
def main():
p=argparse.ArgumentParser(description=__doc__);p.add_argument('--assets',type=Path,required=True);p.add_argument('--output',type=Path,required=True);args=p.parse_args();args.output.mkdir(parents=True,exist_ok=True)
evidence={};text=['# Finished production evidence','', 'Times below are exact quarter-note beats relative to the solo. Counts describe the selected music; they are not targets or listening verdicts.','']
for path in sorted((args.assets/'analysis').glob('*.roles')):
roles=json.loads(path.read_text())
for role,v in roles.items():
key=path.stem+'/'+role
evidence[key]={'document_hash':vocabulary.fingerprint(v['document']),'trace':v['trace']}
if not role.endswith('_solo'):continue
d=v['details'];ps=d['phrases'];ns=[n for p in ps for n in p['draft']['notes']]
operations=collections.Counter(t['operation'] for p in ps for t in p['draft']['transformations'])
span=max(F(p['end']) for p in ps)-min(F(p['start']) for p in ps)
sounding=sum((F(n['end'])-F(n['start']) for n in ns),F())
summary={'attacks':sum(not n['continuation'] for n in ns),'quarter_beats':str(span),'occupancy':float(sounding/span),'fretboard':d['fretboard'],'operations_selected':dict(operations),'operation_funnel':d['selection_trace'].get('operations',{}),'expressions_selected':dict(collections.Counter(e['kind'] for e in d['expressions'])),'expression_funnel':d['selection_trace'].get('expression_operations',{}),'evaluation_total':d['selection_trace']['selection_total'],'unresolved':d['unresolved_treatments'],'boundaries':[]}
evidence[key].update(summary)
text += ['## '+key,'',f"{summary['attacks']} attacks over {span} quarter beats; sounding occupancy {summary['occupancy']:.1%}; sounding MIDI range {d['fretboard']['range_midi']}. Harmonic valid: {d['harmonic_valid']}; unresolved obligations: {len(d['unresolved_treatments'])}.",'', '| Span | Behavior | Destination / actual hold | Home identity |','|---|---|---|---|']
for phrase in ps:
anchors=[{k:a[k] for k in ('role','effect','pitch','actual_start','actual_end','completed')} for a in phrase['anchors']]
summary['boundaries'].append({'start':phrase['start'],'end':phrase['end'],'closure':phrase['closure'],'anchors':anchors,'home':phrase['home']})
destination='; '.join(a['effect']+' '+a['pitch']+' '+str(a['actual_start'])+'–'+str(a['actual_end']) for a in anchors) or 'no forced arrival'
text.append(f"| {phrase['start']}–{phrase['end']} | {phrase['closure']} / {phrase['ending']} | {destination} | `{phrase['home']}` |")
text += ['', 'Selected actions: '+', '.join(f'{k}: {v}' for k,v in sorted(operations.items()))+'.','', 'Typed treatments: '+str(summary['expressions_selected'])+'.','', '### Representative evaluated phrase','']
phrase=next(p for p in ps if p['draft']['notes']);evaluation=phrase['evaluation'];assert abs(phrase['score']-sum(evaluation['contributions'].values()))<1e-10
text += [f"Selected `{phrase['id']}`; score {phrase['score']:.9f}. Identity is a hard feature contract.",'','| Contribution | Raw | Weight | Weighted |','|---|---:|---:|---:|']
for k,value in evaluation['raw'].items():text.append(f"| {k} | {value:.9f} | {evaluation['weights'][k]} | {evaluation['contributions'][k]:.9f} |")
pool=d['selection_trace'].get('source_candidate_pools',{}).get(phrase['passage'],[])
alternatives=sorted((c for c in pool if c['id']!=phrase['draft']['id']),key=lambda c:(c['score'],c['id']))
text += ['', 'Other retained alternatives for this source window (possibly different incoming histories):']
for c in alternatives[:3]:text.append(f"- `{c['id']}`: {c['score']:.9f}, {c['attacks']} attacks; selected ending {c['ending']}.")
text += ['', 'These are local alternatives, not a proof of a global optimum. The chorus frontier compares complete histories using duration-weighted phrase scores. The JSON retains every reported contribution, operation cutoff counts and source input trace.','']
evidence[key]['winner_evaluation']=evaluation;evidence[key]['local_alternatives']=alternatives[:3]
(args.output/'evidence.json').write_text(json.dumps(evidence,indent=2))
(args.output/'phrase_traces.md').write_text('\n'.join(text)+'\n')
if __name__=='__main__':main()
+32
View File
@@ -0,0 +1,32 @@
"""Optional evaluation of independent source excerpts; never a production import."""
from __future__ import annotations
import argparse,json,time
from pathlib import Path
from generator import musicxml,parts,production,vocabulary,score,musicxml_writer
def main():
p=argparse.ArgumentParser(description=__doc__)
p.add_argument('--sources',type=Path,default=Path('tests/evaluation_sources'))
p.add_argument('--data-dir',type=Path,default=Path('data'))
p.add_argument('--output',type=Path,required=True)
args=p.parse_args();args.output.mkdir(parents=True,exist_ok=True)
report={'scope':'Four-bar source excerpts, not complete standards; read adjacent provenance. No target solo used.', 'cases':[]}
for path in sorted(args.sources.glob('*.xml')):
source=production.SourceAnalysis.read(parts.prepare_document(musicxml.load_musicxml(path)))
roles={};case={'source':str(path),'canonical_source':source.musical_key,'roles':{}}
for role in production.ROLES:
start=time.monotonic()
try:
value=production.generate_role(source,role,args.data_dir)
roles[role]=value;case['roles'][role]={'valid':True,'seconds':time.monotonic()-start,'hash':vocabulary.fingerprint(value['document'])}
except ValueError as error:
case['roles'][role]={'valid':False,'seconds':time.monotonic()-start,'diagnostic':str(error)}
print(path.stem,role,case['roles'][role],flush=True)
if len(roles)==len(production.ROLES):
for part,document in production.assemble(source,roles).items():
score.write_json(args.output/(path.stem+'_'+part+'.json'),document)
musicxml_writer.write_musicxml(args.output/(path.stem+'_'+part+'.xml'),document)
report['cases'].append(case)
(args.output/'report.json').write_text(json.dumps(report,indent=2))
return int(any(not r['valid'] for c in report['cases'] for r in c['roles'].values()))
if __name__=='__main__':raise SystemExit(main())