示例#1
0
def unvariablize_by_where_swap(state, match):
    mapping = {
        ele: 'arg' + str(i - 1) if i > 0 else 'sel'
        for i, ele in enumerate(match)
    }
    r_state = rename_flat(state, {mapping[a]: a for a in mapping})
    return r_state
示例#2
0
def variablize_by_where_swap(self, state, rhs, match):
    if (isinstance(state, StateMultiView)):
        state = state.get_view("flat_ungrounded")
    # print(state)
    # print(type(state))
    mapping = {
        'arg' + str(i - 1) if i > 0 else 'sel': ele
        for i, ele in enumerate(match)
    }
    # for i,x in enumerate(state):
    #     print("attr%i"%i,x)
    #     print("val%i"%i,state[x])

    r_state = rename_flat(state, {mapping[a]: a for a in mapping})
    # r_state = state
    #TODO: Do this better...

    # r_state = {key:val for key,val in r_state.items() if "contentEditable" in key or "value" in key}
    if (self.strip_attrs and len(self.strip_attrs) > 0):
        r_state = {
            key: val
            for key, val in r_state.items() if key[0] not in self.strip_attrs
        }

    # for k,v in r_state.items():
    #     print(k,v)
    #     try:
    #         v = float(v)
    #         r_state[k] = v
    #     except Exception as e:
    #         pass
    # pprint("r_state")
    # pprint(r_state)
    return r_state
示例#3
0
def variablize_by_where_append(self, state, rhs, match):
    if (isinstance(state, StateMultiView)):
        state = state.get_view("flat_ungrounded")
    # pprint(state)
    r_state = rename_flat(state, {})
    if (len(match) > 1):
        r_state[("args", tuple(list(match)[1:]))] = True
    r_state[("sel", match[0])] = True
    if (self.strip_attrs and len(self.strip_attrs) > 0):
        r_state = {
            key: val
            for key, val in r_state.items() if key[0] not in self.strip_attrs
        }

    # del_list = []
    # for k,v in r_state.items():
    #     try:
    #         if(not isinstance(v,bool)):
    #             v = float(v)
    #             del_list.append(k)
    #     except Exception as e:
    #         pass
    # for k in del_list:
    #     del r_state[k]
    # pprint("r_state")
    # pprint([v for k,v in r_state.items() if k[0] =='value'])
    return r_state
    def ifit(self, t, x, y):
        # print("IFIT T", t)
        # if y == 0:
        #     return

        x = {
            a: x[a]
            for a in x
            if (isinstance(a, tuple) and a[0] not in self.remove_attrs) or (
                not isinstance(a, tuple) and a not in self.remove_attrs)
        }

        # x = {a: x[a] for a in x if self.is_structural_feature(a, x[a])}
        # x = {a: x[a] for a in x}

        # eles = set([field for field in t])
        # prior_count = 0
        # while len(eles) - prior_count > 0:
        #     prior_count = len(eles)
        #     for a in x:
        #         if isinstance(a, tuple) and a[0] == 'haselement':
        #             if a[2] in eles:
        #                 eles.add(a[1])
        #             # if self.matches(eles, a):
        #             #     names = get_attribute_components(a)
        #             #     eles.update(names)

        # x = {a: x[a] for a in x
        #      if self.matches(eles, a)}

        # foa_mapping = {field: 'foa%s' % j for j, field in enumerate(t)}
        foa_mapping = {}
        for j, field in enumerate(t):
            if field not in foa_mapping:
                foa_mapping[field] = 'foa%s' % j

        # for j,field in enumerate(t):
        #     x[('foa%s' % j, field)] = True
        x = rename_flat(x, foa_mapping)
        # pprint(x)

        # print("adding:")

        ns = NameStandardizer()
        sm = StructureMapper(self.concept)
        x = sm.transform(ns.transform(x))
        # pprint(x)
        self.concept.increment_counts(x)

        if y == 1:
            self.pos_concept.increment_counts(x)
        else:
            self.neg_concept.increment_counts(x)

        # print()
        # print('POSITIVE')
        # pprint(self.pos_concept.av_counts)
        # print('NEGATIVE')
        # pprint(self.neg_concept.av_counts)

        # pprint(self.concept.av_counts)

        pos_instance = {}
        pos_args = set()
        for attr in self.pos_concept.av_counts:
            attr_count = 0
            for val in self.pos_concept.av_counts[attr]:
                attr_count += self.pos_concept.av_counts[attr][val]
            if attr_count == self.pos_concept.count:
                if len(self.pos_concept.av_counts[attr]) == 1:
                    args = get_vars(attr)
                    pos_args.update(args)
                    pos_instance[attr] = val
                else:
                    args = get_vars(attr)
                    val_gensym = value_gensym()
                    args.append(val_gensym)
                    pos_instance[attr] = val_gensym

            # if len(self.pos_concept.av_counts[attr]) == 1:
            #     for val in self.pos_concept.av_counts[attr]:
            #         if ((self.pos_concept.av_counts[attr][val] ==
            #              self.pos_concept.count)):
            #             args = get_vars(attr)
            #             pos_args.update(args)
            #             pos_instance[attr] = val

        # print('POS ARGS', pos_args)

        neg_instance = {}
        for attr in self.neg_concept.av_counts:
            # print("ATTR", attr)
            args = set(get_vars(attr))
            if not args.issubset(pos_args):
                continue

            for val in self.neg_concept.av_counts[attr]:
                # print("VAL", val)
                if ((attr not in self.pos_concept.av_counts
                     or val not in self.pos_concept.av_counts[attr])):
                    neg_instance[attr] = val

        foa_mapping = {'foa%s' % j: '?foa%s' % j for j in range(len(t))}
        pos_instance = rename_flat(pos_instance, foa_mapping)
        neg_instance = rename_flat(neg_instance, foa_mapping)

        conditions = ([(a, pos_instance[a])
                       for a in pos_instance] + [('not', (a, neg_instance[a]))
                                                 for a in neg_instance])

        # print("========CONDITIONS======")
        # pprint(conditions)
        # print("========CONDITIONS======")

        self.target_types = ['?foa%s' % i for i in range(len(t))]
        self.operator = Operator(tuple(['Rule'] + self.target_types),
                                 conditions, [])
