Skip to content
StateSwitch_createExpInfo_words_TEST_171023.m 28.9 KiB
Newer Older
Julian Kosciessa's avatar
Julian Kosciessa committed
%_______________________________________________________________________
%
% Configuration for running StateSwitch experiment
%_______________________________________________________________________
%
% Output
%
% expInfo | configuration for state switch word version (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    - created word randomization version, deleted dot entries
% 170821    - created practice version
% 170823    - changed randomization to account for switch probability
% 170829    - included RT feedback
% 171023    - replaced repelem with version working on older MATLAB versions
%           - draw stimuli from separate practice set
Julian Kosciessa's avatar
Julian Kosciessa committed

function expInfo = StateSwitch_createExpInfo_words_TEST_171023(dim)
Julian Kosciessa's avatar
Julian Kosciessa committed

    % load wordlists
    try
        load('stimuliSelected_practice.mat')
Julian Kosciessa's avatar
Julian Kosciessa committed
    catch
        warning('Stimuli not found, please check path.')
    end

    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.durBlockOnset = 5;  % duration of block onset
    expInfo.durFixCue = 3.5;      % duration of fixcross with cues
    expInfo.durCue = 1;         % duration of cue
    expInfo.durPres = 2.5;        % duration of presentation
Julian Kosciessa's avatar
Julian Kosciessa committed
    expInfo.durResp = 0;        % duration of question
    expInfo.durConf = 0;        % duration of confidence
    expInfo.durReward = 3;      % duration of reward
Julian Kosciessa's avatar
Julian Kosciessa committed
    expInfo.durITI = 2;         % duration of ITI
    expInfo.CTsim = 'no';       % simultaneous presentation of cue + target? Note: If 'yes', set expInfo.durCue to 0.
Julian Kosciessa's avatar
Julian Kosciessa committed
    
    %expInfo.timing = 'absolute'; % use absolute timing with reference to run onset? alternative: 'relative'
    %expInfo.timing = 'relative';
    expInfo.timing = 'relativeITI'; % use relative timing except at beginning of block/trial --> collect temporal jitter in ITI
    
    expInfo.trialDuration.all = expInfo.durFixCue+expInfo.durCue+expInfo.durPres+expInfo.durResp+expInfo.durConf+expInfo.durITI;
    expInfo.trialDuration.FixCue = expInfo.durFixCue;
    expInfo.trialDuration.Cue = expInfo.durFixCue+expInfo.durCue;
    expInfo.trialDuration.Pres = expInfo.durFixCue+expInfo.durCue+expInfo.durPres;
    expInfo.trialDuration.Resp = expInfo.durFixCue+expInfo.durCue+expInfo.durPres+expInfo.durResp;
    expInfo.trialDuration.Conf = expInfo.durFixCue+expInfo.durCue+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 = 1;   % feedback
    
    expInfo.breakTime = 60;                   % pause for 60 seconds between runs
    
    %% word-specific info
    
    % The order of the dimensions is the following:
    
    % 1-animal
    % 2-oneSyllable
    % 3-even
    % 4-H

    expInfo.Cues = {'Tier?'; 'einsilbig?'; 'gerade?'; 'H?'};
    %expInfo.WordCategories = {'animal', 'NoAnimal'; 'oneSyllable', 'twoSyllable'; 'even', 'uneven'; 'H', 'noH'};
    expInfo.WordCategories = {'NoAnimal', 'animal'; 'twoSyllable', 'oneSyllable'; 'uneven', 'even'; 'noH', 'H'}; % yes option is always right, no option left
    
    %% 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@'), KbName('b'), KbName('z')];    % left response
    expInfo.keyRight    = [KbName('RightControl'), KbName('RightAlt'), KbName('RightArrow'),KbName('6^'),KbName('7&'),KbName('g'), KbName('r')];  % right response
    expInfo.keyConf1    = [KbName('LeftControl'), KbName('LeftArrow'), KbName('1!'),KbName('b')];       % lowest confidence
    expInfo.keyConf2    = [KbName('LeftAlt'), KbName('2@'),KbName('z')];                                % intermediate confidence low
    expInfo.keyConf3    = [KbName('RightAlt'),KbName('6^'),KbName('g')];                                % intermediate confidence high
    expInfo.keyConf4    = [KbName('RightControl'), KbName('RightArrow'),KbName('7&'), KbName('r')];      % highest confidence
Julian Kosciessa's avatar
Julian Kosciessa committed
    expInfo.keyModifier = KbName('LeftAlt'); % to prevent accidental input
    expInfo.keyEscape   = KbName('Escape'); %
    expInfo.keyReturn   = [KbName('Return'), KbName('7&'), KbName('g'), KbName('r')]; % continue experiment
Julian Kosciessa's avatar
Julian Kosciessa committed
    expInfo.keyPause    = KbName('p');
    
    % g,r - left; b,z- right (blue does not work)
Julian Kosciessa's avatar
Julian Kosciessa committed

    %% 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,
    % within 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.
    
    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
                        if indOrd == 4
                            A = 1:4;
                            R = 4.*extractMat(indSplit,:);
                            availableOptions = cell2mat(arrayfun(@(a,r)repmat(a,1,r),A,R,'uni',0));
Julian Kosciessa's avatar
Julian Kosciessa committed
                            mostCommon = find(extractMat(indSplit,:)==1);
                            mostCommon = mostCommon(1);
                        elseif indOrd == 3
                            A = 1:4;
                            R = 4.*extractMat(indSplit,:);
                            availableOptions = cell2mat(arrayfun(@(a,r)repmat(a,1,r),A,R,'uni',0));
                            %availableOptions = repelem([1:4], 4.*extractMat(indSplit,:));
Julian Kosciessa's avatar
Julian Kosciessa committed
                            mostCommon = find(extractMat(indSplit,:)==2);
                        elseif indOrd == 2
                            A = 1:4;
                            R = numel(Splits{indSplit})/2.*extractMat(indSplit,:);
                            availableOptions = cell2mat(arrayfun(@(a,r)repmat(a,1,r),A,R,'uni',0));
                            %availableOptions = repelem([1:4], numel(Splits{indSplit})/2.*extractMat(indSplit,:));
Julian Kosciessa's avatar
Julian Kosciessa committed
                            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);
        idxCurrentOrder_mat = find(expInfo.StateOrder == indDim);
        % check number of presented attributes
        for indAtt = 1:4
            PresentedAttNum(indDim, indAtt) = numel(find(expInfo.targetAtt(idxCurrentOrder,:)==indAtt));
            PresentedAttNum_low(indDim, indAtt) = numel(find(expInfo.targetOption(idxCurrentOrder_mat(expInfo.targetAtt(idxCurrentOrder,:)==indAtt))==1));
            PresentedAttNum_high(indDim, indAtt) = numel(find(expInfo.targetOption(idxCurrentOrder_mat(expInfo.targetAtt(idxCurrentOrder,:)==indAtt))==2));
        end
        % check switching probability
        SwitchProb_no(indDim) = numel(find(abs(diff([expInfo.targetAtt(idxCurrentOrder,1), expInfo.targetAtt(idxCurrentOrder,:)],[],2))==0));
        SwitchProb_yes(indDim) = numel(find(abs(diff([expInfo.targetAtt(idxCurrentOrder,1), expInfo.targetAtt(idxCurrentOrder,:)],[],2))> 0));
    end
    [PresentedAttNum, [NaN; NaN; NaN; NaN], PresentedAttNum_low,[NaN; NaN; NaN; NaN], PresentedAttNum_high, [NaN; NaN; NaN; NaN], SwitchProb_no', SwitchProb_yes']
    
    %% select which stimulus in particular will be presented
    
    % The target category is already fixed as done above.
    
    % 1. get current state dim order
    % 2. get current category
    % 3. get high/low option
    % 4. distribute the stimuli evely
    % 5. choose random options for the remaining attributes
    
    combs = allcomb([1,2],[1,2],[1,2],[1,2]); % Note that 1 & 2 refer to the higher/lower prob option here.
    
    for indOrd = 1:4
        for indAtt = 1:4
            for indChoice = 1:2
                idxCurrentOrder_l1 = find(expInfo.StateOrder == indOrd); % indexes trials of current state order
                idxCurrentAtt_l2 =  find(expInfo.targetAtt(idxCurrentOrder_l1) == indAtt);
                indCurrentChoice_l3 = find(expInfo.targetOption(idxCurrentOrder_l1(idxCurrentAtt_l2)) == indChoice);
                indCombined = idxCurrentOrder_l1(idxCurrentAtt_l2(indCurrentChoice_l3));
                % get combinations with current parameters (regarding target attribute & choice)
                curCombs = combs(combs(:,indAtt)==indChoice,:);
                % randomize trials
                indRecomb = indCombined(randperm(numel(indCombined)));
                % repeat to match amount of trials
                curCombs = repmat(curCombs, numel(indRecomb)/size(curCombs,1),1);
                for indTrial = 1:numel(indRecomb)
                    indTargetTrial = indRecomb(indTrial);
                    expInfo.HighProbChoice{indTargetTrial} = curCombs(indTrial,:);
                end
            end % choice
        end % attribute
    end % order
    
    % get combination ID
    for indRow = 1:size(expInfo.HighProbChoice,1)
        for indColumn = 1:size(expInfo.HighProbChoice,2)
            [~, loc] = ismember(expInfo.HighProbChoice{indRow,indColumn}, combs, 'rows');
            expInfo.Combs(indRow,indColumn) = loc;
        end
    end
    
    %% in each order category, use the same stimuli equally often
    
    % get the stimuli for each combination
    for indComb = 1:size(combs,1)
        stims{indComb} = stimuli.(expInfo.WordCategories{1,combs(indComb,1)}).(...
            expInfo.WordCategories{2,combs(indComb,2)}).(...
            expInfo.WordCategories{3,combs(indComb,3)}).(...
            expInfo.WordCategories{4,combs(indComb,4)});
    end
    
    expInfo.WordRand = 'MatchedByDim';
    %expInfo.WordRand = 'NonMatchedByDim';
    
    %% TO DO: select the same four stimuli per combination across subjects
    
    if strcmp(expInfo.WordRand, 'NonMatchedByDim')
        % distribute the stimuli randomly for each order
        expInfo.Words = cell(size(expInfo.Combs));
        for indOrd = 1:4
            idxCurrentOrder = find(expInfo.StateOrder == indOrd); % indexes trials of current state order
            combinationsInDim = expInfo.Combs(idxCurrentOrder); % there are currently four words per category
            % find out how many trials there are for each combination
            for indComb = 1:size(combs,1)
                idxCombs_l2 = find(combinationsInDim == indComb);
                stims_rand = randperm(numel(stims{indComb}),numel(idxCombs_l2));
                for indTrial = 1:numel(stims_rand)
                    curIdx = idxCurrentOrder(idxCombs_l2);
                    expInfo.Words{curIdx(indTrial)} = stims{indComb}(stims_rand(indTrial));
                end
            end
        end
    elseif strcmp(expInfo.WordRand, 'MatchedByDim')
        % distribute the stimuli matched by order [note that different stimuli are possible for different people]
        expInfo.Words = cell(size(expInfo.Combs));
        for indOrd = 1:4
            idxCurrentOrder = find(expInfo.StateOrder == indOrd); % indexes trials of current state order
            combinationsInDim = expInfo.Combs(idxCurrentOrder); % there are currently four words per category
            % find out how many trials there are for each combination
            for indComb = 1:size(combs,1)
                idxCombs_l2 = find(combinationsInDim == indComb);
                if indOrd == 1
                    stims_rand{indComb} = randperm(numel(stims{indComb}),numel(idxCombs_l2));
                end
                for indTrial = 1:numel(stims_rand{indComb})
                    curIdx = idxCurrentOrder(idxCombs_l2);
                    expInfo.Words{curIdx(indTrial)} = stims{indComb}(stims_rand{indComb}(indTrial));
                end
            end
        end
        % sanity check: there should be four instances of each word
        %numel(find(contains([expInfo.Words{:}], expInfo.Words{1}))) == 4;
    end
    
    %% arrange it so that there are only trials that we want
    
    if ismember(dim,1:4)
        [rowx, ~] = find(expInfo.StateOrder(:,1) == 1 & expInfo.targetAtt(:,1) == dim);
        expInfo.StateOrderRun{1} = expInfo.StateOrder(rowx(1),:);
        expInfo.AttCuesRun{1} = expInfo.AttCues(rowx(1),:);
        expInfo.targetAttRun{1} = expInfo.targetAtt(rowx(1),:);
        expInfo.targetOptionRun{1} = expInfo.targetOption(rowx(1),:);
        expInfo.HighProbChoiceRun{1} = expInfo.HighProbChoice(rowx(1),:);
        expInfo.CombsRun{1} = expInfo.Combs(rowx(1),:);
        expInfo.WordsRun{1} = expInfo.Words(rowx(1),:);
    elseif dim == 5 % choose 1 block of 4 state, choose 1 block of 2 state
        [rowx, ~] = find(expInfo.StateOrder(:,1) == 4);
        expInfo.StateOrderRun{1}(1,:) = expInfo.StateOrder(rowx(1),:);
        expInfo.AttCuesRun{1}(1,:) = expInfo.AttCues(rowx(1),:);
        expInfo.targetAttRun{1}(1,:) = expInfo.targetAtt(rowx(1),:);
        expInfo.targetOptionRun{1}(1,:) = expInfo.targetOption(rowx(1),:);
        expInfo.HighProbChoiceRun{1}(1,:) = expInfo.HighProbChoice(rowx(1),:);
        expInfo.CombsRun{1}(1,:) = expInfo.Combs(rowx(1),:);
        expInfo.WordsRun{1}(1,:) = expInfo.Words(rowx(1),:);
        [rowx, ~] = find(expInfo.StateOrder(:,1) == 2);
        expInfo.StateOrderRun{1}(2,:) = expInfo.StateOrder(rowx(1),:);
        expInfo.AttCuesRun{1}(2,:) = expInfo.AttCues(rowx(1),:);
        expInfo.targetAttRun{1}(2,:) = expInfo.targetAtt(rowx(1),:);
        expInfo.targetOptionRun{1}(2,:) = expInfo.targetOption(rowx(1),:);
        expInfo.HighProbChoiceRun{1}(2,:) = expInfo.HighProbChoice(rowx(1),:);
        expInfo.CombsRun{1}(2,:) = expInfo.Combs(rowx(1),:);
        expInfo.WordsRun{1}(2,:) = expInfo.Words(rowx(1),:);
    end
    
end