changeset 1592:d7b66234064b

pure reordering of funcs to make the next diffs smaller
author drewp@bigasterisk.com
date Sat, 04 Sep 2021 23:18:44 -0700
parents 668958454ae2
children b0df43d5494c
files service/mqtt_to_rdf/inference.py
diffstat 1 files changed, 208 insertions(+), 208 deletions(-) [+]
line wrap: on
line diff
--- a/service/mqtt_to_rdf/inference.py	Sat Sep 04 15:34:29 2021 -0700
+++ b/service/mqtt_to_rdf/inference.py	Sat Sep 04 23:18:44 2021 -0700
@@ -35,6 +35,176 @@
     vars: Dict[Variable, Node]
 
 
+inferredFuncs = {
+    ROOM['asFarenheit'],
+    MATH['sum'],
+}
+filterFuncs = {
+    MATH['greaterThan'],
+}
+
+
+def withBinding(toBind: Graph, bindings: Dict[BindableTerm, Node], includeStaticStmts=True) -> Iterator[Triple]:
+    for stmt in toBind:
+        stmt = list(stmt)
+        static = True
+        for i, term in enumerate(stmt):
+            if isinstance(term, (Variable, BNode)):
+                stmt[i] = bindings[term]
+                static = False
+        else:
+            if includeStaticStmts or not static:
+                yield cast(Triple, stmt)
+
+
+def verifyBinding(lhs: Graph, binding: Dict[BindableTerm, Node], workingSet: Graph, usedByFuncs: Graph) -> bool:
+    """Can this lhs be true all at once in workingSet? Does it match with these bindings?"""
+    boundLhs = list(withBinding(lhs, binding))
+    boundUsedByFuncs = list(withBinding(usedByFuncs, binding))
+    if log.isEnabledFor(logging.DEBUG):
+        log.debug(f'                verify all bindings against this lhs:')
+        for stmt in boundLhs:
+            log.debug(f'                    {stmt}')
+
+        log.debug(f'                and against this workingSet:')
+        for stmt in workingSet:
+            log.debug(f'                    {stmt}')
+
+        log.debug(f'                ignoring these usedByFuncs:')
+        for stmt in boundUsedByFuncs:
+            log.debug(f'                    {stmt}')
+    # The static stmts in lhs are obviously going
+    # to match- we only need to verify the ones
+    # that needed bindings.
+    for stmt in boundLhs:  #withBinding(lhs, binding, includeStaticStmts=False):
+        log.debug(f'                check for {stmt}')
+
+        if stmt[1] in filterFuncs:
+            if not mathTest(*stmt):
+                log.debug(f'                    binding was invalid because {stmt}) is not true')
+                return False
+        elif stmt in boundUsedByFuncs:
+            pass
+        elif stmt in workingSet:
+            pass
+        else:
+            log.debug(f'                    binding was invalid because {stmt}) cannot be true')
+            return False
+    return True
+
+
+def findCandidateBindings(lhs: Graph, workingSet: Graph) -> Iterator[Dict[BindableTerm, Node]]:
+    """bindings that fit the LHS of a rule, using statements from workingSet and functions
+    from LHS"""
+    varsToBind: Set[BindableTerm] = set()
+    staticRuleStmts = Graph()
+    for ruleStmt in lhs:
+        varsInStmt = [v for v in ruleStmt if isinstance(v, (Variable, BNode))]
+        varsToBind.update(varsInStmt)
+        if (not varsInStmt  # ok
+                #and not any(isinstance(t, BNode) for t in ruleStmt)  # approx
+           ):
+            staticRuleStmts.add(ruleStmt)
+
+    log.debug(f'        varsToBind: {sorted(varsToBind)}')
+
+    if someStaticStmtDoesntMatch(staticRuleStmts, workingSet):
+        log.debug(f'    someStaticStmtDoesntMatch: {graphDump(staticRuleStmts)}')
+        return
+
+    # the total set of terms each variable could possibly match
+    candidateTermMatches: Dict[BindableTerm, Set[Node]] = findCandidateTermMatches(lhs, workingSet)
+
+    orderedVars, orderedValueSets = organize(candidateTermMatches)
+
+    log.debug(f'        candidate terms:')
+    log.debug(f'            {orderedVars=}')
+    log.debug(f'            {orderedValueSets=}')
+
+    for i, perm in enumerate(itertools.product(*orderedValueSets)):
+        binding: Dict[BindableTerm, Node] = dict(zip(orderedVars, perm))
+        log.debug('')
+        log.debug(f'            ** trying {binding=}')
+        usedByFuncs = Graph()
+        for v, val, used in inferredFuncBindings(lhs, binding):  # loop this until it's done
+            log.debug(f'            inferredFuncBindings tells us {v}={val}')
+            binding[v] = val
+            usedByFuncs += used
+        if len(binding) != len(varsToBind):
+            log.debug(f'                binding is incomplete, needs {varsToBind}')
+
+            continue
+        if not verifyBinding(lhs, binding, workingSet, usedByFuncs):  # fix this
+            log.debug(f'            this binding did not verify')
+            continue
+        yield binding
+
+
+def someStaticStmtDoesntMatch(staticRuleStmts, workingSet):
+    for ruleStmt in staticRuleStmts:
+        if ruleStmt not in workingSet:
+            log.debug(f'            {ruleStmt} not in working set- skip rule')
+
+            return True
+    return False
+
+
+def findCandidateTermMatches(lhs: Graph, workingSet: Graph) -> Dict[BindableTerm, Set[Node]]:
+    candidateTermMatches: Dict[BindableTerm, Set[Node]] = defaultdict(set)
+    lhsBnodes: Set[BNode] = set()
+    for lhsStmt in lhs:
+        for trueStmt in workingSet:
+            log.debug(f'            lhsStmt={graphDump([lhsStmt])} trueStmt={graphDump([trueStmt])}')
+            bindingsFromStatement: Dict[Variable, Set[Node]] = {}
+            for lhsTerm, trueTerm in zip(lhsStmt, trueStmt):
+                # log.debug(f' test {lhsTerm=} {trueTerm=}')
+                if isinstance(lhsTerm, BNode):
+                    lhsBnodes.add(lhsTerm)
+                elif isinstance(lhsTerm, Variable):
+                    bindingsFromStatement.setdefault(lhsTerm, set()).add(trueTerm)
+                elif lhsTerm != trueTerm:
+                    break
+            else:
+                for v, vals in bindingsFromStatement.items():
+                    candidateTermMatches[v].update(vals)
+
+    for trueStmt in itertools.chain(workingSet, lhs):
+        for b in lhsBnodes:
+            for t in [trueStmt[0], trueStmt[2]]:
+                if isinstance(t, (URIRef, BNode)):
+                    candidateTermMatches[b].add(t)
+    return candidateTermMatches
+
+
+def inferredFuncObject(subj, pred, graph, bindings) -> Tuple[Literal, Graph]:
+    """return result from like `(1 2) math:sum ?out .` plus a graph of all the
+    statements involved in that function rule (including the bound answer"""
+    used = Graph()
+    if pred == ROOM['asFarenheit']:
+        obj = Literal(Decimal(subj.toPython()) * 9 / 5 + 32)
+    elif pred == MATH['sum']:
+        operands, operandsStmts = parseList(graph, subj)
+        # shouldn't be redoing this here
+        operands = [bindings[o] if isinstance(o, Variable) else o for o in operands]
+        log.debug(f'                sum {[op.toPython() for op in operands]}')
+        used += operandsStmts
+        obj = Literal(sum(op.toPython() for op in operands))
+    else:
+        raise NotImplementedError(pred)
+
+    used.add((subj, pred, obj))
+    return obj, used
+
+
+def mathTest(subj, pred, obj):
+    x = subj.toPython()
+    y = obj.toPython()
+    if pred == MATH['greaterThan']:
+        return x > y
+    else:
+        raise NotImplementedError(pred)
+
+
 class Inference:
 
     def __init__(self) -> None:
