def add_facts_to_puzzle()

in clutrr/relations/builder.py [0:0]


    def add_facts_to_puzzle(self, puzzle):
        """
            For a given puzzle, add different types of facts
                - 1 : Provide supporting facts. After creating the essential fact graph, expand on any
                k number of edges (randomly)
                - 2: Irrelevant facts: after creating the relevant fact graph, expand on an edge,
                 but only provide dangling expansions
                - 3: Disconnected facts: along with relevant facts, provide a tree which is completely
                separate from the proof path
                - 4: Random attributes: school, place of birth, etc.
            If unable to add the required facts, return False
            Else, return the puzzle
        :return:
        """
        if self.args.noise_support:
            # Supporting facts
            # A <-> B <-> C ==> A <-> D <-> C , A <-> D <-> B <-> C
            story = puzzle.story
            extra_story = []
            for se in story:
                e_pair = self.expand_new(se)
                if e_pair:
                    if puzzle.target_edge not in e_pair and e_pair[0][1] not in set([p for e in puzzle.story for p in e]):
                        extra_story.append(tuple(e_pair))
            if len(extra_story) == 0:
                return False
            else:
                # choose a sample of 1 to k-1 edge pairs
                num_edges = random.choice(range(1, (len(story) // 2) + 1))
                extra_story = random.sample(extra_story, min(num_edges, len(extra_story)))
                # untuple the extra stories
                extra_story = [k for e in extra_story for k in e]
                self._test_supporting(story, extra_story)
            puzzle.add_fact(fact_type='supporting', fact=extra_story)
        if self.args.noise_irrelevant:
            # Irrelevant facts
            # A <-> B <-> C ==> A <-> D <-> E
            # Must have only one common node with the story
            story = puzzle.story
            num_edges = len(story)
            sampled_edge = random.choice(story)
            extra_story = []
            for i in range(num_edges):
                tmp = sampled_edge
                seen_pairs = set()
                pair = self.expand_new(sampled_edge)
                if pair:
                    while len(extra_story) == 0 and (tuple(pair) not in seen_pairs):
                        seen_pairs.add(tuple(pair))
                        for e in pair:
                            if e != puzzle.target_edge and not self._subset(story, [e], k=2):
                                extra_story.append(e)
                                sampled_edge = e
                                break
                    if tmp == sampled_edge:
                        sampled_edge = random.choice(story)
            if len(extra_story) == 0:
                return False
            else:
                # add a length restriction so as to not create super long text
                # length restriction should be k+1 than the current k
                extra_story = random.sample(extra_story, min(len(extra_story), len(story) // 2))
                self._test_irrelevant(story, extra_story)
                puzzle.add_fact(fact_type='irrelevant', fact=extra_story)
        if self.args.noise_disconnected:
            # Disconnected facts
            story = puzzle.story
            nodes_story = set([y for x in list(story) for y in x])
            nodes_not_in_story = set(self.anc.family_data.keys()) - nodes_story
            possible_edges = [(x, y) for x, y in it.combinations(list(nodes_not_in_story), 2) if
                              (x, y) in self.anc.family]
            num_edges = random.choice(range(1, (len(story) // 2) + 1))
            possible_edges = random.sample(possible_edges, min(num_edges, len(possible_edges)))
            if len(possible_edges) == 0:
                return False
            self._test_disconnected(story, possible_edges)
            puzzle.add_fact(fact_type='disconnected', fact=possible_edges)
        return puzzle