1

I am new to working with matlab. I couldn't find an obvious way to to extract the largest subset of linearly independent vectors from a given set of vectors.

So given a set V = [v1 v2 -- vn] where dim(vi) >> n (i=1,2,3,....) I need to find a random set of r linearly independent vectors "vi" (where r is maximal), i.e removing ALL (n-r) linearly dependent "vi" vectors from V. Sorry if this is ambiguous but can't find a better way to state it.

Patzerook
  • 33
  • 1
  • 4
  • Please show some effort! I'll be happy to remove my downvote and close vote if you edit the question and explain more thoroughly what you want to achieve. – Stewie Griffin Jan 12 '15 at 17:08
  • Alright sure i ll give it a try. – Patzerook Jan 12 '15 at 17:12
  • In addition, you should define the problem better. Given the vectors [0 0 1], [0 1 1], [0 1 0], the solution could be {[0 0 1], [0 1 1]}; or it could be {[0 0 1], [0 1 0]}; or it could be {[0 1 1], [0 1 0]}. Which solution do you want? Only the largest _number_ of independent vectors is well defined – Luis Mendo Jan 12 '15 at 17:14
  • I know this will sound weird but I need a random set. My whole research project is based on exploring the results with taking different linearly independent sets. – Patzerook Jan 12 '15 at 17:20
  • This is not an answer, but this will perhaps put you on the right track. I wrote an answer on detecting which columns in a matrix (vectors) are **linearly dependent**. http://stackoverflow.com/questions/26041671/finding-proportional-columns-in-matrix/26043471#26043471 - You can try using this post and further carry it on so that you can remove these vectors from the matrix to achieve a matrix that is fully independent. Perhaps this is what you are looking for! – rayryeng Jan 12 '15 at 17:35

4 Answers4

6

I'm going to assume that your vectors are all n-dimensional, and that we can concatenate them all into a single matrix. If we go into matrix and linear algebra, what you are looking for is the Column Space of a matrix. Simply put, the column space is defined as the set of columns in your matrix that can uniquely produce another vector in n-dimensional space. Or, it is the set of all possible linear combinations of the column vectors. As such, if you want to find the largest set of linearly independent vectors, all you have to do is determine what the column space of your matrix is.

Therefore, given your matrix V which is of size n x m, where we have m columns / vectors, with each column being of size n x 1 (or n rows), you would call the rref or the Row-Reduced Echelon Form (RREF) command. This reduces your matrix down to its row-reduced echelon form. This is the beginning of finding the column space for a matrix. You would call it like so:

[R, RB] = rref(V);

R would contain the RREF form of V and RB would contain the indices or column numbers of R that form the column space. Therefore, if you want to produce your linearly independent vectors, you simply have to do:

VMax = V(:,RB);

VMax will contain only those columns of V that formed the column space, and hence those that are linearly independent vectors. If you want to determine how many independent vectors we have, you simply have to count how many values of RB we have:

r = numel(RB);

Here's a quick example to illustrate my point. Supposing I have this matrix:

>> V = [1 1 2 0; 2 2 4 9; 3 3 6 7; 4 4 8 3]

V =

     1     1     2     0
     2     2     4     9
     3     3     6     7
     4     4     8     3

The second column / vector is simply the first vector. The third column / vector is simply the first vector plus the second vector, or it could be twice the first or second vector. Either way, this is not a linearly independent vector as this is based off of the first vector. The same goes with the second vector. The last vector is independent of the other three as there is no way we can create combinations or a scaling that can produce this last vector from the other three. If we called rref, this is what will happen:

>> [R, RB] = rref(V)

R =

     1     1     2     0
     0     0     0     1
     0     0     0     0
     0     0     0     0


RB =

     1     4

