from .modifiable_property import ( ModifiableProperty, ModifiablePropertyWithAst, is_modifiable_property, ) def resolve(knowledge_base, elements, value): if isinstance(value, int): return elements[value] elif isinstance(value, tuple) or isinstance(value, list): return integrate_information(knowledge_base, { "elements": elements, "parsed": 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): if value in knowledge_base: # Annotate the property as property groups = knowledge_base[value].get('groups', {'property'}) groups.add('property') knowledge_base[value]['groups'] = groups # And find the property "name" if 'as_property' in knowledge_base[value]: return knowledge_base[value]['as_property'] return knowledge_base[value].get('groups', {'property'}) else: # Consider that any property is... a property knowledge_base[value] = {'groups': {'property'}} return {'property'} def modifiable_property_from_property(prop, path, value): def getter(): nonlocal prop, path, value if isinstance(path, set): # If the property is from a set, it's true if any possible # path has a element as true return any(map(lambda possible_path: ((possible_path in prop) and (prop[possible_path] == value)), path)) else: return (path in prop) and prop[path] == value def setter(): nonlocal prop, path, value if isinstance(path, set): for possible_path in path: prop[possible_path] = value else: prop[path] = value return ModifiableProperty( getter=getter, setter=setter, ) def exists_property_with_value(knowledge_base, elements, subj, value): subj = resolve(knowledge_base, elements, subj) value = resolve(knowledge_base, elements, value) if subj not in knowledge_base: knowledge_base[subj] = {} return modifiable_property_from_property( prop=knowledge_base[subj], path=property_for_value(knowledge_base, value), value=value ) def modifiable_element_for_existance_in_set(container, set_name, element): def getter(): nonlocal container, set_name, element return (set_name in container) and (element in container[set_name]) def setter(): nonlocal container, set_name, element return container[set_name].add(element) return ModifiableProperty( getter=getter, setter=setter, ) def modifiable_element_for_existance_in_group(container, element, backlink, set_name='groups'): def getter(): nonlocal container, element, backlink, set_name return (set_name in container) and (element in container[set_name]) def setter(): nonlocal container, set_name, element backlink['groups'].add(set_name) return container[set_name].add(element) return ModifiableProperty( getter=getter, setter=setter, ) def pertenence_to_group(knowledge_base, elements, subj, group): subj = resolve(knowledge_base, elements, subj) group = resolve(knowledge_base, elements, group) if subj not in knowledge_base: knowledge_base[subj] = {'groups': set()} if "groups" not in knowledge_base[subj]: knowledge_base[subj]["groups"] = set() if group not in knowledge_base: knowledge_base[group] = {'groups': set()} if "groups" not in knowledge_base[group]: knowledge_base[group]["groups"] = set() return modifiable_element_for_existance_in_group( container=knowledge_base[subj], element=group, backlink=knowledge_base[group], ) def has_capacity(knowledge_base, elements, subj, capacity): subj = resolve(knowledge_base, elements, subj) capacity = resolve(knowledge_base, elements, capacity) if subj not in knowledge_base: knowledge_base[subj] = {} if "capacities" not in knowledge_base[subj]: knowledge_base[subj]["capacities"] = set() return modifiable_element_for_existance_in_set( container=knowledge_base[subj], set_name="capacities", element=capacity ) def question(knowledge_base, elements, subj): subj = resolve(knowledge_base, elements, subj) if is_modifiable_property(subj): return subj.getter() return subj def implies(knowledge_base, elements, precedent, consequent): precedent = resolve(knowledge_base, elements, precedent) consequent = resolve(knowledge_base, elements, consequent) if precedent not in knowledge_base: knowledge_base[precedent] = {'groups': set()} if "implications" not in knowledge_base[precedent]: knowledge_base[precedent]["implications"] = set() return modifiable_element_for_existance_in_set( container=knowledge_base[precedent], set_name="implications", element=consequent ) def property_has_value(knowledge_base, elements, subj, prop, value): subj = resolve(knowledge_base, elements, subj) prop = resolve(knowledge_base, elements, prop) value = resolve(knowledge_base, elements, value) if subj not in knowledge_base: knowledge_base[subj] = {'groups': set()} if prop not in knowledge_base[subj]: knowledge_base[subj][prop] = set() return modifiable_element_for_existance_in_set( container=knowledge_base[subj], set_name=prop, element=value ) knowledge_ingestion = { "exists-property-with-value": exists_property_with_value, "pertenence-to-group": pertenence_to_group, "has-capacity": has_capacity, "question": question, "implies": implies, "property-has-value": property_has_value, } def tagged_with_ast(ast, elements, modifiable_property): if not isinstance(modifiable_property, ModifiableProperty): return modifiable_property return ModifiablePropertyWithAst(modifiable_property.getter, modifiable_property.setter, ast, elements) def integrate_information(knowledge_base, example): ast = example['parsed'] method = ast[0] args = ast[1:] elements = example.get('elements', None) return tagged_with_ast( ast, elements, knowledge_ingestion[method](knowledge_base, elements, *args))