Add learning phase to shallow (1 level) nested structures.

This commit is contained in:
kenkeiras 2017-05-15 16:51:39 +02:00
parent 099af2a815
commit 5f6b067e17
4 changed files with 111 additions and 27 deletions

View File

@ -22,6 +22,7 @@ class KnowledgeBase(object):
# Parse everything # Parse everything
parsed_examples = [] parsed_examples = []
for example in examples: for example in examples:
print("\x1b[7;32m> {} \x1b[0m".format(example))
tokens, decomposition, inferred_tree = parsing.integrate_language(self, example) tokens, decomposition, inferred_tree = parsing.integrate_language(self, example)
print(tokens) print(tokens)
result = knowledge_evaluation.integrate_information(self.knowledge, { result = knowledge_evaluation.integrate_information(self.knowledge, {
@ -29,7 +30,10 @@ class KnowledgeBase(object):
"decomposition": decomposition, "decomposition": decomposition,
"parsed": inferred_tree, "parsed": inferred_tree,
}) })
print("\x1b[7;33m< {} \x1b[0m".format(self.get_value(result)))
self.act_upon(result) self.act_upon(result)
print("\x1b[7;34m< {} \x1b[0m".format(self.get_value(result)))
self.examples.append((decomposition, inferred_tree)) self.examples.append((decomposition, inferred_tree))
# Reduce values # Reduce values
@ -59,6 +63,12 @@ class KnowledgeBase(object):
return result, inferred_tree, knowledge_diff_getter return result, inferred_tree, knowledge_diff_getter
def get_value(self, result):
if isinstance(result, ModifiableProperty):
return result.getter()
else:
return result
def act_upon(self, result): def act_upon(self, result):
if isinstance(result, ModifiableProperty): if isinstance(result, ModifiableProperty):
result.setter() result.setter()

View File

