Add learning phase to shallow (1 level) nested structures.
This commit is contained in:
parent
099af2a815
commit
5f6b067e17
@ -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()
|
||||||
|
@ -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,
|
||||||
|
@ -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:")
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user