R contains the row reduced echelon form, while RB tells us which columns are linearly independent or form the column space of A. As you can see, only columns 1 and 4 are linearly independent, which makes perfect sense. If you also take a look at the last two rows of R, we can see that they consist of all zeroes. This alludes to the rank of a matrix, where it is simply the total number of rows (or columns depending on what you're doing) that are non-zero. This also tells you how many vectors form the column space.

To complete your task, simply do:

>> VMax = V(:,RB)

VMax =

     1     0
     2     9
     3     7
     4     3

As you can see, each column of VMax is a linearly independent vector from V, which also forms the column space of V.

Now, your next task is to randomly choose linearly independent vectors from this column space each time you run the algorithm. Bear in mind that because there are multiple ways to produce the column space, the solution by rref will only give you one such column space. If I am interpreting your question correctly, you wish to generate random column spaces and choose a subset of those vectors each time. Thanks to Luis Mendo (and also a gentle prod from knedlsepp), what you can do is randomly rearrange or permute the columns, then run rref on this permuted matrix.

As such, you can do something like this:

ind = randperm(size(V,2));
Vperm = V(:,ind);
[R,RB] = rref(Vperm);
VMax = Vperm(:,RB);

randperm will generate a random permutation array from 1 up to the argument that you specify to randperm. In our case, this is the total number of columns in your matrix V. We use this array to randomly shuffle the columns of V, store this into Vperm and run our code that we have done before. By doing this random shuffling, you are biasing the input to rref so that you are forcing it to choose different basis vectors, but if you have several vectors that are linearly dependent, there will be a case where we will choose one of these linearly dependent vectors to build our basis.

rayryeng
  • 102,964
  • 22
  • 184
  • 193
  • Is `VMax = V(:,RB);` really correct since "`V which consists of n x 1 vectors`"? You'll either get out-of-index error or all values of `V`. Maybe `V` should be `1 x n` or `VMax = V(RB,:)`? – kkuilla Jan 12 '15 at 20:31
  • @kkuilla - No. I probably didn't phrase myself properly. We are finding the **column space**, and so you want to extract the columns out of `V`. It should probably read something like: `V` is a `n x m` matrix, where we have `m` columns / vectors with each column being a `n x 1` vector. Also, you shouldn't get an out-of-index error because `RB` will return the **column** indices of the matrix `V`, and I'm using `RB` to access the columns. I will modify my post. Thank you for the spot! – rayryeng Jan 12 '15 at 20:34
  • I think the first part up until `VMax = V(:,RB)` is possibly the best solution to this problem. However I don't think the `randperm`-part is what the OP wants. Also: Shouldn't it be `VMax(:,RB(ind))` instead of `VMax(:,ind)`? – knedlsepp Jan 12 '15 at 20:47
  • @knedlsepp - I'm going to leave the last part as it is... because to be honest I'm not quite sure if I'm interpreting the problem correctly. Until I receive more clarification, I'll leave it the way it is. – rayryeng Jan 12 '15 at 20:50
  • @rayryeng I like this neat approach. But how does it deal with randomization? Consider `V = [0 0 1; 0 0 2; 0 1 1; 1 1 0].'`. The final set `Vmax` will always pick the first vector, never the second. But actually another possible solution would be to take the second vector instead of the first. And the OP seems to want a random solution (presumably chosen among all possible solutions) – Luis Mendo Jan 12 '15 at 22:35
  • @LuisMendo - Ah that's very true. Now I know what knedlsepp is talking about. I'll remove that edit until I figure that out. Thank you for your comment! – rayryeng Jan 12 '15 at 22:42
  • @LuisMendo - Thank you :) I'll figure something out, but now I do understand what both of you are talking about. Thanks for your input! – rayryeng Jan 12 '15 at 22:47
3

This naive approach to the problem of searching for a basis of the vector space spanned by your vectors is similar to Luis Mendo's. It should however have better theoretical worst case complexity of a maximum of n rank-computations, as opposed to n choose r. The downside is, that the best case will perform r rank-computations, as opposed to 1.

The idea is simple:

  • Compute the rank r of V. This is the maximum number of vectors in your set.
  • Define the set of your chosen vectors as empty.
  • For each vector V(:,k) in V (randomly chosen):
    • If the vector V(:,k) is linearly independent from the vectors in the set chosen:
      • Add it to the set of chosen vectors.
    • If the set chosen already has r elements:
      • Return the chosen vectors as the solution.

The resulting code will look like this:

function chosen = randBasis(V)
% V is a matrix of column vectors
% chosen are the indices of the randomly selected column vectors,
% so that span(V(:,chosen)) == span(V)

