def test_inject_context_IR(self): a = Alist( **{ tt.ID: '1', tt.SUBJECT: 'Ghana', tt.PROPERTY: 'P1082', tt.OBJECT: '', tt.OPVAR: '?x', tt.COST: 1 }) ctx1 = [{ ctx.nationality: 'United Kingdom' }, { ctx.place: 'England', ctx.device: 'phone', ctx.datetime: '2020-04-30 12:00:00' }, { 's': { 'wikidata': 'url://wikidata', 'worldbank': 'wbankID' }, 't': '2020' }] a.set(tt.CONTEXT, ctx1) alist = frank.context.inject_retrieval_context(a, 'worldbank') self.assertEqual(alist.get(tt.TIME), '2020')
def reduce(alist: Alist, children: List[Alist], G: InferenceGraph): y_predict = None X = [] y = [] data_pts = [] for c in children: opVarValue = c.instantiation_value(c.get(tt.OPVAR)) if utils.is_numeric(opVarValue) and utils.is_numeric(c.get(tt.TIME)): x_val = utils.get_number(c.get(tt.TIME), None) y_val = utils.get_number(opVarValue, None) X.append([x_val]) y.append(y_val) data_pts.append([x_val, y_val]) X = np.array(X) y = np.array(y) reg = LinearRegression().fit(X, y) x_predict = utils.get_number(alist.get(tt.TIME), None) y_predict = reg.predict(np.array([[x_predict]]))[0] prediction = [x_predict, y_predict] coeffs = [v for v in reg.coef_] coeffs.insert(0, reg.intercept_) fnStr = 'LIN;' + ';'.join([str(v) for v in reg.coef_]) fnAndData = \ """{{"function":{coeffs}, "data":{data_pts}, "prediction":{prediction}}}""".format( coeffs=coeffs, data_pts=data_pts, prediction=prediction) alist.instantiate_variable(alist.get(tt.OPVAR), y_predict) alist.set(tt.FNPLOT, fnAndData) alist.instantiate_variable( tt.COV, estimate_uncertainty(children, len(data_pts) == len(children), alist.get(tt.OP), len(children))) return alist
def test_context_composition(self): G = InferenceGraph() a = Alist( **{ tt.ID: '1', tt.SUBJECT: 'Ghana', tt.PROPERTY: 'P1082', tt.TIME: '2023', tt.OBJECT: '', tt.OPVAR: '?x', tt.COST: 1 }) ctx1 = [{ ctx.nationality: 'United Kingdom' }, { ctx.place: 'United Kingdom', ctx.device: 'computer', ctx.datetime: '2010-07-27 11:00:00' }, {}] a.set(tt.CONTEXT, ctx1) G.add_alist(a) query_ctx = frank.context.inject_query_context # query context should infer the ctx.accuracy from ctx.device op_alist = Temporal().decompose(query_ctx(a), G) self.assertEqual( (op_alist.get(tt.OP), len(G.child_alists(op_alist.id))), ('gpregress', 19))
def _search_cache(tx, alist_to_instantiate: Alist, attribute_to_instantiate, search_attributes) -> (bool, list): alists = [] conditions = "" resultStatus = False if not attribute_to_instantiate: return (resultStatus, [alist_to_instantiate]) conditions = " AND ".join([ f"n.{x}='{alist_to_instantiate.instantiation_value(x)}'" for x in search_attributes ]) results = tx.run("MATCH (n:Alist)" f"WHERE {conditions}" "RETURN n") for node in results: if node[0]: try: alist = Alist(**node[0]._properties) if alist.is_instantiated(attribute_to_instantiate): alist.set( attribute_to_instantiate, alist.instantiation_value(attribute_to_instantiate)) alist.attributes.pop('sessionId', None) alist.attributes.pop('parentId', None) alist.attributes.pop('src', None) alists.append(alist) resultStatus = True except: print("Error during alist creation from search result") return (resultStatus, alists)
def test_inject_context_inference(self): G = InferenceGraph() a = Alist( **{ tt.ID: '1', tt.SUBJECT: 'Ghana', tt.PROPERTY: 'P1082', tt.TIME: '2023', tt.OBJECT: '', tt.OPVAR: '?x', tt.COST: 1 }) ctx1 = [{ ctx.nationality: 'United Kingdom', ctx.accuracy: 'low', ctx.speed: 'low' }, { ctx.place: 'United Kingdom', ctx.device: 'phone', ctx.datetime: '2020-07-27 11:00:00' }, {}] a.set(tt.CONTEXT, ctx1) G.add_alist(a) op_alist = Temporal().decompose(a, G) self.assertEqual(op_alist.get(tt.OP), 'regress')
def reduce(alist: Alist, children: List[Alist], G: InferenceGraph): # do comparisons vars_to_compare = alist.get(tt.OPVAR).split(' ') # propagate projection vars to parent5 propagate.projections(alist, tuple(children)) response_var = "?_lte_" if len(vars_to_compare) == 0: alist.set(response_var, "false") return alist result = True if len(vars_to_compare) > 1 and utils.is_numeric( alist.instantiation_value(vars_to_compare[0])): for x in vars_to_compare[1:]: if utils.is_numeric( alist.instantiation_value(x)) and utils.is_numeric( alist.instantiation_value(x)): result = (utils.get_number( alist.instantiation_value( vars_to_compare[0]), 0) <= utils.get_number( alist.instantiation_value(x), 0)) and result else: result = False break else: result = False alist.set(response_var, str(result).lower()) # alist.instantiate_variable(tt.COV, estimate_uncertainty( # children, True, alist.get(tt.OP), len(children) # )) return alist
def test_getNestingVars(self): alist = Alist( **{ tt.ID: '1', tt.SUBJECT: '$y', tt.PROPERTY: 'P1082', tt.OBJECT: '?x', tt.TIME: '2010', tt.OPVAR: '?x', tt.COST: 1 }) alist.set('$y', {"$filter": [{"p": "type", "o": "country"}]}) self.assertTrue(alist.nesting_variables())
def test_getVariables(self): alist = Alist( **{ tt.ID: '1', tt.SUBJECT: 'Africa', tt.PROPERTY: 'P1082', tt.OBJECT: '?x', tt.TIME: '2010', tt.OPVAR: '?x', tt.COST: 1 }) alist.set('#d', 34) variables = alist.variables() self.assertTrue(len(variables) == 3, "should have 3 items in dict")
def test_instantiateVariables(self): alist = Alist( **{ tt.ID: '1', tt.SUBJECT: 'Africa', tt.PROPERTY: 'P1082', tt.OBJECT: '?x', tt.TIME: '2010', tt.OPVAR: '?x', tt.COST: 1 }) alist.set('#d', '') alist.set('?x', '#d') alist.instantiate_variable('#d', 99) self.assertEqual(alist.get('?x'), 99, "OBJECT should be 99.")
def test_getInstantiatedAttributes(self): alist = Alist( **{ tt.ID: '1', tt.SUBJECT: 'Africa', tt.PROPERTY: 'P1082', tt.OBJECT: '?x', tt.TIME: '2010', tt.OPVAR: '?x', tt.COST: 1 }) alist.set('#d', 34) alist.set('?x', 100) instantiatedVars = alist.instantiated_attributes() self.assertTrue( len(instantiatedVars) > 0, "there should be 2 instantiated variables.")
def test_isInstantiated2(self): alist = Alist( **{ tt.ID: '1', tt.SUBJECT: 'Africa', tt.PROPERTY: 'P1082', tt.OBJECT: '?x', tt.TIME: '2010', tt.OPVAR: '?x', tt.COST: 1 }) alist.set('#d', 34) results = [ alist.is_instantiated(tt.SUBJECT), alist.is_instantiated(tt.OBJECT), alist.is_instantiated('#d') ] self.assertEqual(results, [True, False, True], "should result in list [True, False, True].")
def cli(query, context={}): session_id = uuid.uuid4().hex interactive = False answer = None if query: query_json = None else: print(f"\n{pcol.CYAN}FRANK CLI{pcol.RESETALL}") query = input(f"Enter question or alist query: \n {pcol.CYAN}>{pcol.RESETALL} ") context = input(f"Enter context: \n {pcol.CYAN}>{pcol.RESETALL} ") query_json = None interactive = True # check if input is question or alist if type(query) == str and '{' in query and '"' in query: query_json = json.loads(query) elif type(query) == dict: query_json = query else: parser = frank.query_parser.parser.Parser() parsedQuestion = parser.getNextSuggestion(query) query_json = parsedQuestion['alist'] if query_json: alist = Alist(**query_json) if context: context_json = json.loads(context) if type(context) == str else context alist.set(tt.CONTEXT, context_json) print(f"{pcol.YELLOW} ├── query alist:{json.dumps(alist.attributes)} {pcol.RESETALL}") print(f"{pcol.YELLOW} └── session id:{session_id} {pcol.RESETALL}\n") launch = Launcher() launch.start(alist, session_id, inference_graphs) if session_id in inference_graphs: answer = inference_graphs[session_id]['answer']['answer'] graph = inference_graphs[session_id]['graph'] graph.plot_plotly(query) if interactive: input("\npress any key to exit") else: print("\nCould not parse question. Please try again.") return answer
def why(self, G: InferenceGraph, alist: Alist, decomp_op, in_place=True): ''' Explain a decomposition of this alist. Assumes a failed instantiation of this alist following KB searches''' expl = "" time = "" children = G.child_alists(alist.id) if alist.get(tt.TIME): time = f" in {alist.get(tt.TIME)}" if decomp_op == 'temporal': expl = f"Could not find the {alist.get(tt.PROPERTY)} of {alist.instantiation_value(tt.SUBJECT)}{time}. " decomp_items = [] # for c in alist.children[0].children: for c in children: decomp_items.append(c.get(tt.TIME)) if len(decomp_items) >= 2: expl += f"Attempted to infer the required value{time} by finding the {alist.get(tt.PROPERTY)} of {alist.instantiation_value(tt.SUBJECT)} " + \ f"at other times between {min(decomp_items)} and {max(decomp_items)}." elif decomp_op == 'geospatial': expl = f"Could not find the {alist.get(tt.PROPERTY)} of {alist.instantiation_value(tt.SUBJECT)}{time}. " decomp_items = [] # for c in alist.children[0].children: for c in G.child_alists(children[0].id): decomp_items.append(c.instantiation_value(tt.SUBJECT)) entities = '' if len(decomp_items) > 8: entities = f"{', '.join(decomp_items[0:8])} etc" else: entities = f"{', '.join(decomp_items[0:len(decomp_items)-1])} and {decomp_items[-1]}" if decomp_items: expl += f"Finding the {alist.get(tt.PROPERTY)}{time} for the constituent parts of " + \ f" {alist.instantiation_value(tt.SUBJECT)}: {entities}." elif decomp_op == 'normalize': expl = f"Need to solve the sub-queries before determining the {alist.get(tt.PROPERTY)}{time}." elif decomp_op == 'comparison': expl = f"Need to solve the sub-queries to determine the items to compare." if in_place: alist.set("why", expl) G.add_alist(alist)
def test_inject_context_query(self): # query context a = Alist( **{ tt.ID: '1', tt.SUBJECT: 'Ghana', tt.PROPERTY: 'P1082', tt.OBJECT: '', tt.OPVAR: '?x', tt.COST: 1 }) ctx1 = [{ ctx.nationality: 'United Kingdom' }, { ctx.place: 'United Kingdom', ctx.device: 'phone', ctx.datetime: '2010-04-30 12:00:00' }, {}] a.set(tt.CONTEXT, ctx1) alist = frank.context.inject_query_context(a) ctx2 = a.get(tt.CONTEXT) self.assertEqual(ctx2[0][ctx.accuracy], 'low')
def test_add_context(self): a = Alist( **{ tt.ID: '1', tt.SUBJECT: 'Africa', tt.PROPERTY: 'P1082', tt.OBJECT: '', tt.TIME: '2010', tt.OPVAR: '?x', tt.COST: 1 }) ctx1 = [{ ctx.nationality: 'United Kingdom' }, { ctx.place: 'United Kingdom', ctx.device: 'phone', ctx.datetime: '2020-04-30 12:00:00' }, {}] a.set(tt.CONTEXT, ctx1) ctx2 = a.get(tt.CONTEXT) alistJson = json.loads(json.dumps(a.attributes)) self.assertEqual(ctx1, ctx2, "Context values do not match")
def test_wikidata_query_object_with_context4(self): a = Alist( **{ tt.ID: '1', tt.SUBJECT: 'London', tt.PROPERTY: 'P6', tt.OBJECT: '', tt.OPVAR: '?x', tt.COST: 1 }) ctx1 = [{ ctx.nationality: 'United Kingdom' }, { ctx.place: 'England', ctx.device: 'phone', ctx.datetime: '2020-04-30 12:00:00', tt.SUBJECT: 'http://www.wikidata.org/entity/Q84' }, {}] a.set(tt.CONTEXT, ctx1) frank.context.inject_retrieval_context(a, "wikidata") result = wikidata.find_property_object(a) self.assertTrue(len(result) > 0, "should have at least one item")
def test_inject_query_context_loc(self): a = Alist( **{ tt.ID: '1', tt.SUBJECT: 'London', tt.PROPERTY: 'P1082', tt.OBJECT: '', tt.OPVAR: '?x', tt.COST: 1 }) ctx1 = [{ ctx.nationality: 'United Kingdom' }, { ctx.place: 'England', ctx.device: 'phone', ctx.datetime: '2020-04-30 12:00:00' }, {}] a.set(tt.CONTEXT, ctx1) alist = frank.context.inject_query_context(a) self.assertEqual( alist.get(tt.CONTEXT)[2][tt.SUBJECT]['wikidata'], 'http://www.wikidata.org/entity/Q84')
def inject_retrieval_context(alist: Alist, source) -> Alist: """ Inject context values into alist attributes to be used for Information Retrieval from KBs. """ context = alist.get(tt.CONTEXT) if not context: return alist context = alist.get(tt.CONTEXT) context_store = {} context_store = { **context[0], **context[1], **context[2] } if context else {} for a in alist.attributes.keys(): if a in context_store: if type(context_store[a]) is dict and source in context_store[a]: alist.set(a, context_store[a][source]) elif type(context_store[a]) is not dict: alist.set(a, context_store[a]) return alist
def reduce(alist: Alist, children: List[Alist], G: InferenceGraph): # do comparisons print(children) vars_to_compare = alist.get(tt.OPVAR).split(' ') # # copy projection vars of min alist to parent # for c in children: # if c.get(tt.OP) != 'comp': # for vc in vars_to_compare: # if vc in c.attributes: # projVars = c.projection_variables() # alist.instantiate_variable(vc, c.instantiation_value(vc), insert_missing=True) # for x in vars_to_compare: # if alist.is_instantiated(x) == False: # # return None # pass # propagate projection vars to parent propagate.projections(alist, tuple(children)) response_var = "?_eq_" if len(vars_to_compare) == 0: alist.set(response_var, "false") return alist result = True for x in vars_to_compare: result = (alist.instantiation_value(x) == alist.instantiation_value(vars_to_compare[0])) and result alist.instantiate_variable(response_var, str( result).lower(), insert_missing=True) # alist.instantiate_variable(tt.COV, estimate_uncertainty( # children, True, alist.get(tt.OP), len(children) # )) return alist
def test_search_with_context(self): a = Alist( **{ tt.ID: '1', tt.SUBJECT: 'Ghana', tt.PROPERTY: 'P1082', tt.OBJECT: '', tt.OPVAR: '?x', tt.COST: 1 }) ctx1 = [{ ctx.nationality: 'United Kingdom' }, { ctx.place: 'United Kingdom', ctx.device: 'phone', ctx.datetime: '2010-04-30 12:00:00' }, {}] a.set(tt.CONTEXT, ctx1) a = frank.context.inject_retrieval_context(a, "wikidata") result = wikidata.find_property_object(a) v = '0' if result: v = result[0].get(tt.OBJECT) self.assertAlmostEqual(utils.get_number(v, 0), 26908262, 1)
def test_getInstantiationValue(self): alist = Alist( **{ tt.ID: '1', tt.SUBJECT: 'Africa', tt.PROPERTY: 'P1082', tt.OBJECT: '?x', tt.TIME: '2010', tt.OPVAR: '?x', tt.COST: 1 }) alist.set('#d', '') alist.set('?x', '#d') alist.set('$y', '') alist.instantiate_variable('#d', 99) results = (alist.instantiation_value('#d'), alist.instantiation_value('?x'), alist.instantiation_value(tt.OBJECT), alist.instantiation_value(tt.TIME), alist.instantiation_value('$y')) self.assertEqual(results, (99, 99, 99, '2010', ''))
def inject_query_context(alist: Alist) -> Alist: """ Inject context values into query alist. """ context = alist.get(tt.CONTEXT) if not context and len(context) < 2: return alist if len(context) == 3 and \ ctx.accuracy not in context[0] and \ ctx.device in context[1]: if context[1][ctx.device] == 'phone': context[0][ctx.accuracy] = 'low' elif context[1][ctx.device] == 'computer': context[0][ctx.accuracy] = 'high' # alist context alist.set(tt.CONTEXT, context) # check for time in alist if not alist.get(tt.TIME): time = get_env_context(alist, ctx.datetime) year = '' if time: year = datetime.strptime(time, '%Y-%m-%d %H:%M:%S').year year = str(year) alist.set(tt.TIME, year) set_query_context(alist, tt.TIME, year) # disambiguate entity based on user location context user_place = get_env_context(alist, ctx.place) user_nationality = get_user_context(alist, ctx.nationality) s_context = {} if user_place: if alist.get(tt.SUBJECT) == '': # if subject is empty, use place context alist.set(tt.SUBJECT, user_place) for source_name, source in { 'wikidata': wikidata, 'worldbank': worldbank }.items(): locations = source.find_location_of_entity( alist.get(tt.SUBJECT)) set_flag = False # use nationality as context for the user's location if no subject if user_nationality: for loc in locations: if user_nationality == loc[2]: s_context[source_name] = loc[0] set_flag = True break if not set_flag and locations and source_name in ['wikidata']: # if no location matched the nationality, use the first location s_context[source_name] = locations[0][0] # set_query_context(alist, tt.SUBJECT, {source_name: locations[0][0]}) else: for source_name, source in { 'wikidata': wikidata, 'worldbank': worldbank }.items(): locations = source.find_location_of_entity( alist.get(tt.SUBJECT)) set_flag = False for loc in locations: if user_place == loc[2]: s_context[source_name] = loc[0] set_flag = True break # if set_flag: # set_query_context(alist, tt.SUBJECT, s_context) if not set_flag and locations and source_name in ['wikidata']: # if no location matched the nationality, use the first location s_context[source_name] = locations[0][0] # set_query_context(alist, tt.SUBJECT, {source_name: locations[0][0]}) if s_context: set_query_context(alist, tt.SUBJECT, s_context) return alist
def what(self, G: InferenceGraph, alist: Alist, is_reduced: bool, in_place=True): ''' Explain a reduction of this alist. ''' what = '' how = '' time = "" if alist.get(tt.TIME): time = f" in {alist.get(tt.TIME)}" if not is_reduced: if alist.get(tt.OP) in ['eq', 'gt', 'gte', 'lt', 'lte']: what = f"Failed to compare the values since the values of all items being compare are not known. " elif alist.get(tt.OP) in ['comp']: what = f"Failed to solve the sub-problem. " elif alist.get(tt.OP) in ['value', 'values']: what = f"Failed to determine the {self.ops_text[alist.get(tt.OP)]} of {alist.get(tt.PROPERTY)}{time}." else: what = f"Failed to calculate the {self.ops_text[alist.get(tt.OP)]} of {alist.get(tt.PROPERTY)}{time}." else: if alist.get(tt.OP) in ['eq', 'gt', 'gte', 'lt', 'lte']: vars_compared = alist.get(tt.OPVAR).split(' ') if len(vars_compared) > 1: what = f"Inferred value is '{alist.instantiation_value('?'+ alist.get(tt.OP))}'." how = f"Did a comparison to determine if {alist.instantiation_value(vars_compared[0])} is " + \ f"{self.ops_text[alist.get(tt.OP)]} {alist.instantiation_value(vars_compared[1])}." elif alist.get(tt.OP) in ['comp']: listed_str = '' listed = alist.instantiation_value(alist.get(tt.OPVAR)) if listed: listed = listed.split(',') if len(listed) > 8: listed_str += f"{', '.join(listed[0:8])}, etc" else: listed_str += ', '.join(listed) if listed_str: what = f"Solved the sub-query and found the following values: {listed_str}." else: inferred_value = '' projected = alist.projection_variables() if projected: inferred_value = list(projected.values())[0] if not inferred_value: inferred_value = alist.instantiation_value( alist.get(tt.OPVAR)) if inferred_value: if ':' in alist.get(tt.PROPERTY): listed_str = '' listed = alist.instantiation_value(alist.get( tt.OPVAR)).split(',') if len(listed) > 8: listed_str += f"{', '.join(listed[0:8])}, etc" else: listed_str += ', '.join(listed) what = f"The {alist.get(tt.PROPERTY).split(':')[1]} values found for the sub-query include: {listed_str}." elif (projected or inferred_value) and not alist.get(tt.PROPERTY): # for alists with just a projected value but no property what = f"An input value for operation is {inferred_value}." elif projected and alist.get( tt.OPVAR) not in projected and alist.get( tt.OP) in ['max', 'min']: what = f"The entity whose {alist.get(tt.PROPERTY)}{time} has the {self.ops_text[alist.get(tt.OP)]} of {alist.instantiation_value(alist.get(tt.OPVAR))} is {inferred_value}." elif projected and alist.get( tt.OPVAR) not in projected and alist.get( tt.OP) not in ['max', 'min']: what = f"The {self.ops_text[alist.get(tt.OP)]} of the {alist.get(tt.PROPERTY)}{time} of {inferred_value} is {alist.instantiation_value(alist.get(tt.OPVAR))}." else: what = f"The {self.ops_text[alist.get(tt.OP)]} of the {alist.get(tt.PROPERTY)} of {alist.instantiation_value(tt.SUBJECT)}{time} is {inferred_value}." if alist.get(tt.OP) in [ 'regress', 'nnpredict', 'linregress', 'gpregress', 'nnregress' ]: decomp_items = [] children = G.child_alists(alist.id) # for c in alist.children[0].children: for c in G.child_alists(children[0].id): decomp_items.append(c.get(tt.TIME)) if len(decomp_items) > 0: how = f"Generated a regression function from times between {min(decomp_items)} and {max(decomp_items)}." if in_place: alist.set("what", what) alist.set("how", how) G.add_alist(alist)