<commit_before>from collections import OrderedDict
import collections
from disclosuregame.results import Result
import itertools

class Measures(object):
    def __init__(self, measures, dump_after=0, dump_every=25):
        self.measures = measures
        self.dump_after = dump_after
        self.dump_every = dump_every

    def add(self, other):
        """
        Add the measures defined in the other measure object to this one.
        """
        self.measures.update(other.measures)

    def keys(self):
        return self.measures.keys()

    def values(self):
        return self.measures.values()

    def dump(self, women, rounds, game, results=None):
        """
        A results dumper. Takes a tuple of a game and players, and two dictionaries.
        Measures should contain a mapping from a field name to method for getting a result
        given an appointment, set of players, and a game. Params should contain mappings
        from parameter names to values.
        Optionally takes an exist results object to add records to. This should have the same
        measures and params.
        Returns a results object for writing to csv.
        """
        if results is None:
            results = Result(self.measures.keys(), game.parameters, [])
        if women is None:
            return results
        line = map(lambda x: x.measure(rounds, women, game), self.measures.values())
        if rounds >= self.dump_after and (rounds % self.dump_every == 0 or rounds == (game.rounds - 1)):
            results.add_results(Result(self.measures.keys(), game.parameters, [line]))
        return results

# Measures

class Measure(object):
    def __init__(self, player_type=None, midwife_type=None, signal=None):
        self.player_type = player_type
        self.midwife_type = midwife_type
        self.signal = signal

    def filter_present(self, women, roundnum):
        """
        Filter out any women not present on this round.
        """
        women = filter(lambda x: x.started < roundnum, women)
        women = filter(lambda x: x.finished > roundnum, women)
        return women


class NumRounds(Measure):
    """
    Return the average number of rounds a player played before finishing.
    """
    def measure(self, roundnum, women, game):
        if self.player_type is not None:
            women = filter(lambda x: x.player_type == self.player_type, women)
        women = filter(lambda x: x.is_finished, women)
        if len(women) == 0:
            return 0.
        return sum(map(lambda woman: woman.finished - woman.started, women)) / float(len(women))


class NumRoundsCumulative(Measure):
    def __init__(self, player_type=None, midwife_type=None, signal=None, counted=set()):
        super(NumRoundsCumulative, self).__init__(player_type, midwife_type, signal)
        self.count = 0
        self.rounds = 0.
        self.counted = counted

    """
    Return the cumulative average number of rounds played by a type.
    """
    def measure(self, roundnum, women, game):
        if self.player_type is not None:
            women = filter(lambda x: x.player_type == self.player_type, women)
        women = filter(lambda x: x.is_finished, women)

        women = filter(lambda x: hash(x) not in self.counted, women)
        self.counted.update(map(hash, women))
        self.count += len(women)
        self.rounds += sum(map(lambda woman: woman.finished - woman.started, women))
        if self.count == 0:
            return 0.
        return self.rounds / self.count


class Referred(Measure):
    """
    Return the fraction of players referred this round.
    """

    def measure(self, roundnum, women, game):
        return len(filter(lambda x: 1 in x.get_memory()[1][2], women)) / float(len(women))

class Appointment(Measure):
    def measure(self, roundnum, women, game):
        """
        Return the value passed as roundnum.
        """
        return roundnum

class TypeFinished(Measure):
    """
    Return the fraction of women of a particular type who finished this round.
    """
    def measure(self, roundnum, women, game):
        if self.player_type is not None:
            women = filter(lambda x: x.player_type == self.player_type, women)
        num_women = float(len(women))
        num_finished = len(filter(lambda x: x.is_finished, women))
        if num_women == 0:
            return 0.
        return num_finished / num_women


class TypeSignalBreakdown(Measure):
    """
    Return a function that yields the fraction of women of some type signalling
    a particular way who had a midwife of a particular type in the last round.
    """
    def measure(self, roundnum, women, game):
        if self.player_type is not None:
            women = filter(lambda x: x.player_type == self.player_type, women)
        if self.midwife_type is not None:
            women = filter(lambda x: x.get_memory()[1][0][len(x.get_memory()[1][0]) - 1] == self.midwife_type, women)
        num_women = float(len(women))

        women = filter(lambda x: x.get_memory()[1][1][len(x.get_memory()[1][1]) - 1] == self.signal, women)
        signalled = len(women)
        if num_women == 0:
            return 0.
        return signalled / num_women
    

