diff --git a/generators/nb_gm_004.py b/generators/nb_gm_004.py index bbac64f..5c0d43f 100644 --- a/generators/nb_gm_004.py +++ b/generators/nb_gm_004.py @@ -3,21 +3,31 @@ class SequenceGenerator: - """nb_gm_003 - Generates a sequence of trials with even distribution of stimuli. - """ + """Generate a sequence progressively according to a predefined TL ratio and an even distribution""" - def __init__(self, choices, trials, n=3, targets_ratio=0.33): - self.trials, self.choices, self.n, self.targets_ratio = trials, choices, n, targets_ratio - self.seq = [] + def __init__(self, choices, trials, tl=4.0, n=3, targets_ratio=0.33): + """Initialize the genetic algorithm optimizer for n-back sequences. + :param choices: + :param trials: + :param tl: + :param n: + """ + self.tl, self.trials, self.choices, self.n, self.targets_ratio = tl, trials, choices, n, targets_ratio + self.sequence = list() self.norm_even_dist = scipy.stats.norm(0, trials/2) self.norm_targets_ratio_dist = scipy.stats.norm(targets_ratio, 0.5) + self.norm_tl_ratio_dist = scipy.stats.norm(tl, trials/2) def generate(self): - print('next') - while not self.seq or len(self.seq) < self.trials: - self.seq = self.__find_best_next_sequence(self.seq, self.choices) - return self.seq + while not self.sequence or len(self.sequence) < self.trials: + self.sequence = self.__find_best_next_sequence(self.sequence, self.choices) + return self.sequence + + def next_trial(self): + if self.sequence and len(self.sequence) >= self.trials: + return None + self.sequence = self.__find_best_next_sequence(self.sequence, self.choices) + return self.sequence[-1] def __find_best_next_sequence(self, seq: list, choices: list) -> list: import sys @@ -26,20 +36,24 @@ random.shuffle(choices) # to avoid ordering effect for choice in choices: tmp_seq = seq + list(choice) - cost = self.__cost(tmp_seq) + cost = self.cost(tmp_seq) if cost < min_cost: min_cost = cost best_seq = tmp_seq return best_seq - def __even_distribution_cost(self, seq): + def calc_even_distribution_distance(self, seq): + """ + Calculate fitness according to the similarity to the desired uniform distribution. + :param seq: a string + :return: + """ costs = {c: 0.0 for c in self.choices} for c in list(seq): costs[c] += (1.0 if costs.__contains__(c) else 0.0) even_ratio = self.trials / len(self.choices) costs = {k: abs(v - even_ratio)/self.trials for k, v in costs.items()} - max_cost = max(list(costs.values())) - return 1.0 - self.norm_even_dist.pdf(max_cost) + return max(list(costs.values())) def cost(self, seq): """ @@ -77,14 +91,15 @@ def __generate_stat_csv(filename): alphabetic_choices = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] - trials = 24 + trials = 64 n = 2 import csv import heapq with open(filename, mode='w') as stat_dist_file: writer = csv.writer(stat_dist_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL) writer.writerow(['index'] + alphabetic_choices + ['ralph_skewed']) - for i in range(100): + for i in range(10): + print(f'generating sequence {i}...') generator = SequenceGenerator(alphabetic_choices, n=n, trials=trials) seq = generator.generate() dist = [float(seq.count(c)) for c in alphabetic_choices] @@ -93,4 +108,4 @@ if __name__ == '__main__': - __generate_stat_csv('../stat/nb_gm_003_2back_24trials.csv') + __generate_stat_csv('../stat/progressive_random_2back_24trials.csv')