diff --git a/README.md b/README.md index a24051a..623d3e4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# N-Back Sequence Generator with [Hidden] Markov Chain +# N-Back Sequence Generators **Note #1:** It's a work in progress (WIP), and commits will be tagged with WIP if it's not expected to work! @@ -7,7 +7,9 @@ ## Compile/Build -To build code and compile use `sbt compile` and `sbt build`. It's recommended to use `sbt clean` before running any of these commands :-). +All python classes include scripts to manage executing a sample code. Just use `python ` to the sample codes of a generator. + +To build Scala codes and compile them use `sbt compile` and `sbt build`. It's recommended to use `sbt clean` before running any of these commands :-). ## Run diff --git a/README.md b/README.md index a24051a..623d3e4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# N-Back Sequence Generator with [Hidden] Markov Chain +# N-Back Sequence Generators **Note #1:** It's a work in progress (WIP), and commits will be tagged with WIP if it's not expected to work! @@ -7,7 +7,9 @@ ## Compile/Build -To build code and compile use `sbt compile` and `sbt build`. It's recommended to use `sbt clean` before running any of these commands :-). +All python classes include scripts to manage executing a sample code. Just use `python ` to the sample codes of a generator. + +To build Scala codes and compile them use `sbt compile` and `sbt build`. It's recommended to use `sbt clean` before running any of these commands :-). ## Run diff --git a/py/ga_optimized_random_generator.py b/py/ga_optimized_random_generator.py index c66d42d..4f2ef4c 100644 --- a/py/ga_optimized_random_generator.py +++ b/py/ga_optimized_random_generator.py @@ -5,9 +5,8 @@ class GAOptimizedRandomGenerator: """Generate even random sequences according to a predefined TL ration (Ralph, 2014)""" - def __init__(self, choices, trials=64, tl=1, pool_size=100, n=3): - """ - Initialize the genetic algorithm optimizer for n-back sequences. + def __init__(self, choices, trials, tl=2.0, pool_size=100, n=3): + """Initialize the genetic algorithm optimizer for n-back sequences. :param choices: :param trials: :param tl: @@ -19,32 +18,32 @@ self.__init_pool(pool_size) def generate(self): - """ - Generate a sequence of trials based on passed parameters. TL ratio and distribution are expected to be + """Generate a sequence of trials based on passed parameters. TL ratio and distribution are expected to be close to the desired ones but not exactly the same. :return: a sequence of items in "list" format. """ generation = 0 best_parent = self.__find_best_parents(1)[0] - while self.cost(best_parent) > 0.1 and generation < 10000: + while self.cost(best_parent) > 0.1 and generation < 1000: generation += 1 - self.pool = self.mutate() + if random.random() > 0.5: + self.pool = list(map(lambda s: self.mutate(s), self.pool)) self.pool = self.crossover_all() best_parent = self.__find_best_parents(1)[0] - print(best_parent, 'fitness=%f' % self.cost(best_parent)) + print(best_parent, 'cost=%f' % self.cost(best_parent)) return best_parent - def __init_pool(self, pool_size): + def __init_pool(self, pool_size) -> list: """ - - :param pool_size: DNA size or number of parents in the GA pool. - :return: A DNA or pool in list format. + Initialize solution pool. + :param pool_size: Num of initial random solutions + :return: initial pool of """ print("Initializing the pool...") self.pool.clear() all_comb = it.combinations_with_replacement(self.choices, self.trials) sample = random.sample(list(all_comb), pool_size) - self.pool.extend(map(lambda sampi: ''.join(sampi), sample)) + self.pool.extend(map(lambda _: ''.join(_), sample)) return self.pool def __find_best_parents(self, count=1): @@ -101,20 +100,24 @@ pos = random.randint(0, self.trials) return [seq1[:pos] + seq2[pos:], seq2[:pos] + seq1[pos:]] - def mutate(self): - # pass - return self.pool + def mutate(self, seq): + if random.random() > 0.5: + pos = random.randint(0, len(seq)-1) + seq_list = list(seq) + seq_list[pos] = random.choice(self.choices) + return ''.join(seq_list) + return seq @staticmethod - def calculate_tl_ratio(seq, N): + def calculate_tl_ratio(seq, n: int): """Calculates the T/L ratio in a block of trials.""" targets = 0.0 lures = 0.0 - for index in range(N, len(seq)): + for index in range(n, len(seq)): item = seq[index] - if item == seq[index - N]: + if item == seq[index - n]: targets += 1.0 - elif item == seq[index - (N-1)] or item == seq[index - (N+1)]: + elif item == seq[index - (n-1)] or item == seq[index - (n+1)]: lures += 1.0 if lures - 0.0 < 0.001: # avoid division by zero lures = 0.001 @@ -123,9 +126,9 @@ if __name__ == '__main__': - generator = GAOptimizedRandomGenerator(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'], trials=16) + generator = GAOptimizedRandomGenerator(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'], trials=16, n=2) sq = generator.generate() - tl_ratio = generator.calculate_tl_ratio(sq, 2) + tl_ratio = generator.calculate_tl_ratio(sq, n=2) even_dist = generator.even_dist_cost(sq) - print('GA-Optimized Sequence: %s' % sq, 'with tl_ratio=%f' % tl_ratio, 'and even_dist=%f' % even_dist) + print('GA-Optimized Sequence: %s' % sq, 'with tl_ratio=%f' % tl_ratio, 'and even_dist_cost=%f' % even_dist)