import random
import scipy.stats
import benchmarks.common as common
class SequenceGenerator:
"""nb_gm_005:
- pseudo-random sampling.
- fixed number of targets,lures, and distractors.
- all stimuli presented equally as target, lure, or distractor.
"""
def __init__(
self,
choices,
n
):
self.trials, self.targets_ratio, self.choices, self.n = None, None, choices, n
self.seq = []
# create norm distributions for cost functions
self.skewness_norm = None
self.lures_ratio_norm = None
self.targets_ratio_norm = None
def reset(self, trials, targets, lures):
self.trials = trials
self.targets_ratio_norm = scipy.stats.norm(targets/trials, 0.2)
self.lures_ratio_norm = scipy.stats.norm(lures/trials, 0.2)
self.skewness_norm = scipy.stats.norm(0 , trials/len(self.choices))
print(self.skewness_norm.pdf(0))
print(self.targets_ratio_norm.pdf(1.0/3.0))
print(self.lures_ratio_norm.pdf(1.0/6.0))
self.seq = []
def generate(self, trials, targets, lures):
self.reset(trials, targets, lures)
while not self.seq or len(self.seq) < self.trials:
#self.seq += self.best_choice()
chunk_size = 3 if len(self.seq) + 3 <= self.trials else self.trials-len(self.seq)
self.seq += self.best_chunk(chunk_size)
return self.seq
def best_chunk(self, chunk_size) -> list:
from itertools import permutations
min_cost, best_chunk = None, None
best_chunk_size = min(len(self.choices), chunk_size)
chunks = list(permutations(self.choices, best_chunk_size))
random.shuffle(chunks)
for chunk in chunks:
cost = self.cost(self.seq + list(chunk))
if min_cost is None or cost < min_cost:
min_cost, best_chunk = cost, chunk
return list(best_chunk)
def best_choice(self) -> list:
best_choice, min_cost = None, None
random.shuffle(self.choices) # to avoid ordering effect
for choice in self.choices:
cost = self.cost(self.seq + [choice])
if min_cost is None or cost < min_cost:
min_cost, best_choice = cost, choice
return [best_choice]
def cost(self, seq):
targets, lures = common.count_targets_and_lures(seq, n)
targets_ratio, lures_ratio = targets/len(seq), lures/len(seq)
c1, c2, c3 = self.skewness_cost(seq), self.targets_cost(targets_ratio), self.lures_cost(lures_ratio)
# print(c1,c2,c3)
return c1+c2+c3
def skewness_cost(self, seq):
even_ratio = self.trials / len(self.choices)
costs = {c: abs(seq.count(c) - even_ratio) for c in self.choices}
max_deviation_from_even_dist = max(list(costs.values()))
return 1.0 - self.skewness_norm.pdf(max_deviation_from_even_dist)
def targets_cost(self, targets_ratio):
return 1.0 - self.targets_ratio_norm.pdf(targets_ratio)
def lures_cost(self, lures_ratio) -> float:
return 1.0 - self.lures_ratio_norm.pdf(lures_ratio)
if __name__ == '__main__':
import time
import numpy as np
trials, targets, lures = 24, 8, 4
choices = ['1', '2', '3', '4', '5', '6', '7', '8']
print('alg,n,trials,time,targets,lures')
for s in range(1, common.sample_size):
n = np.random.randint(2, 8)
gen = SequenceGenerator(choices, n)
st = time.time()
s = gen.generate(trials, targets, lures)
st = time.time() - st
t, l = common.count_targets_and_lures(s, n)
print(f"nb_gm_004,{n},{trials},{st:0.2f},{t},{l}")