blocking matrix in matlab - matlab

Suppose that I have a matrix with non square size such as 30X35 and I want to split into blocks such as 4 blocks it would be like 15X18 and fill the added cell by zeros could that be done in matlab?

You can do it by copying the matrix (twice) and then setting to 0's the part you want to:
m = rand([30 35]);
mLeft = m;
mLeft(1:15, :) = 0;
mRight = m;
mRight(16:end, :) = 0;
Or it could be the other way around, first you create a matrix full of 0's and then copy the content you are interested.
mLeft = zeros(size(m));
mLeft(16:end, :) = m(16:end, :);
A generalisation could be done as:
% find the splits, the position where blocks end
splits = round(linspace(1, numRows+1, numBlocks+1));
% and for each block
for s = 1:length(splits)-1
% create matrix with 0s the size of m
mAux = zeros(size(m));
% copy the content only in block you are interested on
mAux( splits(s):splits(s+1)-1, : ) = m( splits(s):splits(s+1)-1, : )
% do whatever you want with mAux before it is overwriten on the next iteration
end
So with the 30x35 example (numRows = 30), and assuming you want 6 blocks (numBlocks = 6), splits will be:
splits = [1 6 11 16 21 26 31]
meaning that the i-th block starts at splits(i) and finsished at row splits(i-1)-1.
Then you create an empty matrix:
mAux = zeros(size(m));
And copy the content from m from column splits(i) to splits(i+1)-1:
mAux( splits(s):splits(s+1)-1, : ) = m( splits(s):splits(s+1)-1, : )
This example ilustrates if you want to have subdivision that span ALL the columns. If you want subsets of rows AND columns you will have to find the splits in both directions and then do 2 nested loops with:
for si = 1:legth(splitsI)-1
for sj = 1:legth(splitsj)-1
mAux = zeros(size(m));
mAux( splitsI(si):splitsI(si+1)-1, splitsJ(sj):splitsJ(sj+1)-1 ) = ...
m( splitsI(si):splitsI(si+1)-1, splitsJ(sj):splitsJ(sj+1)-1 );
end
end

Have you looked at blockproc ?

Related

MATLAB list manipulation

Consider I have a code segment as follows:
Case 1
n = 20;
for i = 2 : n
mat = rand([2,i]);
mat = [mat, mat(:,1)]; %add the first column to the last
%feed the variable 'mat' to a function
end
Case 2
n = 10;
list = [];
for i = 1 : n
a = rand([2,1]);
b = rand([2,2])
list = [list, [a,b]];
end
In this way, MATLAB gives the below suggestion:
The variable 'mat' appears to change size on every loop. Consider preallocating for speed up.
The variable 'list' appears to change size on every loop. Consider preallocating for speed up.
I am a MATLAB newconer, So I would like to know how to deal with this issue. How to do this in native MATLAB style? Thanks in advance.
I'll focus on the second case, as it's the only one that makes sense:
n = 10;
list = [];
for i = 1 : n
a = rand([2,1]);
b = rand([2,2])
list = [list, [a,b]];
end
That you are doing here, for each loop, is to create two vectors with random numbers, a and b. a has dimension 2x1, and b has dimension 2x2. Then, you concatenate these two, with the matrix list.
Note that each call to rand are independent, so rand(2,3) will behave the same way [rand(2,2), rand(2,1)] does.
Now, since you loop 10 times, and you add rand(2,3) every time, you're essentially doing [rand(2,2), rand(2,1), rand(2,2), rand(2,1) ...]. This is equivalent to rand(2,30), which is a lot faster. Therefore, "Consider preallocating for speed up."
Now, if your concatenations doesn't contain random matrices, but are really the output from some function that can't output the entire matrix you want, then preallocate and insert it to the matrix using indices:
Let's define a few functions:
function x = loopfun(n)
x = n*[1; 2];
end
function list = myfun1(n)
list = zeros(2, n);
for ii = 1:n
list(:,ii) = loopfun(ii);
end
end
function list = myfun2(n)
list = [];
for ii = 1:n
list = [list, loopfun(ii)];
end
end
f1 = #() myfun1(100000); f2 = #() myfun2(100000);
fprintf('Preallocated: %f\nNot preallocated: %f\n', timeit(f1), timeit(f2))
Preallocated: 0.141617
Not preallocated: 0.318272
As you can see, the function with preallocation is twice as fast as the function with an increasing sized matrix. The difference is smaller if there are few iterations, but the general idea is the same.
f1 = #() myfun1(5); f2 = #() myfun2(5);
fprintf('Preallocated: %f\nNot preallocated: %f\n', timeit(f1), timeit(f2))
Preallocated: 0.000010
Not preallocated: 0.000018

