I have a 3x3 matrix, k1, that I would like to convert into a 5x5 matrix, k1g. k1g is created by inserting zeros into certain rows and columns of k1. In this case I would like to insert zeros into rows 3 and 4 and columns 3 and 4, and keep existing values from k1 matrix. The code below accomplishes what I am trying to do but seems that it is a long method and I need to do this many times in numerous problems.
clc
clear all
format long;
k1 = [20,50,-20;
60,20,-20;
-20,-20,40]
k1g = zeros(5,5);
k1g(1:2,1:2) = k1(1:2,1:2);
k1g(5:5,1:2) = k1(3:3,1:2);
k1g(1:2,5:5) = k1(1:2,3:3);
k1g(5,5) = k1(3,3)
Here is output of above code:
k1 =
20 50 -20
60 20 -20
-20 -20 40
k1g =
20 50 0 0 -20
60 20 0 0 -20
0 0 0 0 0
0 0 0 0 0
-20 -20 0 0 40
Is there a better way to accomplish this?
You just need to generalise your approach. e.g. with:
function k1g = rowcolsof0s(k1,rowsof0s,colsof0s)
k1g = ones(size(k1)+[numel(rowsof0s) numel(colsof0s)]); %Initialising matrix with ones
k1g(rowsof0s,:) = 0; %Changing the elements of desired rows to zeros
k1g(:,colsof0s) = 0; %Changing the elements of desired columns to zeros
k1g(logical(k1g)) = k1; %Transferring the contents of k1 into k1g
end
Now call that function with:
rowsof0s = [3 4]; %rows where you want to insert zeros
colsof0s = [3 4]; %columns where you want to insert zeros
k1g = rowcolsof0s(k1, rowsof0s, colsof0s);
Related
I have two matrices. One is of size 1,000,000 x 9 and the other is 500,000 x 9.
The columns have the same meaning and the first 7 columns have the function of a key. Correspondingly, the last two columns have data character. There are many overlapping key values in both of the matrices and I would like to have a big matrix to compare the values. This big matrix should be of dimension 1,000,000 x 11.
For example:
A = [0 0 0 0 0 0 0 10 20; 0 0 0 0 0 0 1 30 40];
B = [0 0 0 0 0 0 0 50 60];
A merged matrix would look like this:
C = [0 0 0 0 0 0 0 10 20 50 60; 0 0 0 0 0 0 1 30 40 0 0];
As you can see, the first row of C has columns 8, 9 from matrix A and columns 10,11 from matrix B. The second row uses the columns 8, 9 from matrix A and 0,0 for the last to columns because there is no corresponding entry in matrix B.
I have accomplished this task theoretically, but it is very, very slow. I use loops a lot. In any other programming language, I would sort both tables, would iterate both of the tables in one big loop keeping two pointers.
Is there a more efficient algorithm available in Matlab using vectorization or at least a sufficiently efficient one that is idiomatic/short?
(Additional note: My largest issue seems to be the search function: Given my matrix, I would like to throw in one column vector 7x1, let's name it key to find the corresponding row. Right now, I use bsxfun for that:
targetRow = data( min(bsxfun(#eq, data(:, 1:7), key), [], 2) == 1, :);
I use min because the result of bsxfun is a vector with 7 match flags and I obviously want all of them to be true. It seems to me that this could be bottleneck of a Matlab algorithm)
Maybe with ismember and some indexing:
% locates in B the last ocurrence of each key in A. idxA has logicals of
% those keys found, and idxB tells us where in B.
[idxA, idxB] = ismember(A(:,1:7), B(:,1:7),'rows');
C = [ A zeros(size(A, 1), 2) ];
C(idxA, 10:11) = B(idxB(idxA), 8:9); % idxB(idxA) are the idxB != 0
I think this does what you want, only tested with your simple example.
% Initial matrices
A = [0 0 0 0 0 0 0 10 20;
0 0 0 0 0 0 1 30 40];
B = [0 0 0 0 0 0 0 50 60];
% Stack matrices with common key columns, 8&9 or 10&11 for data columns
C = [[A, zeros(size(A,1),2)]; [B(:,1:7), zeros(size(B,1),2), B(:,8:9)]];
% Sort C so that matching key rows will be consecutive
C = sortrows(C,1:7);
% Loop through rows
curRow = 1;
lastRow = size(C,1) - 1;
while curRow < lastRow
if all(C(curRow,1:7) == C(curRow+1,1:7))
% If first 7 cols of 2 rows match, take max values (override 0s)
% It may be safer to initialise the 0 columns to NaNs, as max will
% choose a numeric value over NaN, and it allows your data to be
% negative values.
C(curRow,8:11) = max(C(curRow:curRow+1, 8:11));
% Remove merged row
C(curRow+1,:) = [];
% Decrease size counter for matrix
lastRow = lastRow - 1;
else
% Increase row counter
curRow = curRow + 1;
end
end
Answer:
C = [0 0 0 0 0 0 0 10 20 50 60
0 0 0 0 0 0 1 30 40 0 0]
I would like to write a "syntactical sugar" Octave or Matlab zero-padding function, to which the user sends an n-dimensional object and a vector of <= n entries. The vector contains new, equal or larger dimensions for the object, and the object is zero-padded to match these dimensions. Any dimensions not specified are left alone. One expected use is, given for example a 5d block X of 3d medical image volumes, I can call
y = simplepad(X, [128 128 128]);
and thus pad the first three dimensions to a power of two for wavelet analysis (in fact I use a separate function nextpwr2 to find these dimensions) while leaving the others.
I have racked my brains on how to write this method avoiding the dreaded eval, but cannot thus far find a way. Can anyone suggest a solution? Here is more or less what I have:
function y = simplepad(x, pad)
szx = size(x);
n_pad = numel(pad);
szy = [pad szx(n_pad+1:end)];
y = zeros(szy);
indices_string = '(';
for n = 1:numel(szx)
indices_string = [indices_string, '1:', num2str(szx(n))];
if n < numel(szx)
indices_string = [indices_string, ','];
else
indices_string = [indices_string, ')'];
end
end
command = ['y',indices_string,'=x;'];
eval(command);
end
Here's a solution that should handle all the little corner cases:
function A = simplepad(A, pad)
% Add singleton dimensions (i.e. ones) to the ends of the old size of A
% or pad as needed so they can be compared directly to one another:
oldSize = size(A);
dimChange = numel(pad)-numel(oldSize);
oldSize = [oldSize ones(1, dimChange)];
pad = [pad ones(1, -dimChange)];
% If all of the sizes in pad are less than or equal to the sizes in
% oldSize, there is no padding done:
if all(pad <= oldSize)
return
end
% Use implicit zero expansion to pad:
pad = num2cell(pad);
A(pad{:}) = 0;
end
And a few test cases:
>> M = magic(3)
M =
8 1 6
3 5 7
4 9 2
>> simplepad(M, [1 1]) % No change, since the all values are smaller
ans =
8 1 6
3 5 7
4 9 2
>> simplepad(M, [1 4]) % Ignore the 1, pad the rows
ans =
8 1 6 0
3 5 7 0
4 9 2 0
>> simplepad(M, [4 4]) % Pad rows and columns
ans =
8 1 6 0
3 5 7 0
4 9 2 0
0 0 0 0
>> simplepad(M, [4 4 2]) % Pad rows and columns and add a third dimension
ans(:,:,1) =
8 1 6 0
3 5 7 0
4 9 2 0
0 0 0 0
ans(:,:,2) =
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
As I understand, you want just pass the some dynamic arguments to function.
You can do this by converting these arguments to cell and call your function with passing cell content. So, your function will look like:
function y = simplepad(x, pad)
szx = size(x);
n_pad = numel(pad);
szy = [pad szx(n_pad+1:end)];
y = x;
szyc = num2cell(szy);
y(szyc{:}) = 0; % warning: assume x array only grows
end
I want to create a vector in Matlab with two step sizes that will alternate.
vector =
0 50 51 101 102 152 etc.
So the step size is 50 and 1 which will alternate. How to write a script that will create this vector?
Code
N = 6; %// Number of elements needed in the final output
sz1 = 50; %// Stepsize - 1
sz2 = 4; %// Stepsize - 2
startval = 8; %// First element of the output
vector = reshape(bsxfun(#plus,[startval startval+sz1]',[0:N/2-1]*(sz1+sz2)),1,[])
Output
vector =
8 58 62 112 116 166
Note: For your problem, you need to use sz2 = 1 and startval = 0 instead.
Explanation
Internally it creates two matrices which when "flattened-out" to form vectors would resemble the two vectors that you have pointed out in the comments. You can get those two matrices with the following two sets of conditions.
Set #1: If you keep N = 6, sz1 = 50, sz2 = 0 and startval = 0 -
bsxfun(#plus,[startval startval+sz1]',[0:N/2-1]*(sz1+sz2))
gives us -
0 50 100
50 100 150
Set #2: If you keep N = 6, sz1 = 0, sz2 = 1 and startval = 0 -
bsxfun(#plus,[startval startval+sz1]',[0:N/2-1]*(sz1+sz2))
gives us -
0 1 2
0 1 2
Good thing about bsxfun is that these two matrices can be summed internally to give the final output -
0 51 102
50 101 152
Since, you needed the output as a vector, we need to flatten it out using reshape -
reshape(...,1,[])
giving us -
0 50 51 101 102 152
Thus, we have the final code that was listed earlier.
Here are some ideas I've been playing around with:
Initialization (comparable to Divakar's answer):
N = 6; %// Number of pairs in the final output
firstStep = 50;
secndStep = 1;
startVal = 8; %// First element of the output
And then:
%// Idea 1:
V1 = [startVal cumsum(repmat([firstStep,secndStep],[1,N])) + startVal];
%// Idea 2:
trimVec = #(vec)vec(1:end-1);
V2 = trimVec(circshift(kron((startVal:firstStep:startVal + ...
N*firstStep),[1,1]),[0,-1]) + kron((0:N),[1,1]));
Note that both of these vectors result in length = 2*N + 1.
The thing I'd like to point out is that if you create your vector of differences (e.g. [1 50 1 50 ...]), cumsum() really does the trick from there (you can also have more than 2 step sizes if you choose).
Let the input data be
step1 = 50;
step2 = 1;
start = 0;
number = 9; %// should be an odd number
Then:
n = (number-1)/2;
vector = cumsum([start reshape(([repmat(step1,1,n); repmat(step2,1,n)]),1,[])]);
The result in this example is
vector =
0 50 51 101 102 152 153 203 204
I'm looking for an elegant solution to this very simple problem in MATLAB. Suppose I have a matrix
>> M = magic(5)
M =
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
and a logical variable of the form
I =
0 0 0 0 0
0 1 1 0 0
0 1 1 0 0
0 0 0 0 0
0 0 0 0 0
If I try to retrieve the elements of M associated to 1 values in I, I get a column vector
>> M(I)
ans =
5
6
7
13
What would be the simplest way to obtain the matrix [5 7 ; 6 13] from this logical indexing?
If I know the shape of the non-zero elements of I, I can use a reshape after the indexing, but that's not a general case.
Also, I'm aware that the default behavior for this type of indexing in MATLAB enforces consistency with respect to the case in which non-zero values in I do not form a matrix, but I wonder if there is a simple solution for this particular case.
This is a one way to do this. It is assumed that all rows of I have same number of ones. It is also assumed that all columns of I have same number have ones, because Submatrix must be rectangular.
%# Define the example data.
M = magic(5);
I = zeros(5);
I(2:3, 2:3) = 1;
%# Create the Submatrix.
Submatrix = reshape(M(find(I)), max(sum(I)), max(sum(I')));
Here is a very simple solution:
T = I(any(I'),any(I));
T(:) = M(I);
M = magic(5);
I = [ ... ];
ind = find(I); %# find indices of ones in I
[y1, x1] = ind2sub(size(M), ind(1)); %# get top-left position
[y2, x2] = ind2sub(size(M), ind(end)); %# get bottom-right position
O = M(y1:y2, x1:x2); %# copy submatrix
I Have my function below, the idea being that X is a 3x3 extract from T to be used in the loop, it correctly extracts the 3 rows but for some reason produces far too many columns, see example below.
function T = tempsim(rows, cols, topNsideTemp, bottomTemp, tol)
T = zeros(rows,cols);
T(1,:) = topNsideTemp;
T(:,1) = topNsideTemp;
T(:,rows) = topNsideTemp;
T(rows,:) = bottomTemp;
S = [0 1 0; 1 1 1; 0 1 0];
X = zeros(3,3);
A = zeros(3,3);
for ii = 2:(cols-1);
jj = 2:(rows-1);
X = T([(ii-1) ii (ii+1)], [(jj-1) jj (jj+1)])
A = X.*S;
T = (sum(sum(A)))/5
end
test sample
EDU>> T = tempsim(5,4,100,50,0)
X =
100 100 100 100 100 100 100 100 100
100 0 0 0 0 0 0 0 100
100 0 0 0 0 0 0 0 100
ans =
100 100 100 100 100 100 100 100 100
100 0 0 0 0 0 0 0 100
100 0 0 0 0 0 0 0 100
??? Error using ==> times
Matrix dimensions must agree.
Error in ==> tempsim at 14
A = X.*S;
any thoughts on how to fix this?
There's no need to preallocate X and A if you do a complete assignment anyway. Then, you replace T with a scalar inside the loop, which makes you run into problems in the next iteration. What I'm guessing you want could look something like this:
function T = tempsim(rows, cols, topNsideTemp, bottomTemp, tol)
T = zeros(rows,cols);
T(1,:) = topNsideTemp;
T(:,1) = topNsideTemp;
T(:,rows) = topNsideTemp;
T(rows,:) = bottomTemp;
S = [0 1 0; 1 1 1; 0 1 0];
for ii = 1:(cols-2);
for jj = 1:(rows-2);
X = T(ii:ii+2, jj:jj+2);
A = X.*S;
T(ii,jj) = (sum(sum(A)))/5;
end
end
Although I'm not sure if you really mean to do that – you're working on T while modifying it. As a wild guess, I suspect you might be looking for something like
conv2(T, S/5, 'same')
instead, perhaps after making your fixed-temp borders twice as thick and re-setting them after the call (since conv2 does zero-padding at the outer borders).
Here:
jj = 2:(rows-1);
X = T([(ii-1) ii (ii+1)], [(jj-1) jj (jj+1)])
jj becomes [2 3 4]
so X is
T([1 2 3], [ [2 3 4]-1 [2 3 4] [2 3 4]+1 ])
You probably missed a for loop.