class TypeReferralBreakdown(Measure):
    """
    Return a function that yields the fraction of women of some type signalling
    a particular way who had a midwife of a particular type and got referred.
    If signal is None, then this is for all signals.
    If midwife_type is None, then this is for all midwife types.
    """
    def measure(self, roundnum, women, game):
        if self.player_type is not None:
            women = filter(lambda x: x.player_type == self.player_type, women)
        if self.midwife_type is not None:
            women = filter(lambda x: x.get_memory()[1][0][len(x.get_memory()[1][0]) - 1] == self.midwife_type, women)
        if self.signal is not None:
            women = filter(lambda x: x.get_memory()[1][1][len(x.get_memory()[1][1]) - 1] == self.signal, women)
        num_women = float(len(women))
        women = filter(lambda x: 1 in x.get_memory()[1][2], women)
        signalled = len(women)
        if num_women == 0:
            return 0.
        return signalled / num_women

class PayoffType(Measure):
    """
    Return a function that gives the average payoff in the last
    round for a given type. If type is None, then the average
    for all types is returned.
    """
    def measure(self, roundnum, women, game):
        if self.player_type is not None:
            women = filter(lambda x: x.player_type == self.player_type, women)
        if len(women) == 0:
            return 0.
        return sum(map(lambda x: x.payoff_log[len(x.payoff_log)], women)) / float(len(women))
    

class SignalChange(Measure):
    """
    Return a function that yields average change in signal
    by women this round from last round.
    """
    def measure(self, roundnum, women, game):
        if roundnum == 0:
            return 0.
        women = filter(lambda x: x.player_type == self.player_type, women)
        num_women = len(women)
        if num_women == 0:
            return 0.
        change = map(lambda x: x.get_memory()[1][1][roundnum - x.started] - x.get_memory()[1][1][roundnum - 1 - x.started], women)
        return sum(change) / float(num_women)
    

