Matlab: Finding the permutation matrices that produce another matrix - algorithm

I'm trying to write MATLAB code that will allow me to find the permutation matrices of a matrix.
Let's consider the example below. I'm given the matrices A and B:
A = [1 2 3;4 5 6; 7 8 9] % is a given matrix
B = [9 7 8;3 1 2; 6 4 5] % is a permuted version of A.
My goal is to find the matrices L (that pre-multiply A) and R (that post-multiply A) such that L*A*R = B:
% L is an n by n (3 by 3) that re-order the rows a matrix when it pre-multiply that matrix
L = [0 0 1;1 0 0;0 1 0]
% R is an n by n that re-order the columns of a matrix
R = [0 1 0;0 0 1;1 0 0]
B = L*A*R
How to find L and R when I know A and B?

To give a baseline solution, here is the brute-force method:
function [L,R] = find_perms(A,B)
[n,n] = size(A);
p = perms(1:n);
I = eye(n);
for i=1:size(p,1)
for j=1:size(p,1)
L = I(p(i,:),:);
R = I(:,p(j,:));
if isequal(L*A*R, B)
return;
end
end
end
% none found
L = [];
R = [];
end
Let's test it:
A = [1 2 3; 4 5 6; 7 8 9];
B = [9 7 8; 3 1 2; 6 4 5];
[L,R] = find_perms(A,B);
assert(isequal(L*A*R, B));
The left/right permutation matrices are as expected:
>> L
L =
0 0 1
1 0 0
0 1 0
>> R
R =
0 1 0
0 0 1
1 0 0

Related

Creating adjacency matrix from 2D array

I have an array like the following:
a b c d
e f g h
j k l m
n o p q
My idea is to create an adjacency matrix from this for only horizontal and vertical movement, where the costs are the ASCII value in the destination.
The solution would find the following kind of adjacency matrix (simplified 'a'=1):
a b c d e f g h <- start
a 0 1 0 0 1 0 0 0
b 2 0 2 0 0 2 0 0
c 0 3 0 3 0 0 3 0
d 0 0 4 0 0 0 0 4
e 5 0 0 0 0 5 0 0
f 0 6 0 0 6 0 6 0
g 0 0 7 0 0 7 0 7
h 0 0 0 8 0 0 8 0
^ destination
I removed the last two rows of the original matrix for brevity.
I've come as far as to realize that a row has only one specific cost, and has a maximum of 4 adjacencies. My question is how do I find these adjacencies? If possible, I want to only iterate through the original matrix to save myself from using the exponentially larger adjacency matrix.
As with all good problems I needed some pen and paper. The solution seems to be the following code, where 'M' is the original matrix and 'adj' is the generated adjacency matrix with dimensions x and y:
makeAdjacencyMatrix(M,adj)
for row = 0 .. y do
for col = 0 .. x do
val = M[row,col]
loc = row * x + col
above = loc - x
below = loc + x
if loc + 1 < x * y then
adj[loc, loc + 1] = val
if loc - 1 >= 0 then
adj[loc, loc - 1] = val
if above >= 0 then
adj[loc, above] = val;
if below < x * y then
adj[loc, below] = val
return adj
I will mark question as answered when possible.

Algorithm to finding if the numbers in the list, when added or subtracted, are equal to a mod b

