Mercurial > code > home > repos > homeauto
annotate service/mqtt_to_rdf/inference.py @ 1651:20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
A Chunk is a Triple plus any rdf lists.
author | drewp@bigasterisk.com |
---|---|
date | Sat, 18 Sep 2021 23:57:20 -0700 |
parents | 2061df259224 |
children | dddfa09ea0b9 |
rev | line source |
---|---|
1587 | 1 """ |
2 copied from reasoning 2021-08-29. probably same api. should | |
3 be able to lib/ this out | |
4 """ | |
1588
0757fafbfdab
WIP inferencer - partial var and function support
drewp@bigasterisk.com
parents:
1587
diff
changeset
|
5 import itertools |
1587 | 6 import logging |
1601 | 7 import time |
1594 | 8 from collections import defaultdict |
1626 | 9 from dataclasses import dataclass |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
10 from typing import Dict, Iterator, List, Optional, Sequence, Tuple, Union, cast |
1588
0757fafbfdab
WIP inferencer - partial var and function support
drewp@bigasterisk.com
parents:
1587
diff
changeset
|
11 |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
12 from prometheus_client import Histogram, Summary |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
13 from rdflib import RDF, BNode, Graph, Namespace |
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
14 from rdflib.graph import ConjunctiveGraph |
1640 | 15 from rdflib.term import Node, URIRef, Variable |
1587 | 16 |
1638
0ba1625037ae
don't crash, just skip the rule if there's a BindingConflict (no clear test case yet)
drewp@bigasterisk.com
parents:
1637
diff
changeset
|
17 from candidate_binding import BindingConflict, CandidateBinding |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
18 from inference_types import BindingUnknown, Inconsistent, Triple |
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
19 from lhs_evaluation import functionsFor |
1650
2061df259224
move graphDump (on its way out, since reprs are getting better)
drewp@bigasterisk.com
parents:
1649
diff
changeset
|
20 from rdf_debug import graphDump |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
21 from stmt_chunk import Chunk, ChunkedGraph, applyChunky |
1605 | 22 |
1587 | 23 log = logging.getLogger('infer') |
1593
b0df43d5494c
big rewrite- more classes, smaller methods, more typesafe, all current tests passing
drewp@bigasterisk.com
parents:
1592
diff
changeset
|
24 INDENT = ' ' |
1587 | 25 |
1626 | 26 INFER_CALLS = Summary('inference_infer_calls', 'calls') |
27 INFER_GRAPH_SIZE = Histogram('inference_graph_size', 'statements', buckets=[2**x for x in range(2, 20, 2)]) | |
1587 | 28 |
29 ROOM = Namespace("http://projects.bigasterisk.com/room/") | |
30 LOG = Namespace('http://www.w3.org/2000/10/swap/log#') | |
31 MATH = Namespace('http://www.w3.org/2000/10/swap/math#') | |
32 | |
33 | |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
34 class NoOptions(ValueError): |
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
35 """ChunkLooper has no possibilites to add to the binding; the whole rule must therefore not apply""" |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
36 |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
37 |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
38 _chunkLooperShortId = itertools.count() |
1632 | 39 |
40 | |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
41 @dataclass |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
42 class ChunkLooper: |
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
43 """given one LHS Chunk, iterate through the possible matches for it, |
1632 | 44 returning what bindings they would imply. Only distinct bindings are |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
45 returned. The bindings build on any `prev` ChunkLooper's results. |
1632 | 46 |
47 This iterator is restartable.""" | |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
48 lhsChunk: Chunk |
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
49 prev: Optional['ChunkLooper'] |
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
50 workingSet: 'ChunkedGraph' |
1634
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
51 parent: 'Lhs' # just for lhs.graph, really |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
52 |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
53 def __repr__(self): |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
54 return f'{self.__class__.__name__}{self._shortId}{"<pastEnd>" if self.pastEnd() else ""}' |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
55 |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
56 def __post_init__(self): |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
57 self._shortId = next(_chunkLooperShortId) |
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
58 self._myWorkingSetMatches = self.lhsChunk.myMatches(self.workingSet) |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
59 |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
60 self._current = CandidateBinding({}) |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
61 self._pastEnd = False |
1635
22d481f0a924
refactor: use CandidateBinding throughout, not loose dicts
drewp@bigasterisk.com
parents:
1634
diff
changeset
|
62 self._seenBindings: List[CandidateBinding] = [] |
1648 | 63 |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
64 log.debug(f'{INDENT*6} introducing {self!r}({self.lhsChunk}, {self._myWorkingSetMatches=})') |
1648 | 65 |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
66 self.restart() |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
67 |
1635
22d481f0a924
refactor: use CandidateBinding throughout, not loose dicts
drewp@bigasterisk.com
parents:
1634
diff
changeset
|
68 def _prevBindings(self) -> CandidateBinding: |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
69 if not self.prev or self.prev.pastEnd(): |
1635
22d481f0a924
refactor: use CandidateBinding throughout, not loose dicts
drewp@bigasterisk.com
parents:
1634
diff
changeset
|
70 return CandidateBinding({}) |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
71 |
1635
22d481f0a924
refactor: use CandidateBinding throughout, not loose dicts
drewp@bigasterisk.com
parents:
1634
diff
changeset
|
72 return self.prev.currentBinding() |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
73 |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
74 def advance(self): |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
75 """update to a new set of bindings we haven't seen (since last restart), or go into pastEnd mode""" |
1633
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
76 if self._pastEnd: |
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
77 raise NotImplementedError('need restart') |
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
78 log.debug('') |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
79 augmentedWorkingSet: Sequence[Chunk] = [] |
1633
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
80 if self.prev is None: |
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
81 augmentedWorkingSet = self._myWorkingSetMatches |
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
82 else: |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
83 augmentedWorkingSet = list( |
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
84 applyChunky(self.prev.currentBinding(), self._myWorkingSetMatches, returnBoundStatementsOnly=False)) |
1633
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
85 |
1634
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
86 log.debug(f'{INDENT*6} {self}.advance has {augmentedWorkingSet=}') |
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
87 |
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
88 if self._advanceWithPlainMatches(augmentedWorkingSet): |
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
89 return |
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
90 |
1639 | 91 if self._advanceWithFunctions(): |
1634
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
92 return |
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
93 |
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
94 log.debug(f'{INDENT*6} {self} is past end') |
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
95 self._pastEnd = True |
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
96 |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
97 def _advanceWithPlainMatches(self, augmentedWorkingSet: Sequence[Chunk]) -> bool: |
1634
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
98 log.debug(f'{INDENT*7} {self} mines {len(augmentedWorkingSet)} matching augmented statements') |
1633
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
99 for s in augmentedWorkingSet: |
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
100 log.debug(f'{INDENT*7} {s}') |
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
101 |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
102 for chunk in augmentedWorkingSet: |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
103 try: |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
104 outBinding = self.lhsChunk.totalBindingIfThisStmtWereTrue(self._prevBindings(), chunk) |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
105 except Inconsistent: |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
106 log.debug(f'{INDENT*7} ChunkLooper{self._shortId} - {chunk} would be inconsistent with prev bindings') |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
107 continue |
1632 | 108 |
1634
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
109 log.debug(f'{INDENT*7} {outBinding=} {self._seenBindings=}') |
1635
22d481f0a924
refactor: use CandidateBinding throughout, not loose dicts
drewp@bigasterisk.com
parents:
1634
diff
changeset
|
110 if outBinding not in self._seenBindings: |
22d481f0a924
refactor: use CandidateBinding throughout, not loose dicts
drewp@bigasterisk.com
parents:
1634
diff
changeset
|
111 self._seenBindings.append(outBinding.copy()) |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
112 self._current = outBinding |
1632 | 113 log.debug(f'{INDENT*7} new binding from {self} -> {outBinding}') |
1634
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
114 return True |
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
115 return False |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
116 |
1639 | 117 def _advanceWithFunctions(self) -> bool: |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
118 pred: Node = self.lhsChunk.predicate |
1640 | 119 if not isinstance(pred, URIRef): |
120 raise NotImplementedError | |
1632 | 121 |
1637 | 122 for functionType in functionsFor(pred): |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
123 fn = functionType(self.lhsChunk, self.parent.graph) |
1634
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
124 try: |
1637 | 125 out = fn.bind(self._prevBindings()) |
126 except BindingUnknown: | |
1634
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
127 pass |
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
128 else: |
1637 | 129 if out is not None: |
130 binding: CandidateBinding = self._prevBindings().copy() | |
131 binding.addNewBindings(out) | |
132 if binding not in self._seenBindings: | |
133 self._seenBindings.append(binding) | |
134 self._current = binding | |
135 log.debug(f'{INDENT*7} new binding from {self} -> {binding}') | |
136 return True | |
1634
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
137 |
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
138 return False |
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
139 |
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
140 def _boundOperands(self, operands) -> List[Node]: |
1635
22d481f0a924
refactor: use CandidateBinding throughout, not loose dicts
drewp@bigasterisk.com
parents:
1634
diff
changeset
|
141 pb: CandidateBinding = self._prevBindings() |
1634
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
142 |
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
143 boundOperands: List[Node] = [] |
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
144 for op in operands: |
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
145 if isinstance(op, (Variable, BNode)): |
1635
22d481f0a924
refactor: use CandidateBinding throughout, not loose dicts
drewp@bigasterisk.com
parents:
1634
diff
changeset
|
146 boundOperands.append(pb.applyTerm(op)) |
1634
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
147 else: |
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
148 boundOperands.append(op) |
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
149 return boundOperands |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
150 |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
151 def currentBinding(self) -> CandidateBinding: |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
152 if self.pastEnd(): |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
153 raise NotImplementedError() |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
154 return self._current |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
155 |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
156 def pastEnd(self) -> bool: |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
157 return self._pastEnd |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
158 |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
159 def restart(self): |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
160 self._pastEnd = False |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
161 self._seenBindings = [] |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
162 self.advance() |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
163 if self.pastEnd(): |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
164 raise NoOptions() |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
165 |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
166 |
1594 | 167 @dataclass |
1593
b0df43d5494c
big rewrite- more classes, smaller methods, more typesafe, all current tests passing
drewp@bigasterisk.com
parents:
1592
diff
changeset
|
168 class Lhs: |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
169 graph: ChunkedGraph # our full LHS graph, as input. See below for the statements partitioned into groups. |
1594 | 170 |
171 def __post_init__(self): | |
1648 | 172 |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
173 self.myPreds = self.graph.allPredicatesExceptFunctions() |
1602 | 174 |
1609
34f2817320cc
new tests for a smaller part of the inner loop
drewp@bigasterisk.com
parents:
1608
diff
changeset
|
175 def __repr__(self): |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
176 return f"Lhs({self.graph!r})" |
1609
34f2817320cc
new tests for a smaller part of the inner loop
drewp@bigasterisk.com
parents:
1608
diff
changeset
|
177 |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
178 def findCandidateBindings(self, knownTrue: ChunkedGraph, stats, ruleStatementsIterationLimit) -> Iterator['BoundLhs']: |
1593
b0df43d5494c
big rewrite- more classes, smaller methods, more typesafe, all current tests passing
drewp@bigasterisk.com
parents:
1592
diff
changeset
|
179 """bindings that fit the LHS of a rule, using statements from workingSet and functions |
b0df43d5494c
big rewrite- more classes, smaller methods, more typesafe, all current tests passing
drewp@bigasterisk.com
parents:
1592
diff
changeset
|
180 from LHS""" |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
181 if not self.graph: |
1633
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
182 # special case- no LHS! |
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
183 yield BoundLhs(self, CandidateBinding({})) |
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
184 return |
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
185 |
1640 | 186 if self._checkPredicateCounts(knownTrue): |
187 stats['_checkPredicateCountsCulls'] += 1 | |
188 return | |
189 | |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
190 if not all(ch in knownTrue for ch in self.graph.staticChunks): |
1648 | 191 stats['staticStmtCulls'] += 1 |
192 return | |
193 | |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
194 if not self.graph.patternChunks: |
1648 | 195 # static only |
196 yield BoundLhs(self, CandidateBinding({})) | |
197 return | |
198 | |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
199 log.debug(f'{INDENT*4} build new ChunkLooper stack') |
1593
b0df43d5494c
big rewrite- more classes, smaller methods, more typesafe, all current tests passing
drewp@bigasterisk.com
parents:
1592
diff
changeset
|
200 |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
201 try: |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
202 chunkStack = self._assembleRings(knownTrue, stats) |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
203 except NoOptions: |
1632 | 204 log.debug(f'{INDENT*5} start up with no options; 0 bindings') |
1593
b0df43d5494c
big rewrite- more classes, smaller methods, more typesafe, all current tests passing
drewp@bigasterisk.com
parents:
1592
diff
changeset
|
205 return |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
206 self._debugChunkStack('initial odometer', chunkStack) |
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
207 self._assertAllRingsAreValid(chunkStack) |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
208 |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
209 lastRing = chunkStack[-1] |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
210 iterCount = 0 |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
211 while True: |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
212 iterCount += 1 |
1648 | 213 if iterCount > ruleStatementsIterationLimit: |
214 raise ValueError('rule too complex') | |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
215 |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
216 log.debug(f'{INDENT*4} vv findCandBindings iteration {iterCount}') |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
217 |
1633
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
218 yield BoundLhs(self, lastRing.currentBinding()) |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
219 |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
220 self._debugChunkStack('odometer', chunkStack) |
1607
b21885181e35
more modules, types. Maybe less repeated computation on BoundLhs
drewp@bigasterisk.com
parents:
1605
diff
changeset
|
221 |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
222 done = self._advanceAll(chunkStack) |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
223 |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
224 self._debugChunkStack(f'odometer after ({done=})', chunkStack) |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
225 |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
226 log.debug(f'{INDENT*4} ^^ findCandBindings iteration done') |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
227 if done: |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
228 break |
1607
b21885181e35
more modules, types. Maybe less repeated computation on BoundLhs
drewp@bigasterisk.com
parents:
1605
diff
changeset
|
229 |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
230 def _debugChunkStack(self, label: str, chunkStack: List[ChunkLooper]): |
1632 | 231 log.debug(f'{INDENT*5} {label}:') |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
232 for l in chunkStack: |
1632 | 233 log.debug(f'{INDENT*6} {l} curbind={l.currentBinding() if not l.pastEnd() else "<end>"}') |
234 | |
1640 | 235 def _checkPredicateCounts(self, knownTrue): |
236 """raise NoOptions quickly in some cases""" | |
1648 | 237 |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
238 if self.graph.noPredicatesAppear(self.myPreds): |
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
239 log.info(f'{INDENT*2} checkPredicateCounts does cull because not all {self.myPreds=} are in knownTrue') |
1640 | 240 return True |
1648 | 241 log.info(f'{INDENT*2} checkPredicateCounts does not cull because all {self.myPreds=} are in knownTrue') |
1640 | 242 return False |
243 | |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
244 def _assembleRings(self, knownTrue: ChunkedGraph, stats) -> List[ChunkLooper]: |
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
245 """make ChunkLooper for each stmt in our LHS graph, but do it in a way that they all |
1633
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
246 start out valid (or else raise NoOptions)""" |
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
247 |
1648 | 248 log.info(f'{INDENT*2} stats={dict(stats)}') |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
249 log.info(f'{INDENT*2} taking permutations of {len(self.graph.patternChunks)=}') |
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
250 for i, perm in enumerate(itertools.permutations(self.graph.patternChunks)): |
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
251 stmtStack: List[ChunkLooper] = [] |
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
252 prev: Optional[ChunkLooper] = None |
1648 | 253 if log.isEnabledFor(logging.DEBUG): |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
254 log.debug(f'{INDENT*5} [perm {i}] try stmts in this order: {" -> ".join(repr(p) for p in perm)}') |
1633
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
255 |
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
256 for s in perm: |
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
257 try: |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
258 elem = ChunkLooper(s, prev, knownTrue, parent=self) |
1633
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
259 except NoOptions: |
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
260 log.debug(f'{INDENT*6} permutation didnt work, try another') |
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
261 break |
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
262 stmtStack.append(elem) |
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
263 prev = stmtStack[-1] |
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
264 else: |
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
265 return stmtStack |
1648 | 266 if i > 5000: |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
267 raise NotImplementedError(f'trying too many permutations {len(self.graph.patternChunks)=}') |
1648 | 268 |
1633
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
269 log.debug(f'{INDENT*6} no perms worked- rule cannot match anything') |
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
270 raise NoOptions() |
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
271 |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
272 def _advanceAll(self, stmtStack: List[ChunkLooper]) -> bool: |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
273 carry = True # 1st elem always must advance |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
274 for i, ring in enumerate(stmtStack): |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
275 # unlike normal odometer, advancing any earlier ring could invalidate later ones |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
276 if carry: |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
277 log.debug(f'{INDENT*5} advanceAll [{i}] {ring} carry/advance') |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
278 ring.advance() |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
279 carry = False |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
280 if ring.pastEnd(): |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
281 if ring is stmtStack[-1]: |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
282 log.debug(f'{INDENT*5} advanceAll [{i}] {ring} says we done') |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
283 return True |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
284 log.debug(f'{INDENT*5} advanceAll [{i}] {ring} restart') |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
285 ring.restart() |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
286 carry = True |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
287 return False |
1607
b21885181e35
more modules, types. Maybe less repeated computation on BoundLhs
drewp@bigasterisk.com
parents:
1605
diff
changeset
|
288 |
1633
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
289 def _assertAllRingsAreValid(self, stmtStack): |
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
290 if any(ring.pastEnd() for ring in stmtStack): # this is an unexpected debug assertion |
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
291 log.debug(f'{INDENT*5} some rings started at pastEnd {stmtStack}') |
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
292 raise NoOptions() |
6107603ed455
fix farenheit rule case, fix some others that depend on rings order, but this breaks some performance because of itertools.perm
drewp@bigasterisk.com
parents:
1632
diff
changeset
|
293 |
1592
d7b66234064b
pure reordering of funcs to make the next diffs smaller
drewp@bigasterisk.com
parents:
1591
diff
changeset
|
294 |
1622
38bd8ef9ef67
add CandidateTermMatches, unused so far
drewp@bigasterisk.com
parents:
1621
diff
changeset
|
295 @dataclass |
1607
b21885181e35
more modules, types. Maybe less repeated computation on BoundLhs
drewp@bigasterisk.com
parents:
1605
diff
changeset
|
296 class BoundLhs: |
b21885181e35
more modules, types. Maybe less repeated computation on BoundLhs
drewp@bigasterisk.com
parents:
1605
diff
changeset
|
297 lhs: Lhs |
1610 | 298 binding: CandidateBinding |
1607
b21885181e35
more modules, types. Maybe less repeated computation on BoundLhs
drewp@bigasterisk.com
parents:
1605
diff
changeset
|
299 |
b21885181e35
more modules, types. Maybe less repeated computation on BoundLhs
drewp@bigasterisk.com
parents:
1605
diff
changeset
|
300 |
b21885181e35
more modules, types. Maybe less repeated computation on BoundLhs
drewp@bigasterisk.com
parents:
1605
diff
changeset
|
301 @dataclass |
b21885181e35
more modules, types. Maybe less repeated computation on BoundLhs
drewp@bigasterisk.com
parents:
1605
diff
changeset
|
302 class Rule: |
b21885181e35
more modules, types. Maybe less repeated computation on BoundLhs
drewp@bigasterisk.com
parents:
1605
diff
changeset
|
303 lhsGraph: Graph |
b21885181e35
more modules, types. Maybe less repeated computation on BoundLhs
drewp@bigasterisk.com
parents:
1605
diff
changeset
|
304 rhsGraph: Graph |
1632 | 305 |
1607
b21885181e35
more modules, types. Maybe less repeated computation on BoundLhs
drewp@bigasterisk.com
parents:
1605
diff
changeset
|
306 def __post_init__(self): |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
307 self.lhs = Lhs(ChunkedGraph(self.lhsGraph, functionsFor)) |
1632 | 308 # |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
309 self.rhsBnodeMap = {} |
1607
b21885181e35
more modules, types. Maybe less repeated computation on BoundLhs
drewp@bigasterisk.com
parents:
1605
diff
changeset
|
310 |
1648 | 311 def applyRule(self, workingSet: Graph, implied: Graph, stats: Dict, ruleStatementsIterationLimit): |
1651
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
312 # this does not change for the current applyRule call. The rule will be |
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
313 # tried again in an outer loop, in case it can produce more. |
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
314 workingSetChunked = ChunkedGraph(workingSet, functionsFor) |
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
315 |
20474ad4968e
WIP - functions are broken as i move most layers to work in Chunks not Triples
drewp@bigasterisk.com
parents:
1650
diff
changeset
|
316 for bound in self.lhs.findCandidateBindings(workingSetChunked, stats, ruleStatementsIterationLimit): |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
317 log.debug(f'{INDENT*5} +rule has a working binding: {bound}') |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
318 |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
319 # rhs could have more bnodes, and they just need to be distinct per rule-firing that we do |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
320 existingRhsBnodes = set() |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
321 for stmt in self.rhsGraph: |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
322 for t in stmt: |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
323 if isinstance(t, BNode): |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
324 existingRhsBnodes.add(t) |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
325 # if existingRhsBnodes: |
1632 | 326 # log.debug(f'{INDENT*6} mapping rhs bnodes {existingRhsBnodes} to new ones') |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
327 |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
328 for b in existingRhsBnodes: |
1612
272f78d4671a
mark skipped tests. move applyRule into Rule. minor cleanups.
drewp@bigasterisk.com
parents:
1611
diff
changeset
|
329 |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
330 key = tuple(sorted(bound.binding.binding.items())), b |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
331 self.rhsBnodeMap.setdefault(key, BNode()) |
1638
0ba1625037ae
don't crash, just skip the rule if there's a BindingConflict (no clear test case yet)
drewp@bigasterisk.com
parents:
1637
diff
changeset
|
332 try: |
0ba1625037ae
don't crash, just skip the rule if there's a BindingConflict (no clear test case yet)
drewp@bigasterisk.com
parents:
1637
diff
changeset
|
333 bound.binding.addNewBindings(CandidateBinding({b: self.rhsBnodeMap[key]})) |
0ba1625037ae
don't crash, just skip the rule if there's a BindingConflict (no clear test case yet)
drewp@bigasterisk.com
parents:
1637
diff
changeset
|
334 except BindingConflict: |
0ba1625037ae
don't crash, just skip the rule if there's a BindingConflict (no clear test case yet)
drewp@bigasterisk.com
parents:
1637
diff
changeset
|
335 continue |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
336 |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
337 # for lhsBoundStmt in bound.binding.apply(bound.lhsStmtsWithoutEvals()): |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
338 # log.debug(f'{INDENT*6} adding to workingSet {lhsBoundStmt=}') |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
339 # workingSet.add(lhsBoundStmt) |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
340 # log.debug(f'{INDENT*6} rhsGraph is good: {list(self.rhsGraph)}') |
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
341 |
1612
272f78d4671a
mark skipped tests. move applyRule into Rule. minor cleanups.
drewp@bigasterisk.com
parents:
1611
diff
changeset
|
342 for newStmt in bound.binding.apply(self.rhsGraph): |
1631
2c85a4f5dd9c
big rewrite of infer() using statements not variables as the things to iterate over
drewp@bigasterisk.com
parents:
1627
diff
changeset
|
343 # log.debug(f'{INDENT*6} adding {newStmt=}') |
1612
272f78d4671a
mark skipped tests. move applyRule into Rule. minor cleanups.
drewp@bigasterisk.com
parents:
1611
diff
changeset
|
344 workingSet.add(newStmt) |
272f78d4671a
mark skipped tests. move applyRule into Rule. minor cleanups.
drewp@bigasterisk.com
parents:
1611
diff
changeset
|
345 implied.add(newStmt) |
272f78d4671a
mark skipped tests. move applyRule into Rule. minor cleanups.
drewp@bigasterisk.com
parents:
1611
diff
changeset
|
346 |
1607
b21885181e35
more modules, types. Maybe less repeated computation on BoundLhs
drewp@bigasterisk.com
parents:
1605
diff
changeset
|
347 |
1648 | 348 @dataclass |
1587 | 349 class Inference: |
1648 | 350 rulesIterationLimit = 3 |
351 ruleStatementsIterationLimit = 3 | |
1587 | 352 |
353 def __init__(self) -> None: | |
1648 | 354 self.rules: List[Rule] = [] |
355 self._nonRuleStmts: List[Triple] = [] | |
1587 | 356 |
357 def setRules(self, g: ConjunctiveGraph): | |
1648 | 358 self.rules = [] |
359 self._nonRuleStmts = [] | |
1599
abbf0eb0e640
fix a bug with a slightly moer complicated set of rules
drewp@bigasterisk.com
parents:
1598
diff
changeset
|
360 for stmt in g: |
abbf0eb0e640
fix a bug with a slightly moer complicated set of rules
drewp@bigasterisk.com
parents:
1598
diff
changeset
|
361 if stmt[1] == LOG['implies']: |
1607
b21885181e35
more modules, types. Maybe less repeated computation on BoundLhs
drewp@bigasterisk.com
parents:
1605
diff
changeset
|
362 self.rules.append(Rule(stmt[0], stmt[2])) |
1649
bb5d2b5370ac
add nonRuleStatments to Inference api. there's already a test in an eariler commit
drewp@bigasterisk.com
parents:
1648
diff
changeset
|
363 else: |
bb5d2b5370ac
add nonRuleStatments to Inference api. there's already a test in an eariler commit
drewp@bigasterisk.com
parents:
1648
diff
changeset
|
364 self._nonRuleStmts.append(stmt) |
bb5d2b5370ac
add nonRuleStatments to Inference api. there's already a test in an eariler commit
drewp@bigasterisk.com
parents:
1648
diff
changeset
|
365 |
bb5d2b5370ac
add nonRuleStatments to Inference api. there's already a test in an eariler commit
drewp@bigasterisk.com
parents:
1648
diff
changeset
|
366 def nonRuleStatements(self) -> List[Triple]: |
bb5d2b5370ac
add nonRuleStatments to Inference api. there's already a test in an eariler commit
drewp@bigasterisk.com
parents:
1648
diff
changeset
|
367 return self._nonRuleStmts |
1587 | 368 |
1601 | 369 @INFER_CALLS.time() |
1587 | 370 def infer(self, graph: Graph): |
371 """ | |
372 returns new graph of inferred statements. | |
373 """ | |
1626 | 374 n = graph.__len__() |
375 INFER_GRAPH_SIZE.observe(n) | |
376 log.info(f'{INDENT*0} Begin inference of graph len={n} with rules len={len(self.rules)}:') | |
1601 | 377 startTime = time.time() |
1607
b21885181e35
more modules, types. Maybe less repeated computation on BoundLhs
drewp@bigasterisk.com
parents:
1605
diff
changeset
|
378 stats: Dict[str, Union[int, float]] = defaultdict(lambda: 0) |
1649
bb5d2b5370ac
add nonRuleStatments to Inference api. there's already a test in an eariler commit
drewp@bigasterisk.com
parents:
1648
diff
changeset
|
379 |
1589
5c1055be3c36
WIP more debugging, working towards bnode-matching support
drewp@bigasterisk.com
parents:
1588
diff
changeset
|
380 # everything that is true: the input graph, plus every rule conclusion we can make |
1593
b0df43d5494c
big rewrite- more classes, smaller methods, more typesafe, all current tests passing
drewp@bigasterisk.com
parents:
1592
diff
changeset
|
381 workingSet = Graph() |
1649
bb5d2b5370ac
add nonRuleStatments to Inference api. there's already a test in an eariler commit
drewp@bigasterisk.com
parents:
1648
diff
changeset
|
382 workingSet += self._nonRuleStmts |
1593
b0df43d5494c
big rewrite- more classes, smaller methods, more typesafe, all current tests passing
drewp@bigasterisk.com
parents:
1592
diff
changeset
|
383 workingSet += graph |
1587 | 384 |
1594 | 385 # just the statements that came from RHS's of rules that fired. |
1587 | 386 implied = ConjunctiveGraph() |
387 | |
1648 | 388 rulesIterations = 0 |
1587 | 389 delta = 1 |
1607
b21885181e35
more modules, types. Maybe less repeated computation on BoundLhs
drewp@bigasterisk.com
parents:
1605
diff
changeset
|
390 stats['initWorkingSet'] = cast(int, workingSet.__len__()) |
1648 | 391 while delta > 0 and rulesIterations <= self.rulesIterationLimit: |
1620 | 392 log.debug('') |
1648 | 393 log.info(f'{INDENT*1}*iteration {rulesIterations}') |
394 | |
1587 | 395 delta = -len(implied) |
1607
b21885181e35
more modules, types. Maybe less repeated computation on BoundLhs
drewp@bigasterisk.com
parents:
1605
diff
changeset
|
396 self._iterateAllRules(workingSet, implied, stats) |
1587 | 397 delta += len(implied) |
1648 | 398 rulesIterations += 1 |
1597 | 399 log.info(f'{INDENT*2} this inference iteration added {delta} more implied stmts') |
1648 | 400 stats['iterations'] = rulesIterations |
1607
b21885181e35
more modules, types. Maybe less repeated computation on BoundLhs
drewp@bigasterisk.com
parents:
1605
diff
changeset
|
401 stats['timeSpent'] = round(time.time() - startTime, 3) |
b21885181e35
more modules, types. Maybe less repeated computation on BoundLhs
drewp@bigasterisk.com
parents:
1605
diff
changeset
|
402 stats['impliedStmts'] = len(implied) |
1648 | 403 log.info(f'{INDENT*0} Inference done {dict(stats)}.') |
404 log.debug('Implied:') | |
405 log.debug(graphDump(implied)) | |
1587 | 406 return implied |
407 | |
1607
b21885181e35
more modules, types. Maybe less repeated computation on BoundLhs
drewp@bigasterisk.com
parents:
1605
diff
changeset
|
408 def _iterateAllRules(self, workingSet: Graph, implied: Graph, stats): |
1612
272f78d4671a
mark skipped tests. move applyRule into Rule. minor cleanups.
drewp@bigasterisk.com
parents:
1611
diff
changeset
|
409 for i, rule in enumerate(self.rules): |
272f78d4671a
mark skipped tests. move applyRule into Rule. minor cleanups.
drewp@bigasterisk.com
parents:
1611
diff
changeset
|
410 self._logRuleApplicationHeader(workingSet, i, rule) |
1648 | 411 rule.applyRule(workingSet, implied, stats, self.ruleStatementsIterationLimit) |
1587 | 412 |
1607
b21885181e35
more modules, types. Maybe less repeated computation on BoundLhs
drewp@bigasterisk.com
parents:
1605
diff
changeset
|
413 def _logRuleApplicationHeader(self, workingSet, i, r: Rule): |
1594 | 414 if not log.isEnabledFor(logging.DEBUG): |
415 return | |
416 | |
417 log.debug('') | |
418 log.debug(f'{INDENT*2} workingSet:') | |
1648 | 419 # for j, stmt in enumerate(sorted(workingSet)): |
420 # log.debug(f'{INDENT*3} ({j}) {stmt}') | |
421 log.debug(f'{INDENT*3} {graphDump(workingSet, oneLine=False)}') | |
1594 | 422 |
423 log.debug('') | |
424 log.debug(f'{INDENT*2}-applying rule {i}') | |
1632 | 425 log.debug(f'{INDENT*3} rule def lhs:') |
1634
ba59cfc3c747
hack math:sum in there. Test suite is passing except some slow performers
drewp@bigasterisk.com
parents:
1633
diff
changeset
|
426 for stmt in sorted(r.lhsGraph, reverse=True): |
1632 | 427 log.debug(f'{INDENT*4} {stmt}') |
1607
b21885181e35
more modules, types. Maybe less repeated computation on BoundLhs
drewp@bigasterisk.com
parents:
1605
diff
changeset
|
428 log.debug(f'{INDENT*3} rule def rhs: {graphDump(r.rhsGraph)}') |