class SignalRisk(Measure):
    """
    Return a function that gives the average risk associated
    with sending signal by players of this type who had that<commit_msg>Memory pollution again<commit_after>from collections import OrderedDict
import collections
from disclosuregame.results import Result
import itertools

class Measures(object):
    def __init__(self, measures, dump_after=0, dump_every=25):
        self.measures = measures
        self.dump_after = dump_after
        self.dump_every = dump_every

    def add(self, other):
        """
        Add the measures defined in the other measure object to this one.
        """
        self.measures.update(other.measures)

    def keys(self):
        return self.measures.keys()

    def values(self):
        return self.measures.values()

    def dump(self, women, rounds, game, results=None):
        """
        A results dumper. Takes a tuple of a game and players, and two dictionaries.
        Measures should contain a mapping from a field name to method for getting a result
        given an appointment, set of players, and a game. Params should contain mappings
        from parameter names to values.
        Optionally takes an exist results object to add records to. This should have the same
        measures and params.
        Returns a results object for writing to csv.
        """
        if results is None:
            results = Result(self.measures.keys(), game.parameters, [])
        if women is None:
            return results
        line = map(lambda x: x.measure(rounds, women, game), self.measures.values())
        if rounds >= self.dump_after and (rounds % self.dump_every == 0 or rounds == (game.rounds - 1)):
            results.add_results(Result(self.measures.keys(), game.parameters, [line]))
        return results

# Measures

class Measure(object):
    def __init__(self, player_type=None, midwife_type=None, signal=None):
        self.player_type = player_type
        self.midwife_type = midwife_type
        self.signal = signal

    def filter_present(self, women, roundnum):
        """
        Filter out any women not present on this round.
        """
        women = filter(lambda x: x.started < roundnum, women)
        women = filter(lambda x: x.finished > roundnum, women)
        return women


class NumRounds(Measure):
    """
    Return the average number of rounds a player played before finishing.
    """
    def measure(self, roundnum, women, game):
        if self.player_type is not None:
            women = filter(lambda x: x.player_type == self.player_type, women)
        women = filter(lambda x: x.is_finished, women)
        if len(women) == 0:
            return 0.
        return sum(map(lambda woman: woman.finished - woman.started, women)) / float(len(women))


class NumRoundsCumulative(Measure):
    def __init__(self, player_type=None, midwife_type=None, signal=None, counted=set()):
        super(NumRoundsCumulative, self).__init__(player_type, midwife_type, signal)
        self.count = 0
        self.rounds = 0.
        self.counted = counted

    """
    Return the cumulative average number of rounds played by a type.
    """
    def measure(self, roundnum, women, game):
        if self.player_type is not None:
            women = filter(lambda x: x.player_type == self.player_type, women)
        women = filter(lambda x: x.is_finished, women)

        women = filter(lambda x: hash(x) not in self.counted, women)
        self.counted.update(map(hash, women))
        self.count += len(women)
        self.rounds += sum(map(lambda woman: woman.finished - woman.started, women))
        if self.count == 0:
            return 0.
        return self.rounds / self.count


class Referred(Measure):
    """
    Return the fraction of players referred this round.
    """

    def measure(self, roundnum, women, game):
        return len(filter(lambda x: 1 in x.get_memory()[1][2], women)) / float(len(women))

class Appointment(Measure):
    def measure(self, roundnum, women, game):
        """
        Return the value passed as roundnum.
        """
        return roundnum

class TypeFinished(Measure):
    """
    Return the fraction of women of a particular type who finished this round.
    """
    def measure(self, roundnum, women, game):
        if self.player_type is not None:
            women = filter(lambda x: x.player_type == self.player_type, women)
        num_women = float(len(women))
        num_finished = len(filter(lambda x: x.is_finished, women))
        if num_women == 0:
            return 0.
        return num_finished / num_women


class TypeSignalBreakdown(Measure):
    """
    Return a function that yields the fraction of women of some type signalling
    a particular way who had a midwife of a particular type in the last round.
    """
    def measure(self, roundnum, women, game):
        if self.player_type is not None:
            women = filter(lambda x: x.player_type == self.player_type, women)
        if self.midwife_type is not None:
            women = filter(lambda x: x.get_memory()[1][0][len(x.get_memory()[1][0]) - 1] == self.midwife_type, women)
        num_women = float(len(women))

        women = filter(lambda x: x.get_memory()[1][1][len(x.get_memory()[1][1]) - 1] == self.signal, women)
        signalled = len(women)
        if num_women == 0:
            return 0.
        return signalled / num_women
    

class TypeReferralBreakdown(Measure):
    """
    Return a function that yields the fraction of women of some type signalling
    a particular way who had a midwife of a particular type and got referred.
    If signal is None, then this is for all signals.
    If midwife_type is None, then this is for all midwife types.
    """
    def measure(self, roundnum, women, game):
        if self.player_type is not None:
            women = filter(lambda x: x.player_type == self.player_type, women)
        if self.midwife_type is not None:
            women = filter(lambda x: x.get_memory()[1][0][len(x.get_memory()[1][0]) - 1] == self.midwife_type, women)
        if self.signal is not None:
            women = filter(lambda x: x.get_memory()[1][1][len(x.get_memory()[1][1]) - 1] == self.signal, women)
        num_women = float(len(women))
        women = filter(lambda x: 1 in x.get_memory()[1][2], women)
        signalled = len(women)
        if num_women == 0:
            return 0.
        return signalled / num_women

class PayoffType(Measure):
    """
    Return a function that gives the average payoff in the last
    round for a given type. If type is None, then the average
    for all types is returned.
    """
    def measure(self, roundnum, women, game):
        if self.player_type is not None:
            women = filter(lambda x: x.player_type == self.player_type, women)
        if len(women) == 0:
            return 0.
        try:
            result = sum(map(lambda x: x.get_memory()[1][3][len(x.get_memory()[1][3])], women)) / float(len(women))
        except AttributeError:
            result = sum(map(lambda x: x.payoff_log[len(x.payoff_log)], women)) / float(len(women))
        return result
    

class SignalChange(Measure):
    """
    Return a function that yields average change in signal
    by women this round from last round.
    """
    def measure(self, roundnum, women, game):
        if roundnum == 0:
            return 0.
        women = filter(lambda x: x.player_type == self.player_type, women)
        num_women = len(women)
        if num_women == 0:
            return 0.
        change = map(lambda x: x.get_memory()[1][1][roundnum - x.started] - x.get_memory()[1][1][roundnum - 1 - x.started], women)
        return sum(change) / float(num_women)
    

class SignalRisk(Measure):
    """
    Return a function that gives the average risk associated
    with sending signal by players of this type who had that
{'fraction_non_alphanumeric': 0.10266009852216748, 'fraction_numerical': 0.0073563218390804595, 'mean_word_length': 2.5442271880819365, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1767647', 'n_tokens_mistral': 4520, 'n_tokens_neox': 4300, 'n_words': 1470}