示例#5
0
    def train(self, state, selection, action, inputs, reward, skill_label,
              foci_of_attention):
        """
        Doc String
        """

        # print('\n'*5)
        # print('state', skill_label)
        # print('skill_label', skill_label)
        # print('selection', selection)
        # print('action', action)
        # print('inputs', inputs)
        # print('reward', reward)
        # print('state')
        # pprint(state)

        # label = 'math'

        # create example dict
        example = {}
        example['state'] = state
        example['skill_label'] = skill_label
        example['selection'] = selection
        example['action'] = action
        example['inputs'] = inputs
        example['reward'] = float(reward)

        tup = Tuplizer()
        flt = Flattener()
        example['flat_state'] = flt.transform(tup.transform(state))

        knowledge_base = FoPlanner(
            [(ground(a),
              example['flat_state'][a].replace('?', 'QM') if isinstance(
                  example['flat_state'][a], str) else example['flat_state'][a])
             for a in example['flat_state']], self.feature_set)

        knowledge_base.fc_infer(depth=1, epsilon=self.epsilon)

        example['flat_state'] = {
            unground(a): v.replace("QM", "?") if isinstance(v, str) else v
            for a, v in knowledge_base.facts
        }

        if skill_label not in self.skills:
            self.skills[skill_label] = {}

        explanations = []
        secondary_explanations = []

        # the base explaination (the constants)
        input_args = tuple(sorted([arg for arg in inputs]))
        sai = ('sai', selection, action, *[inputs[a] for a in input_args])

        # Need to do stuff with features here too.

        # used for grounding out plans, don't need to build up each time.
        # print(function_sets[self.action_set])

        # knowledge_base = FoPlanner([(ground(a),
        #                              example['flat_state'][a].replace('?', 'QM')
        #                              if isinstance(example['flat_state'][a], str)
        #                              else example['flat_state'][a])
        #                             for a in example['flat_state']],
        #                            self.function_set)
        # knowledge_base.fc_infer(depth=self.search_depth, epsilon=self.epsilon)

        # FACTS AFTER USING FUNCTIONS.
        # pprint(knowledge_base.facts)

        #DANNY: The gist of this is to find_ applicable_skills (explanations because the inputs/outputs are literals)
        for skill, learner_dict in self.skills[skill_label].items():
            exp, iargs = skill
            for match in self.explain_sai(skill, learner_dict, sai,
                                          knowledge_base,
                                          example['flat_state']):

                # print("MATCH", match)
                # print("COVERED", exp, m)

                #DANNY NOTES:
                #sai = ('sai', 'JCommTable5.R0C0', 'UpdateTextArea', '16')
                #exp  =  ('sai', ('id', '?foa0'), 'UpdateTextArea', ('value', ('Multiply', ('value', '?foa1'), ('value', '?foa2'))))
                #r_exp  =  the explanation renamed with the match literals
                #ARGS = A list of input arguements to the explanations
                #IARGS: = A tuple of outputs? Or maybe a set of property names (i.e. 'value').
                #Match = A dictionary mapping from ?foas to element strings (the element names have QM instead of ?)

                r_exp = unground(list(rename_flat({exp: True}, match))[0])
                args = get_vars(exp)

                # print("sai:", sai)
                # print("exp:", exp)
                # print("r_exp:", r_exp)
                # print("ARGS:", args)
                # print("IARGS:", iargs, type(iargs))
                # print("match", match)

                # Need to check if it would have been actully generated
                # under where and when.
                # Danny: Makes sure that there is a match for every arguement
                if len(args) != len(match):
                    continue

                # print("HERE1")

                #DANNY: Checks that the match resolves to string elements
                grounded = True
                for ele in match:
                    if not isinstance(match[ele], str):
                        grounded = False
                        break
                if not grounded:
                    #DANNY: Doesn't really happen... not sure in what circumstances this would happen
                    # print("BAD MATCH: ", match)
                    continue

                # print("HERE2")

                tup = tuple([
                    match["?foa%s" % i].replace("QM", "?")
                    for i in range(len(match))
                ])

                # print("tup:", tup)

                #tup = a tuple of the matches
                #Danny: Makes sure that the explanation hasn't used an foa twice
                if len(tup) != len(set(tup)):
                    continue

                # print("HERE3")

                secondary_explanations.append(r_exp)

                #Danny: Check that the where learner approves of the match
                #       It seems like the where learner should have just generated this if it was going to check it anyway
                #       This is only at the end it seems to allow for secondary explanations which the where learner is not yet aware of
                # print("A", self.skills[skill_label])
                # print("B", self.skills[skill_label][(exp, iargs)])
                skill_where = self.skills[skill_label][(exp, iargs)]['where']
                if not skill_where.check_match(tup, example['flat_state']):
                    continue

                # print("ADDING", r_exp)
                explanations.append(r_exp)

        if len(explanations) == 0 and len(secondary_explanations) > 0:
            explanations.append(choice(secondary_explanations))

        elif len(explanations) == 0:

            explanations = self.explanations_from_how_search(
                example['flat_state'], ('sai', selection, action, inputs),
                input_args)

        #Danny: Do the training for all the applicable explanations
        # print("EXPLAINS", explanations)
        for exp in explanations:
            args = get_vars(exp)
            foa_vmapping = {
                field: '?foa%s' % j
                for j, field in enumerate(args)
            }
            foa_mapping = {field: 'foa%s' % j for j, field in enumerate(args)}
            r_exp = (list(rename_flat({exp: True},
                                      foa_vmapping))[0], input_args)

            if r_exp not in self.skills[skill_label]:

                # TODO - Hack for specific action set
                # if self.action_set == "tutor knowledge":
                #     constraints = self.generate_tutor_constraints(r_exp[0])
                # else:
                #     constraints = self.extract_mg_h(r_exp[0])
                # constraints = extract_mg_h(r_exp[0])
                constraints = generate_html_tutor_constraints(r_exp[0])

                # print("CONSTRAINTS")
                # print(constraints)

                w_args = tuple(['?foa%s' % j for j, _ in enumerate(args)])

                self.skills[skill_label][r_exp] = {}
                where_inst = self.where(args=w_args, constraints=constraints)
                self.skills[skill_label][r_exp]['where'] = where_inst
                self.skills[skill_label][r_exp]['when'] = self.when()

            self.skills[skill_label][r_exp]['where'].ifit(
                args, example['flat_state'], example['reward'])
            # print('done where learning')

            # TODO
            # Need to add computed features.
            # need to rename example with foa's that are not variables
            r_flat = rename_flat(example['flat_state'], foa_mapping)

            self.skills[skill_label][r_exp]['when'].ifit(
                r_flat, example['reward'])
