How to do rank-1 factorization in MATLAB? - matlab

I have a matrix M of dimensions 6x6 and it has rank 1. How can I factorize it into two matrices of dimensions 6x1 (say A) and 1x6 (say B) so that M=A*B.

take the largest eigen vector and multiply it by the largest eigenvalue :
A=[1 2 3 4]'*[1 2 3 4]
A =
1 2 3 4
2 4 6 8
3 6 9 12
4 8 12 16
[v,e] = eigs(A,1);
sqrt(e)*v
ans =
-1.0000
-2.0000
-3.0000
-4.0000
of course, the result is good only up to a sign change.
EDIT:
if you assume that the two vectors can be different:
A=[1 2 3 4]'*[5 6 7 8]
[uu,ss,vv]=svd(A);
u=uu(:,1)*ss(1,1)
v=vv(:,1)
assert(norm(u*v'-A)<1E-10)
Now the solution is even less unique. You are determining 2*n values based on only n. This is one solution among many.
For example, look at this other even simpler solution (which will assume your matrix is perfectly rank 1) :
aa=A(:,:)./repmat(A(1,:),[size(A,1),1]);
bb=A(:,:)./repmat(A(:,1),[1,size(A,2)]);
u=aa(:,1);
v=bb(1,:)'*A(1);
assert(norm(u*v'-A)<1E-10)
it produces a totally different result, but that still factorizes the matrix. If you want non-negative factorizations only to slightly reduce the space of possible results, I'd suggest you ask a new question!

If it has rank 1, then all columns/rows are multiples of the first column/row (or indeed of any non-zero column/row). i.e.:
m = M(:,1);
M = [ a*m, b*m, c*m, d*m, e*m, f*m ];
Hopefully you can take it from there.

Related

nth permutation of a vector in MATLAB

Suppose I have a vector of integers like this:
A = [1 2 3]
What I need is nth permutation of vector A. As we now a vector of n numbers has n! permutation, For example some permutation of A is:
[1 2 3]
[1 3 2]
[2 1 3]
[2 3 1]
...
Is there any built-in function for calculating nth permutation? if not, can anyone please offer me a efficient algorithm for calculate it? Any suggestion would be highly appreciated
I found my answer from #Divakar comment (special thanks to #Divakar)
What I need is:
% this my vector 1, 2, 3 , ..., N
A = 1 : N;
P = perms(A);
% nth permutation of A is nth row of P
nthPerm = P(n, :);
If A is just the trivial sequence 1:N, as #Divakar said, the command
perms(1:N)
produces the permutations you need.
If A is an array whose content is generic and whose length is N, perms can be used to obtain the indices allowing the permutations, i.e.
A_permutations = A(perms(1:N))
Example:
given
A =
3 7 9
A(perms(1:3))
9 7 3
9 3 7
7 9 3
7 3 9
3 7 9
3 9 7
perms(v) works for the n! case,
http://www.mathworks.de/matlabcentral/fileexchange/11462-npermutek/content/npermutek.m
works for the n^n or n^k case.
If you like doing stuff in less lines of code, you can also do:
A=1:N;
nthPerm=getfield(perms(A),{n,A})
Note that this is only valid if A=1,2,3,...,N. For different values of A, you would have to change this into:
A=1:N;
nthPerm=getfield(perms(A),{n,1:length(A)})

Matlab matrices dimension

I am new to matlab and just wondering if you guys can help me out with this problem.
For instance, I have two matrices:
A = [X1 X2 X3 X4]
B = [Y1; Y2; Y3]
now what I really want to achieve is to multiply these two matrices in this way:
[X1Y1 X2Y1 X3Y1 X4Y1;
X1Y2 X2Y2 X3Y2 X4Y2;
X1Y3 X2Y3 X3Y3 X4Y3;
.... and so on]
I tried using A(1,:).*B(:,1) but matlab is saying that matrix dimensions must agree.
I just don't know how to manipulate this on matlab but in excel is possible.
This is a simple outer product. kron is not needed (although it will work.) bsxfun is wild overkill, although will yield what you have asked for. repmat is inappropriate, because while it will help you do what you wish, it replicates the arrays in memory, using more resources than are needed. (Avoid using inefficient programming styles when there are good ones immediately at your disposal.)
All you need use is the simple * operator.
A is a row vector. B a column vector.
C = B*A
will yield the result C(i,j)=B(i)*A(j), which is exactly what you are looking for. Note that this works because B is 3x1 and A is 1x4, so the "inner" dimensions of B and A do conform.
In MATLAB, IF you are unsure if something works, TRY IT!
A = [1 2 3 4];
B = [1;2;3];
C = B*A
ans =
1 2 3 4
2 4 6 8
3 6 9 12
See that kron did indeed work, although I'd bet that use of kron here is probably less efficient than is the simple outer product multiply.
C = kron(B,A)
C =
1 2 3 4
2 4 6 8
3 6 9 12
As well, bsxfun will work here too, although since we are using a general tool to do something that a basic operator will do, I'd bet it is slightly less efficient.
C = bsxfun(#times,B,A)
C =
1 2 3 4
2 4 6 8
3 6 9 12
The WORST choice is repmat. Again, since it artificially replicates the vectors in memory FIRST, it must go out and grab big chunks of memory in the case of large vectors.
C = repmat(B,1,4).*repmat(A,3,1)
C =
1 2 3 4
2 4 6 8
3 6 9 12
I suppose for completeness, you could also have used meshgrid or ndgrid. See that it is doing exactly what repmat did, but here it explicitly creates new matrices. Again, this is a poor programming style when there are good tools to do exactly what you wish.
[BB,AA] = ndgrid(B,A)
BB =
1 1 1 1
2 2 2 2
3 3 3 3
AA =
1 2 3 4
1 2 3 4
1 2 3 4
C = BB.*AA
C =
1 2 3 4
2 4 6 8
3 6 9 12
What you need to understand is exactly why each of these tools COULD have been used for the job, and why they are different.
In Matlab there is * and .* and they are very different.
* is normal matrix multiplication which is what you want i.e. B*A, note the B must come first as the inner dimension must match. You can multiply a column by a row but not a row by a column (unless they have the same number of elements).
.* is element by element multiplication in which case the matrices must be exactly the same size and shape so for example [1 2 3].*[4 5 6] = [1*4 2*5 3*6] = [4 10 18]
Do not do a ".*". You should rather do a "*".
The ".*" is for index by index multiplication and should have given you [X1Y1 X2Y2 X3Y3] were they vectors have been equal in size.
If you do the regular multiplication "*", this is actually matrix multiplication.
I think you just need to transpose one of the vectors. You are multiplying a column vector (A(1,:)) with a row vector (B(:,1)). This should work:
C = A(1,:).*B(:,1)';

MATLAB search row index of matrix with values of another matrix

In MATLAB I have a very large matrix (matrix A). Now I would like to find the row-index of the row which contain certain values in the second column. These values - which I'm looking for in Matrix A - are stored in anonther Matrix (Matrix B) with consists out of a row (800 numbers).
Besides I would like to redo this calculation for the same matrix A, but for ten different matrices, with different sizes (which contain the values I'm looking for in different columns of matrix A).
Because of the sizes of the matrix I think i need a loop to extract the row in matrix A which contain te value of Matrix B. How can I do this?
regards,
V
Thanks for the quick response! Indeed the problem is maybe a bit complex to answer without an example, and indeed duplicate entries cause some problems. Therefore hereby an example
For example I have a -simplified- matrix A:
1 2 3 4
9 9 9 9
4 3 2 1
And a -simplified- matrix (row) B: [9 3]
And a -simplified- matrix (row) C: [9 2]
Then I would like to get matrix D and matrix E.These matrices should contain in the first column the numbers from the original matrix D(or E) and in the second column the corresponding row-location of this value in matrix A.
So, matrix D =
9 2
3 3
matrix E =
9 2
2 3
As represented in this example matrix B and matrix C can contain data which is present in several column of matrix A (like the nine). However, martix B should "search" in column 2 of matrix A. Likewise, should matrix C "search" in column 3 of Matrix A, resulting in matrix D and E as given in the example.
As mentionned by Shai in his comment, your question is quite vague and a lot of special case could arise (duplicate entries, relative size of A and B, etc.). But in all generality I tried a small piece of code that seems to do what you want. There are certainly quicker ways of doing it, and certainly more information on your problem could help optimize this.
colA=2;
% Example
nmax=10;
nA=5;
A=randi(nmax,[nA nA]);
nB=3;
B=randi(nmax,[1 nB]);
% Find rows
rows=cell(size(B));
for i=1:numel(B)
rows(i)={find(A(:,colA)==B(i))};
end
The input / output was:
A =
3 7 8 5 4
9 7 3 7 5
8 2 9 9 8
9 5 9 7 9
3 3 4 6 8
B =
1 7 5
rows =
[0x1 double] [1;2] [4]
Assuming you have two vectors, largeDataIndex (the second column of your matrix) and interestingIndex (your b) and you want the following:
For each value of interestingIndex , find the position in largeDataIndex
Then an easy method would be this:
result = zeros(size(interestingIndex))
for i = 1:length(result)
result(i) = find(interestingIndex(i) == largeDataIndex)
end
Note that this assumes there is always just one entry that matches, otherwise you should define result as a cell array rather than a vector.

How does "/" really work on two row vectors?

I have the following basic observation:
[1 2 3 4]/[2 4 6 8] % output: 0.5
[1 2 3 4]/[2 3 4 5] % output: 0.7407
([1 2 3 4]*[2 4 6 8] % error of course)
It does not look for me as A*inv(B) kind of operation (nor like mrdivide on timeseries which would work like [1 2 3 4]./[2 4 6 8] if Im not mistaken).
Now, my question is, what operation does "/" define on two row vectors with the same length?
UPDATE:
#user1884905 gave the idea that a/b on two row vectors might minimise norm(b*x - a). So far it seemed to work on some numeric tests. If it is true, can you give some official reference behind this please?
Yes, it seems I was right. From MathWorks mrdivide
"If A is a rectangular m-by-n matrix with m ~= n, and B is a row vector with n elements or a matrix with n columns, then x = B/A returns a least-squares solution of the system of equations x*A = B."

Averaging every n elements of a vector in matlab

I would like to average every 3 values of an vector in Matlab, and then assign the average to the elements that produced it.
Examples:
x=[1:12];
y=%The averaging operation;
After the operation,
y=
[2 2 2 5 5 5 8 8 8 11 11 11]
Therefore the produced vector is the same size, and the jumping average every 3 values replaces the values that were used to produce the average (i.e. 1 2 3 are replaced by the average of the three values, 2 2 2). Is there a way of doing this without a loop?
I hope that makes sense.
Thanks.
I would go this way:
Reshape the vector so that it is a 3×x matrix:
x=[1:12];
xx=reshape(x,3,[]);
% xx is now [1 4 7 10; 2 5 8 11; 3 6 9 12]
after that
yy = sum(xx,1)./size(xx,1)
and now
y = reshape(repmat(yy, size(xx,1),1),1,[])
produces exactly your wanted result.
Your parameter 3, denoting the number of values, is only used at one place and can easily be modified if needed.
You may find the mean of each trio using:
x = 1:12;
m = mean(reshape(x, 3, []));
To duplicate the mean and reshape to match the original vector size, use:
y = m(ones(3,1), :) % duplicates row vector 3 times
y = y(:)'; % vector representation of array using linear indices