matlab: filling matrix diagonalwise [duplicate] - matlab

This question already has answers here:
adding values to diagonals of matrix using element-wise addition in matlab
(3 answers)
Closed 7 years ago.
I have an (2n-1)-by-1 vector with certain values and I want to obtain an n-n matrix with the diagonals filled using the same value.
Eg. if I have
a = [1; 2; 3; 4; 5];
I want to obtain
A = [[3 4 5];[2 3 4];[1 2 3]]
= 3 4 5
2 3 4
1 2 3
My matrix dimensions are a lot bigger so I'd want this as efficient as possible. I already found following solutions:
n = 3;
A = toeplitz(a);
A = A(1:n,end-n+1:end)
and
A = a(n)*eye(n);
for j=1:n-1
A(1+j:n+1:end-j*n) = a(n-j);
A(j*n+1:n+1:end) = a(n+j);
end
I wonder if there are more efficient ways to obtain this result, keeping in mind that I am working with huge matrices and really need the speed.

ix=bsxfun(#plus,[1:n],[n-1:-1:0]'); %generate indices
A=a(ix);
or
A=hankel(a) %might be faster than toeplitz because half the matrix is zero
A(n:-1:1,1:n)
here is what hankel does internally (at least in ML R2013a), adapted to this problem:
c=[1:n];
r=[n-1:-1:0]';
idx=c(ones(n,1),:)+r(:,ones(n,1));
A=a(ix);
I guess the bsxfun solution and what thewaywewalk supposed is the fastest (it's basically the same)

Go with:
n = (numel(a)+1)/2;
A = a(bsxfun(#minus, n+1:n+n, (1:n).'));

Related

How to vectorize the evaluation of outer product matrix for every row of the 2D matrix? [duplicate]

This question already has answers here:
Efficiently compute a 3D matrix of outer products - MATLAB
(3 answers)
Closed 3 years ago.
I am trying to speed the process in evaluation the outer product matrix. I have a 4*n matrix named a. I want to evaluate the outer product matrix for every row of a, by the formula:
K = a*a';
If I code this process using a for loop, it is as below:
K=zeros(4,4,size(a,2));
for i=1:size(a,2)
K(:,:,i) = a(:,i)*a(:,i)';
end
I have found another method, using cellfun, which is even slower than before.
acell = num2cell(a, 1);
b = cellfun(#(x)(x*x'),acell,'UniformOutput',false);
K = reshape(cell2mat(b),4,4,[]);
Is there any good way to implement these process, such as vectorization?
You can use kron to repeat the matrix n time, so no need to preallocation, then perform an element wise multiplication with a(:).', finally reshape to add a 3rd dimension.
%Dummy 2D matrix 4x3
a = [1 4 7
2 5 8
3 6 9
4 7 10]
%Size of the first dimension
n = size(a,1);
%Repeat the matrix n time
p = kron(a,ones(1,n)).*a(:).'
%Reshape to A = 4x4x3
A = reshape(p,n,n,[])
You loose the readability of the for loop method but you should increase the performance.

How to create matrices that are subsets of larger matrices

I'm learning matlab. I'd like to create a smaller array from a larger one. I know how to do this with simple columns or rows, but I get lost in the nomenclature for m x n arrays / matrices.
Original matrix = 10 x 9
mat_original=ones(10,9) in fact, rather than use all ones.. this may make more sense.. lets use mat_original = magic(10)
How do I create a component matrix say with rows 5 to 8 (all columns)?
mat_rows5to8 = mat_original[5 thru 8; :]
How do I create a component matrix, say with columns 2 to 5, (all rows?)
mat_cols2to5 = mat_original[: ; 2 thru 5 ]
and finally how would I create a sub-component array... say rows 4 thru 7, and columns 5 thru 9 ?
mat_small = mat_original[ 4 thru 7; 5 thru 9 ]
How do you remember this stuff?
No need to remember things when you have Google: Matrix Indexing in MATLAB.
Answers to your questions:
mat_rows5to10 = mat_original(5:8,:)
mat_cols2to5 = mat_original(:,2:5)
mat_small = mat_original(4:7,5:9)
In other words:
output = input(<row_first>:<row_last>,<col_first>:<col_last>)
Leave any of the parameters out to include all.

Calculate the first N terms of a geometric sequence in Matlab [duplicate]

This question already has answers here:
Common way to generate finite geometric series in MATLAB
(2 answers)
Closed 7 years ago.
How to calculate the first N terms of the geometric sequence Un = 2^n in Matlab?
Are there any Matlab functions that I'm not aware of to facilitate this? or do I have to pick a math book to understand this and implement it in a for loop or something?
Any links to similar Matlab code would be appreciated, or if you could explain it for me that would be appreciated!
First, you set the N terms for your sequence, i.e.:
N = 10 %//set first 10
Now you want to make a vector from 1 to N, i.e.:
n= [1:N]
Un = 2.^n %//Note the dot is very important! I almost forgot
%//ans = [2,4,8,16...1024]
This would make function a vector of 1 by N where each element is the corresponding answer to your function.
for your second question (in comment)
you want to do something like:
Bflip = B' %//This flips the matrix B so that what use to be column is now rows
So Bflip would be the result you want, I tested with your example:
A = [2 2 2;4 4 4; 6 6 6];
B = [0 0 0; 1 1 1; 2 2 2];
Bflit = [ 0 1 2
0 1 2
0 1 2]
This will generate a 3 dimension matrix. To call on each of the 4 sets of results, just do something like result1 = permutation(:,:,1)

What is the quickest way to keep the non dominated elements and omit the rest in MATLAB?

For example [2 , 5] dominates [3 , 8] cause (2 < 3) and (5 < 8)
but [2 , 5] does not dominates [3 , 1] cause though (2 < 3) but (5 > 1) so these two vectors are non dominated
now for example assume that I have a matrix like this :
a =[ 1 8;
2 6;
3 5;
4 6];
here the first three are non dominated but the last one is dominated by (3,5), I need a code which can omit it and give me this output:
ans =
[ 1 8;
2 6;
3 5]
note that there may be lots of non dominated elements in a Nx2 matrix
Compare one row with other rows using bsxfun
Do this for every row using arrayfun (or a loop if you prefer that) and transform the output back to a matrix with cell2mat
use any and all to check which rows are dominated
remove these rows
code:
a=[1 8;2 6;3 5;4 6];
dominated_idxs = any(cell2mat(arrayfun(#(ii) all(bsxfun(#(x,y) x>y,a,a(ii,:)),2),1:size(a,1),'uni',false)),2);
a(dominated_idxs,:) = [];
edit
If you want to use >= instead of > comparison, each row will dominate itself and will be removed, so you'll end up with an empty matrix. Filter these false-positives out by adjusting the code as follows:
a=[1 8;2 6;3 5;4 6];
N = size(a,1);
compare_matrix = cell2mat(arrayfun(#(ii) all(bsxfun(#(x,y) x>=y,a,a(ii,:)),2),1:N,'uni',false));
compare_matrix(1:N+1:N^2)=false; % set diagonal to false
dominated_idxs = any(compare_matrix,2);
a(dominated_idxs ,:) = [];
This problem is identical to identifying the so-called Pareto front.
If the number of elements N grows large and/or you need to carry out this sort of operation often (as I suspect you do), you might want to give a thought to a fully optimized MEX file for this purpose (available on the Mathworks File Exchange):
Compiling this, putting the mex in your Matlab path, and then using something like
a = a(paretofront(a));
will accomplish your task much quicker than any combination of Matlab-builtins is able to.

Is there a vectorized way to operate on a different number of values per column in MATLAB?

In MATLAB, is there a more concise way to handle discrete conditional indexing by column than using a for loop? Here's my code:
x=[1 2 3;4 5 6;7 8 9];
w=[5 3 2];
q=zeros(3,1);
for i = 1:3
q(i)=mean(x(x(:,i)>w(i),i));
end
q
My goal is to take the mean of the top x% of a set of values for each column. The above code works, but I'm just wondering if there is a more concise way to do it?
You mentioned that you were using the function PRCTILE, which would indicate that you have access to the Statistics Toolbox. This gives you yet another option for how you could solve your problem, using the function NANMEAN. In the following code, all the entries in x less than or equal to the threshold w for a column are set to NaN using BSXFUN, then the mean of each column is computed with NANMEAN:
x(bsxfun(#le,x,w)) = nan;
q = nanmean(x);
I don't know of any way to index the columns the way you want. This may be faster than a for loop, but it also creates a matrix y that is the size of x.
x=[1 2 3;4 5 6;7 8 9];
w=[5 3 2];
y = x > repmat(w,size(x,1),1);
q = sum(x.*y) ./ sum(y)
I don't claim this is more concise.
Here's a way to solve your original problem: You have an array, and you want to know the mean of the top x% of each column.
%# make up some data
data = magic(5);
%# find out how many rows the top 40% are
nRows = floor(size(data,1)*0.4);
%# sort the data in descending order
data = sort(data,1,'descend');
%# take the mean of the top 20% of values in each column
topMean = mean(data(1:nRows,:),1);