84 lines
4.6 KiB
Python
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()
|