@@ -93,6 +263,33 @@
         return out
 
 
+def applyRule(lhs: Graph, rhs: Graph, workingSet: Graph, implied: Graph):
+    for bindings in findCandidateBindings(lhs, workingSet):
+        log.debug(f'        rule gave {bindings=}')
+        for lhsBoundStmt in withBinding(lhs, bindings):
+            workingSet.add(lhsBoundStmt)
+        for newStmt in withBinding(rhs, bindings):
+            workingSet.add(newStmt)
+            implied.add(newStmt)
+
+
+def parseList(graph, subj) -> Tuple[List[Node], Set[Triple]]:
+    out = []
+    used = set()
+    cur = subj
+    while True:
+        # bug: mishandles empty list
+        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
+        if cur == RDF.nil:
+            break
+    return out, used
+
+
 def graphDump(g: Union[Graph, List[Triple]]):
     if not isinstance(g, Graph):
         g2 = Graph()
@@ -106,61 +303,18 @@
     return ' '.join(lines)
 
 
-def applyRule(lhs: Graph, rhs: Graph, workingSet: Graph, implied: Graph):
-    for bindings in findCandidateBindings(lhs, workingSet):
-        log.debug(f'        rule gave {bindings=}')
-        for lhsBoundStmt in withBinding(lhs, bindings):
-            workingSet.add(lhsBoundStmt)
-        for newStmt in withBinding(rhs, bindings):
-            workingSet.add(newStmt)
-            implied.add(newStmt)
-
-
-def findCandidateBindings(lhs: Graph, workingSet: Graph) -> Iterator[Dict[BindableTerm, Node]]:
-    """bindings that fit the LHS of a rule, using statements from workingSet and functions
-    from LHS"""
-    varsToBind: Set[BindableTerm] = set()
-    staticRuleStmts = Graph()
-    for ruleStmt in lhs:
-        varsInStmt = [v for v in ruleStmt if isinstance(v, (Variable, BNode))]
-        varsToBind.update(varsInStmt)
-        if (not varsInStmt  # ok
-                #and not any(isinstance(t, BNode) for t in ruleStmt)  # approx
-           ):
-            staticRuleStmts.add(ruleStmt)
-
-    log.debug(f'        varsToBind: {sorted(varsToBind)}')
+def organize(candidateTermMatches: Dict[BindableTerm, Set[Node]]) -> Tuple[List[BindableTerm], List[List[Node]]]:
+    items = list(candidateTermMatches.items())
+    items.sort()
+    orderedVars: List[BindableTerm] = []
+    orderedValueSets: List[List[Node]] = []
+    for v, vals in items:
+        orderedVars.append(v)
+        orderedValues: List[Node] = list(vals)
+        orderedValues.sort(key=str)
+        orderedValueSets.append(orderedValues)
 
