6.9 KiB · file hash computed
Text · original UTF-8 line locators · 6.9 KiB
"""Public fixed-suite dynamics evaluation v2; numerical agreement, not a generalization certificate."""
import json, os, sys, pathlib, subprocess, signal, resource, time, tempfile
import importlib.metadata
import numpy as np
from physics import make_instance, gate
CHILD = r'''
import json,sys,importlib.util,resource,time
method, batch, output = sys.argv[1:]
try:
spec=importlib.util.spec_from_file_location('method',method)
mod=importlib.util.module_from_spec(spec); spec.loader.exec_module(mod)
p=getattr(mod,'PRIORS',None)
if not isinstance(p,dict) or not isinstance(p.get('family'),str) or not p['family'].strip() or not isinstance(p.get('parameters'),dict) or not isinstance(p.get('notes'),str):
raise ValueError('PRIORS must contain nonempty family:string, parameters:dict and notes:string')
json.dumps(p,allow_nan=False)
results=[]
for inst in json.load(open(batch)):
t=time.monotonic()
import numpy as np
y=np.asarray(mod.simulate(inst,inst['times']),dtype=float).tolist()
results.append({'trace':y,'seconds':time.monotonic()-t})
json.dump({'ok':True,'priors':p,'results':results,'peak_rss_kib':resource.getrusage(resource.RUSAGE_SELF).ru_maxrss},open(output,'w'),allow_nan=False)
except BaseException as e:
json.dump({'ok':False,'error':type(e).__name__+': '+str(e)[:500]},open(output,'w'))
'''
def run_batch(method, instances, seconds, policy, scratch, label):
batch=scratch/(label+'.json'); output=scratch/(label+'-out.json')
batch.write_text(json.dumps(instances)); child=scratch/'child.py'; child.write_text(CHILD)
env={'PATH':os.environ.get('PATH',''),'HOME':str(scratch),'PYTHONDONTWRITEBYTECODE':'1'}
env.update({k:str(policy['child_threads']) for k in ('OMP_NUM_THREADS','OPENBLAS_NUM_THREADS','MKL_NUM_THREADS','NUMBA_NUM_THREADS')})
def limits():
cap=policy['child_memory_mb']*1024**2; resource.setrlimit(resource.RLIMIT_AS,(cap,cap))
start=time.monotonic()
proc=subprocess.Popen([sys.executable,'-I',str(child),str(method),str(batch),str(output)],cwd=scratch,env=env,preexec_fn=limits,start_new_session=True,stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL)
timeout=False
try: proc.wait(timeout=seconds)
except subprocess.TimeoutExpired: timeout=True
finally:
try: os.killpg(proc.pid,signal.SIGKILL)
except ProcessLookupError: pass
proc.wait()
wall=time.monotonic()-start
if timeout: return {'ok':False,'error':f'{label} exceeded its full {seconds}s budget','wall_seconds':wall}
try: result=json.loads(output.read_text())
except Exception: result={'ok':False,'error':'child produced no valid JSON'}
result['wall_seconds']=wall
return result
​
def main():
inp=pathlib.Path(os.environ.get('TFP_INPUT','/input')); out=pathlib.Path(os.environ.get('TFP_OUTPUT','/output'))
manifest=json.loads((inp/'manifest.json').read_text())
refs={e['key']:pathlib.Path(e['path']) for e in manifest['reference']}
method=next(pathlib.Path(e['path']) for e in manifest['artifacts'] if e['role']=='method')
fam=json.loads(refs['family'].read_text()); policy=json.loads(refs['spec'].read_text()); truth=json.loads(refs['traces'].read_text())
ev={'family':fam['family'],'suite_version':fam['suite']['version'],'instance_errors':[], 'accuracy_probe_error':None,
'runtime':{'python':sys.version.split()[0],**{x:importlib.metadata.version(x) for x in ('numpy','scipy','quimb','physics-tenpy')}},
'reference_validation':truth['validation'],'resource_limits':policy,'budgets':fam['budget_seconds']}
def finish(verdict,reason,score=None):
me,parent,uid=os.getpid(),os.getppid(),os.getuid()
for name in os.listdir('/proc'):
if not name.isdigit() or int(name) in (me,parent): continue
try:
status=pathlib.Path('/proc')/name/'status'
if any(line.startswith('Uid:') and int(line.split()[1])==uid for line in status.read_text().splitlines()): os.kill(int(name),signal.SIGKILL)
except (OSError,ValueError): pass
(out/'evidence').mkdir(parents=True,exist_ok=True)
(out/'evidence/summary.json').write_text(json.dumps(ev,allow_nan=False,indent=1))
result={'result':verdict,'reason':reason}
if score is not None: result['score']=score
(out/'result.json').write_text(json.dumps(result,allow_nan=False)); print(json.dumps(result),flush=True)
if len(method.read_bytes())>policy['max_source_bytes']: return finish('refuted','Source exceeds byte limit')
seeds=fam['suite']['seeds']
if len(truth['cases'])!=len(seeds) or truth['version']!=fam['suite']['version']: return finish('inconclusive','Reference suite mismatch')
for seed,case in zip(seeds,truth['cases']):
if case['seed']!=seed or case['instance']!=make_instance(fam,fam['exact']['size'],seed): return finish('inconclusive','Reference instance mismatch')
probe=truth['accuracy_probe']
if probe['instance']!=make_instance(fam,fam['accuracy_probe']['size'],fam['accuracy_probe']['seed']): return finish('inconclusive','Probe mismatch')
scale=make_instance(fam,fam['scaling']['size'],seeds[0]+100000)
groups=[('scaling',[scale],None),('exact_suite',[c['instance'] for c in truth['cases']],[c['trace'] for c in truth['cases']]),('accuracy_probe',[probe['instance']],[probe['trace']])]
with tempfile.TemporaryDirectory(prefix='dynamics-v2-',dir=out) as temp:
scratch=pathlib.Path(temp)
for label,instances,expected in groups:
result=run_batch(method,instances,fam['budget_seconds'][label],policy,scratch,label)
ev[label]={'wall_seconds':result['wall_seconds'],'peak_rss_kib':result.get('peak_rss_kib')}
if not result.get('ok'): return finish('refuted',result.get('error','Invalid method'))
if 'priors' in ev and ev['priors']!=result['priors']: return finish('refuted','PRIORS changed between evaluation batches')
ev['priors']=result['priors']
if len(result['results'])!=len(instances): return finish('refuted','Wrong number of output traces')
for i,(inst,row) in enumerate(zip(instances,result['results'])):
reason=gate(row['trace'],inst,policy['bounds_tolerance'],policy['conservation_tolerance'],label)
if reason: return finish('refuted',reason)
if expected is not None:
err=float(np.max(np.abs(np.array(row['trace'])-np.array(expected[i]))))
if label=='exact_suite': ev['instance_errors'].append(err)
else: ev['accuracy_probe_error']=err
ev['worst_instance_error']=max(ev['instance_errors']); ev['mean_instance_max_abs_error']=float(np.mean(ev['instance_errors']))
finish('verified','Public-suite numerical error measured; larger-size run passed sanity gates. Probe error is reported separately; generalization and source honesty are not certified.',ev['mean_instance_max_abs_error'])
if __name__=='__main__': main()
​