# -*- coding: utf-8 -*-
"""
:Author: Dominic Hunt
:Reference: Jumping to conclusions: a network model predicts schizophrenic patients’ performance on a probabilistic reasoning task.
`Moore, S. C., & Sellen, J. L. (2006)`.
Cognitive, Affective & Behavioral Neuroscience, 6(4), 261–9.
Retrieved from http://www.ncbi.nlm.nih.gov/pubmed/17458441
"""
import numpy as np
from tasks.taskTemplate import Task
from model.modelTemplate import Stimulus, Rewards
# Bead Sequences:
beadSequences = {"MooreSellen": [1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0]}
defaultBeads = beadSequences["MooreSellen"]
[docs]class Beads(Task):
"""Based on the Moore & Sellen Beads 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
----------
N : int, optional
Number of beads that could potentially be shown
beadSequence : list or array of {0,1}, optional
The sequence of beads to be shown. Bead sequences can also be embedded
in the code and then referred to by name. The only current one is
`MooreSellen`, the default sequence.
"""
def __init__(self, N=None, beadSequence=defaultBeads):
super(Beads, self).__init__()
if isinstance(beadSequence, str):
if beadSequence in beadSequences:
self.beads = beadSequences[beadSequence]
else:
raise Exception("Unknown bead sequence")
else:
self.beads = beadSequence
if N:
self.T = N
else:
self.T = len(self.beads)
self.parameters["N"] = self.T
self.parameters["beadSequence"] = self.beads
# Set trialstep count
self.t = -1
# Recording variables
self.recBeads = [-1]*self.T
self.recAction = [-1]*self.T
self.firstDecision = 0
def __next__(self):
""" Produces the next bead for the iterator
Returns
-------
bead : {0,1}
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
self.storeState()
nextStim = self.beads[self.t]
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.recAction[self.t] = action
if action and not self.firstDecision:
self.firstDecision = self.t + 1
[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["Observables"] = np.array(self.recBeads)
results["Actions"] = self.recAction
results["FirstDecision"] = self.firstDecision
return results
[docs] def storeState(self):
"""
Stores the state of all the important variables so that they can be
output later
"""
self.recBeads[self.t] = self.beads[self.t]
[docs]def generateSequence(numBeads, oneProb, switchProb):
"""
Designed to generate a sequence of beads with a probability of switching
jar at any time.
Parameters
----------
numBeads : int
The number of beads in the sequence
oneProb : float in ``[0,1]``
The probability of a 1 from the first jar. This is also the probability
of a 0 from the second jar.
switchProb : float in ``[0,1]``
The probability that the drawn beads change the jar they are being
drawn from
Returns
-------
sequence : list of ``{0,1}``
The generated sequence of beads
"""
sequence = np.zeros(numBeads)
probs = np.random.rand(numBeads, 2)
bead = 1
for i in range(numBeads):
if probs[i, 1] < switchProb:
bead = 1-bead
if probs[i, 0] < oneProb:
sequence[i] = bead
else:
sequence[i] = 1-bead
return sequence
[docs]class StimulusBeadDirect(Stimulus):
"""
Processes the beads stimuli for models expecting just the event
"""
[docs] def processStimulus(self, observation):
"""
Processes the decks stimuli for models expecting just the event
Returns
-------
stimuliPresent : int or list of int
stimuliActivity : float or list of float
"""
return 1, observation
[docs]class StimulusBeadDualDirect(Stimulus):
"""
Processes the beads stimuli for models expecting a tuple of ``[event,1-event]``
"""
[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
"""
stimulus = np.array([observation, 1-observation])
return 1, stimulus
[docs]class StimulusBeadDualInfo(Stimulus):
"""
Processes the beads stimuli for models expecting the reward information
from two possible actions
Parameters
----------
oneProb : float in ``[0,1]``
The probability of a 1 from the first jar. This is also the probability
of a 0 from the second jar. ``event_info`` is calculated as
``oneProb*event + (1-oneProb)*(1-event)``
"""
oneProb = [0, 1]
[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
"""
stim = self.oneProb*observation + (1-self.oneProb)*(1-observation)
stimulus = np.array([stim, 1-stim])
return 1, stimulus
[docs]class RewardBeadDirect(Rewards):
"""
Processes the beads reward for models expecting just the reward
"""
[docs] def processFeedback(self, feedback, lastAction, stimuli):
"""
Returns
-------
modelFeedback:
"""
return feedback