What's the idea?
- The idea is to be able to ask more successful questions than data provided.
- To have a kind of simple database
How is this done?
- A releationship is always though as a from of older/younger or bigger/smaller. You have to define those opposite meanings by calling 'defineAntagonism'
- After this you can define a relationship by calling 'defineRelationship' using one of the opposite meanings and two ... I say names (can be persons or objects)
- When you define that somebody/someting is bigger than somebody/something else then you implicitly provide two information (bigger <-> smaller)
- Also when defining - more commonly explained - that A > B and B > C then also A > C and C < A.
- That's the main logic implemented by this python code.
Special notes
- We have to avoid inconsistent data; when it is defined that A > B then you are not allowed to say that B > A.
- We have to sort relations because they build up - I name it like this - a dependency chain. When a query checks for A > C but A > B and B > C is defined only we need an order for searching.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | """
Result of this application:
Is Barney older than Lieschen? -> True!
Is Thomas older than Lieschen? -> True!
Is Thomas older than Barney? -> True!
Is Iris older than Lieschen? -> True!
Is Iris older than Barney? -> True!
Is Thomas older than Iris? -> Not enough information!
Is Iris older than Thomas? -> Not enough information!
Is Lieschen younger than Barney? -> True!
Is Lieschen younger than Iris? -> True!
Is Lieschen younger than Thomas? -> True!
Is Barney younger than Iris? -> True!
Is Barney younger than Thomas? -> True!
Is Thomas younger than Iris? -> Not enough information!
Is Iris younger than Thomas? -> Not enough information!"""
class KnowledgeBase:
def __init__(self):
self.antagonism = {}
self.relationship = {}
def specialCriteria(self, relationA, relationB):
""" enuring order of dependency chain: A > B, B > C, ... """
if relationA[1] == relationB[0]:
return -1
if relationA[0] < relationB[0]:
return -1
if relationA[0] == relationB[0]:
if relationA[1] < relationB[1]:
return -1
elif relationA[1] > relationB[1]:
return 1
return 0
def defineAntagonism(self, meaning, oppositeMeaning):
if meaning in self.antagonism or \
oppositeMeaning in self.antagonism:
return False
self.antagonism[meaning] = oppositeMeaning
return True
def defineRelationship(self, meaning, nameA, nameB):
# a register pair meaning/opposite meaning is mandatory
if not meaning in self.antagonism and \
not meaning in self.antagonism.values():
return False
if not meaning in self.relationship:
self.relationship[meaning] = [(nameA, nameB)]
else:
# is information still available?
if (nameA, nameB) in self.relationship[meaning]:
return False
# you cannot define both: A > B and B > A
if (nameB, nameA) in self.relationship[meaning]:
return False
self.relationship[meaning].append((nameA, nameB))
# ensure correct order for later search in dependency chain
self.relationship[meaning].sort(cmp=self.specialCriteria)
return True
def indirectQuery(self, nameA, nameB, meaningBase):
search = nameA
for key , value in meaningBase:
if key == search:
search = value
if search == nameB:
break
return search == nameB
def query(self, meaning, nameA, nameB):
# straight forwared query...
if meaning in self.relationship:
meaningBase = self.relationship[meaning]
# is the information directly stored?
if (nameA, nameB) in meaningBase:
return True
else:
if self.indirectQuery(nameA, nameB, meaningBase):
return True
# inverse query...
elif meaning in self.antagonism.values():
for key, value in self.antagonism.items():
if value == meaning:
meaningBase = self.relationship[key]
# is the information directly stored?
if (nameB, nameA) in meaningBase:
return True
else:
if self.indirectQuery(nameB, nameA, meaningBase):
return True
break
return False
if __name__ == "__main__":
base = KnowledgeBase()
assert base.defineAntagonism("older", "younger")
# trying to store existing information again
assert not base.defineAntagonism("older", "younger")
# trying to store existing information again
assert not base.defineAntagonism("younger", "older")
assert base.defineRelationship("older", "Iris", "Barney")
assert base.defineRelationship("older", "Barney", "Lieschen")
assert base.defineRelationship("older", "Thomas", "Barney")
# trying to store existing information again
assert not base.defineRelationship("older", "Iris" , "Barney")
# trying to generate inconsistent data. Iris cannot be older and
# younger than Barney and Barney cannot be older and younger than Iris
assert not base.defineRelationship("older", "Barney", "Iris")
testData = \
[("older", "Barney", "Lieschen"), # directly stored \
("older", "Thomas", "Lieschen"), # directly stored (indirect query) \
("older", "Thomas", "Barney"), # directly stored \
("older", "Iris", "Lieschen"), # directly stored (indirect query) \
("older", "Iris", "Barney"), # directly stored \
("older", "Thomas", "Iris"), # not defined \
("older", "Iris", "Thomas"), # not defined \
("younger", "Lieschen", "Barney"), # directly stored (inverse search) \
("younger", "Lieschen", "Iris"), # directly stored (inverser, indirect search) \
("younger", "Lieschen", "Thomas"), # directly stored (inverser, indirect search) \
("younger", "Barney", "Iris"), # directly stored (inverse search) \
("younger", "Barney", "Thomas"), # directly stored (inverse search) \
("younger", "Thomas", "Iris"), # not defined \
("younger", "Iris", "Thomas")] # not defined
for meaning, nameA, nameB in testData:
result = base.query(meaning, nameA, nameB)
if result:
print("Is %s %s than %s? -> True!" % (nameA, meaning, nameB))
else:
print("Is %s %s than %s? -> Not enough information!" % (nameA, meaning, nameB))
|
Future extensions:
- I would like to know the oldest/youngest.
- I would like to know all relationships which are not directly defined.
- The query does say "Yes" or "I don't know". Sometimes it should be able to say "No".
- "is" and "is not" looks very for using "defineAntagonism" but it's wrong. Barney is a cat and Thomas (me) is not a cat but that's about states not relations. We don't build up this logical dependency chain (A > B, B > C, then A > C)
- Provide that the logic is independent from letter case ("Barney", "barney", "BarNey", ...)
- "indirectQuery" and "query" can be one method
- Unittest class
- new method "defineAttribute" to say defineAttribute("barney", "age", 6) and a query for attributes.
- allow: query("older, "barney", 6) -> False, query("older, "barney", 5) -> True