Files
digital-drosophila/models/male-cns-lif/runtime-credit-v1/phase4o_atomic.py
T

84 lines
4.6 KiB
Python

#!/usr/bin/env python3
"""Real Phase 4C event/CSR atomic-collision micro-reproduction (read-only inputs)."""
from __future__ import annotations
import hashlib
import json
from pathlib import Path
import numpy as np
import pyarrow.parquet as pq
import torch
import yaml
from phase4o_a import EXP,FROZEN,ROOT,save
def main():
trial='mechanosensory-50hz'
step=6625
delay=18
focus=[3942,3954]
ref=pq.read_table(FROZEN/trial/'spike-events.parquet',columns=['step','neuron_idx']).to_pandas()
src=ref.loc[ref.step==step-delay,'neuron_idx'].to_numpy(np.int32)
graph=ROOT/'datasets/male-cns-v1.0/processed/neuron-only/gpu'
indptr=np.load(graph/'csr-indptr.int64.npy',mmap_mode='r')
indices=np.load(graph/'csr-indices.int32.npy',mmap_mode='r')
raw=np.load(graph/'csr-weights.int64.npy',mmap_mode='r')
cfg=yaml.safe_load((ROOT/'models/male-cns-lif/runtime-v1/phase4c.yaml').read_text())
meta=pq.read_table(ROOT/'datasets/male-cns-v1.0/processed/neuron-only/neuron-index/unified-metadata.parquet',columns=['neurotransmitter']).column('neurotransmitter').to_pylist()
signs=[]
policy=cfg['sign_policy'];mp=policy['neurotransmitter_sign']
for n in src:
val=meta[int(n)]
key='' if val is None else str(val).strip().lower()
signs.append(policy['unknown_sign'] if not key else policy['unclear_sign'] if key=='unclear' else mp[key])
edge_ids=np.concatenate([np.arange(int(indptr[n]),int(indptr[n+1]),dtype=np.int64) for n in src]) if len(src) else np.empty(0,np.int64)
edge_src=np.repeat(src,(indptr[src+1]-indptr[src]).astype(np.int64))
sign_edge=np.repeat(np.asarray(signs,np.int8),(indptr[src+1]-indptr[src]).astype(np.int64))
tgt=np.asarray(indices[edge_ids],np.int32)
w=(np.asarray(raw[edge_ids],np.float32)*sign_edge.astype(np.float32)*np.float32(cfg['model']['w_syn_mv_per_anatomical_synapse'])).astype(np.float32)
counts=np.bincount(tgt,minlength=166700)
# Run the unchanged scatter_add_ ordering against the real active-event edge subset.
target_gpu=torch.as_tensor(tgt,dtype=torch.int64,device='cuda:0')
weight_gpu=torch.as_tensor(w,dtype=torch.float32,device='cuda:0')
samples=[];all_samples=[]
for _ in range(100):
out=torch.zeros(166700,dtype=torch.float32,device='cuda:0')
out.scatter_add_(0,target_gpu,weight_gpu)
all_samples.append(out.cpu().numpy().copy())
samples.append(all_samples[-1][focus].copy())
sampled=np.asarray(samples,np.float32)
full=np.asarray(all_samples,np.float32)
spread=np.ptp(full,axis=0)
variable=np.flatnonzero(spread>0)
detail=[]
for j,n in enumerate(focus):
loc=np.flatnonzero(tgt==n)
contrib=w[loc]
# Deterministic reference keyed by original anatomical edge_id.
order=np.argsort(edge_ids[loc],kind='stable')
acc=np.float32(0)
for value in contrib[order]: acc=np.float32(acc+value)
detail.append({'target_neuron_idx':n,'same_target_writes':len(loc),'incoming_source_neuron_idx':edge_src[loc].tolist(),
'incoming_edge_ids':edge_ids[loc].tolist(),'incoming_effective_weights_mv':contrib.tolist(),
'cpu_edge_order_float32_sum_mv':float(acc),'cpu_float64_sum_mv':float(np.sum(contrib.astype(np.float64))),
'gpu_atomic_min_mv':float(sampled[:,j].min()),'gpu_atomic_max_mv':float(sampled[:,j].max()),
'gpu_atomic_unique_values':np.unique(sampled[:,j]).tolist()})
report={'reference_divergence_event_step':step,'arrival_source_step':step-delay,
'arrival_presynaptic_count':len(src),'fanout_edges':len(edge_ids),
'targets_with_multiple_concurrent_writes':int(np.count_nonzero(counts>1)),
'maximum_same_target_writes':int(counts.max()),
'targets_with_nonidentical_atomic_sum_across_100_repeats':len(variable),
'max_atomic_sum_range_mv':float(spread.max()),
'variable_target_examples':variable[:30].tolist(),
'focus':detail,'gpu_atomic_repetitions':len(samples),
'interpretation':'Collisions and float-order sensitivity are necessary evidence, not by themselves proof of the first state divergence.'}
save(EXP/'atomic/real-edge-subset.json',report)
print(json.dumps({'source_step':step-delay,'fanout_edges':len(edge_ids),'collision_targets':report['targets_with_multiple_concurrent_writes'],
'max_fanin':report['maximum_same_target_writes'],'focus':[{'neuron_idx':x['target_neuron_idx'],
'writes':x['same_target_writes'],'gpu_unique':len(x['gpu_atomic_unique_values'])} for x in detail]}),flush=True)
if __name__=='__main__':main()