Newer
Older
adaptive-nback / py / even_random_generator.py
from constraint import *

class EvenRandomGenerator:
    """Generate even random sequences according to a predefined TL ration (Ralph, 2014)"""

    def __init__(self, choices, trials=64, tl=1):
        self.tl, self.trials, self.choices = tl, trials, choices

    def generate(self):
        seq = self._generate_initial_sequence()
        return self._optimize_sequence(seq)

    def _generate_initial_sequence(self):
        """
            Generates initial sequence of items based on choices and number of desired trials.
            In EvenRandom sequences, all stimuli have same number of appearances.
        """
        num_of_each_choice = int(self.trials / len(self.choices))
        seq = []
        for c in self.choices:
            seq.append([c for t in range(num_of_each_choice)])

        # if it's too short, add some new items
        if len(seq) < self.trials:
            seq += [self.choices[-1] for t in range(self.trials-len(seq))]

        return seq

    def _optimize_sequence(self, seq, tl_ratio):
        """Optimize a sequence to match a desired tl ratio"""

        p = Problem()

        # TODO add all possible values for seq (its domain)
        p.addVariable("seq", [seq])

        p.addConstraint(lambda s: self.calculate_tl_ratio(s) - tl_ratio < 0.05)

        return seq

    @staticmethod
    def calculate_tl_ratio(seq):
        """Calculates the T:L ratio of a sequence."""
        targets = 0
        lures = 0
        for index, item in seq:
            if item == seq[index-2]:
                targets += 1
            elif item == seq[index-1] or item == seq[index-3]:
                lures += 1
        # avoid division by zero
        if lures == 0:
            lures = 1
        return targets/lures


if __name__ == '__main__':
    generator = EvenRandomGenerator(['a','b','c'])
    generated_seq = generator.generate()
    print('Even Random Sequence: %s' % ''.join(generated_seq))