MatLab block transpose - matlab

This is a tab-delimited txt that looks like
A 2000 a B 2001 b C 1999 c
X 2005 x Y 1995 y
There will be hundreds of rows like these.
I want to create matrices like
mat1 = [A 2000 a ; B 2001 b ; C 1999 c]
mat2 = [X 2005 x ; Y 1995 y]
I think this is doable if I just use for and if and so on.
But I am not sure if I can do it by some more efficient matlab command using block transpose.

id = fopen('input.txt');
tline = fgetl(id);
ii = 1;
while ischar(tline)
cell_{ii} = cellfun(#(x)(str2double(x)),reshape(regexp(tline,'\t','split')',3,[])');
ii = ii+1;
tline = fgetl(id);
end
fclose(id);
The output matrices are stored in the cell array , cell_
input file is
564 564 5646 65466 458 545
785 878 8745 555 547 5665 55966 66588 6654
output is
cell_{1}
ans =
564 564 5646
65466 458 545
cell_{2}
ans =
785 878 8745
555 547 5665
55966 66588 6654

Related

Data arrangement in vector

I have the following vector:
Here is the code to produce this vector:
A = [11 115 167 44 51 5 6];
B = [100 1 1 87];
C = [2000 625];
D = [81 623 45 48 6 14 429 456 94];
E = [89];
F = [44 846 998 2035 498 4 68 4 1 89];
G = {A,B,C,D,E,F};
[max_val, idx] = max(cellfun(#numel, G)); % Find max sizes of vectors
% Create vector with zeros filling open matrix space
LeftIndented = zeros(idx,max_val);
for k = 1:numel(G), LeftIndented(k,1:numel(G{k})) = G{k}; end
I would like to have a vector with:
Data to the right (zeros to the left)
Centered data (surrounded with zeros)
(Notice that if data cannot be exactly centered, it is ok if it is off by one vector space to the left)
How can I achieve this?
You can pad each vector with zeros:
A = [11 115 167 44 51 5 6];
B = [100 1 1 87];
C = [2000 625];
D = [81 623 45 48 6 14 429 456 94];
E = [89];
F = [44 846 998 2035 498 4 68 4 1 89];
G = {A,B,C,D,E,F};
[max_val, idx] = max(cellfun(#numel, G)); % Find max sizes of vectors
% Create vector with zeros filling open matrix space
LeftIndented = zeros(idx,max_val);
Centered = zeros(idx,max_val);
RightAligned = zeros(idx,max_val);
for k = 1:numel(G)
LeftIndented(k,1:numel(G{k})) = G{k};
l = length(G{k});
padding = max_val - l;
leftPadding = floor(padding / 2);
Centered(k, :) = [zeros(1, leftPadding), G{k}, zeros(1, padding - leftPadding)];
RightAligned(k, :) = [zeros(1, padding), G{k}];
end
This is equivalent to
A = [11 115 167 44 51 5 6];
B = [100 1 1 87];
C = [2000 625];
D = [81 623 45 48 6 14 429 456 94];
E = [89];
F = [44 846 998 2035 498 4 68 4 1 89];
G = {A,B,C,D,E,F};
[max_val, idx] = max(cellfun(#numel, G)); % Find max sizes of vectors
% Create vector with zeros filling open matrix space
LeftIndented = zeros(idx,max_val);
Centered = zeros(idx,max_val);
RightAligned = zeros(idx,max_val);
for k = 1:numel(G)
LeftIndented(k,1:numel(G{k})) = G{k};
l = length(G{k});
padding = max_val - l;
leftPadding = floor(padding / 2);
Centered(k, 1 + leftPadding:leftPadding + l) = G{k};
RightAligned(k, 1 + padding:end) = G{k};
end
but in the second code the values of the vectors are written into the correct position in a zero vector.
A solution using strjust:
A = [11 115 167 44 51 5 6];
B = [100 1 1 87];
C = [2000 625];
D = [81 623 45 48 6 14 429 456 94];
E = [89];
F = [44 846 998 2035 498 4 68 4 1 89];
G = {A,B,C,D,E,F};
data = [G{:}];
N = cellfun(#numel, G);
M = max(N);
idx = char((N.' >= (1:M))+32);
Le = strjust(idx, 'left');
Ri = strjust(idx, 'right');
Ce = strjust(idx, 'center');
LeftAdjusted = zeros(M, N);
RightAdjusted = zeros(M, N);
Centered = zeros(M, N);
LeftAdjusted(Le.' ~= ' ') = data;
RightAdjusted(Ri.' ~= ' ') = data;
Centered(Ce.' ~= ' ') = data;
LeftAdjusted = LeftAdjusted.';
RightAdjusted = RightAdjusted.';
Centered = Centered.';

Polynomial Evaluation

I read a Matlab tutorial script and I'm not sure how the function polyvalm works.
The polynomial is as follow: p(X)=X^3 -2*X -5I (where I is the identity matrix)
polynomial coefficients of p(X)is [1 0 -2 -5]
X = [2 4 5; -1 0 3; 7 1 5];
Y = polyvalm(p,X)
My interpretation is X.^3 - 2*X -5*eye(3) but my result is totally different.
Sorry for the ugly typesetting but stack overflow doesn't offer Latex so can't help it
You are using element wise cube (X.^3) which is of course different from actually cubing a matrix. So for your p the polynomial is actually X^3 - 2*X - 5*eye(size(X)):
p = [1 0 -2 -5];
X = [2 4 5; -1 0 3; 7 1 5];
% anonymous function to illustrate
f = #(X,p) p(1)*X^3 + p(2)*X^2 + p(3)*X + p(4)*eye(size(X));
y_polyvalm = polyvalm(p,X)
y_fun = f(X,p)
This results in
y_polyvalm =
377 179 439
111 81 136
490 253 639
y_fun =
377 179 439
111 81 136
490 253 639

I am looking for another alternative to "X = X1(abs(N(4,:)-N(5,:))>0.24*abs(N(5,:)))"

The objective of this question:
I am looking for a code that does not take into account the column order of the matrices N and M. So I try to replace the following line in the code below :
X = X1(abs(N(4,:)-N(5,:))>0.24*abs(N(5,:)));
The result X is dependent on the column order of N and M
The problem:
my goal is to put all values of M(4,:) corresponding to N(1:3,i), i=1,2,3,4,5 in one vector of a cell X if abs(N(4,i)-N(5,i)) > 0.24*abs(N(5,i))
N(1:3,:) is formed by unique column vectors of M(1:3,:)
N(4:5,:) is used for finding X
The entity A is added to display M otherwise.
M = [1007 4044 1007 4044 1007 5002 5002 5002 622 622 1007 1007 1007;
552 300 552 300 552 431 431 431 124 124 552 11 11;
2010 1113 2010 1113 2010 1100 1100 1100 88 88 2010 20 20;
12 25 15 12 30 2 10 55 32 12 7 12 7];
A = [1007 4044 5002 622 1007
552 300 431 124 11
2010 1113 1100 88 20
12 25 2 32 12
15 12 10 12 7
30 55
7 ]
N = [622 1007 1007 4044 5002;
124 11 552 300 431;
88 20 2010 1113 1100;
2 4 -1.1 2.1 -3;
2.01 1 -1 2 -5];
[~,~,idx] = unique(M(1:3,:)','rows','stable')
%// Accumulate elements from the fourth row of M based on the IDs
X1 = accumarray(idx(:),M(4,:).',[],#(x) {x});
%// Use mask corresponding to abs(N(4,i)-N(5,i))>0.24*N(5,i) and
%// filter out some of the cells from the output
X = X1(abs(N(4,:)-N(5,:))>0.24*abs(N(5,:)));
For my example:
if N and M are ordered properly:
X = {[12,7],[2 10 55]}
[12 7] correspond to N(1:3,2), abs(N(4,2)-N(5,2))>0.24*abs(N(5,2))
[2 10 55] correspond to N(1:3,5), abs(N(4,5)-N(5,5))>0.24*abs(N(5,5))
Possible Solution: (gives correct result with my real data)
for i = 1:size(N,2)
N(6,i) = i;
end
for h = 1:size(M,2)
for l = 1:size(N,2)
if M(1:3,h) == N(1:3,l)
M(5,h) = N(6,l);
end
end
end
p = 0;
for i = 1:size(N,2)
if abs(N(4,i)-N(5,i))>0.24*abs(N(5,i))
Mint = M(:,ismember(M(5,:).',i.', 'rows').');
p = p+1;
X{1,p} = Mint(4,:);
end
end
ismember is a good solution to your problem. It tells you when elements (or rows) of one matrix occur in a second matrix and will be much faster than your method using loops. This code matches your solution on the larger dataset you posted:
isGood = abs(N(4,:)-N(5,:))>0.24*abs(N(5,:));
[junk, inds] = ismember(M(1:3, :)', N(1:3, isGood)', 'rows');
X = cell(1, sum(isGood));
for i = 1:sum(isGood)
X{i} = M(4, inds==i);
end
See if this works for you -
%// Inputs
M = [1007 4044 1007 4044 1007 5002 5002 5002 622 622 1007 1007 1007;
552 300 552 300 552 431 431 431 124 124 552 11 11;
2010 1113 2010 1113 2010 1100 1100 1100 88 88 2010 20 20;
12 25 15 12 30 2 10 55 32 12 7 12 7];
N = [622 1077 1007 4044 5002;
124 11 552 300 431;
88 20 2010 1113 1100;
2 4 -1.1 2.1 -3;
2.01 1 -1 2 -5];
[unqrows,~,idx] = unique(M(1:3,:)','rows','stable')
unqcols = unqrows.';
%// Accumulate elements from the fourth row of M based on the IDs
X1 = accumarray(idx(:),M(4,:).',[],#(x) {x}); %//'
%// "Regularize" X1 %//'
[~,sort_idx] = sortrows(unqcols.'); %//'
X1_sorted = X1(sort_idx);
%// Use mask corresponding to abs(N(4,i)-N(5,i))>0.24*N(5,i) and
%// filter out some of the cells from the output
X = X1_sorted(abs(N(4,:)-N(5,:))>0.24*abs(N(5,:)));
%// Sort, keep unique elements and make them row vectors
%// within each cell of X (if needed)
X = cellfun(#(x) unique(x).',X,'Uni',0);
Output -
>> celldisp(X)
X{1} =
7 12
X{2} =
2 10 55
Using logical indexing will speed up your script dramatically. MATLAB is not really doing well with for loop. Try the following code:
k = size(N,2);
r = size(M,2);
M(5:7,:) = 0;
for ii = 1:k
index = sum(M(1:3,:) == repmat(N(1:3,ii),1,r),1)>2;
M(5,index) = ii;
M(6,index) = N(4,ii);
M(7,index) = N(5,ii);
end
filter = abs(M(6,:)-M(7,:))>0.24*abs(M(7,:));
X = {};
for ii = 1:k
X = [X, M(4,M(5,:) == ii& filter)];
end
On my computer, executing your code took 0.017825 seconds. Mine took 0.002780 seconds. I'd say that's quite some improvement. If you want to have a more detailed comparison, use profile.

How to avoid the loop to reduce the computation time of this code?

how to avoid the loop to reduce the computation time of this code (one solution of my last question):
I hope to find the column vectors of A(1:3,:) whose corresponding values in M(4,:) are not part of one of the vectors of the cell X (and obviously not equal to one of these vectors). I look for a fast solution if X is very large.
M = [1007 1007 4044 1007 4044 1007 5002 5002 5002 622 622;
552 552 300 552 300 552 431 431 431 124 124;
2010 2010 1113 2010 1113 2010 1100 1100 1100 88 88;
7 12 25 15 12 30 2 10 55 32 12];
Here I take directly A:
A = [1007 4044 5002 622;
552 300 431 124;
2010 1113 1100 88];
A contains unique column vectors of M(1:3,:)
X = {[2 5 68 44],[2 10 55 9 17],[1 55 6 7 8 9],[32 12]};
[~, ~, subs] = unique(M(1:3,:)','rows');
A4 = accumarray(subs(:),M(4,:).',[],#(x) {x});
%// getting a mask of which columns we want
idxC(length(A4)) = false;
for ii = 1:length(A4)
idxC(ii) = ~any(cellfun(#(x) all(ismember(A4{ii},x)), X));
end
Displaying the columns we want
out = A(:,idxC)
Results:
>> out
out =
1007 4044
552 300
2010 1113
the column vector [5002;431;1100] was eliminated because [2;10;55] is contained in X{2} = [2 10 55 9 17]
the column vector [622;124;88] was eliminated because [32 12] = X{4}
Another example: with the same X
M = [1007 4044 1007 4044 1007 5002 5002 5002 622 622 1007 1007 1007;
552 300 552 300 552 431 431 431 124 124 552 11 11;
2010 1113 2010 1113 2010 1100 1100 1100 88 88 2010 20 20;
12 25 15 12 30 2 10 55 32 12 7 12 7];
X = {[2 5 68 44],[2 10 55 9 17],[1 55 6 7 8 9],[32 12]};
A = [1007 4044 5002 622 1077;
552 300 431 124 11;
2010 1113 1100 88 20];
Results: (with scmg answer)
I get if A sorted according to the first row: (correct result)
out =
1007 1007 4044
11 552 300
20 2010 1113
if I do not sort the matrix A, I get: (false result)
out =
4044 5002 622
300 431 124
1113 1100 88
the column vector A(:,4) = [622;124;88] should be eliminated because [32 12] = X{4}.
the column vector [5002;431;1100] should be eliminated because [2;10;55] is contained in X{2} = [2 10 55 9 17]
The answer of Ben Voigt is great, but the line for A4i = A4{ii} is the one causing issues : the for loop doesn't work this way with column vectors :
%row vector
for i = 1:3
disp('foo');
end
foo
foo
foo
%column vector
for i = (1:3).'
disp('foo');
end
foo
Just try for A4i = A4{ii}.' instead and it should get your work done!
Now, if we look at the output :
A(:,idxC) =
4044 5002
300 431
1113 1100
As you can see, the final result is not what we expected.
As long as unique does a kind of sort, the subs are not numbered by the order of encounter in A, but by order of encounter in C (which is sorted) :
subs =
2
2
3
2
3
2
4
4
4
1
1
Therefore you should pass by the matrix given by unique rather than A to get your final output
Enter
[C, ~, subs] = unique(M(1:3,:)','rows');
%% rather than [~, ~, subs] = unique(M(1:3,:)','rows');
Then, to get the final output, enter
>> out = C(idxC,:).'
out =
1007 4044
552 300
2010 1113
In this case, you should not be trying to eliminate loops. The vectorization is actually hurting you badly.
In particular (giving a name to your anonymous lambda)
issubset = #(x) all(ismember(A4{ii},x))
is ridiculously inefficient, because it doesn't short-circuit. Replace that with a loop.
Same for
any(cellfun(issubset, X))
Use an approach similar to this instead:
idxC = true(size(A4));
NX = numel(X);
for ii = 1:length(A4)
for jj = 1:NX
xj = X{jj};
issubset = true;
for A4i=A4{ii}
if ~ismember(A4i, xj)
issubset = false;
break;
end;
end;
if issubset
idxC(ii) = false;
break;
end;
end;
end;
The two break statements, and especially the second one, trigger an early exit that potentially saves you a huge amount of computation.
Shot #1
Listed in this section is an approach that is supposed to be a quick and direct approach to solve our case. Please note that since A is the matrix of unique columns from M considering upto the third row, it is skipped here as the input because we generate it internally with the solution code. This is maintained in the next approach/shot as well. Here's the implementation -
function out = shot1_func(M,X)
%// Get unique columns and corresponding subscripts
[unqrows, ~, subs_idx] = unique(M(1:3,:)','rows');
unqcols = unqrows.'; %//'
counts = accumarray(subs_idx(:),1); %// Counts of each unique subs_idx
%// Modify each cell of X based on their relevance with the fourth row of M
X1 = cellfun(#(x) subs_idx(ismember(M(4,:),x)),X,'Uni',0);
lensX = cellfun('length',X1); %// Cell element count of X1
Xn = vertcat(X1{:}); %// Numeric array version of X
N = max(subs_idx); %// Number of unique subs_idx
%// Finally, get decision mask to select the correst columns from unqcols
sums = cumsum(bsxfun(#eq,Xn,1:N),1);
cumsums_at_shifts = sums(cumsum(lensX),:);
mask1 = any(bsxfun(#eq,diff(cumsums_at_shifts,[],1),counts(:).'),1); %//'
decision_mask = mask1 | cumsums_at_shifts(1,:) == counts(:).'; %//'
out = unqcols(:,~decision_mask);
return
Shot #2
The earlier mentioned approach might have a bottleneck at :
cellfun(#(x) subs_idx(ismember(M4,x)),X,'Uni',0)
So, alternatively to keep performance as a good motivation, one can separate out the whole process into two stages. The first stage could take care of cells of X that are not repeated in the fourth row of M, which could be implemented with a vectorized approach and another stage solving for the rest of X's cells with our slower cellfun based approach.
Thus, the code would bloat out a bit, but hopefully would be better with performance. The final implementation would look something like this -
%// Get unique columns and corresponding subscripts
[unqrows, ~, subs_idx] = unique(M(1:3,:)','rows')
unqcols = unqrows.' %//'
counts = accumarray(subs_idx,1);
%// Form ID array for X
lX = cellfun('length',X)
X_id = zeros(1,sum(lX))
X_id([1 cumsum(lX(1:end-1)) + 1]) = 1
X_id = cumsum(X_id)
Xr = cellfun(#(x) x(:).',X,'Uni',0); %//'# Convert to cells of row vectors
X1 = [Xr{:}] %// Get numeric array version
%// Detect cells that are to be processed by part1 (vectorized code)
[valid,idx1] = ismember(M(4,:),X1)
p1v = ~ismember(1:max(X_id),unique(X_id(accumarray(idx1(valid).',1)>1))) %//'
X_part1 = Xr(p1v)
X_part2 = Xr(~p1v)
%// Get decision masks from first and second passes and thus the final output
N = size(unqcols,2);
dm1 = first_pass(X_part1,M(4,:),subs_idx,counts,N)
dm2 = second_pass(X_part2,M(4,:),subs_idx,counts)
out = unqcols(:,~dm1 & ~dm2)
Associated functions -
function decision_mask = first_pass(X,M4,subs_idx,counts,N)
lensX = cellfun('length',X)'; %//'# Get X cells lengths
X1 = [X{:}]; %// Extract cell data from X
%// Finally, get the decision mask
vals = changem(X1,subs_idx,M4) .* ismember(X1,M4);
sums = cumsum(bsxfun(#eq,vals(:),1:N),1);
cumsums_at_shifts = sums(cumsum(lensX),:);
mask1 = any(bsxfun(#eq,diff(cumsums_at_shifts,[],1),counts(:).'),1); %//'
decision_mask = mask1 | cumsums_at_shifts(1,:) == counts(:).'; %//'
return
function decision_mask = second_pass(X,M4,subs_idx,counts)
%// Modify each cell of X based on their relevance with the fourth row of M
X1 = cellfun(#(x) subs_idx(ismember(M4,x)),X,'Uni',0);
lensX = cellfun('length',X1); %// Cell element count of X1
Xn = vertcat(X1{:}); %// Numeric array version of X
N = max(subs_idx); %// Number of unique subs_idx
%// Finally, get decision mask to select the correst columns from unqcols
sums = cumsum(bsxfun(#eq,Xn,1:N),1);
cumsums_at_shifts = sums(cumsum(lensX),:);
mask1 = any(bsxfun(#eq,diff(cumsums_at_shifts,[],1),counts(:).'),1); %//'
decision_mask = mask1 | cumsums_at_shifts(1,:) == counts(:).'; %//'
return
Verficication
This section lists code to verify the output. Here's the code to do so to verify the shot #1 code -
%// Setup inputs and output
load('matrice_data.mat'); %// Load input data
X = cellfun(#(x) unique(x).',X,'Uni',0); %// Consider X's unique elements
out = shot1_func(M,X); %// output with Shot#1 function
%// Accumulate fourth row data from M based on the uniqueness from first 3 rows
[unqrows, ~, subs] = unique(M(1:3,:)','rows'); %//'
unqcols = unqrows.'; %//'
M4 = accumarray(subs(:),M(4,:).',[],#(x) {x}); %//'
M4 = cellfun(#(x) unique(x),M4,'Uni',0);
%// Find out cells in M4 that correspond to unique columns unqcols
[unqcols_idx,~] = find(pdist2(unqcols.',out.')==0);
%// Finally, verify output
for ii = 1:numel(unqcols_idx)
for jj = 1:numel(X)
if all(ismember(M4{unqcols_idx(ii)},X{jj}))
error('Error: Wrong output!')
end
end
end
disp('Success!')
Maybe you can use 2 times cellfun:
idxC = cellfun(#(a) ~any(cellfun(#(x) all(ismember(a,x)), X)), A4, 'un', 0);
idxC = cell2mat(idxC);
out = A(:,idxC)

Fast way to find the neighboor of pixel

I am programming for task that finds the neighbor of a given pixel x in image Dthat can formula as:
The formula shown pixels y which satisfy the distance to pixel x is 1, then they are neighbor of pixel x. This is my matlab code. However, it still takes long time to find. Could you suggest a faster way to do it. Thank you so much
%-- Find the neighborhood of one pixel
% x is pixel coordinate
% nrow, ncol is size of image
function N = find_neighbor(x,nrow,ncol)
i = x(1);
j = x(2);
I1 = i+1;
if (I1 > nrow)
I1 = nrow;
end
I2 = i-1;
if (I2 < 1)
I2 = 1;
end
J1 = j+1;
if (J1 > ncol)
J1 = ncol;
end
J2 = j-1;
if (J2 < 1)
J2 = 1;
end
N = [I1, I2, i, i; j, j, J1, J2];
For example: ncol=128; nrow=128; x =[30;110] then output
N =31 29 30 30; 110 110 111 109]
For calling the function in loop
x=[30 31 32 33; 110 123 122 124]
for i=1:length(x)
N = find_neighbor(x(:,i),nrow,ncol);
end
Here's a vectorized approach using bsxfun:
% define four neighbors as coordinate differences
d = [-1 0 ; 1 0 ; 0 -1 ; 0 1]';
% add to pixel coordinates
N = bsxfun(#plus, x, permute(d, [1 3 2]));
% make one long list for the neighbors of all pixels together
N = reshape(N, 2, []);
% identify out-of-bounds coordinates
ind = (N(1, :) < 1) | (N(1, :) > nrow) | (N(2, :) < 1) | (N(2, :) > ncol);
% and remove those "neighbors"
N(:, ind) = [];
The permute is there to move the "dimension" of four different neighbors into the 3rd array index. This way, using bsxfun, we get the combination of every pair of original pixel coordinates with every pair of relative neighbor coordinates. The out-of-bounds check assumes that nrow belongs to the first coordinate and ncol to the second coordinate.
With
ncol=128;
nrow=128;
x = [30 31 32 33; 110 123 122 124];
the result is
N =
29 30 31 32 31 32 33 34 30 31 32 33 30 31 32 33
110 123 122 124 110 123 122 124 109 122 121 123 111 124 123 125
Different neighbors of different pixels can end up to be the same pixel, so there can be duplicates in the list. If you only want each resulting pixel once, use
% remove duplicates?
N = unique(N', 'rows')';
to get
N =
29 30 30 30 31 31 31 32 32 32 33 33 33 34
110 109 111 123 110 122 124 121 123 124 122 123 125 124
Matlab's performance is horrible when calling small functions many time. The Matlab approach is to do vectorize as much as possible. A vectorized version of your code:
function N = find_neighbor(x,nrow,ncol)
N = [min(x(1,:)+1,nrow), max(x(1,:)-1,1), x(1,:), x(1,:); x(2,:), x(2,:),min(x(2,:)+1,ncol), max(x(2,:)-1,1)];
end
and usage
x=[30 31 32 33; 110 123 122 124]
N = find_neighbor(x,nrow,ncol);
BTW, for pixels on the border , your solution always gives 4 neighbors. This is wrong. the neighbors of (1,1) for examples should be only (2,1) and (1,2), while you add two extra (1,1).
The solution to this is quite simple - delete all neighbors that are outside the image
function N = find_neighbor(x,nrow,ncol)
N = [x(1,:)+1, x(1,:)-1, x(1,:), x(1,:); x(2,:), x(2,:),x(2,:)+1, x(2,:)-1];
N(:,N(1,:)<1 | N(1,:)> nrow | N(2,:)<1 | N(2,:)>ncol)=[];
end