This commit is contained in:
khodowany
2026-10-05 08:51:03 -05:00
parent ef62af892b
commit 654299decd
25 changed files with 1695 additions and 351 deletions
+197
View File
@@ -0,0 +1,197 @@
"""Development-only shared integer ranking from COMPLETE ordinary rollouts.
The returned coefficients depend on the training examples. Target event arrays,
source identifiers and diagnostic oracle paths are never production artifacts.
"""
from collections import Counter
from fractions import Fraction as F
import itertools
import math
from generator import vocabulary
from generator.solo import selection
def contextual_candidates(selector,notes):
"""Induce only whitelisted two/three-condition event contexts.
These counts are training-dependent. No title, time index, song key, event
array, fingerprint or arbitrary predicate can appear in the rule schema.
"""
values=Counter()
for context,ticks in selector.contexts(notes):
terms=sorted((k,v) for k,v in context.items() if v in selection.CONDITIONS[k])
for size in (2,3):
for terms_ in itertools.combinations(terms,size):
values['joint/'+'&'.join(k+'='+v for k,v in terms_)]+=ticks
return values
def vector(builder,actions,home=()):
e=builder.selector.complete(actions,home,start=builder.start,end=builder.end)
# Equal spans: clear normalization without rounding any musical time.
span=builder.end-builder.start
features={k:F(v)*span for k,v in e.raw.items() if not k.startswith('prior/') and v}
prior=sum(F(v)*span for k,v in e.contributions.items() if k.startswith('prior/'))
return features,prior
def constraint(role,gold,other,case):
left,lp=gold;right,rp=other
delta={k:left.get(k,0)-right.get(k,0) for k in left.keys()|right.keys()}
delta={k:v for k,v in delta.items() if v}
selection.validate_weights(dict.fromkeys(delta,0))
return {'role':role,'delta':delta,'prior':lp-rp,'case':case}
def solve(rows,bound=1024):
"""One shared coefficient table per role; deterministic pinned integer solver."""
import z3
if z3.get_version_string()!='4.13.3':raise ValueError('Use pinned z3-solver==4.13.3.0')
z3.set_param('smt.random_seed',0)
# Exact zero/one-coefficient cases need no combinatorial cardinality search.
# Checking every feature's integer interval proves the minimum support and
# L1 objective when all independent roles have such a solution. This does
# not claim the resulting sparse model reproduces any complete melody.
simple={}
for role in sorted({r['role'] for r in rows}):
subset=[r for r in rows if r['role']==role]
if all(r['prior']<=-1 for r in subset):simple[role]={};continue
choices=[]
for key in sorted({k for r in subset for k in r['delta']}):
low,high=-bound,bound
for r in subset:
slope=F(r['delta'].get(key,0));limit=-1-F(r['prior'])
if slope>0:high=min(high,math.floor(limit/slope))
elif slope<0:low=max(low,math.ceil(limit/slope))
elif limit<0:low,high=1,0;break
if low<=high:
value=low if low>0 else high if high<0 else 0
choices.append((abs(value),key,value))
if not choices:break
_,key,value=min(choices);simple[role]={key:value}
if set(simple)=={r['role'] for r in rows}:
for weights in simple.values():selection.validate_weights(weights)
return {'status':'solved','weights':simple,'bound':bound,
'nonzero':sum(len(w) for w in simple.values()),'l1':sum(abs(v) for w in simple.values() for v in w.values()),
'method':'exhaustive zero/one-coefficient integer intervals; minimum support and L1 within that support proven'}
names=sorted({(r['role'],k) for r in rows for k in r['delta']})
variables={n:z3.Int('w_'+str(i)) for i,n in enumerate(names)}
limits=[v>=-bound for v in variables.values()]+[v<=bound for v in variables.values()]
rational=lambda v:z3.RealVal(str(F(v)))
constraints=[z3.Sum([variables[(r['role'],k)]*rational(v) for k,v in r['delta'].items()])+rational(r['prior'])<=-1 for r in rows]
check=z3.Solver();check.set(rlimit=2000000);check.add(*limits)
for i,c in enumerate(constraints):check.assert_and_track(c,'comparison_'+str(i))
status=check.check()
if status==z3.unknown:return {'status':'solver_unknown','stage':'feasibility','reason':check.reason_unknown()}
if status==z3.unsat:
return {'status':'incompatible_with_current_features_and_bounds','bound':bound,
'conflicts':[str(x) for x in check.unsat_core()],
'identical_feature_pairs':[i for i,r in enumerate(rows) if not r['delta'] and r['prior']>=0]}
opt=z3.Optimize();opt.add(*limits,*constraints)
# Deterministic solver work budget. Exhaustion yields no proposed model;
# elapsed wall time never chooses a musical winner.
opt.set(rlimit=2000000)
opt.minimize(z3.Sum([z3.If(v==0,0,1) for v in variables.values()]))
opt.minimize(z3.Sum([z3.If(v<0,-v,v) for v in variables.values()]))
if opt.check()!=z3.sat:return {'status':'solver_unknown','reason':opt.reason_unknown()}
model=opt.model();weights={r:{} for r,_ in names}
for (role,key),v in variables.items():
value=model.eval(v,model_completion=True).as_long()
if value:weights[role][key]=value
for w in weights.values():selection.validate_weights(w)
return {'status':'solved','weights':weights,'bound':bound,
'nonzero':sum(len(w) for w in weights.values()),'l1':sum(abs(v) for w in weights.values() for v in w.values())}
def sounded(actions):
from generator.solo.types import sounding_notes
return tuple((n.start,n.end,n.pitch.number()) for n in sounding_notes(tuple(n for a in actions for n in a.notes)))
class CoverageTrace:
"""Read-only observer. Targets diagnose cuts, never supply search decisions."""
def __init__(self,gold):
self.gold=sounded(gold);self.records=[]
def matches(self,notes,end):
# These are committed whole actions, not a truncated playback preview.
# A quarter-note attack cannot reproduce a half-note target merely because
# its first quarter sounds the same. Future actions do not reopen it.
from generator.solo.types import sounding_notes
actual=tuple((n.start,n.end,n.pitch.number()) for n in sounding_notes(notes))
expected=tuple((a,b,p) for a,b,p in self.gold if a<end)
return actual==expected
def __call__(self,stage,at,state,proposed,retained):
if stage=='successors':
if not self.matches(state.notes,at):return
eligible=[a for a in proposed if self.matches((*state.notes,*a.notes),a.end)]
survivors=[a for a in retained if self.matches((*state.notes,*a.notes),a.end)]
else:
eligible=[s for s in proposed if self.matches(s.notes,s.action.end if s.action else at)]
survivors=[s for s in retained if self.matches(s.notes,s.action.end if s.action else at)]
if eligible and not survivors:
self.records.append({'time':str(at),'status':'pruned_at_'+stage,'matching_proposals':len(eligible)})
elif stage=='successors' and not eligible:
self.records.append({'time':str(at),'status':'not_proposed_in_actual_incoming_state'})
def fit_complete(examples,passes,on_checkpoint=None,resources=None):
weights={role:dict(b.selector.weights) for _,role,b,_ in examples}
rows=[];history=[];last_solver={};exact=False;comparisons=[];induced=[]
for iteration in range(passes):
cases=[];errors=0
for name,role,b,gold in examples:
b.selector.weights=weights[role]
trace=CoverageTrace(gold);b.observe=trace
# Honor the explicitly selected development data directory during lazy
# operator expansion too, not just when constructing the builder.
with vocabulary.using(resources or vocabulary.current()['data'],role):
b.compose() # No target argument, prefix, candidate injection or oracle.
b.observe=None
state=__import__('generator.solo.construction',fromlist=['State']).State()
for a in gold:state=b.advance(state,None,a)
positive=vector(b,gold,state.home)
correct=sounded(b.selected_actions)==sounded(gold)
cases.append({'case':name,'exact_complete_output':correct,
'completed_candidates':len(b.completed),'winner':str(b.winner_evaluation.total),
'earliest_observed_failures':trace.records[:8],
'target_in_completed_pool':any(sounded(s.actions)==sounded(gold) for s in b.completed)})
if not correct:errors+=1
for s in b.completed:
if sounded(s.actions)!=sounded(gold):
comparisons.append((name,role,b,gold,state.home,s.actions,s.home))
rows.append(constraint(role,positive,vector(b,s.actions,s.home),name))
print(name,'exact' if correct else 'complete-output mismatch',flush=True)
history.append({'iteration':iteration+1,'incorrect_complete_outputs':errors,'cases':cases})
if not errors:exact=True
result={'weights':weights,'history':history,'complete':exact,'solver':last_solver,
'induced_rules':induced,
'training_dependency':'Coefficients learned from supplied authored examples; runtime target-free is not training independence.',
'release_gate':'Ordinary cold full-song outputs must independently pass exact comparison; derivation is not success.'}
if on_checkpoint:on_checkpoint(result)
if exact:break
last_solver=solve(rows)
if last_solver['status']!='solved':
# Add a context only for a demonstrated feature collision. General
# ranking failure is not permission to expand vocabulary indiscriminately.
collisions=last_solver.get('identical_feature_pairs',[])
if collisions and len(induced)<8 and iteration+1<passes:
i=collisions[0];name,role,b,gold,gh,other,oh=comparisons[i]
g=contextual_candidates(b.selector,tuple(n for a in gold for n in a.notes))
o=contextual_candidates(b.selector,tuple(n for a in other for n in a.notes))
keys=sorted((k for k in g.keys()|o.keys() if g.get(k,0)!=o.get(k,0) and k not in weights[role]),key=lambda k:(k.count('&'),k))
if keys:
key=keys[0]
for r in weights:weights[r][key]=0
induced.append({'rule':key,'reason':'complete-candidate feature collision','training_case':name,
'schema':'two or three whitelisted chord/relative-motion/rhythm/source conditions; no song identity'})
rows=[]
for name,r,b,gold,gh,other,oh in comparisons:
b.selector.weights=weights[r]
rows.append(constraint(r,vector(b,gold,gh),vector(b,other,oh),name))
continue
result['solver']=last_solver;break
if iteration+1<passes:weights={r:last_solver['weights'].get(r,{}) for r in weights}
# Do not call an untested final solver update a successful checkpoint.
result['solver']=last_solver
result['constraints']=[{**r,'delta':{k:str(v) for k,v in r['delta'].items()},'prior':str(r['prior'])} for r in rows]
return result