Beispiel #1
0
    def predict(self, entry: Entry) -> str:
        events = entry.qa['events']
        answer_is_numbers = any(d in entry.answer for d in string.digits)
        question_is_comparison = 'comparison' in entry.qa['reasoning']
        if question_is_comparison:
            candidates = [
                f"{a['first']} {a['last']}" for e in events
                for a in list(e['attributes'].values()) + [e['actor']]
                if isinstance(a, dict)
            ]
            candidates = [c for c in candidates if c in entry.question]
            candidates = list(set(candidates))
            assert all(c in entry.passage for c in candidates)
            assert len(candidates) == 2
        elif answer_is_numbers:
            candidates = [
                str(a) for e in events for a in list(e['attributes'].values())
                if isinstance(a, int)
            ]
        else:
            candidates = [
                f"{a['first']} {a['last']}" for e in events
                for a in list(e['attributes'].values()) + [e['actor']]
                if isinstance(a, dict)
            ]

        choices = Choices([c for c in candidates if c in entry.passage])
        return choices.random()
Beispiel #2
0
    def create_attribute(self, name):
        if name == 'distance':
            return random.choice(list(range(11, 35)))

        if name == 'time':
            last_ts = 0
            for sentence in self.sentences[::-1]:
                last_ts = sentence.attributes.get("time", 0)
                if last_ts:
                    break
            m = 3
            # rv = expon(scale=20)
            # TODO: if too slow, change to linear...
            if last_ts >= 91 - m:
                return last_ts + 1
            # p = [rv.pdf(x) for x in range(last_ts + 1, 90)]
            # m = 91 - last_ts
            # t = 5
            # p2 = [-m*x+t-last_ts for x in range(last_ts + 1, 90)]
            # sum_p = sum(p)
            # sum_p_2 = sum(p2)
            # p2_norm = [x / sum_p_2 for x in p2]
            # p_norm = [x / sum_p for x in p]

            b = (90 - last_ts) / m
            p = [-m * x + (90 - last_ts) + (0.5 * b) for x in range(1, int(b))] + \
                [-(1 / m) * x + b for x in range(int(b), 90 - last_ts)]
            p_norm = [x / sum(p) for x in p]

            return random.choices(list(range(last_ts + 1, 90)), weights=p_norm, k=1)[0]

        if name == 'coactor':
            logger.debug(f"Chosen Actors: {[a.id for a in self.chosen_actors]}")
            own_team = Choices(p for p in self.world.players if p.team != self.current_event.actor.team)
            other_team = Choices(p for p in self.world.players if p.team == self.current_event.actor.team)
            if self.current_event.event_type == 'foul':
                if self.unique_coactors:
                    remaining_pool = other_team - self.chosen_actors
                    logger.debug(f"Remaining pool: {[a.id for a in remaining_pool]}")
                else:
                    remaining_pool = other_team
                player = remaining_pool.random()
            elif self.current_event.event_type == 'goal':
                if self.unique_coactors:
                    remaining_pool = other_team - self.chosen_actors
                    logger.debug(f"Remaining pool: {[a.id for a in remaining_pool]}")
                else:
                    # can't assist yourself, innit?
                    remaining_pool = own_team - self.current_event.actor.team
                player = remaining_pool.random()
            else:
                raise NotImplementedError()
            if self.unique_coactors:
                self.chosen_actors.append(player)
            return player
Beispiel #3
0
    def predict(self, entry: Entry) -> str:
        events = entry.qa['events']

        candidates = [
            str(a) if isinstance(a, int) else f"{a['first']} {a['last']}"
            for e in events
            for a in list(e['attributes'].values()) + [e['actor']]
        ]
        choices = Choices([c for c in candidates if c in entry.passage])

        return choices.random()
Beispiel #4
0
def generate_one_possible_template_choice(events: List[Event], templates, must_haves, has_template_attribute):
    if any(must_haves):
        must_have_per_event = Counter()
        for e, mh in zip(events, must_haves):
            et = e.event_type
            if mh:
                must_have_per_event[(et, mh)] += 1
        for (e, mh), needed in must_have_per_event.items():
            has = len([t for t in templates[e] if has_template_attribute(t, mh)])
            if not has >= needed:
                raise YouIdiotException(f"{e}.{mh} does not have enough templates! has: {has} needed: {needed} ")

        choices = defaultdict(list)
        # noinspection PyTypeChecker
        result: List[Tuple[str, int]] = [None] * len(events)
        # do the one with must_haves first
        for i, (event, must_have) in enumerate(zip(events, must_haves)):
            et = event.event_type
            logger.debug("Choices[et]", choices[et])
            if must_have:
                candidate_choices = [i for i, t in enumerate(templates[et])
                                     if has_template_attribute(t, must_have) and i not in choices[et]]
                logger.debug(f"Candidates: {candidate_choices}")
                choice = Choices(candidate_choices).random()
                assert choice is not None, must_haves
                logger.debug(f"Choice: {choice}")
                choices[et].append(choice)
                result[i] = (et, choice)
                logger.debug(f"Result: {result}")
        # do the others later
        for i, (event, must_have) in enumerate(zip(events, must_haves)):
            et = event.event_type
            logger.debug(f"Choices[et]: {choices[et]}")
            if not must_have:
                candidate_choices = [i for i, t in enumerate(templates[et])
                                     if i not in choices[et]]
                logger.debug(f"Candidates {candidate_choices}")
                choice = Choices(candidate_choices).random()
                assert choice is not None, must_haves
                choices[et].append(choice)
                result[i] = (et, choice)
        return result
    else:
        event_types = Counter()
        for e in events:
            event_types[e.event_type] += 1
        choice_iter = {e: iter(sample(range(len(templates[e])), n)) for e, n in event_types.items()}
        result = []
        for e in events:
            result.append((e.event_type, next(choice_iter[e.event_type])))
        return result
