annotate service/mqtt_to_rdf/lhs_evaluation.py @ 1606:6cf39d43fd40

realign tests, turn off slow ones for now
author drewp@bigasterisk.com
date Mon, 06 Sep 2021 01:15:14 -0700
parents 449746d1598f
children b21885181e35
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1605
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
1 import logging
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
2 from dataclasses import dataclass, field
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
3 from decimal import Decimal
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
4 from typing import Dict, Iterable, Iterator, List, Set, Tuple, Union, cast
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
5
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
6 from prometheus_client import Summary
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
7 from rdflib import RDF, BNode, Graph, Literal, Namespace, URIRef
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
8 from rdflib.graph import ReadOnlyGraphAggregate
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
9 from rdflib.term import Node, Variable
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
10
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
11 log = logging.getLogger('infer')
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
12
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
13 INDENT = ' '
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
14
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
15 Triple = Tuple[Node, Node, Node]
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
16 Rule = Tuple[Graph, Node, Graph]
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
17 BindableTerm = Union[Variable, BNode]
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
18 ReadOnlyWorkingSet = ReadOnlyGraphAggregate
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
19
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
20 ROOM = Namespace("http://projects.bigasterisk.com/room/")
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
21 LOG = Namespace('http://www.w3.org/2000/10/swap/log#')
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
22 MATH = Namespace('http://www.w3.org/2000/10/swap/math#')
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
23
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
24 # Graph() makes a BNode if you don't pass
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
25 # identifier, which can be a bottleneck.
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
26 GRAPH_ID = URIRef('dont/care')
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
27
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
28
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
29 class EvaluationFailed(ValueError):
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
30 """e.g. we were given (5 math:greaterThan 6)"""
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
31
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
32
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
33 class Evaluation:
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
34 """some lhs statements need to be evaluated with a special function
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
35 (e.g. math) and then not considered for the rest of the rule-firing
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
36 process. It's like they already 'matched' something, so they don't need
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
37 to match a statement from the known-true working set.
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
38
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
39 One Evaluation instance is for one function call.
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
40 """
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
41
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
42 @staticmethod
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
43 def findEvals(graph: Graph) -> Iterator['Evaluation']:
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
44 for stmt in graph.triples((None, MATH['sum'], None)):
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
45 operands, operandsStmts = _parseList(graph, stmt[0])
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
46 yield Evaluation(operands, stmt, operandsStmts)
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
47
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
48 for stmt in graph.triples((None, MATH['greaterThan'], None)):
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
49 yield Evaluation([stmt[0], stmt[2]], stmt, [])
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
50
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
51 for stmt in graph.triples((None, ROOM['asFarenheit'], None)):
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
52 yield Evaluation([stmt[0]], stmt, [])
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
53
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
54 # internal, use findEvals
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
55 def __init__(self, operands: List[Node], mainStmt: Triple, otherStmts: Iterable[Triple]) -> None:
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
56 self.operands = operands
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
57 self.operandsStmts = Graph(identifier=GRAPH_ID)
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
58 self.operandsStmts += otherStmts # may grow
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
59 self.operandsStmts.add(mainStmt)
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
60 self.stmt = mainStmt
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
61
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
62 def resultBindings(self, inputBindings) -> Tuple[Dict[BindableTerm, Node], Graph]:
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
63 """under the bindings so far, what would this evaluation tell us, and which stmts would be consumed from doing so?"""
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
64 pred = self.stmt[1]
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
65 objVar: Node = self.stmt[2]
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
66 boundOperands = []
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
67 for op in self.operands:
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
68 if isinstance(op, Variable):
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
69 try:
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
70 op = inputBindings[op]
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
71 except KeyError:
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
72 return {}, self.operandsStmts
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
73
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
74 boundOperands.append(op)
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
75
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
76 if pred == MATH['sum']:
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
77 obj = Literal(sum(map(numericNode, boundOperands)))
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
78 if not isinstance(objVar, Variable):
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
79 raise TypeError(f'expected Variable, got {objVar!r}')
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
80 res: Dict[BindableTerm, Node] = {objVar: obj}
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
81 elif pred == ROOM['asFarenheit']:
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
82 if len(boundOperands) != 1:
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
83 raise ValueError(":asFarenheit takes 1 subject operand")
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
84 f = Literal(Decimal(numericNode(boundOperands[0])) * 9 / 5 + 32)
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
85 if not isinstance(objVar, Variable):
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
86 raise TypeError(f'expected Variable, got {objVar!r}')
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
87 res: Dict[BindableTerm, Node] = {objVar: f}
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
88 elif pred == MATH['greaterThan']:
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
89 if not (numericNode(boundOperands[0]) > numericNode(boundOperands[1])):
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
90 raise EvaluationFailed()
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
91 res: Dict[BindableTerm, Node] = {}
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
92 else:
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
93 raise NotImplementedError(repr(pred))
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
94
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
95 return res, self.operandsStmts
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
96
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
97
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
98 def numericNode(n: Node):
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
99 if not isinstance(n, Literal):
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
100 raise TypeError(f'expected Literal, got {n=}')
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
101 val = n.toPython()
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
102 if not isinstance(val, (int, float, Decimal)):
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
103 raise TypeError(f'expected number, got {val=}')
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
104 return val
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
105
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
106
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
107 def _parseList(graph, subj) -> Tuple[List[Node], Set[Triple]]:
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
108 """"Do like Collection(g, subj) but also return all the
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
109 triples that are involved in the list"""
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
110 out = []
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
111 used = set()
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
112 cur = subj
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
113 while cur != RDF.nil:
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
114 out.append(graph.value(cur, RDF.first))
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
115 used.add((cur, RDF.first, out[-1]))
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
116
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
117 next = graph.value(cur, RDF.rest)
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
118 used.add((cur, RDF.rest, next))
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
119
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
120 cur = next
449746d1598f WIP move evaluation to new file
drewp@bigasterisk.com
parents:
diff changeset
121 return out, used