Mercurial > code > home > repos > homeauto
diff service/mqtt_to_rdf/inference.py @ 1605:449746d1598f
WIP move evaluation to new file
author | drewp@bigasterisk.com |
---|---|
date | Mon, 06 Sep 2021 01:13:55 -0700 |
parents | 7f8bf68534ed |
children | b21885181e35 |
line wrap: on
line diff
--- a/service/mqtt_to_rdf/inference.py Mon Sep 06 00:57:28 2021 -0700 +++ b/service/mqtt_to_rdf/inference.py Mon Sep 06 01:13:55 2021 -0700 @@ -15,6 +15,8 @@ from rdflib.graph import ConjunctiveGraph, ReadOnlyGraphAggregate from rdflib.term import Node, Variable +from lhs_evaluation import EvaluationFailed, Evaluation + log = logging.getLogger('infer') INDENT = ' ' @@ -33,9 +35,6 @@ # identifier, which can be a bottleneck. GRAPH_ID = URIRef('dont/care') -class EvaluationFailed(ValueError): - """e.g. we were given (5 math:greaterThan 6)""" - class BindingUnknown(ValueError): """e.g. we were asked to make the bound version @@ -156,7 +155,6 @@ self.evaluations = list(Evaluation.findEvals(self.graph)) - def findCandidateBindings(self, workingSet: ReadOnlyWorkingSet) -> Iterator[CandidateBinding]: """bindings that fit the LHS of a rule, using statements from workingSet and functions from LHS""" @@ -175,7 +173,6 @@ log.debug(f'{INDENT*3} trying all permutations:') - for perm in itertools.product(*orderedValueSets): binding = CandidateBinding(dict(zip(orderedVars, perm))) log.debug('') @@ -258,80 +255,6 @@ log.debug(f'{INDENT*5}{val!r}') -class Evaluation: - """some lhs statements need to be evaluated with a special function - (e.g. math) and then not considered for the rest of the rule-firing - process. It's like they already 'matched' something, so they don't need - to match a statement from the known-true working set. - - One Evaluation instance is for one function call. - """ - - @staticmethod - def findEvals(graph: Graph) -> Iterator['Evaluation']: - for stmt in graph.triples((None, MATH['sum'], None)): - operands, operandsStmts = _parseList(graph, stmt[0]) - yield Evaluation(operands, stmt, operandsStmts) - - for stmt in graph.triples((None, MATH['greaterThan'], None)): - yield Evaluation([stmt[0], stmt[2]], stmt, []) - - for stmt in graph.triples((None, ROOM['asFarenheit'], None)): - yield Evaluation([stmt[0]], stmt, []) - - # internal, use findEvals - def __init__(self, operands: List[Node], mainStmt: Triple, otherStmts: Iterable[Triple]) -> None: - self.operands = operands - self.operandsStmts = Graph(identifier=GRAPH_ID) - self.operandsStmts += otherStmts # may grow - self.operandsStmts.add(mainStmt) - self.stmt = mainStmt - - def resultBindings(self, inputBindings) -> Tuple[Dict[BindableTerm, Node], Graph]: - """under the bindings so far, what would this evaluation tell us, and which stmts would be consumed from doing so?""" - pred = self.stmt[1] - objVar: Node = self.stmt[2] - boundOperands = [] - for op in self.operands: - if isinstance(op, Variable): - try: - op = inputBindings[op] - except KeyError: - return {}, self.operandsStmts - - boundOperands.append(op) - - if pred == MATH['sum']: - obj = Literal(sum(map(numericNode, boundOperands))) - if not isinstance(objVar, Variable): - raise TypeError(f'expected Variable, got {objVar!r}') - res: Dict[BindableTerm, Node] = {objVar: obj} - elif pred == ROOM['asFarenheit']: - if len(boundOperands) != 1: - raise ValueError(":asFarenheit takes 1 subject operand") - f = Literal(Decimal(numericNode(boundOperands[0])) * 9 / 5 + 32) - if not isinstance(objVar, Variable): - raise TypeError(f'expected Variable, got {objVar!r}') - res: Dict[BindableTerm, Node] = {objVar: f} - elif pred == MATH['greaterThan']: - if not (numericNode(boundOperands[0]) > numericNode(boundOperands[1])): - raise EvaluationFailed() - res: Dict[BindableTerm, Node] = {} - else: - raise NotImplementedError(repr(pred)) - - return res, self.operandsStmts - - -def numericNode(n: Node): - if not isinstance(n, Literal): - raise TypeError(f'expected Literal, got {n=}') - val = n.toPython() - if not isinstance(val, (int, float, Decimal)): - raise TypeError(f'expected number, got {val=}') - return val - - class Inference: def __init__(self) -> None: @@ -351,7 +274,7 @@ """ log.info(f'{INDENT*0} Begin inference of graph len={graph.__len__()} with rules len={len(self.rules)}:') startTime = time.time() - self.stats: Dict[str, Union[int,float]] = defaultdict(lambda: 0) + self.stats: Dict[str, Union[int, float]] = defaultdict(lambda: 0) # everything that is true: the input graph, plus every rule conclusion we can make workingSet = Graph() workingSet += graph @@ -410,23 +333,6 @@ implied.add(newStmt) -def _parseList(graph, subj) -> Tuple[List[Node], Set[Triple]]: - """"Do like Collection(g, subj) but also return all the - triples that are involved in the list""" - out = [] - used = set() - cur = subj - while cur != RDF.nil: - out.append(graph.value(cur, RDF.first)) - used.add((cur, RDF.first, out[-1])) - - next = graph.value(cur, RDF.rest) - used.add((cur, RDF.rest, next)) - - cur = next - return out, used - - def graphDump(g: Union[Graph, List[Triple]]): if not isinstance(g, Graph): g2 = Graph()