Beispiel #5
0
 def __init__(self, config, get_world: Callable[[], World],
              event_plan: EventPlan, modifier_types, *args, **kwargs):
     super().__init__(config, get_world, *args, **kwargs)
     self.same_actors_map = defaultdict(lambda: None)
     self.event_plan = event_plan
     self.modifier_type: Choices[str] = Choices(modifier_types).random()
     self.ordered_attribute_map = defaultdict(dict)
Beispiel #6
0
 def predict(self, entry: Entry) -> str:
     events = entry.qa['events']
     answer_is_numbers = any(d in entry.answer for d in string.digits)
     if answer_is_numbers:
         candidates = [
             str(a) for e in events for a in list(e['attributes'].values())
             if isinstance(a, int)
         ]
     else:
         candidates = [
             f"{a['first']} {a['last']}" for e in events
             for a in list(e['attributes'].values()) + [e['actor']]
             if isinstance(a, dict)
         ]
     choices = Choices([c for c in candidates if c in entry.passage])
     return choices.random()
Beispiel #7
0
 def set_actor(self):
     # check whether the currently processed event is the actual first non-modified one
     # if unique actors, the functionality is already implemented by base generation
     if self._is_current_event_first_nonmodified_event(
     ) and not self.unique_actors:
         # if so, select an actor that did not appear in any modified event before the actual event
         modified_actors = [
             sent.actor for sent in self.sentences
             if sent.event_type in self.modify_event_type
             and self._is_event_modified(sent)
         ]
         self.current_event.actor = Choices([
             p for p in self.get_actor_choices() if p not in modified_actors
         ]).random()
     else:
         super().set_actor()
