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

import itertools as it

import Numberjack as nj

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):
        seqs = self._generate_initial_sequences()
        return self._find_optimal_sequence(seqs, 0.2)

    def _generate_initial_sequences(self):
        """
            Generates initial sequence of items based on choices and number of desired trials.
            In EvenRandom sequences, all stimuli have same number of appearances.
        """

        pool = it.product(self.choices, repeat=self.trials)
        return pool

    def _find_optimal_sequence_numberjack(self,tl_ratio):
        """Optimize with Numberjack"""

        cost = nj.Variable(0, 100, 'cost')
        seqs = nj.Variable([]) # all sequences

        model = nj.Model(
            seqs.,
            cost == self.calculate_tl_ratio(seq) - tl_ratio,
            nj.Minimise(cost)
        )
        solver = model.load('Mistral')
        if solver.solve():
            solver.printStatistics()
        else:
            print("No solution with Numberjack")


    def _find_optimal_sequence(self, sequences, tl_ratio):
        """Optimize a sequence to match a desired tl ratio with python-constraints"""

        p = Problem()

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

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

        return p.getSolution()

    @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'], trials = 4)
    generated_seq = generator.generate()
    print('Even Random Sequence: %s' % ''.join(generated_seq))