Source code for tasks.decks

# -*- coding: utf-8 -*-
"""
:Author: Dominic Hunt

:Reference: Regulatory fit effects in a choice task
                `Worthy, D. a, Maddox, W. T., & Markman, A. B. (2007)`.
                Psychonomic Bulletin & Review, 14(6), 1125–32.
                Retrieved from http://www.ncbi.nlm.nih.gov/pubmed/18229485
"""
import numpy as np

from tasks.taskTemplate import Task

from model.modelTemplate import Stimulus, Rewards

deckSets = {"WorthyMaddox": np.array([[2,  2,  1,  1,  2,  1,  1,  3,  2,  6,  2,  8,  1,  6,  2,  1,  1,
                                    5,  8,  5, 10, 10,  8,  3, 10,  7, 10,  8,  3,  4,  9, 10,  3,  6,
                                    3,  5, 10, 10, 10,  7,  3,  8,  5,  8,  6,  9,  4,  4,  4, 10,  6,
                                    4, 10,  3, 10,  5, 10,  3, 10, 10,  5,  4,  6, 10,  7,  7, 10, 10,
                                    10,  3,  1,  4,  1,  3,  1,  7,  1,  3,  1,  8],
                                   [7, 10,  5, 10,  6,  6, 10, 10, 10,  8,  4,  8, 10,  4,  9, 10,  8,
                                    6, 10, 10, 10,  4,  7, 10,  5, 10,  4, 10, 10,  9,  2,  9,  8, 10,
                                    7,  7,  1, 10,  2,  6,  4,  7,  2,  1,  1,  1,  7, 10,  1,  4,  2,
                                    1,  1,  1,  4,  1,  4,  1,  1,  1,  1,  3,  1,  4,  1,  1,  1,  5,
                                    1,  1,  1,  7,  2,  1,  2,  1,  4,  1,  4,  1]])}
defaultDecks = deckSets["WorthyMaddox"]