I was doing some interview problems when I ran into an interesting one that I could not think of a solution for. The problems states:
Design a function that takes in an array of integers. The last two numbers
in this array are 'a' and 'b'. The function should find if all of the
numbers in the array, when summed/subtracted in some fashion, are equal to
a mod b, except the last two numbers a and b.
So, for example, let us say we have an array:
array = [5, 4, 3, 3, 1, 3, 5].
I need to find out if there exists any possible "placement" of +/- in this array so that the numbers can equal 3 mod 5. The function should print True for this array because 5+4-3+3-1 = 8 = 3 mod 5.
The "obvious" and easy solution would be to try and add/subtract everything in all possible ways, but that is an egregiously time complex solution, maybe
O(2n).
Is there any way better to do this?
Edit: The question requires the function to use all numbers in the array, not any. Except, of course, the last two.
If there are n numbers, then there is a simple algorithm that runs in O (b * n): For k = 2 to n, calculate the set of integers x such that the sum or difference of the first k numbers is equal to x modulo b.
For k = 2, the set contains (a_0 + a_1) modulo b and (a_0 - a_1) modulo b. For k = 3, 4, ..., n you take the numbers in the previous set, then either add or subtract the next number in the array. And finally check if a is element of the last set.
O(b * n). Let's take your example, [5, 4, 3, 3, 1]. Let m[i][j] represent whether a solution exists for j mod 5 up to index i:
i = 0:
5 = 0 mod 5
m[0][0] = True
i = 1:
0 + 4 = 4 mod 5
m[1][4] = True
but we could also subtract
0 - 4 = 1 mod 5
m[1][1] = True
i = 2:
Examine the previous possibilities:
m[1][4] and m[1][1]
4 + 3 = 7 = 2 mod 5
4 - 3 = 1 = 1 mod 5
1 + 3 = 4 = 4 mod 5
1 - 3 = -2 = 3 mod 5
m[2][1] = True
m[2][2] = True
m[2][3] = True
m[2][4] = True
i = 3:
1 + 3 = 4 mod 5
1 - 3 = 3 mod 5
2 + 3 = 0 mod 5
2 - 3 = 4 mod 5
3 + 3 = 1 mod 5
3 - 3 = 0 mod 5
4 + 3 = 2 mod 5
4 - 3 = 1 mod 5
m[3][0] = True
m[3][1] = True
m[3][2] = True
m[3][3] = True
m[3][4] = True
We could actually stop there, but let's follow a different solution than the one in your example backwards:
i = 4:
m[3][2] True means we had a solution for 2 at i=3
=> 2 + 1 means m[4][3] = True
+ 1
+ 3
+ 3
- 4
(0 - 4 + 3 + 3 + 1) = 3 mod 5
I coded a solution based on the mathematical explanation provided here. I didn't comment the solution, so if you want an explanation, I recommend you read the answer!
def kmodn(l):
k, n = l[-2], l[-1]
A = [0] * n
count = -1
domath(count, A, l[:-2], k, n)
def domath(count, A, l, k, n):
if count == len(l):
boolean = A[k] == 1
print boolean
elif count == -1:
A[0] = 1; # because the empty set is possible
count += 1
domath(count, A, l, k, n)
else:
indices = [i for i, x in enumerate(A) if x == 1]
b = [0] * n
for i in indices:
idx1 = (l[count] + i) % n
idx2 = (i - l[count]) % n
b[idx1], b[idx2] = 1, 1
count += 1
A = b
domath(count, A, l, k, n)

How to change the elements by different values in a matrix simultaneously in Octave?

I want to change the individual elements in a matrix by different values simultaneously.
How do I do that?
For example: I want to change the first element in matrix A by certain amount and the second element by a different amount simultaneously.
{ A = [1; 2]
% instead of doing A(1) = .....
A(2) = .....
}
You can access the elements of a vector or matrix and replace them.
For a vector this is intuitive.
octave:16> A = 1:9
A =
1 2 3 4 5 6 7 8 9
octave:17> A([1 3 5 7 9]) = 0
A =
0 2 0 4 0 6 0 8 0
This can be done for a matrix as well. The elements of a matrix are arranged in a column-first manner. You can use a single index to access the elements of a matrix.
octave:18> A = [1 2 3; 4 5 6; 7 8 9]
A =
1 2 3
4 5 6
7 8 9
The 2nd element of A is the same as A(2, 1). The 4th element of A is the same as A(1, 2).
octave:21> A(2)
ans = 4
octave:22> A(4)
ans = 2
So, you can set all the odd elements of A to 0 in one go like this:
octave:19> A([1 3 5 7 9]) = 0
A =
0 2 0
4 0 6
0 8 0
Just add a vector with the differences. A += [0.1; 0.2]
octave:1> A = [1; 2];
octave:2> A += [0.1; 0.2]
A =
1.1000
2.2000

MATLAB identify adjacient regions in 3D image

