all possible combinations of a set in Matlab - matlab

I'm trying to find all possible combinations of a set but the order of the elements are also important for my problem.
For example for the set set={A, B, C}, the possible subsets are subsets={A},{B},{C},{A,B},{A,C},{B,A},{B,C},{C,A},{C,B},{A,B,C},{A,C,B},{B,A,C},{B,C,A},{C,A,B},{C,B,A}.
Are there any Matlab function to find that?
Thanks in advance.

I couldn't bear to see all those for loops in Tommaso's answer, so here's one with no loops:
a = {'A' 'B' 'C'};
% Build an array of binary vectors which we will use to select subsets of
% the array to be permuted
nGroups = 2^numel(a) - 1;
selector = dec2bin(1:nGroups) == '1'; % hack to convert numbers to binary vectors
selectVectors = arrayfun(#(x) selector(x,:), 1:size(selector, 1), 'UniformOutput', false);
% Get the permutations of each subset of the array
permsCell = cellfun(#(s) perms(a(s)), selectVectors, 'UniformOutput', false);
% Rearrange the permutations into a one-dimensional cell array with one
% permutation in each element
rowsAsCells = #(ca) arrayfun(#(x) ca(x,:), 1:size(ca,1), 'UniformOutput', false);
permsAsRows = cellfun(rowsAsCells, permsCell, 'UniformOutput', false);
result = cat(2, permsAsRows{:});
This returns a cell array with one permutation in each element, like Tommaso's second solution.
Whether this version is preferable is a matter of taste ;-)

a = {'A' 'B' 'C'};
a_len = numel(a);
res_len = 0;
for i = 1:a_len
res_len = res_len + (factorial(a_len) / factorial(a_len - i));
end
res = cell(res_len,a_len);
res_off = 1;
for i = 1:a_len
bin = nchoosek(a,i);
for j = 1:size(bin,1)
bin_j = bin(j,:);
per = perms(bin_j);
per_hei = size(per,1);
res_ran = res_off + per_hei - 1;
res(res_off:res_ran,:) = [per repmat({''},size(per,1),a_len - i)];
res_off = res_off + per_hei;
end
end
Alternatively, if you don't want results organized into equally sized columns, but rather inserted into a single vector with variable length:
a = {'A' 'B' 'C'};
a_len = numel(a);
res_len = 0;
for i = 1:a_len
res_len = res_len + (factorial(a_len) / factorial(a_len - i));
end
res = cell(res_len,1);
res_off = 1;
for i = 1:numel(a)
bin = nchoosek(a,i);
for j = 1:size(bin,1)
bin_j = bin(j,:);
per = perms(bin_j);
for y = 1:size(per,1)
res{res_off,1} = {per{y,:}};
res_off = res_off + 1;
end
end
end

Related

How to correct grid search?

Trying to find the optimal hyperparameters for my svm model using a grid search, but it simply returns 1 for the hyperparameters.
function evaluations = inner_kfold_trainer(C,q,k,features_xy,labels)
features_xy_flds = kdivide(features_xy, k);
labels_flds = kdivide(labels, k);
evaluations = zeros(k,3);
for i = 1:k
fprintf('Fold %i of %i\n',i,k);
train_data = cell2mat(features_xy_flds(1:end ~= i));
train_labels = cell2mat(labels_flds(1:end ~= i));
test_data = cell2mat(features_xy_flds(i));
test_labels = cell2mat(labels_flds(i));
%AU1
train_labels = train_labels(:,1);
test_labels = test_labels(:,1);
[k,~] = size(test_labels);
%train
sv = fitcsvm(train_data,train_labels, 'KernelFunction','polynomial', 'PolynomialOrder',q,'BoxConstraint',C);
sv.predict(test_data);
%Calculate evaluative measures
%svm_outputs = zeros(k,1);
sv_predictions = sv.predict(test_data);
[precision,recall,F1] = evaluation(sv_predictions,test_labels);
evaluations(i,1) = precision;
evaluations(i,2) = recall;
evaluations(i,3) = F1;
end
save('eval.mat', 'evaluations');
end
an inner-fold cross validation function
and below the grid function where something seems to be going wrong
function [q,C] = grid_search(features_xy,labels,k)
% n x n grid
n = 3;
q_grid = linspace(1,19,n);
C_grid = linspace(1,59,n);
tic
evals = zeros(n,n,3);
for i = 1:n
for j = 1:n
fprintf('## i=%i, j=%i ##\n', i, j);
svm_results = inner_kfold_trainer(C_grid(i), q_grid(j),k,features_xy,labels);
evals(i,j,:) = mean(svm_results(:,:));
% precision only
%evals(i,j,:) = max(svm_results(:,1));
toc
end
end
f = evals;
% retrieving the best value of the hyper parameters, to use in the outer
% fold
[M1,I1] = max(f);
[~,I2] = max(M1(1,1,:));
index = I1(:,:,I2);
C = C_grid(index(1))
q = q_grid(index(2))
end
When I run grid_search(features_xy,labels,8) for example, I get C=1 and q=1, for any k(the no. of folds) value. Also features_xy is a 500*98 matrix.

Matlab: iterate through image blocks

I would like to divide an image into 8 by 6 blocks and then from each block would like to get the average of red, green and blue values then store the average values from each block into an array. Say that if I have image divided into 4 blocks the result array would be:
A = [average_red, average_green, average_blue,average_red, ...
average_green, average_blue,average_red, average_green, ...
average_blue,average_red, average_green, average_blue,...
average_red, average_green, average_blue,]
The loop I have created looks very complicated, takes a long time to run and I'm not even sure if it's working properly or not as I have no clue how to check. Is there any simpler way to implement this.
Here is the loop:
[rows, columns, ~] = size(img);
[rows, columns, ~] = size(img);
rBlock = 6;
cBlock = 8;
NumberOfBlocks = rBlock * cBlock;
bRow = ceil(rows/rBlock);
bCol = ceil(columns/cBlock);
row = bRow;
col = bCol;
r = zeros(row*col,1);
g = zeros(row*col,1);
b = zeros(row*col,1);
n = 1;
cl = 1;
rw = 1;
for x = 1:NumberOfBlocks
for i = cl : col
for j = rw : row
% some code
end
end
%some code
if i == columns && j ~= rows
cl = 1;
rw = j - (bRow -1);
col = (col - col) + bCol;
row = row + bRaw;
elseif a == columns && c == rows
display('done');
else
cl = i + 1;
rw = j - (bRow -1);
col = col + col;
row = row + row;
end
end
Because there are only 48 block, you may use simple for loop iterating blocks. (I think it's going to be fast enough).
Here is my code:
%Build test image
img = double(imresize(imread('peppers.png'), [200, 300]));
[rows, columns, ~] = size(img);
rBlock = 6;
cBlock = 8;
NumberOfBlocks = rBlock * cBlock;
bRow = ceil(rows/rBlock);
bCol = ceil(columns/cBlock);
idx = 1;
A = zeros(1, rBlock*cBlock*3);
for y = 0:rBlock-1
for x = 0:cBlock-1
%Block (y,x) boundaries: (x0,y0) to (x1,y1)
x0 = x*bCol+1;
y0 = y*bRow+1;
x1 = min(x0+bCol-1, columns); %Limit x1 to columns
y1 = min(y0+bRow-1, rows); %Limit y1 to rows
redMean = mean2(img(y0:y1, x0:x1, 1)); %Mean of red pixel in block (y,x)
greenMean = mean2(img(y0:y1, x0:x1, 2)); %Mean of green pixel in block (y,x)
blueMean = mean2(img(y0:y1, x0:x1, 3)); %Mean of blue pixel in block (y,x)
%Fill 3 elements of array A.
A(idx) = redMean;
A(idx+1) = greenMean;
A(idx+2) = blueMean;
%Advance index by 3.
idx = idx + 3;
end
end

Manually upsample/replicate matrix

I'm trying to upsample a matrix by two by replicating another matrix, but i'm confused with the code, basically what i want is if:
Y = [1,2]
then the upsampled version would look like:
Up = [1,1,2,2;1,1,2,2]
What i've written so far is:
[row,col] = size(y)
Up = zeros(row*2,col*2);
for i = 1:2:row*2
for j = 1:2:col*2
Up(i, j) = Y(i,j);
Up(i+1, j) = Y(i,j);
Up(i, j+1) = Y(i,j);
Up(i+1, j+1) = Y(i,j);
end
end
but it says Index exceeds matrix dimensions, which i understand is because of the +1s but i'm not sure how else to go about doing this...
Data:
Y = [1,2]; % matrix
n = 2; % repetition factor
Solution using the repelem function (introduced in R2015a):
Up = repelem(Y,n,n);
Solution using indexing;
Up = Y(ceil(1/n:1/n:end), ceil(1/n:1/n:end));
Solution using a Kronecker product:
Up = kron(Y, ones(n))
The solution i ended up using is:
[row,col] = size(Y);
Up = zeros(row*2,col*2);
idx_row = 1;
for i = 1:D:row
idx_col = 1;
for j = 1:D:col
Up(i:i+1, j:j+1) = repmat(repmat(Y(idx_row,idx_col),1,2),2,1);
idx_col = idx_col + 1;
end
idx_row = idx_row + 1;
end

Using xlswrite to save numerical data

Hi I would like to save numerical data from an operation inside a loop. Lets see my segmentation example:
clear all, clc;
a=1:35;
A = arrayfun( #(x) sprintf( '%04d', x ), a, 'UniformOutput', false );
I = cellfun( #(b) imread( ['C:Teste/' b '/c1/' b '.png'] ), A, 'UniformOutput', false );
for i = a
% Gaussian Filter
W = fspecial('gaussian',[10,10],2);
J = imfilter(I,W);
% Finding Circular objects -- Houng Transform
[centers, radii, metric] = imfindcircles(J,[5 10], 'Sensitivity',0.93,'Edge',0.27);
idx_mask = ones(size(radii));
min_dist = 2; % relative value.
for i = 2:length(radii)
cur_cent = centers(i, :);
for j = 1:i-1
other_cent = centers(j,:);
x_dist = other_cent(1) - cur_cent(1);
y_dist = other_cent(2) - cur_cent(2);
if sqrt(x_dist^2+y_dist^2) < min_dist*(radii(i) + radii(j)) && idx_mask(j) == 1
idx_mask(i) = 0;
break
end
end
end
idx_mask = logical(idx_mask);
centers_use = centers(idx_mask, :);
radii_use = radii(idx_mask, :);
metric_use = metric(idx_mask, :);
viscircles(centers_use, radii_use,'EdgeColor','b');
a=length(centers_use)
end
So the point is to save the 35 results in one column of an xls file.
I was trying to do this but only the last element of the loop is printed in the exel file...
filename = 'testdata.xlsx';
A = vertcat('Test', 'Results', num2cell(a'));
sheet = 1;
xlRange = 'F03';
xlswrite(filename,A,sheet,xlRange)
Can please anyone help me out? I know there many questions related to this one but none of them covers my issue...
I will leave here one image for testing:
Thanks a lot in advance.
John
As #excaza said, you need to expand b
a=1:35;
for i = a
b=10+a;
end
filename = 'testdata.xlsx';
A = vertcat('Example', 'Results', num2cell(b'));
sheet = 1;
xlRange = 'B1';
xlswrite(filename,A,sheet,xlRange)

What is the fastest way of appending an element to an array?

This is a follow-up question to How to append an element to an array in MATLAB? That question addressed how to append an element to an array. Two approaches are discussed there:
A = [A elem] % for a row array
A = [A; elem] % for a column array
and
A(end+1) = elem;
The second approach has the obvious advantage of being compatible with both row and column arrays.
However, this question is: which of the two approaches is fastest? My intuition tells me that the second one is, but I'd like some evidence for or against that. Any idea?
The second approach (A(end+1) = elem) is faster
According to the benchmarks below (run with the timeit benchmarking function from File Exchange), the second approach (A(end+1) = elem) is faster and should therefore be preferred.
Interestingly, though, the performance gap between the two approaches is much narrower in older versions of MATLAB than it is in more recent versions.
R2008a
R2013a
Benchmark code
function benchmark
n = logspace(2, 5, 40);
% n = logspace(2, 4, 40);
tf = zeros(size(n));
tg = tf;
for k = 1 : numel(n)
x = rand(round(n(k)), 1);
f = #() append(x);
tf(k) = timeit(f);
g = #() addtoend(x);
tg(k) = timeit(g);
end
figure
hold on
plot(n, tf, 'bo')
plot(n, tg, 'ro')
hold off
xlabel('input size')
ylabel('time (s)')
leg = legend('y = [y, x(k)]', 'y(end + 1) = x(k)');
set(leg, 'Location', 'NorthWest');
end
% Approach 1: y = [y, x(k)];
function y = append(x)
y = [];
for k = 1 : numel(x);
y = [y, x(k)];
end
end
% Approach 2: y(end + 1) = x(k);
function y = addtoend(x)
y = [];
for k = 1 : numel(x);
y(end + 1) = x(k);
end
end
How about this?
function somescript
RStime = timeit(#RowSlow)
CStime = timeit(#ColSlow)
RFtime = timeit(#RowFast)
CFtime = timeit(#ColFast)
function RowSlow
rng(1)
A = zeros(1,2);
for i = 1:1e5
A = [A rand(1,1)];
end
end
function ColSlow
rng(1)
A = zeros(2,1);
for i = 1:1e5
A = [A; rand(1,1)];
end
end
function RowFast
rng(1)
A = zeros(1,2);
for i = 1:1e5
A(end+1) = rand(1,1);
end
end
function ColFast
rng(1)
A = zeros(2,1);
for i = 1:1e5
A(end+1) = rand(1,1);
end
end
end
For my machine, this yields the following timings:
RStime =
30.4064
CStime =
29.1075
RFtime =
0.3318
CFtime =
0.3351
The orientation of the vector does not seem to matter that much, but the second approach is about a factor 100 faster on my machine.
In addition to the fast growing method pointing out above (i.e., A(k+1)), you can also get a speed increase from increasing the array size by some multiple, so that allocations become less as the size increases.
On my laptop using R2014b, a conditional doubling of size results in about a factor of 6 speed increase:
>> SO
GATime =
0.0288
DWNTime =
0.0048
In a real application, the size of A would needed to be limited to the needed size or the unfilled results filtered out in some way.
The Code for the SO function is below. I note that I switched to cos(k) since, for some unknown reason, there is a large difference in performance between rand() and rand(1,1) on my machine. But I don't think this affects the outcome too much.
function [] = SO()
GATime = timeit(#GrowAlways)
DWNTime = timeit(#DoubleWhenNeeded)
end
function [] = DoubleWhenNeeded()
A = 0;
sizeA = 1;
for k = 1:1E5
if ((k+1) > sizeA)
A(2*sizeA) = 0;
sizeA = 2*sizeA;
end
A(k+1) = cos(k);
end
end
function [] = GrowAlways()
A = 0;
for k = 1:1E5
A(k+1) = cos(k);
end
end