Matlab: Looping through an array

This is my one dimensional array A. containing 10 numbers
A = [-8.92100000000000 10.6100000000000 1.33300000000000 ...
-2.57400000000000 -4.52700000000000 9.63300000000000 ...
4.26200000000000 16.9580000000000 8.16900000000000 4.75100000000000];
I want the loop to go through like this;
(calculating mean interval wise) - Interval length of 2,4,8
(a(1)+a(2))/2 - value stored in one block of a matrix say m= zeros(10)
then (a(1)+a(2)+a(3)+a(4))/4 ------ mean-----
then (a(1)+a(2)..... a(8))/8
then shift index;
(a(2)+a(3))/2; - mean
(a(2)+a(3)+a(4)+a(5))/4
(a(2)+a(3)...a(9))/8
SO basically 2^n length interval
You could do this using conv without loops
avg_2 = mean([A(1:end-1);A(2:end)])
avg_4 = conv(A,ones(1,4)/4,'valid')
avg_8 = conv(A,ones(1,8)/8,'valid')
Output for the sample Input:
avg_2 =
0.8445 5.9715 -0.6205 -3.5505 2.5530 6.9475 10.6100 12.5635 6.4600
avg_4 =
0.1120 1.2105 0.9662 1.6985 6.5815 9.7555 8.5350
avg_8 =
3.3467 5.4830 4.7506
Finding Standard Deviation for an example (std_4)
%// each 1x4 sliding sub-matrix is made a column
%// for eg:- if A is 1x6 you would get 1-2-3-4, 2-3-4-5, 3-4-5-6 each as a column
%// ending with 3 columns. for 1x10 matrix, you would get 7 columns
reshaped_4 = im2col(A,[1 4],'sliding'); %// change 4 to 2 or 8 for other examples
%// calculating the mean of every column
mean_4 = mean(reshaped_4);
%// Subtract each value of the column with the mean value of corresponding column
out1 = bsxfun(#minus,reshaped_4,mean_4);
%// finally element-wise squaring, mean of each column
%// and then element-wise sqrt to get the output.
std_4 = sqrt(mean(out1.^2))
Output for the sample Input:
std_4 =
7.0801 5.8225 5.4304 5.6245 7.8384 4.5985 5.0906
Full code for OP
clc;
clear;
close all;
A = [-8.92100000000000 10.6100000000000 1.33300000000000 ...
-2.57400000000000 -4.52700000000000 9.63300000000000 ...
4.26200000000000 16.9580000000000 8.16900000000000 4.75100000000000];
reshaped_2 = im2col(A,[1 2],'sliding'); %// Length Two
mean_2 = mean(reshaped_2);
out1 = bsxfun(#minus,reshaped_2,mean_2);
std_2 = sqrt(mean(out1.^2))
reshaped_4 = im2col(A,[1 4],'sliding'); %// Four
mean_4 = mean(reshaped_4);
out1 = bsxfun(#minus,reshaped_4,mean_4);
std_4 = sqrt(mean(out1.^2))
reshaped_8 = im2col(A,[1 8],'sliding'); %// Eight
mean_8 = mean(reshaped_8);
out1 = bsxfun(#minus,reshaped_8,mean_8);
std_8 = sqrt(mean(out1.^2))

Concatenate more than two matrices - get out of memory error

I would like to concatenate some matrices (20-30). I wrote a simple function:
function [ appendedResults ] = appendResults( startNumber, endNumber )
str2 = '_simulation.xlsx';
str1 = num2str(startNumber);
InputFilename = strcat(str1, str2);
appendedResults = uint16( xlsread(InputFilename ) );
for i= startNumber+1 : endNumber
temp_simulationResults = uint16( xlsread(InputFilename ) );
appendedResults = vertcat( appendedResults, temp_simulationResults );
end
filename1 = strcat('appended', str2);
xlswrite(filename1, appendedResults);
end
It's works fine if I use 3-4 matrices. But when I'm using more, I get an error:
Error using xlswrite (line 219)
Error: Not enough memory
Then the matlab use 6 GigaByte (!!) memory. The matrices are only 7 MegaByte!
I wrote another function with for loops( without Matlab Vertcat function).
I get the same error!
function [ appendedResults ] = appendResultsInOneMatrix( startNumber, endNumber )
str2 = '__simulation.xlsx';
str1 = num2str(startNumber);
InputFilename = strcat(str1, str2);
numberOfItems = (endNumber - startNumber) + 1 ;
firstResults = uint16( xlsread(InputFilename ) );
[row , col] = size(firstResults);
appendedResults = zeros ( row * numberOfItems , col);
for i=1: row
for j=1:col
appendedResults( i , j ) = firstResults( i , j);
end
end
for i= startNumber+1 : endNumber
str1 = num2str(i);
InputFilename = strcat(str1, str2);
temp_simulationResults = uint16( xlsread(InputFilename ) );
[temp_row , temp_col] = size(temp_simulationResults);
for m = 1 : temp_row
for n = 1 : temp_col
appendedResults( m+row , n ) = temp_simulationResults( m , n);
end
end
end
filename1 = strcat('appended', str2);
xlswrite(filename1, appendedResults);
end
What's wrong?
If you concatenate matrices, the resulting dimensions will be the maxima of the individual dimensions of the input matrices times the number of matrices; for example, if matrix A is 1x1,000,000 and matrix B is 1,000,000x1, the individual storage of these matrices would only be 1 million elements, but the resulting matrix would need to store 2* 1012 elements!
EDIT: also, Excel files definitely are not the storage you should be using for tables with more than a million entries!
EDIT2: Take a piece of paper. Draw a 1cm x 10cm (width x height) rectangle on it, write "matrix A" on it so you know how the rectangle is oriented and don't accidentially rotate it. Cut it out. Draw a 10cm x 1cm rectange, write "matrix B" on it, for the same reason.
Concatenate both rectangles. What is the area of the rectangle you need to enclose this shape? What's the sum of areas of the "matrix A" and "matrix B" rectangles?
Matrices are rectangular, and by default you will have to have enough space to store the minimum rectangle that contains the concatenation of your matrices. You can change that by using sparse matrices in Matlab (that's a long topic, and can't be explained in a single StackOverflow answer), but that won't change the fact that what you're doing probably doesn't make the least sense.

Saving different sized vectors from a nested for loop in MATLAB

I have a 3 nested for loop that produces a vector, but each time it runs through the loops the vector that is produced changes size. I need to save each of these vectors at the ended of the for loops, so I was thinking of using mat2cell and store them in a cell. But I don't know the code get out a cell vector that will contain each of these different sized vectors.
I will give an example code
for ip = n_low:n_up
for jx = x_low:x_up
for jphi = phi_lowx:phi_upx
lx = find_path(ip,jx,jphi,0,1);
.
.
.
A_r = volumeintegrate(integr_final_r , r , z , phi);
end
end
end
Obviously, you don't know what these variables are or the numbers but I think its not needed to solve the problem. Anyways A_r is what is spit out at the end of the loops, but A_r varies in size as the loop repeats itself. I need to save every A_r vector.
Add a counter and save to a cell element: for example:
counter=0
for ...
for ...
for ...
counter=counter+1;
A_r{counter} = volumeintegrate(integr_final_r , r , z , phi);
then to extract the n-th vector just write A_r{n}
Just create a cell array:
A_r = cell(Ni, Nj, Nk)
Then create loops - note I am indexing over well behaved integers which I will use as index into my cell array, then computing the actual value for the variables you need by looking at the array iVec etc:
iVec = n_low:n_up;
Ni = numel(iVec);
jVec = x_low:x_up;
Nj = numel(jVec);
kVec = phi_lowx:phi_upx;
Nk = numel(kVec);
A_r = cell(Ni, Nj, Nk);
for ii = 1:Ni
ip = iVec(ii);
for jj = 1:Nj
jx = jVec(jj);
for kk = 1:Nk
jphi = kVec(kk);
lx = find_path(ip,jx,jphi,0,1);
....
A_r{ii,jj,kk} = volumeintegrate(integr_final_r , r , z , phi);;
end
end
end
You can now access each array in the same way that it was assigned:
A_r{ii,jj,kk}

How to improve execution time of the following Matlab code

Please help me to improve the following Matlab code to improve execution time.
Actually I want to make a random matrix (size [8,12,10]), and on every row, only have integer values between 1 and 12. I want the random matrix to have the sum of elements which has value (1,2,3,4) per column to equal 2.
The following code will make things more clear, but it is very slow.
Can anyone give me a suggestion??
clc
clear all
jum_kel=8
jum_bag=12
uk_pop=10
for ii=1:uk_pop;
for a=1:jum_kel
krom(a,:,ii)=randperm(jum_bag); %batasan tidak boleh satu kelompok melakukan lebih dari satu aktivitas dalam satu waktu
end
end
for ii=1:uk_pop;
gab1(:,:,ii) = sum(krom(:,:,ii)==1)
gab2(:,:,ii) = sum(krom(:,:,ii)==2)
gab3(:,:,ii) = sum(krom(:,:,ii)==3)
gab4(:,:,ii) = sum(krom(:,:,ii)==4)
end
for jj=1:uk_pop;
gabh1(:,:,jj)=numel(find(gab1(:,:,jj)~=2& gab1(:,:,jj)~=0))
gabh2(:,:,jj)=numel(find(gab2(:,:,jj)~=2& gab2(:,:,jj)~=0))
gabh3(:,:,jj)=numel(find(gab3(:,:,jj)~=2& gab3(:,:,jj)~=0))
gabh4(:,:,jj)=numel(find(gab4(:,:,jj)~=2& gab4(:,:,jj)~=0))
end
for ii=1:uk_pop;
tot(:,:,ii)=gabh1(:,:,ii)+gabh2(:,:,ii)+gabh3(:,:,ii)+gabh4(:,:,ii)
end
for ii=1:uk_pop;
while tot(:,:,ii)~=0;
for a=1:jum_kel
krom(a,:,ii)=randperm(jum_bag); %batasan tidak boleh satu kelompok melakukan lebih dari satu aktivitas dalam satu waktu
end
gabb1 = sum(krom(:,:,ii)==1)
gabb2 = sum(krom(:,:,ii)==2)
gabb3 = sum(krom(:,:,ii)==3)
gabb4 = sum(krom(:,:,ii)==4)
gabbh1=numel(find(gabb1~=2& gabb1~=0));
gabbh2=numel(find(gabb2~=2& gabb2~=0));
gabbh3=numel(find(gabb3~=2& gabb3~=0));
gabbh4=numel(find(gabb4~=2& gabb4~=0));
tot(:,:,ii)=gabbh1+gabbh2+gabbh3+gabbh4;
end
end
Some general suggestions:
Name variables in English. Give a short explanation if it is not immediately clear,
what they are indented for. What is jum_bag for example? For me uk_pop is music style.
Write comments in English, even if you develop source code only for yourself.
If you ever have to share your code with a foreigner, you will spend a lot of time
explaining or re-translating. I would like to know for example, what
%batasan tidak boleh means. Probably, you describe here that this is only a quick
hack but that someone should really check this again, before going into production.
Specific to your code:
Its really easy to confuse gab1 with gabh1 or gabb1.
For me, krom is too similar to the built-in function kron. In fact, I first
thought that you are computing lots of tensor products.
gab1 .. gab4 are probably best combined into an array or into a cell, e.g. you
could use
gab = cell(1, 4);
for ii = ...
gab{1}(:,:,ii) = sum(krom(:,:,ii)==1);
gab{2}(:,:,ii) = sum(krom(:,:,ii)==2);
gab{3}(:,:,ii) = sum(krom(:,:,ii)==3);
gab{4}(:,:,ii) = sum(krom(:,:,ii)==4);
end
The advantage is that you can re-write the comparsisons with another loop.
It also helps when computing gabh1, gabb1 and tot later on.
If you further introduce a variable like highestNumberToCompare, you only have to
make one change, when you certainly find out that its important to check, if the
elements are equal to 5 and 6, too.
Add a semicolon at the end of every command. Having too much output is annoying and
also slow.
The numel(find(gabb1 ~= 2 & gabb1 ~= 0)) is better expressed as
sum(gabb1(:) ~= 2 & gabb1(:) ~= 0). A find is not needed because you do not care
about the indices but only about the number of indices, which is equal to the number
of true's.
And of course: This code
for ii=1:uk_pop
gab1(:,:,ii) = sum(krom(:,:,ii)==1)
end
is really, really slow. In every iteration, you increase the size of the gab1
array, which means that you have to i) allocate more memory, ii) copy the old matrix
and iii) write the new row. This is much faster, if you set the size of the
gab1 array in front of the loop:
gab1 = zeros(... final size ...);
for ii=1:uk_pop
gab1(:,:,ii) = sum(krom(:,:,ii)==1)
end
Probably, you should also re-think the size and shape of gab1. I don't think, you
need a 3D array here, because sum() already reduces one dimension (if krom is
3D the output of sum() is at most 2D).
Probably, you can skip the loop at all and use a simple sum(krom==1, 3) instead.
However, in every case you should be really aware of the size and shape of your
results.
Edit inspired by Rody Oldenhuis:
As Rody pointed out, the 'problem' with your code is that its highly unlikely (though
not impossible) that you create a matrix which fulfills your constraints by assigning
the numbers randomly. The code below creates a matrix temp with the following characteristics:
The numbers 1 .. maxNumber appear either twice per column or not at all.
All rows are a random permutation of the numbers 1 .. B, where B is equal to
the length of a row (i.e. the number of columns).
Finally, the temp matrix is used to fill a 3D array called result. I hope, you can adapt it to your needs.
clear all;
A = 8; B = 12; C = 10;
% The numbers [1 .. maxNumber] have to appear exactly twice in a
% column or not at all.
maxNumber = 4;
result = zeros(A, B, C);
for ii = 1 : C
temp = zeros(A, B);
for number = 1 : maxNumber
forbiddenRows = zeros(1, A);
forbiddenColumns = zeros(1, A/2);
for count = 1 : A/2
illegalIndices = true;
while illegalIndices
illegalIndices = false;
% Draw a column which has not been used for this number.
randomColumn = randi(B);
while any(ismember(forbiddenColumns, randomColumn))
randomColumn = randi(B);
end
% Draw two rows which have not been used for this number.
randomRows = randi(A, 1, 2);
while randomRows(1) == randomRows(2) ...
|| any(ismember(forbiddenRows, randomRows))
randomRows = randi(A, 1, 2);
end
% Make sure not to overwrite previous non-zeros.
if any(temp(randomRows, randomColumn))
illegalIndices = true;
continue;
end
end
% Mark the rows and column as forbidden for this number.
forbiddenColumns(count) = randomColumn;
forbiddenRows((count - 1) * 2 + (1:2)) = randomRows;
temp(randomRows, randomColumn) = number;
end
end
% Now every row contains the numbers [1 .. maxNumber] by
% construction. Fill the zeros with a permutation of the
% interval [maxNumber + 1 .. B].
for count = 1 : A
mask = temp(count, :) == 0;
temp(count, mask) = maxNumber + randperm(B - maxNumber);
end
% Store this page.
result(:,:,ii) = temp;
end
OK, the code below will improve the timing significantly. It's not perfect yet, it can all be optimized a lot further.
But, before I do so: I think what you want is fundamentally impossible.
So you want
all rows contain the numbers 1 through 12, in a random permutation
any value between 1 and 4 must be present either twice or not at all in any column
I have a hunch this is impossible (that's why your code never completes), but let me think about this a bit more.
Anyway, my 5-minute-and-obvious-improvements-only-version:
clc
clear all
jum_kel = 8;
jum_bag = 12;
uk_pop = 10;
A = jum_kel; % renamed to make language independent
B = jum_bag; % and a lot shorter for readability
C = uk_pop;
krom = zeros(A, B, C);
for ii = 1:C;
for a = 1:A
krom(a,:,ii) = randperm(B);
end
end
gab1 = sum(krom == 1);
gab2 = sum(krom == 2);
gab3 = sum(krom == 3);
gab4 = sum(krom == 4);
gabh1 = sum( gab1 ~= 2 & gab1 ~= 0 );
gabh2 = sum( gab2 ~= 2 & gab2 ~= 0 );
gabh3 = sum( gab3 ~= 2 & gab3 ~= 0 );
gabh4 = sum( gab4 ~= 2 & gab4 ~= 0 );
tot = gabh1+gabh2+gabh3+gabh4;
for ii = 1:C
ii
while tot(:,:,ii) ~= 0
for a = 1:A
krom(a,:,ii) = randperm(B);
end
gabb1 = sum(krom(:,:,ii) == 1);
gabb2 = sum(krom(:,:,ii) == 2);
gabb3 = sum(krom(:,:,ii) == 3);
gabb4 = sum(krom(:,:,ii) == 4);
gabbh1 = sum(gabb1 ~= 2 & gabb1 ~= 0)
gabbh2 = sum(gabb2 ~= 2 & gabb2 ~= 0);
gabbh3 = sum(gabb3 ~= 2 & gabb3 ~= 0);
gabbh4 = sum(gabb4 ~= 2 & gabb4 ~= 0);
tot(:,:,ii) = gabbh1+gabbh2+gabbh3+gabbh4;
end
end