100 lines
2.6 KiB
Python
Executable File
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()
|