[docs]class Decks(Task): """ Based on the Worthy&Maddox 2007 paper "Regulatory fit effects in a choice task. Many methods are inherited from the tasks.taskTemplate.Task class. Refer to its documentation for missing methods. Attributes ---------- Name : string The name of the class used when recording what has been used. Parameters ---------- draws: int, optional Number of cards drawn by the participant decks: array of floats, optional The decks of cards discard: bool Defines if you discard the card not chosen or if you keep it. """ def __init__(self, draws=None, decks=defaultDecks, discard=False): super(Decks, self).__init__() self.discard = discard if isinstance(decks, str): if decks in deckSets: self.decks = deckSets[decks] else: raise Exception("Unknown deck sets") else: self.decks = decks if draws: self.T = draws else: self.T = len(self.decks[0]) self.parameters["Draws"] = self.T self.parameters["Discard"] = self.discard self.parameters["Decks"] = self.decks # Set draw count self.t = -1 self.cardValue = None self.action = None if self.discard: self.drawn = -1 else: self.drawn = [-1, -1] # Recording variables self.recCardVal = [-1]*self.T self.recAction = [-1]*self.T def __next__(self): """ Produces the next stimulus for the iterator Returns ------- stimulus : None nextValidActions : Tuple of ints or ``None`` The list of valid actions that the model can respond with. Set to (0,1), as they never vary. Raises ------ StopIteration """ self.t += 1 if self.t == self.T: raise StopIteration nextStim = None nextValidActions = (0, 1) return nextStim, nextValidActions
[docs] def receiveAction(self, action): """ Receives the next action from the participant Parameters ---------- action : int or string The action taken by the model """ self.action = action
[docs] def feedback(self): """ Responds to the action from the participant """ deckDrawn = self.action if self.discard: cardDrawn = self.drawn + 1 self.drawn = cardDrawn else: cardDrawn = self.drawn[deckDrawn] + 1 self.drawn[deckDrawn] = cardDrawn self.cardValue = self.decks[deckDrawn, cardDrawn] self.storeState() return self.cardValue
[docs] def proceed(self): """ Updates the task after feedback """ pass
[docs] def returnTaskState(self): """ Returns all the relevant data for this task run Returns ------- results : dictionary A dictionary containing the class parameters as well as the other useful data """ results = self.standardResultOutput() results["Actions"] = self.recAction results["cardValue"] = self.recCardVal results["finalDeckDraws"] = self.drawn return results
[docs] def storeState(self): """ Stores the state of all the important variables so that they can be output later """ self.recAction[self.t] = self.action self.recCardVal[self.t] = self.cardValue
[docs]class StimulusDecksLinear(Stimulus):
[docs] def processStimulus(self, observation): """ Processes the decks stimuli for models expecting just the event Returns ------- stimuliPresent : int or list of int The elements present of the stimulus stimuliActivity : float or list of float The activity of each of the elements """ return 1, 1
[docs]class RewardDecksLinear(Rewards): """ Processes the decks reward for models expecting just the reward """
[docs] def processFeedback(self, feedback, lastAction, stimuli): """ Returns ------- modelFeedback: """ return feedback
[docs]class RewardDecksNormalised(Rewards): """ Processes the decks reward for models expecting just the reward, but in range [0,1] Parameters ---------- maxReward : int, optional The highest value a reward can have. Default ``10`` See Also -------- model.OpAL """ maxReward = 10
[docs] def processFeedback(self, feedback, lastAction, stimuli): """ Returns ------- modelFeedback: """ return feedback / self.maxReward
[docs]class RewardDecksPhi(Rewards): """ Processes the decks reward for models expecting just the reward, but in range [0, 1] Parameters ---------- phi : float The scaling value of the reward """ phi = 1
[docs] def processFeedback(self, feedback, lastAction, stimuli): """ Returns ------- modelFeedback: """ return feedback * self.phi
[docs]class RewardDecksAllInfo(Rewards): """ Processes the decks reward for models expecting the reward information from all possible actions Parameters ---------- maxRewardVal : int The highest value a reward can have minRewardVal : int The lowest value a reward can have number_actions : int The number of actions the participant can perform. Assumes the lowest valued action is 0 Returns ------- deckRew : function The function expects to be passed a tuple containing the reward and the last action. The reward that is a float and action is {0,1}. The function returns a array of length (maxRewardVal-minRewardVal)*number_actions. Attributes ---------- Name : string The identifier of the function Examples -------- >>> rew = RewardDecksAllInfo(maxRewardVal=10, minRewardVal=1, number_actions=2) >>> rew.processFeedback(6, 0, 1) array([1., 1., 1., 1., 1., 2., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]) >>> rew.processFeedback(6, 1, 1) array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 2., 1., 1., 1., 1.]) """ maxRewardVal = 10 minRewardVal = 1 number_actions = 2
[docs] def processFeedback(self, reward, action, stimuli): """ Returns ------- modelFeedback: """ numDiffRewards = self.maxRewardVal - self.minRewardVal + 1 rewardProc = np.ones(numDiffRewards * self.number_actions) rewardProc[numDiffRewards*action + reward - 1] += 1 return rewardProc.T
[docs]class RewardDecksDualInfo(Rewards): """ Processes the decks reward for models expecting the reward information from two possible actions. """ maxRewardVal = 10 epsilon = 1
[docs] def processFeedback(self, reward, action, stimuli): """ Returns ------- modelFeedback: """ divisor = self.maxRewardVal + self.epsilon rew = (reward / divisor) * (1 - action) + (1 - (reward / divisor)) * action rewardProc = [[rew], [1-rew]] return np.array(rewardProc)
[docs]class RewardDecksDualInfoLogistic(Rewards): """ Processes the decks rewards for models expecting the reward information from two possible actions. """ maxRewardVal = 10 minRewardVal = 1 epsilon = 0.3
[docs] def processFeedback(self, reward, action, stimuli): """ Returns ------- modelFeedback: """ mid = (self.maxRewardVal + self.minRewardVal) / 2 x = np.exp(self.epsilon * (reward-mid)) rew = (x/(1+x))*(1-action) + (1-(x/(1+x)))*action rewardProc = [[rew], [1-rew]] return np.array(rewardProc)