aft-may25-2023/aft.py

100 lines
2.6 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Implements code for stable revision.
When run, will compute the least stable fixedpoint of a knowledge base
usage: python aft.py knowledge_bases/simple.hmknf
OR
usage: python aft.py < knowledge_bases/simple.hmknf
"""
from sys import stdin, flags, argv
from AST import KB, Set, atom, loadProgram
from hmknf import objective_knowledge
from util import printp
Kinterp = tuple[Set[atom], Set[atom]]
def add_immediate_XY(kb: KB, X: Set[atom], Y: Set[atom]) -> Set[atom]:
"""
When X is T and Y is P, will compute the atoms that must be true as a consequence of the rules and the ontology
When they are flipped, i.e. X = P, and Y = T, then it computes what is "possibly true"
This function is monotone w.r.t. the precision ordering
"""
_, X, _ = objective_knowledge(kb, X, Set())
for rule in kb.rules:
if not X.issuperset(rule.pbody):
continue
if Y.intersection(rule.nbody):
continue
X = X.union({rule.head[0]})
return X
def extract_OBT_entails_false(kb: KB, T: Set[atom]):
"""
Returns the set of atoms that are objectively false w.r.t. T
Function is antitone w.r.t. subset relation
"""
_, _, F = objective_knowledge(kb, T, Set())
return F
def approximator(kb: KB, T: Set[atom], P: Set[atom]) -> Kinterp:
return (
add_immediate_XY(kb, T, P),
add_immediate_XY(kb, P, T) - extract_OBT_entails_false(kb, T),
)
def fixpoint(op, initial):
"""
Iteratively apply a function beginning with the value initial until a fixpoint is reached
E.g.
op(op(op(initation)))
"""
prev = initial
while (current := op(prev)) != prev:
prev = current
return prev
def stable_revision(kb: KB, T: Set[atom], P: Set[atom]):
def left(T):
return add_immediate_XY(kb, T, P)
def right(P):
return add_immediate_XY(kb, P, T) - extract_OBT_entails_false(kb, T)
return (
fixpoint(left, Set()),
fixpoint(right, Set()),
)
def stable_revision_extend(kb: KB, initialT: Set[atom], initialP: Set[atom]):
def stable_revision_tuple(TP: Kinterp) -> Kinterp:
T, P = TP
return stable_revision(kb, T, P)
return fixpoint(stable_revision_tuple, (initialT, initialP))
def least_stable_fixedpoint(kb: KB):
return stable_revision_extend(kb, Set(), kb.katoms)
def main():
""""""
if len(argv) > 1:
in_file = open(argv[1], "rt", encoding="utf8")
else:
in_file = stdin
kb = loadProgram(in_file.read())
T, P = least_stable_fixedpoint(kb)
printp(T, P)
if __name__ == "__main__" and not flags.interactive:
main()