I have a 3D image, divided into contiguous regions where each voxel has the same value. The value assigned to this region is unique to the region and serves as a label. The example image below describes the 2D case:
1 1 1 1 2 2 2
1 1 1 2 2 2 3
Im = 1 4 1 2 2 3 3
4 4 4 4 3 3 3
4 4 4 4 3 3 3
I want to create a graph describing adjaciency between these regions. In the above case, this would be:
0 1 0 1
A = 1 0 1 1
0 1 0 1
1 1 1 0
I'm looking for a speedy solution to do this for large 3D images in MATLAB. I came up with a solution that iterates over all regions, which takes 0.05s per iteration - unfortunately, this will take over half an hour for an image with 32'000 regions. Does anybody now a more elegant way of doing this? I'm posting the current algorithm below:
labels = unique(Im); % assuming labels go continuously from 1 to N
A = zeros(labels);
for ii=labels
% border mask to find neighbourhood
dil = imdilate( Im==ii, ones(3,3,3) );
border = dil - (Im==ii);
neighLabels = unique( Im(border>0) );
A(ii,neighLabels) = 1;
end
imdilate is the bottleneck I would like to avoid.
Thank you for your help!
I came up with a solution which is a combination of Divakar's and teng's answers, as well as my own modifications and I generalised it to the 2D or 3D case.
To make it more efficient, I should probably pre-allocate the r and c, but in the meantime, this is the runtime:
For a 3D image of dimension 117x159x126 and 32000 separate regions: 0.79s
For the above 2D example: 0.004671s with this solution, 0.002136s with Divakar's solution, 0.03995s with teng's solution.
I haven't tried extending the winner (Divakar) to the 3D case, though!
noDims = length(size(Im));
validim = ones(size(Im))>0;
labels = unique(Im);
if noDims == 3
Im = padarray(Im,[1 1 1],'replicate', 'post');
shifts = {[-1 0 0] [0 -1 0] [0 0 -1]};
elseif noDims == 2
Im = padarray(Im,[1 1],'replicate', 'post');
shifts = {[-1 0] [0 -1]};
end
% get value of the neighbors for each pixel
% by shifting the image in each direction
r=[]; c=[];
for i = 1:numel(shifts)
tmp = circshift(Im,shifts{i});
r = [r ; Im(validim)];
c = [c ; tmp(validim)];
end
A = sparse(r,c,ones(size(r)), numel(labels), numel(labels) );
% make symmetric, delete diagonal
A = (A+A')>0;
A(1:size(A,1)+1:end)=0;
Thanks for the help!
Try this out -
Im = padarray(Im,[1 1],'replicate');
labels = unique(Im);
box1 = [-size(Im,1)-1 -size(Im,1) -size(Im,1)+1 -1 1 size(Im,1)-1 size(Im,1) size(Im,1)+1];
mat1 = NaN(numel(labels),numel(labels));
for k2=1:numel(labels)
a1 = find(Im==k2);
for k1=1:numel(labels)
a2 = find(Im==k1);
t1 = bsxfun(#plus,a1,box1);
t2 = bsxfun(#eq,t1,permute(a2,[3 2 1]));
mat1(k2,k1) = any(t2(:));
end
end
mat1(1:size(mat1,1)+1:end)=0;
If it works for you, share with us the runtimes as comparison? Would love to see if the coffee brews any faster than half an hour!
Below is my attempt.
Im = [1 1 1 1 2 2 2;
1 1 1 2 2 2 3;
1 4 1 2 2 3 3;
4 4 4 4 3 3 3;
4 4 4 4 3 3 3];
% mark the borders
validim = zeros(size(Im));
validim(2:end-1,2:end-1) = 1;
% get value of the 4-neighbors for each pixel
% by shifting the images 4 times in each direction
numNeighbors = 4;
adj = zeros([prod(size(Im)),numNeighbors]);
shifts = {[0 1] [0 -1] [1 0] [-1 0]};
for i = 1:numNeighbors
tmp = circshift(Im,shifts{i});
tmp(validim == 0) = nan;
adj(:,i) = tmp(:);
end
% mark neighbors where it does not eq Im
imDuplicates = repmat(Im(:),[1 numNeighbors]);
nonequals = adj ~= imDuplicates;
% neglect the border
nonequals(isnan(adj)) = 0;
% get these neighbor values and the corresponding Im value
compared = [imDuplicates(nonequals == 1) adj(nonequals == 1)];
% construct your 'A' % possibly could be more optimized here.
labels = unique(Im);
A = zeros(numel(labels));
for i = 1:size(compared,1)
A(compared(i,1),compared(i,2)) = 1;
end
#Lisa
Yours reasoning is elegant, though it obviously gives wrong answers for labels on the edges.
Try this simple label matrix:
Im =
1 2 2
3 3 3
3 4 4
The resulting adjacency matrix , according to your code is:
A =
0 1 1 0
1 0 1 1
1 1 0 1
0 1 1 0
which claims an adjacency between labels "2" and "4": obviously wrong. This happens simply because you are reading padded Im labels based on "validim" indices, which now doesn't match the new Im and goes all the way down to the lower borders.

How to get this matrix

I have this matrix:
S.No. A B
1 5268020 1756
2 15106230 5241
3 24298744 9591
4 23197375 9129
I want to get a matrix which will have two columns [X,Y]. X will take values from S.No. and Y will can be either 1 or 0. For example, for 1 5268020 1756 there should be total 5268020 (1,0) i.e, (X,Y) pairs and 1756 (1,1) pairs.
How can I get this matrix in Octave ??
If I understand your question correctly, you want to fill a matrix with repeated entries (x,0) and (x,1), where x=1...4, where repetition is determined by values found in column A and B. Given the values you supplied that's going to be a huge matrix (67,896,086 rows). So, you could try something like this (replace m below, which has less elements for illustrative purpose):
m = [1, 2, 1;
2, 3, 2;
3, 2, 1;
4, 2, 2];
res = [];
for k = 1:4
res = [res ; [k*ones(m(k, 2), 1), zeros(m(k, 2), 1);
k*ones(m(k, 3), 1), ones(m(k, 3), 1)]];
endfor
which yields
res =
1 0
1 0
1 1
2 0
2 0
2 0
2 1
2 1
3 0
3 0
3 1
4 0
4 0
4 1
4 1
Out of curiosity, is there any reason not to consider a matrix like
1 0 n
1 1 m
2 0 p
2 1 q
...
where n, m, p, q, are values found in columns A and B. This would probably be easier to handle , no?

Resources