Beispiel #8
0
class FootballGenerator(StoryGenerator):
    EVENT_TYPES = Choices(['goal', 'foul'])
    ATTRIBUTES = Choices(['time', 'distance', 'coactor'])

    CAUSES = Choices(['error', 'run', 'freekick'])
    EFFECTS = Choices(['penalty'])

    POSITIONS = Choices(['forward', 'defender', 'midfielder'])
    world: FootballWorld

    def __init__(self, config, get_world=FootballWorld,
                 team_names: str = 'stresstest/football/resources/team-names.json', *args,
                 **kwargs):
        logger.debug(f"{FootballGenerator.__name__} entering constructor")
        logger.debug(fmt_dict(locals()))
        super().__init__(config, FootballWorld, *args, **kwargs)
        logger.debug(f"{team_names}")
        self.team_names = Config(team_names)
        unique_coactors = config.get('unique_coactors', None)
        if unique_coactors is None:
            self.unique_coactors = self.unique_actors
        else:
            self.unique_coactors = unique_coactors
        logger.debug(f"{FootballGenerator.__name__} finish")

    def do_set_world(self):
        num_players = self.cfg.get("world.num_players", 11)
        gender = self.cfg.get("world.gender", True)
        self.world.gender = self.world.FEMALE if gender else self.world.MALE

        t1_first = self.team_names.as_choices("first").random()
        t1_second = self.team_names.as_choices("second").random()

        t2_first = (self.team_names.as_choices("first") - t1_first).random()
        t2_second = (self.team_names.as_choices("second") - t1_second).random()

        self.world.teams = (
            Team(**{
                "id": "team1",
                "name": " ".join((t1_first, t1_second))
            }),
            Team(**{
                "id": "team2",
                "name": " ".join((t2_first, t2_second))

            })
        )

        self.world.num_players = num_players
        self.world.players = []
        self.world.players_by_id = dict()
        # TODO: unique names (actually non unique would be funny too)
        if self.unique_actors:
            if self.world.num_players < self.world.num_sentences:
                raise YouIdiotException(f"Can't have less players ({self.world.num_players}) "
                                        f"than sentences ({self.world.num_sentences}) if choosing uniquely for actor!")
            elif self.unique_coactors and self.world.num_players < 2 * self.world.num_sentences:
                raise YouIdiotException(f"Can't have less than (4 * players) (you have {self.world.num_players}) "
                                        f"than sentences ({self.world.num_sentences}) if choosing uniquely for "
                                        "actor and coactor!")
        for i in range(1, num_players + 1):
            assert self.world.gender == 'female'
            p1 = Player(**{
                "id": f"player{i}",
                "first": cached_names[f'first:{self.world.gender}'].random(),
                # names.get_first_name(self.world.gender),
                "last": cached_names[f'last'].random(),  # names.get_last_name(),
                'team': self.world.teams[0],
                "position": self.POSITIONS.random()
            })
            p2 = Player(**{
                "id": f"player{i + num_players}",
                "first": names.get_first_name(self.world.gender),
                "last": names.get_last_name(),
                'team': self.world.teams[1],
                "position": self.POSITIONS.random()
            })
            self.world.players.extend((p1, p2))
            self.world.players_by_id[p1.id] = p1
            self.world.players_by_id[p2.id] = p2

    def get_actor_choices(self) -> Choices:
        return Choices(self.world.players)

    def filter_attributes(self, choices):
        if self.current_event.event_type == 'foul':
            choices = choices - ['distance']
        return choices

    def create_attribute(self, name):
        if name == 'distance':
            return random.choice(list(range(11, 35)))

        if name == 'time':
            last_ts = 0
            for sentence in self.sentences[::-1]:
                last_ts = sentence.attributes.get("time", 0)
                if last_ts:
                    break
            m = 3
            # rv = expon(scale=20)
            # TODO: if too slow, change to linear...
            if last_ts >= 91 - m:
                return last_ts + 1
            # p = [rv.pdf(x) for x in range(last_ts + 1, 90)]
            # m = 91 - last_ts
            # t = 5
            # p2 = [-m*x+t-last_ts for x in range(last_ts + 1, 90)]
            # sum_p = sum(p)
            # sum_p_2 = sum(p2)
            # p2_norm = [x / sum_p_2 for x in p2]
            # p_norm = [x / sum_p for x in p]

            b = (90 - last_ts) / m
            p = [-m * x + (90 - last_ts) + (0.5 * b) for x in range(1, int(b))] + \
                [-(1 / m) * x + b for x in range(int(b), 90 - last_ts)]
            p_norm = [x / sum(p) for x in p]

            return random.choices(list(range(last_ts + 1, 90)), weights=p_norm, k=1)[0]

        if name == 'coactor':
            logger.debug(f"Chosen Actors: {[a.id for a in self.chosen_actors]}")
            own_team = Choices(p for p in self.world.players if p.team != self.current_event.actor.team)
            other_team = Choices(p for p in self.world.players if p.team == self.current_event.actor.team)
            if self.current_event.event_type == 'foul':
                if self.unique_coactors:
                    remaining_pool = other_team - self.chosen_actors
                    logger.debug(f"Remaining pool: {[a.id for a in remaining_pool]}")
                else:
                    remaining_pool = other_team
                player = remaining_pool.random()
            elif self.current_event.event_type == 'goal':
                if self.unique_coactors:
                    remaining_pool = other_team - self.chosen_actors
                    logger.debug(f"Remaining pool: {[a.id for a in remaining_pool]}")
                else:
                    # can't assist yourself, innit?
                    remaining_pool = own_team - self.current_event.actor.team
                player = remaining_pool.random()
            else:
                raise NotImplementedError()
            if self.unique_coactors:
                self.chosen_actors.append(player)
            return player

    def post_process_attribute_answers(self, attribute_name, attribute_value):
        if attribute_name == 'coactor':
            return " ".join((attribute_value.first, attribute_value.last))
        return attribute_value

    def post_process_actor_answer(self, actor: Player):
        return " ".join((actor.first, actor.last))
Beispiel #9
0
 def get_actor_choices(self) -> Choices:
     return Choices(self.world.players)
Beispiel #10
0
import names
from names import FILES
from loguru import logger

from stresstest.classes import Choices, Config, YouIdiotException
from stresstest.football.classes import Team, Player, FootballWorld
from stresstest.generator import StoryGenerator
from stresstest.print_utils import fmt_dict


def _load_names(file):
    with open(file) as nf:
        return [line.split()[0].capitalize() for line in nf.readlines()]


cached_names = {k: Choices(_load_names(v)) for k, v in FILES.items()}


class FootballGenerator(StoryGenerator):
    EVENT_TYPES = Choices(['goal', 'foul'])
    ATTRIBUTES = Choices(['time', 'distance', 'coactor'])

    CAUSES = Choices(['error', 'run', 'freekick'])
    EFFECTS = Choices(['penalty'])

    POSITIONS = Choices(['forward', 'defender', 'midfielder'])
    world: FootballWorld

    def __init__(self, config, get_world=FootballWorld,
                 team_names: str = 'stresstest/football/resources/team-names.json', *args,
                 **kwargs):