Permuting elements in an symmetrical matrix with restricted outcomes

9 次查看(过去 30 天)
I would like to derive all possible permutations of a matrix A = [0 2 0 1; 2 0 1 0; 0 1 0 1; 1 0 1 0] by permuting the positions of elements with the following restrictions:
[1] Diagonal elements can only be "0" or "2" (i.e. the permuated matrix A = [0 2 0 1; 0 1 2 0; 0 1 0 1; 1 0 1 0] would NOT be valid as "1" is a diagonal element
[2] The positions and values (i.e. 0, 1 or 2) of elements (not including diagonal elements) must be "mirrored" across the diagonal (i.e. the permuted matrix A = [0 2 0 1; 2 0 1 0; 1 0 0 1; 0 1 1 0] is NOT valid
Can someone help me with a code for this ?
Thus far I have been generating all possible permutation matrices for this 4 x 4 matrix (4!) and iteratively multiplying the matrix A by each permutation matrix but I am not sure if I can derive all possible permutations using this method (not to mention it being extremely time consuming as eventually I will be permuting many more, larger matrices)

采纳的回答

Adam Danz
Adam Danz 2020-1-14
编辑:Adam Danz 2020-1-16
Since the permuted matrices are all symmetric, you really only need to permute the lower (or upper) triangle of the matrix, excluding the diagonal, and then reflect the values. Since your matrix is 4x4, there are 6 values in the lower triangle excluding the diagonal. That results in 6! permutations (720). But there are also 16 variations of the diagonal (4 choices from 2 values [0,2] with replacement; if that's what you're looking for since it was unlcear).
so in total, there are 720 * 16 = 11520 permutations of matrix A.
Some of the lines below could be combined but I chose to keep them separated to increase readability. There may be additional shortcuts that I didn't think of but the code completes in less than 150 milliseconds.
The code requires Jos' permn() function from the file exchange in order to compute the permutations of diagonal elements with replacement.
See the inline comments for detials.
% Input matrix
A = [0 2 0 1; 2 0 1 0; 0 1 0 1; 1 0 1 0];
% Get index of lower triangle values (below diagonal)
trilMat = tril(reshape(1:numel(A),size(A)),-1);
trilIdx = trilMat(trilMat>0);
% List all permutation of lower triangle indices
trilPerms = perms(trilIdx);
% List accepted diagonal values
diagPermitted = [0,2];
% List all permutation of diagonal values (with replacement)
% https://www.mathworks.com/matlabcentral/fileexchange/7147-permn
diagPerms = permn(diagPermitted,numel(diag(trilMat)));
% Loop through all lower-triangle-permutation and diagonal-permutations
diagMask = logical(eye(size(A)));
nPerms = size(trilPerms,1) * size(diagPerms,1); % total number of permutations
A_PERM = nan([size(A),nPerms]); % all permutations
for i = 1:size(trilPerms,1)
for j = 1:size(diagPerms,1)
c = (i-1)*size(diagPerms,1)+j;
base = zeros(size(A));
base(trilIdx) = A(trilPerms(i,:)); % permute lower triangle
base = base + tril(base,-1).'; % reflect lower triangle
base(diagMask) = diagPerms(j,:); % permute diagonal
if ~issymmetric(base)
% Sanity check: matrix is symmetric
error('Matrix not symmetic. i = %d j = %d',i,j)
end
A_PERM(:,:,c) = base; % store matrix
end
end
A_PERM is a [4 x 4 x 11520] array containing all 11520 permutations of the 4x4 matrix A.
[addendum]
"I would like to restrict the resultant, permuted matrices to also have rows and columns that sum to 3,3,2,2, more specifically two of the rows (or columns) in the "accepted" permuted matrices must sum to 2 and the other two must sum to 3, the order of the row (column) sums does not matter."
It would be complicated to work that restriction into the permutation rules. Instead, keep all of the code above, produce all permutations, and then eliminate any that do no follow that rule. That just requires adding the the following two lines below at the end of the code above.
goodRows = ismember(squeeze(sort(sum(A_PERM,2))).',[2 2 3 3],'rows');
A_PERM(:,:,~goodRows) = [];
To see the sum of each row,
sum(A_PERM,2)
[addendum II]
Extract the unique matrices (see the discussion below for details).
% Extract unique matrices.
% Each matrix is collapsed to a row vector and all
% row vector are combined into a mega-matrix that
% contains all of the A_PERM data. Then we'll
% identify unique rows numbers.
megaMat = squeeze(reshape(A_PERM,1,prod(size(A_PERM,[1,2])),size(A_PERM,3))).';
[~, unqRowIdx] = unique(megaMat,'rows');
A_PERM_UNQ = A_PERM(:,:,unqRowIdx);
  18 个评论
Maxwell Day
Maxwell Day 2020-1-16
编辑:Adam Danz 2020-1-16
Thanks @Adam Danz I will use these.
Permuting the diagonal elements in addition to the lower triangle isnt a big deal, I can solve for these "extra" permutations by hand.
One other issue when ploting the graphs has emerged:
I permuted the matrix Ax = [2 0 0 1; 0 0 2 0; 0 2 0 1; 1 0 1 0] and recieved 36 unique permuted matrices, good.
However, when I attempt to plot the graphs based on these matrices using the code:
tiledlayout('flow')
arrayfun(@(n)plot(nexttile,graph(A_PERM_UNQ(:,:,n))),1:size(A_PERM_UNQ,3))
It doesnt work and I recieve the error message:
Error using graph/subsref (line 8)
Indexing not supported.
Error in @(n)plot(nexttile,graph(A_PERM_UNQ(:,:,n)))
Do you know why this is happening? Is there an easy fix here?
Thanks
Adam Danz
Adam Danz 2020-1-16
编辑:Adam Danz 2020-1-16
No error when I try it. A_PERM_UNQ is a 4x4x36 array it produces the figure.

请先登录,再进行评论。

更多回答(2 个)

Maxwell Day
Maxwell Day 2020-1-26
Hey @Adam Danz
The code is working great so far thanks again. I have another interesting problem if you are interested.
After executing the code and generating a set of unique (valid) permuted matrices (A1, A2...An) I would like to determine which of these matrices correspond to non-isomorphic (topologically distinct) graphs (G1,G2...Gn).
Two graphs G1 (from matrix A1) and G2 (from matrix A2) are isomorphic only if there exists a permutation matrix P such that:
(P)(A1)(P^-1) = A2
Here P^-1 is simple the inverted permutation matrix P.
Doing this for certain matrices is not possible as they will have a determinant of 0 and therfore not be invertible.
Is there a way to determine which matrices in a set generate isomorphic graphs by getting MatLab to determine if a permutation matrix P exists that satisfies the above equation? If this permutation matrix P exists we can then say G1 is isomorphic with G2 and eliminate either A1 or A2 (as they are effectively the same), if P did not exist we would keep both A1 and A2.
Such a code would have to apply the above equation to each unique combination of matrices in set. I.e. if we have 12 matrices there would be 66 unique combinations of two matrices as order doesnt matter and there is no reason to pair a matrix with itself.
A1-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12
A2-3,-4,-5,-6,-7,-8,-9,-10,-11,-12
A3-4,-5,-6,-7,-8,-9,-10,-11,-12
etc.
Depending on the size of the matrix, this may be a very large and intensive calculation, let me know if this is possible, thanks.
-Max
  3 个评论
Maxwell Day
Maxwell Day 2020-1-26
When I run this code I get:
Unrecognized function or variable 'A1'.
Do we have to specify what "A1" is?
The permutation matrix "P" or what seems to be A_PERM_UNQ in your code should refer to 1 of n permutation matrices possible for an n x n matrix where the total number of permutation matrices equals n!
i.e. for a 4 x 4 matrix there are 24 permutation matrices (P1-P24), if there are 12 unique matrices the equation should execute as follows:
A1-1 = (P1)(A_PERM_UNQ(:,:,1)(P1^-1)
A1-2 = (P2)(A_PERM_UNQ(:,:,1)(P2^-1)
....... A1-24 = (P24)(A_PERM_UNQ(:,:,1)(P24^-1)
Where A_PERM_UNQ(:,:,1) is the first of the 12 unique matrices
Here, if any of the calculated matrices A1-1 to A1-24 are identical to any of the 12 unique matrices (other than the A_PERM_UNQ(:,:,1) matrix obviously) those two matrices are topologically identical or isomorphic.
The calculation should then proceed with applying all 24 permutation matrices to the second unique matrix (A_PERM_UNQ(:,:,2) as follows:
A2-1 = (P1)(A_PERM_UNQ(:,:,2)(P1^-1)
A2-2 = (P2)(A_PERM_UNQ(:,:,2)(P2^-1)
.......A2-24 = (P24)(A_PERM_UNQ(:,:,2)(P24^-1)
Where A_PERM_UNQ(:,:,2) is the second of the 12 unique matrices
Here, if any of the calculated matrices A2-1 to A2-24 are identical to any of the 12 unique matrices (other than the A_PERM_UNQ(:,:,2) matrix obviously) those two matrices are topologically identical or isomorphic. This is what I am hoping MatLab can tell me.
The calculation would then continue with the third unique matrix (A_PERM_UNQ(:,:,3)) calculating matrices A3-1 to A3-24 by applying all 24 permutation matrices (P1-P24).
I hope this clarifies the problem.
Adam Danz
Adam Danz 2020-1-26
A_PERM_UNQ came from my answer - it contains the the permutations of A.
I don't know what A1 is supposed to be.

请先登录,再进行评论。


Maxwell Day
Maxwell Day 2020-2-1
编辑:Stephen23 2020-2-1
Hello @Adam Danz
I seem to be running into error related to exceeding the maximum array size with a 6 x 6 matrix, I was under the impression the code we had developed could handle matrices of this size.
I tried to permute the following matrix using the following code and recieved this error:
>>
% Input matrix
A = [0 1 1 1 1 0; 1 0 1 1 1 0; 1 1 0 0 0 0; 1 1 0 0 0 1; 1 1 0 0 0 0; 0 0 0 1 0 0];
% Get index of lower triangle values (below diagonal)
trilMat = tril(reshape(1:numel(A),size(A)),-1);
trilIdx = trilMat(trilMat>0);
% List all permutation of lower triangle indices
trilPerms = perms(trilIdx);
% List accepted diagonal values
diagPermitted = [0,2];
% List all permutation of diagonal values (with replacement)
% https://www.mathworks.com/matlabcentral/fileexchange/7147-permn
diagPerms = permn(diagPermitted,numel(diag(trilMat)));
% Loop through all lower-triangle-permutation and diagonal-permutations
diagMask = logical(eye(size(A)));
upperMask = triu(true(size(A)),1);
lowerMask = tril(true(size(A)),-1);
nPerms = size(trilPerms,1) * size(diagPerms,1); % total number of permutations
A_PERM = nan([size(A),nPerms]); % all permutations
for i = 1:size(trilPerms,1)
for j = 1:size(diagPerms,1)
c = (i-1)*size(diagPerms,1)+j;
base = zeros(size(A));
base(trilIdx) = A(trilPerms(i,:)); % permute lower triangle
base = base + tril(base,-1).'; % reflect lower triangle
base(diagMask) = diagPerms(j,:); % permute diagonal (not changed, but comes after reflection)
if ~issymmetric(base) % #UPDATED
% Sanity check: matrix is symmetric
error('Matrix not symmetic. i = %d j = %d',i,j) % #UPDATED
end
A_PERM(:,:,c) = base; % store matrix
end
end
goodRows = ismember(squeeze(sort(sum(A_PERM,2))).',[1 3 3 3 3 3],'rows');
A_PERM(:,:,~goodRows) = []
Error using zeros
Requested 479001600x12 (42.8GB) array exceeds maximum array size preference. Creation of arrays
greater than this limit may take a long time and cause MATLAB to become unresponsive. See array size
limit or preference panel for more information.
Error in perms>permsr (line 49)
P = zeros(nn*m,nn);
Error in perms (line 31)
P = permsr(n);
Is there anyway around this? let me know, Thanks.
  10 个评论
Maxwell Day
Maxwell Day 2020-2-27
Ah, I see, still getting empty arrays for permutations I know should work, assuming this is due to incorrect revisions of the trilIdx code elsewhere
>> % Input matrix
A = [2 1 0 0; 1 0 1 1; 0 1 0 1; 0 1 1 0];
% Get index of lower triangle values (below diagonal)
trilMat = tril(reshape(1:numel(A),size(A)),-1);
trilIdx = trilMat(trilMat>0);
% List all permutation of lower triangle indices
trilPerms = nthperm(trilIdx, 1);
% List accepted diagonal values
diagPermitted = [0,2];
% List all permutation of diagonal values (with replacement)
% https://www.mathworks.com/matlabcentral/fileexchange/7147-permn
diagPerms = permn(diagPermitted,numel(diag(trilMat)));
% Loop through all lower-triangle-permutation and diagonal-permutations
diagMask = logical(eye(size(A)));
upperMask = triu(true(size(A)),1);
lowerMask = tril(true(size(A)),-1);
nPerms = size(trilPerms,1) * size(diagPerms,1); % total number of permutations
A_PERM = nan([size(A),nPerms]); % all permutations
for i = 1:size(trilPerms,1)
for j = 1:size(diagPerms,1)
c = (i-1)*size(diagPerms,1)+j;
base = zeros(size(A));
base(trilIdx) = A(trilPerms(i,:)); % permute lower triangle
base = base + tril(base,-1).'; % reflect lower triangle
base(diagMask) = diagPerms(j,:); % permute diagonal (not changed, but comes after reflection)
if ~issymmetric(base) % #UPDATED
% Sanity check: matrix is symmetric
error('Matrix not symmetic. i = %d j = %d',i,j) % #UPDATED
end
A_PERM(:,:,c) = base; % store matrix
end
end
goodRows = ismember(squeeze(sort(sum(A_PERM,2))).',[2 2 3 3],'rows');
A_PERM(:,:,~goodRows) = []
A_PERM =
4×4×0 empty double array
Adam Danz
Adam Danz 2020-2-27
goodRows = ismember(squeeze(sort(sum(A_PERM,2))).',[2 2 3 3],'rows');
goodRows (a column vector) is all False values. In other words, the [2 2 3 3] vector is not found anywhere in the permuration sums.
squeeze(sort(sum(A_PERM,2))).'

请先登录,再进行评论。

类别

Help CenterFile Exchange 中查找有关 Logical 的更多信息

产品


版本

R2019b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by