Welcome, guest | Sign In | My Account | Store | Cart

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.
Python, 144 lines
  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
Created by Thomas Lehmann on Sun, 4 Dec 2011 (MIT)
Python recipes (4591)
Thomas Lehmann's recipes (18)

Required Modules

  • (none specified)

Other Information and Tasks