Commit db90d6c8 authored by Julian Kosciessa's avatar Julian Kosciessa
Browse files

final state MR version YA; timestamp 171024

parent 7793d825
%% initialize
if ispc
pn.root = ['D:',filesep,'Dokumente und Einstellungen',filesep,'guest',filesep,'Desktop',filesep,'StateSwitchMR',filesep,'C_Paradigm',filesep];
else
disp('Setup no supported.');
pn.root = ['/Users/kosciessa/Desktop/StateSwitchMR/C_Paradigm/'];
end
pn.CB = [pn.root, 'checker',filesep]; addpath(pn.CB);
pn.MAT = [pn.root, 'dotsx',filesep]; addpath(pn.MAT);
pn.SS = [pn.root, 'StateSwitch',filesep]; addpath(pn.SS);
pn.Stroop = [pn.root, 'Stroop',filesep]; addpath(pn.Stroop);
addpath(genpath([pn.root, 'functions',filesep]));
addpath(genpath([pn.root, 'helper',filesep]));
if ispc
addpath(['C:',filesep,'toolbox',filesep,'Psychtoolbox']); % PTB 3.0.11
else
addpath(genpath('/Users/Shared/Psychtoolbox/')); % PTB 3.0.13 (160606)
end
if ispc
Screen('Preference', 'SkipSyncTests', 0);
else
Screen('Preference', 'SkipSyncTests', 1);
oldLevel = Screen('Preference', 'Verbosity', 4); % output debugging info
PsychDebugWindowConfiguration(0,0.3)
end
%% pre-randomize data for MR experiment
for ind1 = 1:2
for ind2 = 1:3
for ind3 = 1:99
if numel(num2str(ind3)) == 1
ind3_conv = ['0', num2str(ind3)];
else ind3_conv = num2str(ind3);
end
ID = [num2str(ind1), num2str(ind2), ind3_conv]; disp(ID);
% create randomization
expInfo = []; expInfo = eval(['StateSwitch_createExpInfo_dynamic_170922']);
% save randomization
save([pn.root,'expInfo_MR/', ID, '_expInfo.mat'], 'expInfo');
end
end
end
% TO DO: indicate correct keys
\ No newline at end of file
function StateSwitch_addSurroundingCues_dynamic(expInfo, screenInfo, indRun, indBlock, indTrial)
% adds the surrounding cues for the next flip
for indAtt = 1:4
CueImg = ['img',filesep, expInfo.MAT.attNames{indAtt},'Q.png'];
[cueLoad,~,~] = imread(CueImg);
cue2Disp = Screen('MakeTexture',screenInfo.curWindow,cueLoad);
smallIm = [0 0 floor(size(cueLoad,2)/1.5) floor(size(cueLoad,1)/1.5)];
switch indAtt
case 1
smallIm = CenterRect([0 0 floor(size(cueLoad,2)/1.5) floor(size(cueLoad,1)/1.5)], [0 0 screenInfo.screenRect(3)/2 screenInfo.screenRect(4)/2]);
case 2
smallIm = CenterRect([0 0 floor(size(cueLoad,2)/1.5) floor(size(cueLoad,1)/1.5)], [screenInfo.screenRect(3)/2 0 screenInfo.screenRect(3) screenInfo.screenRect(4)/2]);
case 3
smallIm = CenterRect([0 0 floor(size(cueLoad,2)/1.5) floor(size(cueLoad,1)/1.5)], [0 screenInfo.screenRect(4)/2 screenInfo.screenRect(3)/2 screenInfo.screenRect(4)]);
case 4
smallIm = CenterRect([0 0 floor(size(cueLoad,2)/1.5) floor(size(cueLoad,1)/1.5)], [screenInfo.screenRect(3)/2 screenInfo.screenRect(4)/2 screenInfo.screenRect(3) screenInfo.screenRect(4)]);
end
if ismember(indAtt, expInfo.AttCuesRun{indRun}{indBlock,indTrial})
Screen('DrawTexture', screenInfo.curWindow, cue2Disp, [], smallIm); % draw the object
end
end
end
\ No newline at end of file
......@@ -10,7 +10,7 @@ function StateSwitch_addSurroundingCues_dynamic_170911(expInfo, screenInfo, indR
[cueLoad,~,~] = imread(CueImg);
cue2Disp = Screen('MakeTexture',screenInfo.curWindow,cueLoad);
posScale1 = 10;
posScale2 = 8;
posScale2 = 7; % use 7 for MR, use 8 for EEG
smallIm = [0 0 floor(posScale1*size(cueLoad,2)) floor(posScale2*size(cueLoad,1))];
x1 = screenInfo.screenRect(3);
x2 = screenInfo.screenRect(4);
......
function StateSwitch_addSurroundingCues_words(expInfo, screenInfo, indRun, indBlock, indTrial)
% adds the surrounding cues for the next flip
% expInfo.Cues = {'Tier?'; 'einsilbig?'; 'gerade?'; 'H?'};
for indAtt = 1:4
switch indAtt
case 1
smallIm = [0 0 screenInfo.screenRect(3)/2 screenInfo.screenRect(4)/2];
case 2
smallIm = [screenInfo.screenRect(3)/2 0 screenInfo.screenRect(3) screenInfo.screenRect(4)/2];
case 3
smallIm = [0 screenInfo.screenRect(4)/2 screenInfo.screenRect(3)/2 screenInfo.screenRect(4)];
case 4
smallIm = [screenInfo.screenRect(3)/2 screenInfo.screenRect(4)/2 screenInfo.screenRect(3) screenInfo.screenRect(4)];
end
if ismember(indAtt, expInfo.AttCuesRun{indRun}{indBlock,indTrial})
oldTextSize = Screen('TextSize', screenInfo.curWindow, 30);
DrawFormattedText(screenInfo.curWindow, expInfo.Cues{indAtt}, 'center', 'center', [], [], [],[],[],[],smallIm);
Screen('TextSize', screenInfo.curWindow, oldTextSize); clear oldTextSize;
end
end
end
\ No newline at end of file
% 171023 | located the word cues centrally
function StateSwitch_addSurroundingCues_words_171023(expInfo, screenInfo, indRun, indBlock, indTrial)
% adds the surrounding cues for the next flip
% expInfo.Cues = {'Tier?'; 'einsilbig?'; 'gerade?'; 'H?'};
for indAtt = 1:4
posScale1 = 10;
posScale2 = 7; % use 7 for MR, use 8 for EEG
x1 = screenInfo.screenRect(3);
x2 = screenInfo.screenRect(4);
coords(1,:) = [.5*x1-(1/posScale1)*x1, .5*x2-(1/posScale2)*x2, .5*x1, .5*x2];
coords(2,:) = [.5*x1, .5*x2-(1/posScale2)*x2, .5*x1+(1/posScale1)*x1, .5*x2];
coords(3,:) = [.5*x1-(1/posScale1)*x1, .5*x2, .5*x1, .5*x2+(1/posScale2)*x2];
coords(4,:) = [.5*x1, .5*x2, .5*x1+(1/posScale1)*x1, .5*x2+(1/posScale2)*x2];
% switch indAtt
% case 1
% smallIm = CenterRect([0 0 floor(size(cueLoad,2)/1.5) floor(size(cueLoad,1)/1.5)], coords(1,:));
% case 2
% smallIm = CenterRect([0 0 floor(size(cueLoad,2)/1.5) floor(size(cueLoad,1)/1.5)], coords(2,:));
% case 3
% smallIm = CenterRect([0 0 floor(size(cueLoad,2)/1.5) floor(size(cueLoad,1)/1.5)], coords(3,:));
% case 4
% smallIm = CenterRect([0 0 floor(size(cueLoad,2)/1.5) floor(size(cueLoad,1)/1.5)], coords(4,:));
% end
if ismember(indAtt, expInfo.AttCuesRun{indRun}{indBlock,indTrial})
oldTextSize = Screen('TextSize', screenInfo.curWindow, 30);
DrawFormattedText(screenInfo.curWindow, expInfo.Cues{indAtt}, 'center', 'center', [], [], [],[],[],[],coords(indAtt,:));
Screen('TextSize', screenInfo.curWindow, oldTextSize); clear oldTextSize;
end
end
end
\ No newline at end of file
%_______________________________________________________________________
%
% Configuration for running dotsExperiment
%_______________________________________________________________________
%
% Output
%
% expInfo | configuration for state switch MAT (struct)
% Written by Julian Kosciessa (kosciessa@mpib-berlin.mpg.de)
% 170704 - incorporated thresholds
% 170809 - incorporated state dimensionality & accompanying
% randomization changes
% 170814 - introduce run format; adapted timing
% 170816 - changed to expInfo format; fixed randomization
% 170823 - changed randomization to account for switch probability
% 170829 - included RT feedback
function expInfo = StateSwitch_createExpInfo_dynamic_170829
expInfo.trialsPerAtt = 16; % number of trials within state order & attribute (half of this for each choice)
expInfo.numOfAtt = 4; % number of attributes to be included
expInfo.numOrders = 4;
expInfo.totalTrials = expInfo.trialsPerAtt*expInfo.numOfAtt*expInfo.numOrders;
%expInfo.runAmount = 4; % number of runs; each run should have each category x times
expInfo.durBlockOnset = 5; % duration of block onset
expInfo.durFixCue = 2; % duration of fixcross with cues
expInfo.durCue = 0; % duration of cue
expInfo.durPres = 3; % duration of presentation
expInfo.durResp = 2; % duration of question
expInfo.durConf = 0; % duration of confidence
expInfo.durReward = 3; % duration of reward
expInfo.durITI = 2; % duration of ITI
expInfo.timing = 'relativeITI';
expInfo.trialDuration.all = expInfo.durFixCue+expInfo.durPres+expInfo.durResp+expInfo.durConf+expInfo.durITI;
expInfo.trialDuration.durFixCue = expInfo.durFixCue;
expInfo.trialDuration.Pres = expInfo.durFixCue+expInfo.durPres;
expInfo.trialDuration.Resp = expInfo.durFixCue+expInfo.durPres+expInfo.durResp;
expInfo.trialDuration.Conf = expInfo.durFixCue+expInfo.durPres+expInfo.durResp+expInfo.durConf;
expInfo.confOptions = '2'; % 2 or 4 confidence options
expInfo.highlightChoice = 1; % highlight choice by retaining only chosen option?
expInfo.feedback = 0; % no feedback
expInfo.dirSet = [180, 0]; % dots in left or right direction
expInfo.numDotField = 1; % show a single dot patches on screen
expInfo.apXYD = [0 0 130]; % coordinates and diameter of aperture
expInfo.speed = [50]; % speed of dot motion
expInfo.trialtype = [2 1 1]; % reaction time, not relevant, keyboard
expInfo.dotSize = 3; % dot size in pixels
expInfo.maxDotTime = 2; % maximum duration of moving dots
expInfo.fixXY = [0 0]; % fixation coordinates
expInfo.fixDiam = 2; % fixation diameter
expInfo.fixColor = [0 150 200]; % blue fixation dot
expInfo.fixMinTime = 0.75; % minimum fixation
expInfo.fixMaxTime = 1.25; % maximum fixation
%expInfo.maxDotsPerFrame = 300; % depends on graphics card
expInfo.fixTime = 2; % JQK: fixed onset fixation time
expInfo.DotsPerFrame = 48*3;
expInfo.breakTime = 60; % pause for 60 seconds between runs
% update frequency of on-screen content
expInfo.Hz_RDM = 30; % kinematogram updates in Hz
% multi-attribute task
expInfo.MAT.percAtt1H = .60;
expInfo.MAT.percAtt2H = .60;
expInfo.MAT.percAtt3H = .65;
expInfo.MAT.percAtt4H = .65;
expInfo.MAT.percAtt1L = 1-expInfo.MAT.percAtt1H;
expInfo.MAT.percAtt2L = 1-expInfo.MAT.percAtt2H;
expInfo.MAT.percAtt3L = 1-expInfo.MAT.percAtt3H;
expInfo.MAT.percAtt4L = 1-expInfo.MAT.percAtt4H;
%expInfo.MAT.color = [255 255 255; 255 0 0]; % define dot color
%expInfo.MAT.color = [177,213,57; 234,35,93]; % define dot color
% saturated & muted
expInfo.MAT.color = [174,205,96; 203,117,143];
expInfo.MAT.color1 = [174,205,96; 203,117,143]; % define dot color
expInfo.MAT.color2 = [177,213,57; 234,35,93]; % green first, then red
% % light & dark
% expInfo.MAT.color = [222,235,151; 241,147,186];
% expInfo.MAT.color1 = [222,235,151; 241,147,186]; % define dot color
% expInfo.MAT.color2 = [125,155,64; 160,26,67];
%
%expInfo.MAT.coherence = 1; % define dot movement (coherence)
expInfo.MAT.coherence = .65; % define dot movement (coherence)
expInfo.MAT.direction = [180 0]; % left and right
expInfo.MAT.size = [5 8]; % define dot size
expInfo.MAT.saturation = [1,2]; % define dot luminance
expInfo.MAT.attNames = {'color'; 'direction'; 'size'; 'saturation'};
expInfo.MAT.attNamesDE = {'Farbe'; 'Richtung'; 'Gre'; 'Sttigung'};
%% feedback
expInfo.RTfeedback.reward = 20;
expInfo.RTfeedback.loss = 0;
expInfo.RTfeedback.slack = .2; % seconds allowed below median RT
expInfo.RTfeedback.type = 'fixed'; % 'fixed' vs. 'RT'
expInfo.RTfeedback.fixedFeedback = [ones(1,25), zeros(1,7)];
expInfo.RTfeedback.fixedFeedback = expInfo.RTfeedback.fixedFeedback(randperm(32));
expInfo.RTfeedback.fixedFeedback = reshape(expInfo.RTfeedback.fixedFeedback, [], 4)';
%% specify keys
% Use OS X keyboard naming scheme across all plattforms
% Otherwise LeftControl/RightControl are not recognized
KbName('UnifyKeyNames');
expInfo.keyLeft = [KbName('LeftControl'), KbName('LeftAlt'), KbName('LeftArrow'), KbName('1!'),KbName('2@')]; % left response
expInfo.keyRight = [KbName('RightControl'), KbName('RightAlt'), KbName('RightArrow'),KbName('6^'),KbName('7&')]; % right response
expInfo.keyConf1 = [KbName('LeftControl'), KbName('LeftArrow'), KbName('1!')]; % lowest confidence
expInfo.keyConf2 = [KbName('LeftAlt'), KbName('2@')]; % intermediate confidence low
expInfo.keyConf3 = [KbName('RightAlt'),KbName('6^')]; % intermediate confidence high
expInfo.keyConf4 = [KbName('RightControl'), KbName('RightArrow'),KbName('7&')]; % highest confidence
expInfo.keyModifier = KbName('LeftAlt'); % to prevent accidental input
expInfo.keyEscape = KbName('Escape'); %
expInfo.keyReturn = [KbName('Return'), KbName('7&')]; % continue experiment
expInfo.keyPause = KbName('p');
%% randomize stimuli and non-target duration
% set random seed
rseed = sum(100*clock);
rng(rseed,'twister');
[expInfo.rngSetting] = rng;
%% Here we need to decide the following settings:
% 1. How many attribute dimensions (i.e. state manipulation)? [block-wise to avoid 'meta-four state']
% 2. Which attributes to be chosen? Same in each block?
% 3. Which target in each trial?
% 4. Which option of the attribute is winning?
%% decide cueing state order (1/2/3/4) & higher probability choice (within attribute)
expInfo.blockLengthDim = 8; % amount of consecutive trials belonging to the same state dimension block; needs to be a multiple of 4
expInfo.blockAmount = (expInfo.trialsPerAtt*expInfo.numOfAtt*expInfo.numOrders)/expInfo.blockLengthDim; % amount of blocks (i.e. determined by total trial count and block length)
expInfo.blocksPerOrd = expInfo.blockAmount/expInfo.numOrders; % amount of blocks per state dimension
expInfo.StateOrder = NaN(expInfo.blockAmount, expInfo.blockLengthDim); % prelim. matrix for state dimension order
expInfo.AttCues = cell(expInfo.blockAmount, expInfo.blockLengthDim); % prelim. cell struc for attribute cues
expInfo.targetAtt = NaN(expInfo.blockAmount, expInfo.blockLengthDim); % prelim. matrix for target attribute
expInfo.targetOption = NaN(expInfo.blockAmount, expInfo.blockLengthDim); % prelim. matrix for target option
expInfo.HighProbChoice = cell(expInfo.blockAmount, expInfo.blockLengthDim); % prelim. cell struc for winning options
expInfo.blockTime = expInfo.durBlockOnset+expInfo.blockLengthDim*...
(expInfo.durCue+expInfo.durPres+expInfo.durResp+expInfo.durConf+expInfo.durReward+expInfo.durITI);
% get amounts of runs to achieve approx. 10 min per run
%expInfo.runAmount = ceil(expInfo.blockAmount*expInfo.blockTime/60/10);
expInfo.runAmount = expInfo.blocksPerOrd/2; % now 4 runs! rather go for many runs vs. not including many breaks
expInfo.blocksPerRun = 8;
% Pseudo-randomize the block order, i.e. allowing for repeting dimension blocks.
% This is performed run-wise, such that each run contains a single
% block of each state order. We also make sure that there are no
% adjacent repeats of dimension blocks.
criterion = 0;
while criterion == 0
allCombsBlocks = perms([1,2,3,4]);
chosenBlockOrders = randperm(size(allCombsBlocks,1),expInfo.blocksPerRun); % have two dimension blocks each iteration
blockDimOrder = reshape(allCombsBlocks(chosenBlockOrders,:)',[],1);
if min(abs(diff(blockDimOrder))) ~= 0 % check that there are no repeats
criterion = 1;
end
end
expInfo.StateOrder = repmat(blockDimOrder,1,expInfo.blockLengthDim); % final state order output for presentation
% blockDimOrder = repmat(1:4,1,16); tmp_rand = randperm(expInfo.blockAmount);
% blockDimOrder = blockDimOrder(tmp_rand);
% expInfo.StateOrder = repmat(blockDimOrder', 1, expInfo.blockLengthDim); % final state order output for presentation
% get combinatorials for attribute cues for each dimension order
for indOrd = 1:expInfo.numOrders
combsDim{indOrd} = nchoosek([1:expInfo.numOfAtt], indOrd); % 4, 6, 4, 1
end
for indOrd = 1:expInfo.numOrders
tmp_blocks = find(blockDimOrder == indOrd);
tmp_blockCues = repmat(combsDim{indOrd},floor(numel(tmp_blocks)/size(combsDim{indOrd},1)),1);
if indOrd == 2 % there are 6 options, hence add two more; important: add all attributes 1-4!
tmp_blockCues = [tmp_blockCues; combsDim{indOrd}(1,:); combsDim{indOrd}(end,:)];
end
rand.blockCues(indOrd,:) = randperm(size(tmp_blockCues,1));
for indBlock = 1:numel(tmp_blocks)
expInfo.AttCues(tmp_blocks(indBlock),:) = {tmp_blockCues(rand.blockCues(indOrd,indBlock),:)}; % encode attribute cues
end
end
%% determine target attribute
% The logic here is the following: We now have blocks, in which the
% same state order and the same attribute targets are presented. Now,
% wihtin those attribute options, but across blocks, we choose trials
% such that each target attribute will occur the same number of times
% within-order (but not necessarily within-cue combination or block).
% Then we also choose half of the target attribute trials randomly and
% allocate them to the target option (i.e. red/white), such that these
% are also matched in amount within-attribute. The target attribute
% matching is done based on the groups of cue conjunctions.
% Note that the current procedure does no make sure, that e.g. every
% option occurs within each cue block.
indCatch = [];
for indOrd = 1:4
disp(num2str(indOrd));
Splits = [];
% for all attributes, get location of the dimension trials among all trials
% trial attributes are assigned among these
for indAtt = 1:4
index = cellfun(@(x) ismember(indAtt,x), expInfo.AttCues(blockDimOrder==indOrd,:), 'UniformOutput', 0);
indCatch{indOrd, indAtt} = find(cell2mat(index));
end
if indOrd == 1
idxCurrentOrder = find(expInfo.StateOrder == indOrd); % indexes trials of current state order
[row, ~] = ind2sub(size(expInfo.targetAtt),idxCurrentOrder); row = unique(row);
expInfo.targetAtt(row,:) = repmat(cell2mat(expInfo.AttCues(row,1)),1,8);
end
if indOrd == 2
Splits{1} = intersect(indCatch{indOrd, 1}, indCatch{indOrd, 2}); % 1 1 0 0
Splits{2} = intersect(indCatch{indOrd, 2}, indCatch{indOrd, 3}); % 0 1 1 0
Splits{3} = intersect(indCatch{indOrd, 2}, indCatch{indOrd, 4}); % 0 1 0 1
Splits{4} = intersect(indCatch{indOrd, 3}, indCatch{indOrd, 4}); % 0 0 1 1
Splits{5} = intersect(indCatch{indOrd, 1}, indCatch{indOrd, 3}); % 1 0 1 0
Splits{6} = intersect(indCatch{indOrd, 1}, indCatch{indOrd, 4}); % 1 0 0 1
extractMat = [1 1 0 0; 0 1 1 0; 0 1 0 1; 0 0 1 1; 1 0 1 0; 1 0 0 1];
end
if indOrd == 3
Splits{1} = intersect(intersect(indCatch{indOrd, 1}, indCatch{indOrd, 2}), indCatch{indOrd, 3}); % 1 2 1 0
Splits{2} = intersect(intersect(indCatch{indOrd, 2}, indCatch{indOrd, 3}), indCatch{indOrd, 4}); % 0 1 2 1
Splits{3} = intersect(intersect(indCatch{indOrd, 1}, indCatch{indOrd, 3}), indCatch{indOrd, 4}); % 1 0 1 2
Splits{4} = intersect(intersect(indCatch{indOrd, 1}, indCatch{indOrd, 2}), indCatch{indOrd, 4}); % 2 1 0 1
% split into four groups to distribute (unequally)
extractMat = [1,2,1,0; 0,1,2,1; 1,0,1,2; 2,1,0,1]; % amount of quartets to be extracted; row: triplet, column: attribute
% Note that due to the fixed allocation, there will always be
% an imbalance of the attributes within each cue condition.
end % 3 state dimension
if indOrd == 4
splitVec = [1:64/4:numel(indCatch{indOrd, 1}), 65]; % create artificial splits to help pseudo-randomisation
for indSplit = 1:4
selectTrials = sub2ind(size(expInfo.AttCues(blockDimOrder==indOrd,:)), ...
[repmat(((indSplit-1)*2+1),8,1); repmat(((indSplit-1)*2+2),8,1)], [1:8, 1:8]');
Splits{indSplit} = selectTrials;
extractMat = [1,1,1,1; 1,1,1,1; 1,1,1,1; 1,1,1,1];
end;
end
%% fix switch probability & select attribute targets
if ismember(indOrd, [2:4])
for indSplit = 1:numel(Splits)
check = 0;
while check == 0 % try to find pseudo-randomization that works
try
% pseudo-randomize to start block with no-switch
% have a maximum of 3 repetitions (i.e. 4 identical trials)
while check == 0
switchVec = [zeros(1,.5*numel(Splits{indSplit})),ones(1,.5*numel(Splits{indSplit}))];
switchVec_rand = randperm(numel(switchVec));
switchVec = switchVec(switchVec_rand);
% check for repetitions
A = switchVec';
J = find(diff([A(1)-1; A]));
if max(diff([J; numel(A)+1])) <= 3 & A(1:8:end)==0
check = 1;
end
end
% fill with attributes:
% sequential allocation without replacement
% start with most numerous option
if indOrd == 4
availableOptions = repelem([1:4], 4.*extractMat(indSplit,:));
mostCommon = find(extractMat(indSplit,:)==1);
mostCommon = mostCommon(1);
elseif indOrd == 3
availableOptions = repelem([1:4], 4.*extractMat(indSplit,:));
mostCommon = find(extractMat(indSplit,:)==2);
elseif indOrd == 2
availableOptions = repelem([1:4], numel(Splits{indSplit})/2.*extractMat(indSplit,:));
mostCommon = find(extractMat(indSplit,:)==1);
mostCommon = mostCommon(1);
end
tmp_availableCats = unique(availableOptions);
switchVec_atts = NaN(1,numel(availableOptions));
for indTrial = 1:numel(switchVec)
if switchVec(indTrial) == 0 & indTrial == 1
switchVec_atts(indTrial) = mostCommon;
elseif switchVec(indTrial) == 0
switchVec_atts(indTrial) = switchVec_atts(indTrial-1);
elseif switchVec(indTrial) == 1
lastAnwer = switchVec_atts(indTrial-1);
nextItem = find(tmp_availableCats>lastAnwer);
if isempty(nextItem)
nextItem = tmp_availableCats(1);
else nextItem = tmp_availableCats(nextItem(1));
end
switchVec_atts(indTrial) = nextItem;
end
% remove last encoded from list (i.e. choose without replacement)
tmp_cur = find(availableOptions == switchVec_atts(indTrial));
availableOptions(tmp_cur(1)) = [];
end
catch % if randomization does not work out, start again ...
check = 0;
end % try
end % while
% randomize order of chunks within each block
tmp_randBlocks = reshape(switchVec_atts,8,[])';
for rowInd = 1:size(tmp_randBlocks,1)
tmp_split = SplitVec(tmp_randBlocks(rowInd,:));
tmp_split_length = sort(SplitVec(tmp_randBlocks(rowInd,:), 'equal','length'),'ascend');
check = 0;
while check == 0 % make sure nothing changes to the number of chunks
tmp_split2 = tmp_split(randperm(numel(tmp_split)));
tmp_split2_length = sort(SplitVec([cell2mat(tmp_split2)], 'equal','length'),'ascend');
if isequal(tmp_split_length, tmp_split2_length)
check = 1;
tmp_randBlocks(rowInd,:) = [cell2mat(tmp_split2)];
end
end
end
% allocate attributes to trials
idxCurrentOrder = find(expInfo.StateOrder == indOrd); % indexes trials of current state order
[row, ~] = ind2sub(size(expInfo.targetAtt),idxCurrentOrder(Splits{indSplit}));
row = unique(row);
expInfo.targetAtt(row,:) = tmp_randBlocks;
end % split loop
end
%% determine target choice
% for each attribute, randomize within-order, which option will be the winner
for indAttribute = 1:4
idxCurrentOrder = find(expInfo.StateOrder == indOrd);
tmp_curTrials = find(expInfo.targetAtt(idxCurrentOrder) == indAttribute);
tmp_curTrialsPerm = reshape(tmp_curTrials(randperm(numel(tmp_curTrials))),2,[]);
expInfo.targetOption(idxCurrentOrder(tmp_curTrialsPerm(1,:))) = 1;
expInfo.targetOption(idxCurrentOrder(tmp_curTrialsPerm(2,:))) = 2;
end; clear tmp*
end % state order loop
%% make sure that each block has all cue options occuring
% This would mess up the transition probability slightly, but it is
% rare that a correction is necessary anyways.
check = zeros(size(expInfo.targetAtt,1),2); % index, whether block fulfills requirements
while min(check(:,1)) == 0 % while matching is not done, go through all blocks again
for indBlock = 1:size(expInfo.targetAtt,1)
% check whether all cued trials are available
TransProb.cuedOptions = expInfo.AttCues{indBlock,1};
while check(indBlock,1) == 0
TransProb.availOptions = unique(expInfo.targetAtt(indBlock,:));
TransProb.missingOptions = setdiff(TransProb.cuedOptions, TransProb.availOptions);
if isempty(TransProb.missingOptions) % all options available
check(indBlock,1) = 1;
else % not all options available
disp('Not all options occur. Readjusting ...')
warning('You should re-check transition probabilities.')
check(indBlock,1) = 0;
% exchange most frequent option with another trial
% sort available options in their order of frequency
[tmp_histn,~]=histcounts(expInfo.targetAtt(indBlock,:));
[~, tmp_sort_histn] = sort(tmp_histn(tmp_histn~=0), 'descend');
TransProb.availOptions = TransProb.availOptions(tmp_sort_histn);
% get trials of current state order (only exchange within
% order!!!) & missing attribute
TransProb.relevantTrials = expInfo.StateOrder == expInfo.StateOrder(indBlock,1) & expInfo.targetAtt == TransProb.missingOptions(1);
% buffer targetAtt & targetOption of the to-be-swapped trials
TransProb.tAttGo_avail = find(expInfo.targetAtt(indBlock,:)==TransProb.availOptions(1));
TransProb.tAttGoIdx = TransProb.tAttGo_avail(randperm(numel(TransProb.tAttGo_avail),1));
TransProb.tAttGoIdx = sub2ind(size(expInfo.targetAtt), indBlock, TransProb.tAttGoIdx); % convert to linear index
TransProb.tAttGoAtt = expInfo.targetAtt(TransProb.tAttGoIdx);
TransProb.tAttGoOpt = expInfo.targetOption(TransProb.tAttGoIdx);
TransProb.tAttGet_avail = find(TransProb.relevantTrials);
TransProb.tAttGetIdx = TransProb.tAttGet_avail(randperm(numel(TransProb.tAttGet_avail),1));
TransProb.tAttGetAtt = expInfo.targetAtt(TransProb.tAttGetIdx);
TransProb.tAttGetOpt = expInfo.targetOption(TransProb.tAttGetIdx);
% do the switch
expInfo.targetAtt(TransProb.tAttGoIdx) = TransProb.tAttGetAtt;
expInfo.targetAtt(TransProb.tAttGetIdx) = TransProb.tAttGoAtt;
expInfo.targetOption(TransProb.tAttGoIdx) = TransProb.tAttGetOpt;
expInfo.targetOption(TransProb.tAttGetIdx) = TransProb.tAttGoOpt;
end
end
end
end; clear TransProb tmp*;
% figure; subplot(1,2,1); imagesc(expInfo.targetAtt); subplot(1,2,2); imagesc(expInfo.StateOrder);
%% sanity check transition probability, number of presented attributes
for indDim = 1:4
idxCurrentOrder = find(expInfo.StateOrder(:,1) == indDim);