n = size(V,2);
r = rank(V);
chosen = []; 
currentRank = 0;
for k = randperm(n)
    if rank(V(:, [chosen, k])) > currentRank
        currentRank = currentRank+1;
        chosen = [chosen, k];
    end
    if currentRank==r
        break
    end
end

Additional remarks:

This approach can be beneficial when you are dealing with sparse matrices, as the check for linear dependency can be replaced by a solution of a linear system instead of the rank computation. As the rank computation involves a call to svd, it is quite expensive in comparison. Despite rayryeng's rref-solution being the more elegant one, for some reason this naive approach seems to be faster even for non-sparse matrices.

Sped up version using mldivide:

function chosen = randBasis(V)
n = size(V,2);
if issparse(V)
    r = sprank(V)
else
    r = rank(V);
end
chosen = []; 
for k = randperm(n)
    if isLinearlyIndependent(V(:,chosen),V(:,k))
        chosen = [chosen, k];
    end
    if numel(chosen)==r
        break
    end
end
end

function b = isLinearlyIndependent(V, v)
    warning('off','MATLAB:singularMatrix');
    bestapprox = V\v;
    bestapprox(~isfinite(bestapprox)) = 0;
    b = ~(norm(V*bestapprox-v,'inf')<=eps*norm(V,'inf'));
    warning('on','MATLAB:singularMatrix');
end

Beware:

Both these iterative approaches suffers from a non-obvious numerical problem: Consider the matrix:

V = diag(10.^(-40:10:0))
V =
        1e-40            0            0            0            0
            0        1e-30            0            0            0
            0            0        1e-20            0            0
            0            0            0        1e-10            0
            0            0            0            0        1e+00

Mathematically you would say this matrix has rank five. Yet numerically only the last two columns are nonzero compared to the others. This is why rank(V) gives 2. The problem with this iterative approach is that adding a linearly independent vector to our set can in fact result in a linearly dependent set! Imagine this algorithm chooses the first vector. Even though all the other vectors are linearly independent mathematically and numerically, the subset {V(:,1), V(:,5)} does not have numerical rank 2, and yet could be chosen by our function. This is why this algorithm will only work well for vectors of similar norm.

The conclusion is:

  • Numerical mathematics is tricky.
  • If you want stability, you have to pay the price of computational cost.
  • rref is the way to go for this problem.
