4 views (last 30 days)

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

Stephen Cobeldick
on 3 Jan 2020

>> 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

Sign in to comment.

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 ?

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.

Sign in to comment.

Sign in to answer this question.

Opportunities for recent engineering grads.

Apply Today
## 0 Comments

Sign in to comment.