-    if someStaticStmtDoesntMatch(staticRuleStmts, workingSet):
-        log.debug(f'    someStaticStmtDoesntMatch: {graphDump(staticRuleStmts)}')
-        return
-
-    # the total set of terms each variable could possibly match
-    candidateTermMatches: Dict[BindableTerm, Set[Node]] = findCandidateTermMatches(lhs, workingSet)
-
-    orderedVars, orderedValueSets = organize(candidateTermMatches)
-
-    log.debug(f'        candidate terms:')
-    log.debug(f'            {orderedVars=}')
-    log.debug(f'            {orderedValueSets=}')
-
-    for i, perm in enumerate(itertools.product(*orderedValueSets)):
-        binding: Dict[BindableTerm, Node] = dict(zip(orderedVars, perm))
-        log.debug('')
-        log.debug(f'            ** trying {binding=}')
-        usedByFuncs = Graph()
-        for v, val, used in inferredFuncBindings(lhs, binding):  # loop this until it's done
-            log.debug(f'            inferredFuncBindings tells us {v}={val}')
-            binding[v] = val
-            usedByFuncs += used
-        if len(binding) != len(varsToBind):
-            log.debug(f'                binding is incomplete, needs {varsToBind}')
-
-            continue
-        if not verifyBinding(lhs, binding, workingSet, usedByFuncs):  # fix this
-            log.debug(f'            this binding did not verify')
-            continue
-        yield binding
+    return orderedVars, orderedValueSets
 
 
 def inferredFuncBindings(lhs: Graph, bindingsBefore) -> Iterator[Tuple[Variable, Node, Graph]]:
@@ -180,162 +334,8 @@
         yield var, resultObject, usedByFunc
 
 