knedlsepp
  • 6,065
  • 3
  • 20
  • 41
  • Very nice! I like the answers and the discussion that is being generated by this question. – rayryeng Jan 12 '15 at 23:27
  • This makes sense in terms of speedup. If you look at the source of `rref`, it's all loops! Nice analysis btw! – rayryeng Jan 13 '15 at 14:31
  • @rayryeng: Yes indeed, I also had a glance at the source. This is certainly due to `svd` being the 'alternative' to `rref` with more practical applications. And thus no need to deliver `rref` as a built-in. [At least as far as I'm concerned, yesterday was the day I first learned about the existence of this form.] – knedlsepp Jan 13 '15 at 14:51
1

I would try something along these lines. It will probably not be fast, though:

  1. Compute the rank of the matrix formed by your vectors. Call that r.
  2. Generate all combinations of r numbers taken from 1:n.
  3. Sort those combinations randomly.
  4. Take the first combination and check if the vectors indicated by that combination are independent (maximum rank). If they aren't, test next combination. By construction it is guaranteed that some combination will succeed.

Code:

vectors = randi(3,4,3); %// example. Each vector is a row
n = size(vectors,1);
r = rank(vectors); %// step 1
combs = nchoosek(1:n,r); %// step 2
c = size(combs,1);
combs = combs(randperm(c),:); %// step 3
for s = 1:r %// step 4
    pick = combs(s,:);
    if rank(vectors(pick,:))==r
        break %// we're done. Now `pick` contains the selected vectors
    end
end
result = vectors(pick,:); %// each row is a vector
Luis Mendo
  • 110,752
  • 13
  • 76
  • 147
  • @knedlsepp That's another possible approach, yes. But I doubt it reduces complexity a lot. It may require many tries until you succeed at gathering `r` independent vectors by this procedure – Luis Mendo Jan 12 '15 at 22:04
  • @knedlsepp I think I now see what you mean. Yes, that sounds like a good idea. One pass through the `n` vectors is enough (and they can be randomly sorted initially to achieve a randomized result). Post that as an answer! – Luis Mendo Jan 12 '15 at 22:23
  • @knedlsepp But in rayryeng's approach, consider `V = [0 0 1; 0 0 2; 0 1 1; 1 1 0].'`. `Vmax` will always include the first vector, never the second. So no randomization there. Am I correct? – Luis Mendo Jan 12 '15 at 22:31
  • Yes, the randomization part of rayryeng's solution is still missing, but in terms of finding *any* subset it's superior I guess. – knedlsepp Jan 12 '15 at 22:37
  • @knedlsepp , Luis Mendo - Yes both of you are correct. I haven't figured out the randomization part yet. That is something I'll have to think about. Thanks for your input! – rayryeng Jan 12 '15 at 22:48
  • @rayryeng For randomization, maybe an initial shuffle of the columns of `V` will do? – Luis Mendo Jan 12 '15 at 22:53
  • @LuisMendo - You read my mind. I was actually about to try that out! – rayryeng Jan 12 '15 at 22:54
  • @LuisMendo - Yes it works! I'll edit my post. I decided to use that sample matrix you provided, ran 20 trials, and I checked to see what bases were returned. Sometimes the first vector is chosen, other times the second vector is chosen. Nicely done! – rayryeng Jan 12 '15 at 23:05
  • @rayryeng It would remain to be seen if all possible solutions are picked with the same probability, which is probably what the OP wants when they just say "randomly". But I wouldn't reallty bother with that – Luis Mendo Jan 12 '15 at 23:08
  • @LuisMendo - The OP wasn't very clear on that, so I'm just going to leave it for now. There is certainly a difference between randomly, and randomly with equal probability. Thank you again for your input! – rayryeng Jan 12 '15 at 23:08
  • @rayryeng Just one of my pet peeves -- people saying "randomly" and thinking that fully specifies what they want. But then again, it's not as bad as "transposing" with `'`:-P – Luis Mendo Jan 12 '15 at 23:11
  • @LuisMendo - BTW, I've +1ed you already, as you properly handled the randomness. – rayryeng Jan 12 '15 at 23:11
  • @rayryeng Thanks! Yes, a little brute-force-ishly, but I did :-) – Luis Mendo Jan 12 '15 at 23:12
  • @LuisMendo - Ahaha! How true! I don't really have a nice eloquent pet peeve like you do, such as `'` with the transpose... but one of the things that bother me the most is the misuse of `imshow`. People put in a `double` matrix which isn't normalized between `[0-1]` and see a completely white image. I've probably answered at least 10 questions on here where that was the essential problem. – rayryeng Jan 12 '15 at 23:19
-1

A partial solution on an example ... Sorry, I did not notice your comment about "different linearly independent sets" ... Do you mean "different maximal linearly independent sets"? I apologize I have found only one of the maximal linearly independent sets ... But the solution using [R, RB] = rref(M) gives the same answer

+ echo ('on')
+ more ('off')
+ format ('bank')
+ M = [0, 0, 1; 0, 1, 1; 0, 1, 0]'
M =

   0.00   0.00   0.00
   0.00   1.00   1.00
   1.00   1.00   0.00

+ [U, S, V] = svd (M)
U =

   0.00   0.00  -1.00
  -0.71   0.71   0.00
  -0.71  -0.71   0.00

S =

Diagonal Matrix

   1.73      0      0
      0   1.00      0
      0      0  -0.00

V =

  -0.41  -0.71  -0.58
  -0.82   0.00   0.58
  -0.41   0.71  -0.58

+ U (:, 1:2) * S (1:2, 1:2) * V (1:2, 1:2)'
ans =

   0.00   0.00
   0.00   1.00
   1.00   1.00

A quote from Applications_of_the_SVD

The left-singular vectors corresponding to the non-zero singular values of M span the range of M.

  • Instead of code dumping, you should perhaps explain what the code is doing and what it specifically means for the left-singular vectors to span the column space of `M`. Only those who are knowledgable in linear algebra will understand your post. – rayryeng Jan 12 '15 at 21:19