4

This may be a very basic question, so apologies in advance, I'm a first-time Mathematica & StackExchange user!

I have a 7x3 matrix X with all rows being unique in a 2D-list format.

For example:

X={{1,0,0},{0,1,0},{0,0,1},{1,1,0},{1,0,1},{0,1,1},{1,1,1}}

I want to choose three of these rows from which to construct a new matrix called Y, then calculate the rank of Y using MatrixRank.

For example: Y={{1,0,0},{0,0,1},{1,0,1}} OR Y={{0,1,0},{0,0,1},{1,1,1}} OR Y = ...

What I really want to do is create a loop that chooses a different set of three rows each time, and calculates the rank each time, until I find a set of three rows where the rank of my matrix Y is some arbitrary value z.

Finally, I want the loop to finish and tell me which rows were used to create Y that gave a rank of z. Is this possible?

PeteG
  • 43
  • 4

2 Answers2

7

You can also use Minors to get all square sub-matrices of desired dimensions:

minors = Join @@ Minors[X, 3, Identity];
mr2minors = Select[MatrixRank@# == 2 &]@minors;

Row[MatrixForm /@ mr2minors] 

enter image description here

List all 3X3 minors and highlight the ones with rank 2:

Grid @ Partition[MatrixForm /@ minors /. 
   a : MatrixForm[Alternatives @@ mr2minors] :> Highlighted @ a, 7]

enter image description here

kglr
  • 394,356
  • 18
  • 477
  • 896
  • Similar to my comment above, this solution works really nicely. However, it runs into the same problems with memory when the matrix X, and the integer z get larger. Any ideas for a solution? Thanks again! – PeteG Feb 14 '20 at 10:31
6

This is a slightly different approach from what you asked, but still produces the wanted result. I won't use a loop, while I will look for all the possible combination "at the same time" (it's not always convenient to use loops in Mathematica).

X = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}, {1, 1, 0}, {1, 0, 1}, {0, 1, 1}, {1, 1, 1}};

Generate all possible subsets of 3 rows:

subs = Subsets[X, {3}];

define a z value (for example 2):

z = 2;

Find all the combinations of rows that give Rank = 2

Select[subs, MatrixRank[#] == z &]

{{{1, 0, 0}, {0, 1, 0}, {1, 1, 0}}, {{1, 0, 0}, {0, 0, 1}, {1, 0, 1}}, {{1, 0, 0}, {0, 1, 1}, {1, 1, 1}}, {{0, 1, 0}, {0, 0, 1}, {0, 1, 1}}, {{0, 1, 0}, {1, 0, 1}, {1, 1, 1}}, {{0, 0, 1}, {1, 1, 0}, {1, 1, 1}}}

If you want the list of the rank of each subset:

MatrixRank /@ subs

{3, 2, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 2, 3, 3, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3}

Fraccalo
  • 6,057
  • 13
  • 28
  • Thanks for your answer, it works perfectly. However, I have another example where my matrix X is far larger (56x21), and I wish z to be 21. This approach causes an error as there is insufficient memory for Mathematica to create all the many thousands of subsets of size 21x21. Is there a way to work out the rank of each subset and then stop when you find one that is 21, or another workaround that will take less memory? Thank you! – PeteG Feb 14 '20 at 10:23
  • You might need to manually write a table or for loop for that, or you might look into lazy lists: https://mathematica.stackexchange.com/questions/9554/lazy-lists-of-tuples-and-subsets . I don't have time now for implementing this solution but I might try it at some point! – Fraccalo Feb 14 '20 at 11:21