示例#6
0
    def request(self, state):
        """
        Doc String
        TODO - several Linter problems with this one
        """
        tup = Tuplizer()
        flt = Flattener()
        state = flt.transform(tup.transform(state))

        knowledge_base = FoPlanner([(ground(a), state[a].replace('?', 'QM') if
                                     isinstance(state[a], str) else state[a])
                                    for a in state], self.feature_set)
        knowledge_base.fc_infer(depth=1, epsilon=self.epsilon)
        state = {
            unground(a): v.replace("QM", "?") if isinstance(v, str) else v
            for a, v in knowledge_base.facts
        }

        skillset = []

        # pprint(self.skills)

        for skill_label in self.skills:
            for exp in self.skills[skill_label]:
                pos = self.skills[skill_label][exp]['where'].num_pos()
                neg = self.skills[skill_label][exp]['where'].num_neg()

                skillset.append(
                    (pos / (pos + neg), pos + neg, random(), skill_label, exp,
                     self.skills[skill_label][exp]))
        skillset.sort(reverse=True)

        # used for grounding out plans, don't need to build up each time.
        # knowledge_base = FoPlanner([(ground(a), state[a].replace('?', 'QM')
        #                              if isinstance(state[a], str)
        #                              else state[a])
        #                             for a in state],
        #                            self.function_set)
        # knowledge_base.fc_infer(depth=self.search_depth, epsilon=self.epsilon)

        # TODO - would it be too expensive to make skillset contain some kind of Skill object?
        # because this for loop is ridiculous
        for _, _, _, skill_label, (exp, input_args), skill in skillset:

            # print("STATE")
            # pprint(state)
            # print("--------")
            # print(exp)
            # print("contentEditable: ",state.get( ('contentEditable',"?ele-" + exp[1]) ,True) )
            # if(state.get( ('contentEditable',"?ele-" + exp[1]) ,True) == False):
            #     continue
            # print("")
            # print("REQUEST_EXPLAINS", exp)

            # Continue until we either do something with the rule. For example,
            # generate an SAI or determine that the rule doesn't match. If we
            # get some kind of failure, such as being unable to execute an
            # action sequence, then we want to learn from that and try again.
            failed = True

            # print("SKILL: ",exp, input_args)

            while failed:

                failed = False

                # print("STATE")
                # pprint(state)
                # print("--------")

                for match in skill['where'].get_matches(state,
                                                        epsilon=self.epsilon):
                    # print("REE1")
                    if len(match) != len(set(match)):
                        continue

                    # print("MATCH FOUND", skill_label, exp, match)
                    vmapping = {
                        '?foa' + str(i): ele
                        for i, ele in enumerate(match)
                    }
                    mapping = {
                        'foa' + str(i): ele
                        for i, ele in enumerate(match)
                    }

                    # print("VMAP")
                    # pprint(vmapping)
                    # print("MAP")
                    # pprint(mapping)

                    r_exp = list(rename_flat({exp: True}, vmapping))[0]
                    r_state = rename_flat(state,
                                          {mapping[a]: a
                                           for a in mapping})

                    # print("KB", knowledge_base)
                    rg_exp = eval_expression(r_exp, knowledge_base,
                                             self.function_set, self.epsilon)
                    # for ele in r_exp:
                    #     if isinstance(ele, tuple):
                    #         # print("THIS HAPPENED", ele, ground(ele), execute_functions(ground(ele)))

                    #                 # execute_functions(subt(u))
                    #                 # rg_exp.append()

                    #             # print("BLEHH:", operator.effects)

                    #         for var_match in knowledge_base.fc_query([(ground(ele), '?v')],
                    #                                                  max_depth=0,
                    #                                                   epsilon=self.epsilon):
                    #             # print("VARM:",var_match, ground(ele))
                    #             if var_match['?v'] != '':
                    #                 rg_exp.append(var_match['?v'])
                    #                 # print("HERE_A",rg_exp[-1])
                    #             break

                    #         operator_output = apply_operators(ele,self.function_set,knowledge_base,self.epsilon)
                    #         # print(operator_output)
                    #         if(operator_output != None and operator_output != ""):
                    #             rg_exp.append(operator_output)
                    #             # print("HERE_B",operator_output)

                    #         # if(operator_output != None):
                    #         #     rg_exp.append(operator_output)

                    #     else:
                    #         rg_exp.append(ele)

                    # print("REE2")

                    # print("rg_exp:", rg_exp)
                    # print("r_exp:", r_exp)

                    if len(rg_exp) != len(r_exp):
                        continue

                    # print("EXP:", r_exp)
                    # print("RSTATE ---------------")
                    # pprint(r_state)
                    # print("---------------")

                    # print("REE3")
                    prediction = skill['when'].predict([r_state])[0]

                    # print("when", skill['when'])

                    # print("PREDICTION:", type(prediction), prediction)

                    if prediction <= 0:
                        continue
                    # print("REE4")
                    response = {}
                    response['skill_label'] = skill_label
                    response['selection'] = rg_exp[1]
                    response['action'] = rg_exp[2]
                    response['inputs'] = {
                        a: rg_exp[3 + i]
                        for i, a in enumerate(input_args)
                    }
                    # response['inputs'] = list(rg_exp[3:])
                    response['foci_of_attention'] = []
                    # pprint(response)
                    return response

        return {}
    def request(self, state):
        # print(state)
        # print("REQUEST RECEIVED")
        tup = Tuplizer()
        flt = Flattener()

        state = flt.transform(tup.transform(state))

        # new = {}
        # for attr in state:
        #     if (isinstance(attr, tuple) and attr[0] == 'value'):
        #         new[('editable', attr[1])] = state[attr] == ''
        #         for attr2 in state:
        #             if (isinstance(attr2, tuple) and attr2[0] == 'value'):
        #                 if (attr2 == attr or attr < attr2 or
        #                     (state[attr] == "" or state[attr2] == "")):
        #                     continue
        #                 if (state[attr] == state[attr2]):
        #                     new[('eq', attr, attr2)] = True
        # state.update(new)

        kb = FoPlanner([(self.ground(a),
                         state[a].replace('?', 'QM') if
                         isinstance(state[a], str) else
                         state[a])
                        for a in state], featuresets[self.action_set])
        kb.fc_infer(depth=1, epsilon=epsilon)
        state = {self.unground(a): v.replace("QM", "?") if isinstance(v, str)
                 else v for a, v in kb.facts}

        # pprint(state)

        # compute features

        # for attr, value in self.compute_features(state):
        #     state[attr] = value

        skillset = []
        for label in self.skills:
            for exp in self.skills[label]:
                pos = self.skills[label][exp]['where'].num_pos()
                neg = self.skills[label][exp]['where'].num_neg()

                skillset.append((pos / (pos + neg), pos + neg,
                                 random(), label, exp,
                                 self.skills[label][exp]))
        skillset.sort(reverse=True)

        # print('####SKILLSET####')
        pprint(skillset)
        # print('####SKILLSET####')

        # used for grounding out plans, don't need to build up each time.
        kb = FoPlanner([(self.ground(a),
                         state[a].replace('?', 'QM') if
                         isinstance(state[a], str) else
                         state[a])
                        for a in state], functionsets[self.action_set])
        kb.fc_infer(depth=search_depth, epsilon=epsilon)

        # print(kb)

        for _, _, _, label, (exp, input_args), skill in skillset:

            # print()
            # print("TRYING:", label, exp)

            # print("Conditions:")
            # pprint(skill['where'].operator.conditions)

            # Continue until we either do something with the rule. For example,
            # generate an SAI or determine that the rule doesn't match. If we
            # get some kind of failure, such as being unable to execute an
            # action sequence, then we want to learn from that and try again.
            failed = True

            while failed:

                failed = False
                for m in skill['where'].get_matches(state, epsilon=epsilon):
                    if len(m) != len(set(m)):
                        # print("GENERATED MATCH WITH TWO VARS BOUND TO ",
                        #       "SAME THING")
                        continue

                    # print("MATCH FOUND", label, exp, m)
                    vmapping = {'?foa' + str(i): ele
                                for i, ele in enumerate(m)}
                    mapping = {'foa' + str(i): ele
                               for i, ele in enumerate(m)}

                    r_exp = list(rename_flat({exp: True}, vmapping))[0]
                    r_state = rename_flat(state,
                                          {mapping[a]: a for a in mapping})

                    # pprint(r_state)

                    # pprint(r_state)

                    rg_exp = []
                    for ele in r_exp:
                        if isinstance(ele, tuple):
                            # kb = FoPlanner([(self.ground(a),
                            #                  state[a].replace('?', 'QM') if
                            #                  isinstance(state[a], str) else
                            #                  state[a])
                            #                 for a in state],
                            #                functionsets[self.action_set])
                            for vm in kb.fc_query([(self.ground(ele), '?v')],
                                                  max_depth=0,
                                                  epsilon=epsilon):
                                # if vm['?v'] == '':
                                #     raise Exception("Should not be an"
                                #                     " empty str")
                                if vm['?v'] != '':
                                    rg_exp.append(vm['?v'])
                                break
                        else:
                            rg_exp.append(ele)

                    if len(rg_exp) != len(r_exp):
                        # print("FAILED TO FIRE RULE")
                        # print(rg_exp, 'from', r_exp)
                        continue

                        # # add neg to where
                        # skill['where'].ifit(m, state, 0)

                        # # add neg to when
                        # foa_mapping = {field: 'foa%s' % j for j, field in
                        #                enumerate(m)}
                        # neg_x = rename_flat(state, foa_mapping)
                        # skill['when'].ifit(neg_x)

                        # failed = True
                        # break

                    # print("predicting")
                    # pprint(r_state)

                    # c = skill['when'].categorize(r_state)
                    p = skill['when'].predict([r_state])[0]

                    # print("###CATEGORIZED CONCEPT###")
                    # print(c)
                    # pprint(c.av_counts)
                    # print(c.predict('correct'))

                    if p == 0:
                        # print("predicting FAIL")
                        continue
                    # print("predicting FIRE")

                    # if not c.predict('correct'):
                    #     print("predicting FAIL")
                    #     continue
                    # print("predicting FIRE")

                    # print("###TREE###")
                    # print(skill['when'])

                    # pprint(r_exp)
                    # pprint(rg_exp)

                    # assert self.explains_sai(kb, r_exp, rg_exp)

                    response = {}
                    response['label'] = label
                    response['selection'] = rg_exp[1]
                    response['action'] = rg_exp[2]
                    response['inputs'] = {a: rg_exp[3+i] for i, a in
                                          enumerate(input_args)}
                    # response['inputs'] = list(rg_exp[3:])
                    response['foas'] = []
                    # pprint(response)
                    return response

        return {}
    def train(self, state, label, foas, selection, action, inputs, correct):
        print('label', label)
        print('selection', selection)
        print('action', action)
        print('input', inputs)
        print('correct', correct)

        # label = 'math'

        # create example dict
        example = {}
        example['state'] = state
        example['label'] = label
        example['selection'] = selection
        example['action'] = action
        example['inputs'] = inputs
        example['correct'] = correct

        tup = Tuplizer()
        flt = Flattener()
        example['flat_state'] = flt.transform(tup.transform(state))
        # print('SAI:', selection, action, inputs)

        # print('State:')
        # pprint(example['state'])
        # print('Flat State:')
        # pprint(example['flat_state'])

        # new = {}
        # for attr in example['flat_state']:
        #     if (isinstance(attr, tuple) and attr[0] == 'value'):
        #         new[('editable', attr[1])] =
        #           example['flat_state'][attr] == ''

        #         for attr2 in example['flat_state']:
        #             if (isinstance(attr2, tuple) and attr2[0] == 'value'):
        #                 if (attr2 == attr or attr < attr2 or
        #                     (example['flat_state'][attr] == "" or
        #                      example['flat_state'][attr2] == "")):
        #                     continue
        #                 if ((example['flat_state'][attr] ==
        #                      example['flat_state'][attr2])):
        #                     new[('eq', attr, attr2)] = True

        # example['flat_state'].update(new)

        kb = FoPlanner([(self.ground(a),
                         example['flat_state'][a].replace('?', 'QM') if
                         isinstance(example['flat_state'][a], str) else
                         example['flat_state'][a])
                        for a in example['flat_state']],
                       featuresets[self.action_set])
        kb.fc_infer(depth=1, epsilon=epsilon)
        example['flat_state'] = {self.unground(a): v.replace("QM", "?") if
                                 isinstance(v, str) else v for a, v in
                                 kb.facts}

        # pprint(example['flat_state'])

        if label not in self.skills:
            self.skills[label] = {}

        explainations = []
        secondary_explainations = []

        # the base explaination (the constants)
        input_args = tuple(sorted([arg for arg in inputs]))
        sai = ('sai', selection, action, *[inputs[a] for a in input_args])

        # Need to do stuff with features here too.

        # used for grounding out plans, don't need to build up each time.
        # print(functionsets[self.action_set])
        kb = FoPlanner([(self.ground(a),
                         example['flat_state'][a].replace('?', 'QM') if
                         isinstance(example['flat_state'][a], str) else
                         example['flat_state'][a])
                        for a in example['flat_state']],
                       functionsets[self.action_set])
        kb.fc_infer(depth=search_depth, epsilon=epsilon)
        # FACTS AFTER USING FUNCTIONS.
        # pprint(kb.facts)

        for exp, iargs in self.skills[label]:
            # kb = FoPlanner([(self.ground(a),
            #                  example['flat_state'][a].replace('?', 'QM') if
            #                  isinstance(example['flat_state'][a], str) else
            #                  example['flat_state'][a])
            #                 for a in example['flat_state']],
            #                functionsets[self.action_set])
            for m in self.explains_sai(kb, exp, sai):
                # print("COVERED", exp, m)

                # Need to check if it would have been actully generated
                # under where and when.

                r_exp = self.unground(list(rename_flat({exp: True}, m))[0])

                args = self.get_vars(exp)

                if len(args) != len(m):
                    # print("EXP not same length")
                    continue

                grounded = True
                for ele in m:
                    if not isinstance(m[ele], str):
                        grounded = False
                        break
                if not grounded:
                    # print("Pattern not fully grounded")
                    continue

                # foa_vmapping = {field: '?foa%s' % j
                #                 for j, field in enumerate(args)}
                # foa_mapping = {field: 'foa%s' % j for j, field in
                #                enumerate(args)}

                t = tuple([m["?foa%s" % i].replace("QM", "?") for i in
                           range(len(m))])

                if len(t) != len(set(t)):
                    # print("TWO VARS BOUND TO SAME")
                    continue

                secondary_explainations.append(r_exp)

                # print("This is my T:", t)

                skill_where = self.skills[label][(exp, iargs)]['where']
                if not skill_where.check_match(t, example['flat_state']):
                    continue

                # print("####### SUCCESSFUL WHERE MATCH########")

                # x = rename_flat(example['flat_state'], foa_mapping)
                # c = self.skills[label][(exp, iargs)]['when'].categorize(x)
                # if not c.predict('correct'):
                #     continue

                # print("ADDING", r_exp)
                explainations.append(r_exp)

        if len(explainations) == 0 and len(secondary_explainations) > 0:
            explainations.append(choice(secondary_explainations))
            # explainations.append(secondary_explanation)

        elif len(explainations) == 0:
            # kb = FoPlanner([(self.ground(a),
            #                  example['flat_state'][a].replace('?', 'QM') if
            #                  isinstance(example['flat_state'][a], str) else
            #                  example['flat_state'][a])
            #                 for a in example['flat_state']],
            #                functionsets[self.action_set])

            selection_exp = selection
            for sel_match in kb.fc_query([('?selection', selection)],
                                         max_depth=0,
                                         epsilon=epsilon):
                selection_exp = sel_match['?selection']
                break

            input_exps = []

            for a in input_args:
                iv = inputs[a]
                # kb = FoPlanner([(self.ground(a),
                #         example['flat_state'][a].replace('?', 'QM') if
                #         isinstance(example['flat_state'][a], str) else
                #         example['flat_state'][a])
                #        for a in example['flat_state']],
                # functionsets[self.action_set])
                input_exp = iv
                # print('trying to explain', [((a, '?input'), iv)])

                # TODO not sure what the best approach is for choosing among
                # the possible explanations. Perhaps we should choose more than
                # one. Maybe the shortest (less deep).

                # f = False
                possible = []
                for iv_m in kb.fc_query([((a, '?input'), iv)],
                                        max_depth=0,
                                        epsilon=epsilon):

                    # input_exp = (a, iv_m['?input'])
                    possible.append((a, iv_m['?input']))
                    # print("FOUND!", input_exp)
                    # f = True
                    # break

                possible = [(self.compute_exp_depth(p), random(), p) for p in
                            possible]
                possible.sort()
                # print("FOUND!")
                # pprint(possible)

                if len(possible) > 0:
                    _, _, input_exp = possible[0]
                    # input_exp = choice(possible)

                # if not f:
                #     print()
                #     print("FAILED TO EXPLAIN INPUT PRINTING GOAL AND FACTS")
                #     print("GOAL:", ((a, '?input'), iv))

                #     for f in kb.facts:
                #         if f[0][0] == 'value':
                #             print(f)
                #     from time import sleep
                #     sleep(30)

                #     # pprint(kb.facts)

                input_exps.append(input_exp)

            explainations.append(self.unground(('sai', selection_exp, action,
                                                *input_exps)))

        for exp in explainations:
            args = self.get_vars(exp)
            foa_vmapping = {field: '?foa%s' % j
                            for j, field in enumerate(args)}
            foa_mapping = {field: 'foa%s' % j for j, field in enumerate(args)}
            x = rename_flat({exp: True}, foa_vmapping)
            r_exp = (list(x)[0], input_args)
            # r_exp = self.replace_vars(exp)
            # print("REPLACED")
            # print(exp)
            # print(r_exp)

            if r_exp not in self.skills[label]:
                # mg_h = self.extract_mg_h(r_exp[0])

                if self.action_set == "tutor knowledge":
                    constraints = self.generate_tutor_constraints(r_exp[0])
                else:
                    constraints = self.extract_mg_h(r_exp[0])

                # print("ACTIONSET")
                # print(self.action_set)

                # print("SAI")
                # print(r_exp[0])

                print("CONSTRAINTS")
                print(constraints)

                w_args = tuple(['?foa%s' % j for j, _ in enumerate(args)])

                self.skills[label][r_exp] = {}
                where_inst = self.where(args=w_args, constraints=constraints)
                self.skills[label][r_exp]['where'] = where_inst
                # initial_h=mg_h)
                self.skills[label][r_exp]['when'] = when_learners[self.when]()

            # print('where learning for ', exp)
            self.skills[label][r_exp]['where'].ifit(args,
                                                    example['flat_state'],
                                                    example['correct'])
            # print('done where learning')

            # TODO
            # Need to add computed features.
            # need to rename example with foa's that are not variables
            x = rename_flat(example['flat_state'], foa_mapping)
            # x['correct'] = example['correct']

            # print('ifitting')
            # pprint(x)
            # self.skills[label][r_exp]['when'].ifit(x)
            self.skills[label][r_exp]['when'].ifit(x, example['correct'])