@ -12,9 +12,33 @@ def resolve(knowledge_base, elements, value):
return value return value
# TODO: improve typing
def infer_type(result):
if isinstance(result, bool):
return "bool"
elif isinstance(result, int):
return "int"
else:
raise Exception("Unknown type for value: {}".format(result))
def get_subquery_type(knowledge_base, atom):
subquery_result = integrate_information(knowledge_base,
{
"parsed": atom,
"elements": [],
})
assert (subquery_result is not None)
result = subquery_result.getter()
result_type = infer_type(result)
return result_type
def property_for_value(knowledge_base, value): def property_for_value(knowledge_base, value):
print(value) # print(value)
print(knowledge_base[value]) # print(knowledge_base[value])
return knowledge_base[value]['as_property'] return knowledge_base[value]['as_property']
@ -27,6 +51,11 @@ def modifiable_property_from_property(prop, path, value):
nonlocal prop, path, value nonlocal prop, path, value
prop[path] = value prop[path] = value
return ModifiableProperty(
getter=getter,
setter=setter,
)
def exists_property_with_value(knowledge_base, elements, subj, value): def exists_property_with_value(knowledge_base, elements, subj, value):
subj = resolve(knowledge_base, elements, subj) subj = resolve(knowledge_base, elements, subj)
@ -50,6 +79,7 @@ def modifiable_element_for_existance_in_set(container, set_name, element):
def setter(): def setter():
nonlocal container, set_name, element nonlocal container, set_name, element
return container[set_name].add(element) return container[set_name].add(element)
return ModifiableProperty( return ModifiableProperty(
getter=getter, getter=getter,
setter=setter, setter=setter,

View File

@ -3,10 +3,16 @@
import knowledge_evaluation import knowledge_evaluation
import re import re
import copy
from functools import reduce from functools import reduce
def make_template(knowledge_base, text, parsed):
tokens = re.findall(r'(\w+|[^\s])', text) # TODO: more flexible tokenization
def to_tokens(text):
return re.findall(r'(\w+|[^\s])', text)
def make_template(knowledge_base, tokens, parsed):
matcher = list(tokens) matcher = list(tokens)
template = list(parsed) template = list(parsed)
for i in range(len(matcher)): for i in range(len(matcher)):
@ -28,50 +34,85 @@ def is_bottom_level(tree):
def get_lower_levels(parsed): def get_lower_levels(parsed):
lower = [] lower = []
def aux(subtree, top_level): def aux(subtree, path):
nonlocal lower nonlocal lower
deeper = top_level deeper = len(path) == 0
for element in subtree: for i, element in enumerate(subtree):
if isinstance(element, list) or isinstance(element, tuple): if isinstance(element, list) or isinstance(element, tuple):
aux(element, top_level=False) aux(element, path + (i,))
deeper = True deeper = True
if not deeper: if not deeper:
lower.append(subtree) lower.append((path, subtree))
aux(parsed, top_level=True) aux(parsed, path=())
return lower return lower
# TODO: probably optimize this, it creates lots of unnecessary tuples
def replace_position(tree, position, new_element):
def aux(current_tree, remaining_route):
if len(remaining_route) == 0:
return new_element
else:
step = remaining_route[0]
return (
tree[:step]
+ (aux(tree[step], remaining_route[1:]),)
+ tree[step + 2:]
)
return aux(tree, position)
def integrate_language(knowledge_base, example): def integrate_language(knowledge_base, example):
text = example["text"].lower() text = example["text"].lower()
parsed = example["parsed"] parsed = example["parsed"]
print("P:", parsed) resolved_parsed = copy.deepcopy(parsed)
tokens = to_tokens(text)
while True: while True:
lower_levels = get_lower_levels(parsed) print("P:", resolved_parsed)
lower_levels = get_lower_levels(resolved_parsed)
print("Lower:", lower_levels) print("Lower:", lower_levels)
if len(lower_levels) == 0: if len(lower_levels) == 0:
break break
for atom in lower_levels: for position, atom in lower_levels:
print("\x1b[1mSelecting\x1b[0m:", atom) print("\x1b[1mSelecting\x1b[0m:", atom)
similar = get_similar_tree(knowledge_base, atom) similar = get_similar_tree(knowledge_base, atom)
print("___>", similar) print("___>", similar)
remix, (start_bounds, end_bounds) = build_remix_matrix(knowledge_base, text, atom, similar) remix, (start_bounds, end_bounds) = build_remix_matrix(knowledge_base, tokens, atom, similar)
tokens, matcher, result = make_template(knowledge_base, text, atom) _, matcher, result = make_template(knowledge_base, tokens, atom)
print("Tx:", tokens) print("Tx:", tokens)
print("Mx:", matcher) print("Mx:", matcher)
print("Rx:", result) print("Rx:", result)
print("Remix:", remix) print("Remix:", remix)
after_remix = apply_remix(tokens[len(start_bounds):-len(end_bounds)], remix) after_remix = apply_remix(tokens[len(start_bounds):-len(end_bounds)], remix)
assert(len(after_remix) + len(start_bounds) + len(end_bounds) == len(tokens)) assert(len(after_remix) + len(start_bounds) + len(end_bounds) == len(tokens))
print(" \\->", after_remix) print( " +->", after_remix)
subquery_type = knowledge_evaluation.get_subquery_type(knowledge_base.knowledge, atom)
print(r" \-> <{}>".format(subquery_type))
# Clean remaining tokens
new_tokens = list(tokens)
offset = len(start_bounds)
for _ in range(len(remix)):
new_tokens.pop(offset)
# TODO: Get a specific types for... types
new_tokens.insert(offset, "<type: {}>".format(subquery_type))
tokens = new_tokens
resolved_parsed = replace_position(resolved_parsed, position, subquery_type)
print("#########") print("#########")
break
tokens, matcher, result = make_template(knowledge_base, text, parsed) tokens, matcher, result = make_template(knowledge_base, tokens, parsed)
print("T:", tokens) print("T:", tokens)
print("M:", matcher) print("M:", matcher)
print("R:", result) print("R:", result)
@ -86,10 +127,11 @@ def apply_remix(tokens, remix):
return rebuilt return rebuilt
def build_remix_matrix(knowledge_base, text, atom, similar): def build_remix_matrix(knowledge_base, tokens, atom, similar):
# print("+" * 20) # print("+" * 20)
tokens, matcher, result = make_template(knowledge_base, text, atom) tokens = list(tokens)
tokens, matcher, result = make_template(knowledge_base, tokens, atom)
similar_matcher, similar_result, similar_result_resolved, _ = similar similar_matcher, similar_result, similar_result_resolved, _ = similar
# print("NEW:") # print("NEW:")

View File

@ -11,10 +11,10 @@ examples = [
"text": "is icecream cold?", "text": "is icecream cold?",
"parsed": ("question", ("exists-property-with-value", 'icecream', 'cold')) "parsed": ("question", ("exists-property-with-value", 'icecream', 'cold'))
}, },
# { {
# "text": "lava is dangerous", "text": "lava is dangerous",
# "parsed": ("exists-property-with-value", 'lava', 'dangerous') "parsed": ("exists-property-with-value", 'lava', 'dangerous')
# }, },
# { # {
# "text": "is lava dangerous?", # "text": "is lava dangerous?",
# "parsed": ("question", ("exists-property-with-value", 'lava', 'dangerous')), # "parsed": ("question", ("exists-property-with-value", 'lava', 'dangerous')),
@ -100,10 +100,12 @@ def main():
) )
differences = knowledge.train(examples) differences = knowledge.train(examples)
# print("----")
# print(differences())
# print("----")
print("----")
print(differences())
print("----")
test_assumption(True, knowledge, {'text': 'is lava dangerous?'})
# for test in [{'text': 'a bus can run'}, {'text': 'io is a moon'}]: # for test in [{'text': 'a bus can run'}, {'text': 'io is a moon'}]:
# row = test['text'] # row = test['text']
# result, inferred_tree, differences = knowledge.process(row) # result, inferred_tree, differences = knowledge.process(row)