-def findCandidateTermMatches(lhs: Graph, workingSet: Graph) -> Dict[BindableTerm, Set[Node]]:
-    candidateTermMatches: Dict[BindableTerm, Set[Node]] = defaultdict(set)
-    lhsBnodes: Set[BNode] = set()
-    for lhsStmt in lhs:
-        for trueStmt in workingSet:
-            log.debug(f'            lhsStmt={graphDump([lhsStmt])} trueStmt={graphDump([trueStmt])}')
-            bindingsFromStatement: Dict[Variable, Set[Node]] = {}
-            for lhsTerm, trueTerm in zip(lhsStmt, trueStmt):
-                # log.debug(f' test {lhsTerm=} {trueTerm=}')
-                if isinstance(lhsTerm, BNode):
-                    lhsBnodes.add(lhsTerm)
-                elif isinstance(lhsTerm, Variable):
-                    bindingsFromStatement.setdefault(lhsTerm, set()).add(trueTerm)
-                elif lhsTerm != trueTerm:
-                    break
-            else:
-                for v, vals in bindingsFromStatement.items():
-                    candidateTermMatches[v].update(vals)
-
-    for trueStmt in itertools.chain(workingSet, lhs):
-        for b in lhsBnodes:
-            for t in [trueStmt[0], trueStmt[2]]:
-                if isinstance(t, (URIRef, BNode)):
-                    candidateTermMatches[b].add(t)
-    return candidateTermMatches
-
-
-def withBinding(toBind: Graph, bindings: Dict[BindableTerm, Node], includeStaticStmts=True) -> Iterator[Triple]:
-    for stmt in toBind:
-        stmt = list(stmt)
-        static = True
-        for i, term in enumerate(stmt):
-            if isinstance(term, (Variable, BNode)):
-                stmt[i] = bindings[term]
-                static = False
-        else:
-            if includeStaticStmts or not static:
-                yield cast(Triple, stmt)
-
-
-def verifyBinding(lhs: Graph, binding: Dict[BindableTerm, Node], workingSet: Graph, usedByFuncs: Graph) -> bool:
-    """Can this lhs be true all at once in workingSet? Does it match with these bindings?"""
-    boundLhs = list(withBinding(lhs, binding))
-    boundUsedByFuncs = list(withBinding(usedByFuncs, binding))
-    if log.isEnabledFor(logging.DEBUG):
-        log.debug(f'                verify all bindings against this lhs:')
-        for stmt in boundLhs:
-            log.debug(f'                    {stmt}')
-
-        log.debug(f'                and against this workingSet:')
-        for stmt in workingSet:
-            log.debug(f'                    {stmt}')
-
-        log.debug(f'                ignoring these usedByFuncs:')
-        for stmt in boundUsedByFuncs:
-            log.debug(f'                    {stmt}')
-    # The static stmts in lhs are obviously going
-    # to match- we only need to verify the ones
-    # that needed bindings.
-    for stmt in boundLhs:  #withBinding(lhs, binding, includeStaticStmts=False):
-        log.debug(f'                check for {stmt}')
-
-        if stmt[1] in filterFuncs:
-            if not mathTest(*stmt):
-                log.debug(f'                    binding was invalid because {stmt}) is not true')
-                return False
-        elif stmt in boundUsedByFuncs:
-            pass
-        elif stmt in workingSet:
-            pass
-        else:
-            log.debug(f'                    binding was invalid because {stmt}) cannot be true')
-            return False
-    return True
-
-
-inferredFuncs = {
-    ROOM['asFarenheit'],
-    MATH['sum'],
-}
-filterFuncs = {
-    MATH['greaterThan'],
-}
-
-
 def isStatic(spo: Triple):
     for t in spo:
         if isinstance(t, (Variable, BNode)):
             return False
     return True
-
-
-def inferredFuncObject(subj, pred, graph, bindings) -> Tuple[Literal, Graph]:
-    """return result from like `(1 2) math:sum ?out .` plus a graph of all the
-    statements involved in that function rule (including the bound answer"""
-    used = Graph()
-    if pred == ROOM['asFarenheit']:
-        obj = Literal(Decimal(subj.toPython()) * 9 / 5 + 32)
-    elif pred == MATH['sum']:
-        operands, operandsStmts = parseList(graph, subj)
-        # shouldn't be redoing this here
-        operands = [bindings[o] if isinstance(o, Variable) else o for o in operands]
-        log.debug(f'                sum {[op.toPython() for op in operands]}')
-        used += operandsStmts
-        obj = Literal(sum(op.toPython() for op in operands))
-    else:
-        raise NotImplementedError(pred)
-
-    used.add((subj, pred, obj))
-    return obj, used
-
-
-def parseList(graph, subj) -> Tuple[List[Node], Set[Triple]]:
-    out = []
-    used = set()
-    cur = subj
-    while True:
-        # bug: mishandles empty list
-        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
-        if cur == RDF.nil:
-            break
-    return out, used
-
-
-def mathTest(subj, pred, obj):
-    x = subj.toPython()
-    y = obj.toPython()
-    if pred == MATH['greaterThan']:
-        return x > y
-    else:
-        raise NotImplementedError(pred)
-
-
-def organize(candidateTermMatches: Dict[BindableTerm, Set[Node]]) -> Tuple[List[BindableTerm], List[List[Node]]]:
-    items = list(candidateTermMatches.items())
-    items.sort()
-    orderedVars: List[BindableTerm] = []
-    orderedValueSets: List[List[Node]] = []
-    for v, vals in items:
-        orderedVars.append(v)
-        orderedValues: List[Node] = list(vals)
-        orderedValues.sort(key=str)
-        orderedValueSets.append(orderedValues)
-
-    return orderedVars, orderedValueSets
-
-
-def someStaticStmtDoesntMatch(staticRuleStmts, workingSet):
-    for ruleStmt in staticRuleStmts:
-        if ruleStmt not in workingSet:
-            log.debug(f'            {ruleStmt} not in working set- skip rule')
-
-            return True
-    return False