# cosmo cartprodΒΆ

```function p=cosmo_cartprod(xs, convert_to_numeric)
% returns the cartesian product with all combinations of the input
%
% p=cosmo_cartprod(xs[, convert_to_numeric])
%
% Inputs:
%   xs                   Px1 cell array with values for which the product
%                        is to be returned. Each element xs{k} should be
%                        - a cell with Qk values
%                        - a numeric array [xk_1,...,xk_Qk], which is
%                          interpreted as the cell {xk_1,...,xk_Qk}.
%                        - or a string s, which is interpreted as {s}.
%                        Alternatively xs can be a struct with P fieldnames
%                        where each value is a cell with Qk values.
%
%   convert_to_numeric   Optional; if true (default), then when the output
%                        contains numeric values only a numerical matrix is
%                        returned; otherwise a cell is returned.
% Output:
%   p                    QxP cartesian product of xs (where Q=Q1*...*Qk)
%                        containing all combinations of values in xs.
%                        - If xs is a cell, then p is represented by either
%                          a matrix (if all values in xs are numeric and
%                          convert_to_numeric==true) or a cell (in all
%                          other cases).
%                        - If xs is a struct, then p is a Qx1 cell. Each
%                          element in p is a struct with the same
%                          fieldnames as xs.
%
% Examples:
%     cosmo_cartprod({{1,2},{'a','b','c'}})'
%     %|| {1,2,1,2,1,2;
%     %|| 'a','a' ,'b','b','c','c'}
%
%     cosmo_cartprod({[1,2],[5,6,7]})'
%     %|| [1,2,1,2,1,2;
%     %||  5,5,6,6,7,7]
%
%     cosmo_cartprod(repmat({1:2},1,4))'
%     %|| [1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2;
%     %||  1 1 2 2 1 1 2 2 1 1 2 2 1 1 2 2;
%     %||  1 1 1 1 2 2 2 2 1 1 1 1 2 2 2 2;
%     %||  1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2]
%
%     s=struct();
%     s.roi={'v1','loc'};
%     s.hemi={'L','R'};
%     s.subj=[1 3 9];
%     s.ana='vis';
%     s.beta=4;
%     p=cosmo_cartprod(s)';
%     cosmo_disp(p);
%     %|| { .roi     .roi     .roi    ... .roi     .roi     .roi
%     %||     'v1'     'loc'    'v1'        'loc'    'v1'     'loc'
%     %||   .hemi    .hemi    .hemi       .hemi    .hemi    .hemi
%     %||     'L'      'L'      'R'         'L'      'R'      'R'
%     %||   .subj    .subj    .subj       .subj    .subj    .subj
%     %||     [ 1 ]    [ 1 ]    [ 1 ]       [ 9 ]    [ 9 ]    [ 9 ]
%     %||   .ana     .ana     .ana        .ana     .ana     .ana
%     %||     'vis'    'vis'    'vis'       'vis'    'vis'    'vis'
%     %||   .beta    .beta    .beta       .beta    .beta    .beta
%     %||     [ 4 ]    [ 4 ]    [ 4 ]       [ 4 ]    [ 4 ]    [ 4 ] }@1x12
%     %
%
% #   see the COPYING file distributed with CoSMoMVPA.           #

if nargin<2, convert_to_numeric=true; end

as_struct=isstruct(xs);

if as_struct
% input is a struct; put the values in each field in a cell.
[xs,fns]=struct2cell(xs);
elseif ~iscell(xs)
error('Unsupported input: expected a cell or struct');
end

if isempty(xs)
p=cell(1,0);
return
end

p=cartprod(xs);

% if input was a struct, output is a cell with structs
if as_struct();
p=cell2structs(p, fns);
elseif convert_to_numeric && ~isempty(p) && ...
all(cellfun(@isnumeric,p(:)))
% all values are numeric; convert to numeric matrix
p=reshape([p{:}],size(p));
end

function p=cartprod(xs)

ndim=numel(xs);

% get values in first dimension (the 'head')
% put numeric arrays in a cell
end

% ensure head is a column vector

if ndim==1
else
% use recursion to find cartprod of remaining dimensions
% (the 'tail')
xtail=xs(2:end);
ptail=cartprod(xtail); % ensure output is always a cell

% get sizes of head and tail
ntail=size(ptail,1);

% allocate space for output
rows=cell(ntail,1);
for k=1:ntail
% ptailk_rep is a repeated version of the k-th tail row
% to match the number of rows in head
end

% stack the rows vertically
p=cat(1,rows{:});
end

function [c,fns]=struct2cell(xs)
fns=fieldnames(xs);
ndim=numel(fns);
c=cell(1,ndim); % space for values in each dimension
for k=1:ndim
c{k}=xs.(fns{k});
end

function struct_cell=cell2structs(p, fns)
% number of output
n=size(p,1);
ndim=numel(fns);

% allocate space for structs
struct_cell=cell(n,1);

% set values for each struct
for k=1:n
s=struct();
for j=1:ndim
% use the same fieldnames as in the input
s.(fns{j})=p{k,j};
end
struct_cell{k}=s;
end
```