# how to determine the relative position of a number in a matrix

4 views (last 30 days)
reebal nimri on 3 Jan 2020
Commented: reebal nimri on 4 Jan 2020
I have a matrix consisting of 1, 0, -1 where
type_vec = [1 0 -1];
and create a permutation matrix using the permn function available online
mat_n_dim = 4;
perm_mat = permn(type_vec , mat_n_dim);
The goal is to generate a matrix where:
• In a single row, there is never a 1 to the right of -1 e.g.
perm_mat = [1 0 0 0 % valid
1 0 0 1 % valid
1 0 0 -1 % valid
1 0 -1 0 % valid
-1 0 0 1 % not valid
1 -1 -1 1 % not valid
];
By finding the valid rows and eliminating the unvalid rows.
I realize it is possible to do that using for loops and if statements but I was wondering if there is a way to do it using the matlab functions

Stephen Cobeldick on 3 Jan 2020
Edited: Stephen Cobeldick on 3 Jan 2020
>> M = [1 0 0 0 % valid
1 0 0 1 % valid
1 0 0 -1 % valid
1 0 -1 0 % valid
-1 0 0 1 % not valid
1 -1 -1 1 % not valid
1 1 -1 1]; % not valid (from your comment)
>> invalid = any(cumsum(M<0,2) & M>0, 2)
invalid =
0
0
0
0
1
1
1

reebal nimri on 3 Jan 2020
It does not work when applied to the full matrix. Such row [ 1 1 -1 1 ] is supposed to be invalid but is undetected.
Stephen Cobeldick on 3 Jan 2020
@reebal nimri: see my edited answer, it seems to fulfill your specification:
>> V = [+1,0,-1];
>> M = permn(V,4);
>> X = any(cumsum(M<0,2) & M>0,2);
>> Z = M(~X,:)
Z =
1 1 1 1
1 1 1 0
1 1 1 -1
1 1 0 1
1 1 0 0
1 1 0 -1
1 1 -1 0
1 1 -1 -1
1 0 1 1
1 0 1 0
1 0 1 -1
1 0 0 1
1 0 0 0
1 0 0 -1
1 0 -1 0
1 0 -1 -1
1 -1 0 0
1 -1 0 -1
1 -1 -1 0
1 -1 -1 -1
0 1 1 1
0 1 1 0
0 1 1 -1
0 1 0 1
0 1 0 0
0 1 0 -1
0 1 -1 0
0 1 -1 -1
0 0 1 1
0 0 1 0
0 0 1 -1
0 0 0 1
0 0 0 0
0 0 0 -1
0 0 -1 0
0 0 -1 -1
0 -1 0 0
0 -1 0 -1
0 -1 -1 0
0 -1 -1 -1
-1 0 0 0
-1 0 0 -1
-1 0 -1 0
-1 0 -1 -1
-1 -1 0 0
-1 -1 0 -1
-1 -1 -1 0
-1 -1 -1 -1
reebal nimri on 4 Jan 2020
Can you elaborate on the method?
Much appreciated, thanks!

Walter Roberson on 3 Jan 2020
first_1_pos = min( (perm_mat == 1) .* (-mat_n_dim:-1), 2 );
first_n1_pos = min( (perm_mat == -1) .* (-mat_n_dim:-1), 2 );
valid_row = first_n1_pos >= first_1_pos;
perm_mat = perm_mat(valid_row, :);
This declares a row to be valid if it has no -1, even if it has no 1 as well.
1 -1 -1 1 % not valid
No, that row is valid according to the rules you have defined. Every -1 is to the right of some +1.
Defining that there is never a 1 to the right of -1 would be a different rule.
You should document your rules for yourself.
• what if there are no 0, is that valid?
• what if there are no -1, is that valid?
• what if there are no +1, is that valid?
• What if every -1 is to the right of some +1, is that valid?
• What if every -1 is to the right of every +1, is that valid? Even if there are no +1 ?

reebal nimri on 3 Jan 2020
I have fixed the question statement. Thanks for bringing that up.
I tried to execute the following code but it did not run
first_1_pos = min( (perm_mat == 1) .* (-mat_n_dim:-1), 2 );
first_n1_pos = min( (perm_mat == -1) .* (-mat_n_dim:-1), 2 );
valid_row = first_n1_pos >= first_1_pos;
perm_mat = perm_mat(valid_row, :);
because valid row is a boolean matrix not a vector.
However, I am more interested in the method used. Can you elaborate on that?
Walter Roberson on 3 Jan 2020
first_1_pos = min( (perm_mat == 1) .* (-mat_n_dim:-1), [], 2 );
first_n1_pos = min( (perm_mat == -1) .* (-mat_n_dim:-1), [], 2 );
valid_row = first_n1_pos >= first_1_pos;
perm_mat = perm_mat(valid_row, :);
This has not been adjusted for your revised rule that there is never a 1 to the right of a -1; this is still for the rule that any -1 must be to the right of some 1. I would need to think more about the best way to adapt for the revised rule.
With regards to the method used:
(perm_mat == 1) .* (-mat_n_dim:-1)
compares each value to 1, giving an array of 0 (not equal to 1) and 1 (is equal to 1). This is then multiplied by the vector -4 -3 -2 -1 which is automatically replicated to the correct number of rows (requires R2016b or later). The positions that are not 1 get zeroed out, leaving for example,
-4 0 0 0
-4 0 0 -1
-4 0 0 0
-4 0 0 0
0 0 0 -1
-4 0 0 -1
The more negative the number, the further left it is. Now, min() along the rows; in the above case you would get [-4; -4; -4; -4; -1; -4] . The effect of the min() on that arrangement of negative values and 0's is to identify per-row what the left-most position is that is equal to +1, counting from the right hand side (-1 is the last column, -2 for the second last, -3 for the third last, -4 for the fourth last, etc.) If no positions were equal to 1, then all of the entries after the multiplication would be 0, and min() of those 0 would be 0. Notice that if we had done a straight numbering from the left, [1 2 3 4] that we would have had the issue that min() between a positive number and 0 is 0. [The revised version of the code for your new rule will involve positive counts and max() in order to find the right-most +1]
We then do the same thing with comparing to -1 . Again, we get out a value that is most negative the further left we are, and 0 if there are no occurrences.
We can now compare the relative values of the position of the first -1 and the position of the first +1: a position to the right is less negative and so > comparison works in the case that both are present.
You do have to be careful about the case where only one of them is present. If there is no -1 then the value for that first_n1_pos will be 0, and that is greater than any negative value expressing the position of the first +1, and that works out fine because the (original) rule is that -1 if present must be to the right of some +1 . If the -1 was present but no +1 then the negative first_n1_pos would not be greater than the 0 of the first_1_pos, and you would fail, but that is fine because that case would violate the (original) rule that any -1 present must be to the right of some +1 .
This all said... I like how compact Stephen's code is, and I suspect his code could be fixed to match your needs.
reebal nimri on 4 Jan 2020
Thank you for your help, much appreciated!