Eureka / src /eureka /math_agent /tools /incremental_engine.py
manxis-contact's picture
Add files using upload-large-folder tool
a30d31a verified
Raw
History Blame Contribute Delete
2.83 kB
from __future__ import annotations
import hashlib,json
from .affordance_engine import mine_rules,RULE_META,GENERIC_TYPES
from .claim_ir import claim_key,summary
def _hash(x):return hashlib.sha256(json.dumps(x,sort_keys=True,ensure_ascii=False,separators=(',',':')).encode()).hexdigest()
class IncrementalMiner:
"""Type-indexed agenda: only rules touched by changed interfaces are recomputed; downstream claim rules propagate once."""
def __init__(self):
self.type_sig={};self.claim_hash={};self.claims={};self.rule_claims={k:[] for k in RULE_META};self.recompute_count=0;self.rule_evaluations=0
def _type_sigs(self,facts):
grouped={}
for t in GENERIC_TYPES:
rows=[{k:f.get(k) for k in ('id','type','payload','assumptions','domain','provenance')} for f in facts if f.get('type')==t]
if rows:grouped[t]=_hash(sorted(rows,key=lambda x:str(x.get('id'))))
return grouped
def update(self,facts:list[dict])->dict:
sig=self._type_sigs(facts);changed={t for t in set(sig)|set(self.type_sig) if sig.get(t)!=self.type_sig.get(t)}
if not changed:return {'changed':False,'delta':[],'recompute_count':self.recompute_count,'rule_evaluations':self.rule_evaluations}
self.type_sig=sig;self.recompute_count+=1
active={name for name,(ft,_) in RULE_META.items() if ft & changed}
# claim-dependent rules are activated when their upstream producer is active.
produced_kinds=set()
for name in list(active):
if name=='relation_extent':produced_kinds.add('relation_extent')
active|={name for name,(_,ck) in RULE_META.items() if ck & produced_kinds}
prior=[c for rows in self.rule_claims.values() for c in rows]
out=mine_rules(facts,prior,active);self.rule_evaluations+=len(active)
for name in active:self.rule_claims[name]=out.get(name,[])
# Re-run downstream inverse-map once with refreshed extents if needed.
if 'relation_extent' in active and 'inverse_map' in active:
prior=[c for rows in self.rule_claims.values() for c in rows]
self.rule_claims['inverse_map']=mine_rules(facts,prior,{'inverse_map'}).get('inverse_map',[]);self.rule_evaluations+=1
claims=[c for rows in self.rule_claims.values() for c in rows]
current={};delta=[]
for c in claims:
key=claim_key(c);h=_hash(c);current[key]=c
if self.claim_hash.get(key)!=h:delta.append({'key':key,'claim':c,'ir':summary(c)})
self.claim_hash={k:_hash(v) for k,v in current.items()};self.claims=current
return {'changed':True,'delta':delta,'recompute_count':self.recompute_count,'rule_evaluations':self.rule_evaluations}
def full_results(self):return list(self.claims.values())