Research source · python

verify_selective_horn.py

site/public/research-artifacts/foundations/verify_selective_horn.py

128 lines. Source is displayed for inspection; it is not executed by this page.

File fingerprint

SHA-256: dcfcb4675c3c3a1277381323ea2d6a149ab5ce93831497f26ed770217d19cbc5

#!/usr/bin/env python3
"""Finite semantics and routing counts. Host sets do not verify pointer costs."""
from dataclasses import dataclass,replace
import random,json
from verify_persistent_horn import Engine,State
from verify_horn_join import Term,reference,leaves
B=frozenset((0,1))
@dataclass(frozen=True)
class Router:
    support:frozenset
    left:object=None
    right:object=None
    engine:object=None
    local:object=None
@dataclass(frozen=True)
class Handle:
    term:object
    router:object
    z:frozenset
    failed:bool=False
@dataclass
class Events:
    V:int=0
    A:int=0
    E:int=0
    deliveries:int=0
    routed:int=0

def prepare(rules):
    e=Engine(3,rules,B);s,d=e.extend(State(),(),True)
    support=frozenset(v for body,h in e.rules for v in body if v in B)
    return Handle(Term('leaf',tuple(rules)),Router(support,engine=e,local=s),frozenset(d),s.conflict)

def route(r,v,ev):
    ev.V+=1
    if v not in r.support:return r,(),False
    if r.engine is not None:
        ev.deliveries+=1
        before=(r.engine.cost.activated,r.engine.cost.occurrences)
        state,delta=r.engine.extend(r.local,(v,))
        ev.A+=r.engine.cost.activated-before[0]
        ev.E+=r.engine.cost.occurrences-before[1]
        return replace(r,local=state),delta,state.conflict
    left,dl,bad=route(r.left,v,ev)
    if bad:return replace(r,left=left),dl,True
    right,dr,bad=route(r.right,v,ev)
    return replace(r,left=left,right=right),dl+dr,bad

def drain(term,r,z,incoming):
    ev=Events();seen=set(z);pending=[]
    def seed(v):
        if v not in seen:seen.add(v);pending.append(v)
    for v in incoming:seed(v)
    while pending:
        v=pending.pop();ev.routed+=1
        r,delta,bad=route(r,v,ev)
        if bad:return Handle(term,r,frozenset(seen),True),ev
        for w in delta:seed(w)
    return Handle(term,r,frozenset(seen)),ev

def join(a,b):
    t=Term('join',None,a.term,b.term)
    r=Router(a.router.support|b.router.support,a.router,b.router)
    if a.failed or b.failed:return Handle(t,r,frozenset(),True),Events()
    # Replay all operand facts, including facts irrelevant to their old routers.
    return drain(t,r,(),tuple(a.z)+tuple(b.z))

def pin(a,vs):
    t=Term('pin',tuple(vs),a.term)
    if a.failed:return Handle(t,a.router,a.z,True),Events()
    return drain(t,a.router,a.z,vs)

def snap(r):
    if r.engine is not None:return (r.support,repr(r.local))
    return (r.support,snap(r.left),snap(r.right))

def check(a):
    want=reference(a.term)
    assert a.failed==(want is None)
    if not a.failed:assert a.z==want,(a,want)

def internal_subscribers(r,v):
    if r.engine is not None:return 0
    return int(v in r.support)+internal_subscribers(r.left,v)+internal_subscribers(r.right,v)

def main():
    rng=random.Random(4201);pool=[]
    for _ in range(25):
        rules=[]
        for j in range(rng.randrange(5)):
            head=rng.choice([None,0,1,2]);vs=[v for v in range(3) if v!=head]
            body=tuple(rng.sample(vs,rng.randrange(min(len(vs),3 if head is None else 2)+1)))
            rules.append((body,head))
        h=prepare(rules);check(h);pool.append(h)
    joins=pins=0
    for _ in range(500):
        a=rng.choice(pool);old=(a.z,snap(a.router))
        if rng.randrange(2):
            b=rng.choice(pool)
            if leaves(a.term)+leaves(b.term)>5:continue
            h,e=join(a,b);joins+=1
        else:
            h,e=pin(a,rng.sample(list(B),rng.randrange(3)));pins+=1
            if not h.failed:
                assert e.V==sum(1+2*internal_subscribers(a.router,v) for v in h.z-a.z)
        check(h);assert (a.z,snap(a.router))==old;pool.append(h)
    empty=prepare([]);h=empty
    for _ in range(63):h,_=join(h,empty)
    h,e=pin(h,(0,));check(h)
    assert (e.V,e.deliveries,e.A,e.E)==(1,0,0,0)
    # Forgotten global facts would fail here.
    g=prepare([((0,),1)]);cross,ce=join(h,g);check(cross)
    assert cross.z==B and ce.deliveries==1
    # Negative-headed bodies must also subscribe.
    bad,be=join(h,prepare([((0,),None)]));check(bad);assert bad.failed
    # A new private fact leads to a globally relevant boundary consequence.
    p=prepare([((0,),2),((2,),1)]);q,qe=join(h,p);check(q);assert q.z==B
    cycle=prepare([((0,),1),((1,),0)]);check(cycle);assert not cycle.z
    dup,de=join(p,p);dup,de=pin(dup,(0,));check(dup)
    assert de.deliveries==2
    # Conditional child states must never replace their original public handles.
    check(p);assert not p.z
    print(json.dumps(dict(random_joins=joins,random_pins=pins,
      empty_64_leaf_pin=vars(e),later_join=vars(ce),negative_body_conflict=True,
      private_chain=True,duplicate_occurrences=True,unseeded_cycle=True,
      successful_pin_routing_identity=True,
      scope='Finite three-variable leaves, two boundary variables, at most five leaves in random oracle checks; 64 empty leaves; no pointer-cost or proof-assistant verification.'),indent=2))
if __name__=='__main__':main()