% STD_BUILDDESIGNMAT - Build the design matrix for an specific design
% specified in the structure ''design'' provided as input
%
% Usage:
%
% [tmpdmat,colLabels,catflag] = std_builddesignmat(design, trialinfo, 1)
%
% Inputs:
% design - Design structure as in the STUDY
% trialinfo - Structure of trial information. Each field should be a
% cell array with one element for each trial
% expanding - Expand the design matrix
% Optional inputs:
%
% Outputs:
% tmpdmat - Design matrix
% colLabels - Labels for each column of the design matrix
% catflag - Binary vector with dimension equal to the number of columns in the design matrix.
% [0] mean a continuous regressor, [1] means a categotical one.
%
% See also: std_combtrialinfo , std_plodtmat
%
% Authors: Ramon Martinez-Cancino
%
% Copyright (C) 2015 Ramon Martinez-Cancino, UCSD, INC, SCCN
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.
function [tmpdmat,colLabels,catflag] = std_builddesignmat(design, trialinfo, expanding)
if nargin < 3, expanding = 0; end
ntrials = length(trialinfo);
varindx = 1:length(design.variable);
% checking if 'group' var (temporal commit to detect group vars, right now only detecting variable 'group')
groupindx = find(strcmp({design.variable.label},'group'));
if ~isempty(groupindx)
varindx(groupindx) = [];
end
tmpdmat = NaN(ntrials,length(varindx));
catflag = strcmp({design.variable.vartype}, 'categorical');
colLabels = {design.variable.label};
for i = 1 : length(varindx)
% case for cont variables
if ~catflag(i)
[trialindsx, eventvals] = std_gettrialsind(trialinfo,design.variable(varindx(i)).label, '');
if ~isempty(trialindsx)
tmpdmat(trialindsx,i) = eventvals;
end
else % case for cat variables
varvaluetmp = design.variable(varindx(i)).value;
% Expanding cells cells
c = 1; varlist = {}; varvallength = []; facval_indx = []; dmatval = 1; jcount = 1;
for ivar = 1:length(varvaluetmp)
% Length of varvaluetmp(i)
if iscellstr(varvaluetmp(ivar))
varvallength(ivar) = length(varvaluetmp(ivar)) ;
elseif iscell(varvaluetmp(ivar))
varvallength(ivar) = length(varvaluetmp{ivar}) ;
else
varvallength(ivar) = length(varvaluetmp{ivar}) ;
end
% Retrieving value and assigning index in design matrix
if ~iscell(varvaluetmp{ivar}) && varvallength(ivar) == 1
varlist{c} = varvaluetmp{ivar};
varindxjoint{ivar} = c;
facval_indx(c) = dmatval;
c = c+1;
else
tmpcindx = [];
for ival = 1: varvallength(ivar)
if iscellstr(varvaluetmp{ivar}(ival))
varlist{c} = varvaluetmp{ivar}{ival};
else
varlist{c} = varvaluetmp{ivar}(ival);
end
facval_indx(c) = dmatval;
tmpcindx = cat(1,tmpcindx,c);
c = c+1;
end
varindxjoint{ivar} = tmpcindx;
end
dmatval = dmatval+1;
%---
for j = 1 :varvallength(ivar)
%
if iscellstr(varlist(varindxjoint{ivar}))
facval = varlist{varindxjoint{ivar}(j)};
elseif iscell(varlist(varindxjoint{ivar}))
tmpval = varlist(varindxjoint{ivar});
if isnumeric(tmpval{j})
facval = tmpval{j};
else
facval = tmpval(j);
end
elseif isnumeric(varlist(varindxjoint{ivar}))
facval = varlist(varindxjoint{ivar}(j));
elseif ischar(varlist(varindxjoint{ivar}))
% facval = varlist(varindxjoint{ivar}(j));
end
% Find indices of triasl for facval
[trialindsx, eventvals] = std_gettrialsind(trialinfo,design.variable(varindx(i)).label, facval);
% Populating the design matrix
if ~isempty(trialindsx)
tmpdmat(trialindsx,i) = facval_indx(jcount);
jcount = jcount+1;
end
end
%---
end
end
end
% -------------------------------------------------------------------------
% expand categ var
if expanding == 1
% count number of columns
nCols = 0;
for iCol = 1:size(tmpdmat,2)
if catflag(iCol)
nCols = nCols+length(design.variable(varindx(iCol)).value);
else
nCols = nCols+1;
end
end
tmpdmatExpanded = NaN(size(tmpdmat,1),nCols);
countCol = 0;
for iCol = 1:size(tmpdmat,2)
if catflag(iCol)
% get unique values for this given categ var
uniqueVals = unique(tmpdmat(:,iCol));
uniqueVals(isnan(uniqueVals)) = [];
% scan unique values
prevCol = countCol;
for iUnique = 1:length(design.variable(varindx(iCol)).value)
countCol = countCol+1;
try tmpval = uniqueVals(iUnique); catch, tmpval = NaN; end
trialSelect = tmpdmat(:,iCol) == tmpval;
otherCols = prevCol+setdiff(1:length(uniqueVals), iUnique);
% putting 0 in other columns ensures we process the NaNs
tmpdmatExpanded(trialSelect, countCol ) = 1;
tmpdmatExpanded(trialSelect, otherCols) = 0;
% get the label for that column
if ischar(design.variable(varindx(iCol)).value{iUnique})
colLabels{countCol} = [design.variable(varindx(iCol)).label '-' design.variable(varindx(iCol)).value{iUnique}];
elseif iscell(design.variable(varindx(iCol)).value{iUnique})
% Concat all vals
varnametmp = design.variable(varindx(iCol)).value{iUnique}{1};
for ivar = 2: length(design.variable(varindx(iCol)).value{iUnique})
varnametmp = [varnametmp '&' design.variable(varindx(iCol)).value{iUnique}{ivar}];
end
colLabels{countCol} = [design.variable(varindx(iCol)).label '-' varnametmp];
elseif isnumeric(design.variable(varindx(iCol)).value{iUnique})
colLabels{countCol} = [design.variable(varindx(iCol)).label '-' int2str(design.variable(varindx(iCol)).value{iUnique})];
end
end
else
countCol = countCol+1;
colLabels{countCol} = design.variable(varindx(iCol)).label;
tmpdmatExpanded(:,countCol) = tmpdmat(:,iCol);
end
end
tmpdmat = tmpdmatExpanded;
end
tmpdmat(:,end+1) = 1;
colLabels{numel(colLabels)+1} = 'constant';