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