"""One synchronous, parameter-free message aggregation on an authored graph."""
from fractions import Fraction as F
import json
X={'A':F(1),'B':F(2),'C':F(4),'D':F(8)}
EDGES=[('A','B'),('C','B'),('B','C')]
def update(features,edges):
    incoming={node:[] for node in features}
    for source,target in edges:
        if source not in features or target not in features:raise ValueError('edge endpoint missing')
        incoming[target].append(features[source])
    return {n:features[n]+(sum(v,F(0))/len(v) if v else F(0)) for n,v in incoming.items()}
if __name__=='__main__':
    first=update(X,EDGES);second=update(first,EDGES)
    assert first=={'A':F(1),'B':F(9,2),'C':F(6),'D':F(8)} and second['C']==F(21,2)
    assert update(X,list(reversed(EDGES)))==first
    names={'A':'n3','B':'n1','C':'n4','D':'n2'}
    renamed=update({names[k]:v for k,v in X.items()},[(names[a],names[b]) for a,b in EDGES])
    assert all(renamed[names[k]]==v for k,v in first.items())
    assert update(X,[('B','A'),('C','B'),('B','C')])!=first
    # Deliberately wrong in-place schedule: C reads already-updated B.
    wrong=X.copy();wrong['B']=wrong['B']+(wrong['A']+wrong['C'])/2;wrong['C']=wrong['C']+wrong['B']
    assert wrong['C']==F(17,2) and wrong['C']!=first['C']
    print(json.dumps({'initial':{k:str(v) for k,v in X.items()},'directed_edges':EDGES,'synchronous_step1':{k:str(v) for k,v in first.items()},'synchronous_step2':{k:str(v) for k,v in second.items()},'wrong_inplace_C':str(wrong['C']),'learned_weights':False,'PyG_run':False},indent=2))
