def runMetropolis(chainIndex): import sys import os DIRNAME = os.path.dirname(__file__) sys.path.append(os.path.join(DIRNAME, "..", "..", "..", "src")) from LCA import PrepareRecurrentWeights, RunLCASimulation, GetValueInputZeroReference, \ getValueInput2Attributes2Choices from LUT import prepareStdNormalLUT, SampleFromLUT import numpy as np import time import pickle from scipy.stats import skew, truncnorm, chisquare # read observed data data = np.genfromtxt("unequalAttentionSimulatedData.csv", delimiter=',') allStakes = np.unique(data[:, -2:], axis=0) np.random.seed() LUTInterval = 0.0001 numAccumulators = 2 stdNormalLUT = prepareStdNormalLUT(LUTInterval) sampleFromLUT = SampleFromLUT(stdNormalLUT) sampleFromZeroMeanLUT = lambda stdDev: sampleFromLUT( 0, stdDev, numAccumulators) # set-up the LCA identityUtilityFunction = lambda x: x getValueInput = GetValueInputZeroReference(identityUtilityFunction) maxTimeSteps = 1000 deltaT = 0.02 prepareRecurrentWeights = PrepareRecurrentWeights(numAccumulators) lca = RunLCASimulation(getValueInput, sampleFromZeroMeanLUT, prepareRecurrentWeights, maxTimeSteps, deltaT) def getStartingActivation(startingBias, threshold): if startingBias < 0: return [-1 * startingBias * threshold, 0] else: return [0, startingBias * threshold] getChoiceAttributes = lambda gain, loss: np.array([[0, 0], [gain, loss]]) getAllThresholds = lambda threshold: [threshold] * numAccumulators attributeProbabilities = [0.5, 0.5] lcaWrapper = lambda gain, loss, decay, competition, noiseStdDev, nonDecisionTime, threshold, constantInput, startingBias: \ lca(attributeProbabilities, getChoiceAttributes(gain, loss), getStartingActivation(startingBias, threshold), decay, competition, constantInput, noiseStdDev, nonDecisionTime, getAllThresholds(threshold)) def selectConditionTrials(data, gain, loss): selectedData = data[data[:, 2] == gain][:] selectedData = selectedData[selectedData[:, 3] == loss][:] return selectedData def computePData(data, gain, loss): conditionTrialData = selectConditionTrials(data, gain, loss) responses = conditionTrialData[:, 0] return np.mean(responses) def computeRTStatsData(data, gain, loss, choice): conditionTrialData = selectConditionTrials(data, gain, loss) dataForThisChoice = conditionTrialData[conditionTrialData[:, 0] == choice] if np.shape(dataForThisChoice)[0] == 0: return (0, 0, 0) reactionTimes = dataForThisChoice[:, 1] return (np.mean(reactionTimes), np.std(reactionTimes), skew(reactionTimes)) def filterFunction(tup): if tup[-1] != -1: return True else: return False # define the cost function class CostFunction: def __init__(self, numSimulationsPerCondition, allStakes): self.numSimulationsPerCondition = numSimulationsPerCondition self.allStakes = allStakes def __call__(self, parameters): allModelData = np.zeros(4) for stakes in self.allStakes: gainValue, lossValue = stakes allSimulations = [ lcaWrapper(gainValue, lossValue, *parameters) for _ in range(self.numSimulationsPerCondition) ] allValidResponseSimulations = list( filter(filterFunction, allSimulations)) numValidResponses = len(allValidResponseSimulations) if numValidResponses < self.numSimulationsPerCondition / 3: return (-1, parameters[3]) _, allModelRTs, allModelResponses = zip( *allValidResponseSimulations) modelStakes = np.hstack((np.full( (numValidResponses, 1), gainValue), np.full((numValidResponses, 1), lossValue))) modelDataForStakes = np.hstack( (np.array(allModelResponses).reshape(-1, 1), np.array(allModelRTs).reshape(-1, 1), modelStakes)) allModelData = np.vstack((allModelData, modelDataForStakes)) allModelData = allModelData[1:, :] actualDataMeanRT = np.mean(data[:, 1]) simDataMeanRT = np.mean(allModelData[:, 1]) delta = simDataMeanRT - actualDataMeanRT if delta > parameters[3]: delta = parameters[3] allModelData[:, 1] = allModelData[:, 1] - delta totalCost = 0 quantiles = np.array([0.1, 0.3, 0.5, 0.7, 0.9]) # quantiles of the chi^2 function observedProportionsChoiceWise = np.array( [0.1, 0.2, 0.2, 0.2, 0.2, 0.1]) # this is to cover some edge cases for stakes in self.allStakes: # loop over all combinations of possible gain and loss gain, loss = stakes observedTrials = selectConditionTrials(data, gain, loss) numObservedTrials = np.shape(observedTrials)[0] modelTrials = selectConditionTrials(allModelData, gain, loss) numModelTrials = np.shape(modelTrials)[0] for choice in range( 2): # loop over choice = 0 (reject) and 1 (accept) observedTrialsForChoice = observedTrials[ observedTrials[:, 0] == choice] observedRTsForChoice = observedTrialsForChoice[:, 1] numObservedRTsForChoice = np.size(observedRTsForChoice) observedPOfThisChoice = numObservedRTsForChoice / numObservedTrials if numObservedRTsForChoice < 5: # less than 5 trials --> can't compute quantile boundaries continue # skip this combination of gain, loss, choice quantilesBoundaries = np.quantile(observedRTsForChoice, quantiles) observedProportions = \ np.histogram(observedRTsForChoice, bins=np.concatenate(([0], quantilesBoundaries, [100])))[ 0] / numObservedTrials # proportions of experimental RTs in all quantiles if numObservedRTsForChoice == 5 or 0 in observedProportions: # some edge cases observedProportions = observedProportionsChoiceWise * observedPOfThisChoice observedFrequencies = numObservedTrials * observedProportions modelTrialsForChoice = modelTrials[modelTrials[:, 0] == choice] modelRTsForChoice = modelTrialsForChoice[:, 1] numModelRTsForChoice = np.size(modelRTsForChoice) modelProportions = \ np.histogram(modelRTsForChoice, bins=np.concatenate(([0], quantilesBoundaries, [100])))[ 0] / numModelTrials modelFrequencies = numObservedTrials * modelProportions totalCost += chisquare(modelFrequencies, observedFrequencies)[0] return (totalCost, parameters[3] - delta) costFunction = CostFunction(75, allStakes) bounds = ( (0, 5), (0, 5), (0, 75), (0, 2), (0, 40), (0, 75), (-1, 0) ) # decay, competition, noiseStdDev, nonDecisionTime, threshold, constantInput, startingBias rangeOfParams = np.diff((np.array(bounds))).flatten() initialParameterVariance = rangeOfParams / (1.5 * numTotalChains) parameterVarianceMultiplier = np.full(np.shape(initialParameterVariance), 0.99) SAVE_DIRECTORY = 'savedModels/onlyStartingBias'.format(str(bounds)) if not os.path.exists(SAVE_DIRECTORY): os.makedirs(SAVE_DIRECTORY) SAVEFILE = os.path.join(SAVE_DIRECTORY, '{}.pickle'.format(str(chainIndex))) def pickleRecord(record): saveFile = open(SAVEFILE, 'wb') pickle.dump(record, saveFile) saveFile.close() def generateProposalParams(currentParams, variances): np.random.seed() newParams = [] for i in range(len(currentParams)): myclip_a = bounds[i][0] myclip_b = bounds[i][1] my_mean = currentParams[i] my_std = variances[i] if my_std == 0: newParam = my_mean else: a, b = (myclip_a - my_mean) / my_std, (myclip_b - my_mean) / my_std newParam = truncnorm.rvs(a, b, loc=my_mean, scale=my_std) newParams.append(newParam) return newParams try: saveFile = open(SAVEFILE, "rb") record = pickle.load(saveFile) bestParameters = record[-1, :-1] minimumCost = record[-1, -1] # print("Best parameters: ", bestParameters, " Best cost: ", minimumCost) numIterationsPrevious = np.shape(record)[0] # ("NumIterations: ", numIterationsPrevious) parameterVarianceMultiplier = parameterVarianceMultiplier**( numIterationsPrevious // 100) # print("Num Iterations: ", numIterationsPrevious, " Multiplier: ", parameterVarianceMultiplier) parameterVariance = np.multiply(initialParameterVariance, parameterVarianceMultiplier) except: numIterationsPrevious = 0 counter = 0 while True: print(counter) counter += 1 # initialParameterValues = generateProposalParams(meanStartingPointForSearch, initialParameterVariance) low, high = list(zip(*bounds)) initialParameterValues = np.random.RandomState().uniform(low, high) # print(initialParameterValues) initialCost, adjustedContTime = costFunction( initialParameterValues) if initialCost != -1: initialParameterValues[3] = adjustedContTime break print("Chain: ", chainIndex, "Initial value identified: ", initialParameterValues, " Cost: ", initialCost) bestParameters = initialParameterValues parameterVariance = np.asarray(initialParameterVariance) minimumCost = initialCost record = np.hstack((bestParameters, minimumCost)) pickleRecord(record) minimizationIteration = numIterationsPrevious pickleFlag = False while True: minimizationIteration += 1 startTime = time.time() # decrease the value of variance if minimizationIteration % 100 == 0 and minimizationIteration != 0: parameterVariance = parameterVarianceMultiplier * parameterVariance # propose new parameters newParameters = generateProposalParams(bestParameters, parameterVariance) # compute cost cost, adjustedNonDecisionTime = costFunction(newParameters) if cost != -1: # update parameters if cost < minimumCost: pickleFlag = True # print("updating parameters and cost") bestParameters = newParameters bestParameters[3] = adjustedNonDecisionTime minimumCost = cost else: pickleFlag = False # record best parameters iterationRecord = np.hstack((bestParameters, minimumCost)) record = np.vstack((record, iterationRecord)) if pickleFlag: pickleRecord(record) # time for iteration endTime = time.time() iterationTime = endTime - startTime # print("Iteration: {} Time: {}".format(minimizationIteration, iterationTime)) # print("Proposed Value of params: ", newParameters) # print("Best Value of params: ", bestParameters) # print("Cost: ", cost) # print("Best cost: ", minimumCost) # print("-------------------------------") print('Chain: {}, iteration: {}, Best cost: {}'.format( chainIndex, minimizationIteration, minimumCost))
allModelRTs = np.array(allModelRTs) modelStakes = np.hstack( (np.full((numValidResponses, 1), gainValue), np.full((numValidResponses, 1), lossValue))) modelDataForStakes = np.hstack( (np.array(allModelResponses).reshape(-1, 1), np.array(allModelRTs).reshape(-1, 1), modelStakes)) allModelData = np.vstack((allModelData, modelDataForStakes)) allModelData = allModelData[1:, :] return allModelData LUTInterval = 0.0001 numAccumulators = 2 stdNormalLUT = prepareStdNormalLUT(LUTInterval) sampleFromLUT = SampleFromLUT(stdNormalLUT) sampleFromZeroMeanLUT = lambda stdDev: sampleFromLUT(0, stdDev, numAccumulators ) # set-up the LCA identityUtilityFunction = lambda x: x getValueInput = GetValueInputZeroReference(identityUtilityFunction) maxTimeSteps = 1000 deltaT = 0.02 prepareRecurrentWeights = PrepareRecurrentWeights(numAccumulators) lca = RunLCASimulation(getValueInput, sampleFromZeroMeanLUT, prepareRecurrentWeights, maxTimeSteps, deltaT)