Transforming two matrices into one matrix using binary numbers - matlab

A1 and A2 are two arrays of integers with the same dimensions 6000x2000.
I want to find a third matrix B by following these steps:
for i=1:1:6000
for j=1:2000
a1 = fliplr(dec2binvec(A1(i,j),14)); % Convert A1(i,j) to a binary vector
a2 = fliplr(dec2binvec(A2(i,j),32)); % Convert A2(i,j) to a binary vector
b = [a1 a2];
B(i,j) = sum(b.*2.^(numel(b)-1:-1:0)); % Convert b to decimal
end
end
my problem is the computation time to find B.
Is there a way to avoid loops in order to reduce the computation time ?
Example:
A1 = [2 3 A2 = [7 6
4 5] 2 9]
A1(1,1) = 2 and A2(1,1) = 7
a1 = [0 0 0 1 0] (eg 5 bits) a2 = [0 0 0 1 1 1] (eg 6 bits)
b = [a1 a2] = [0 0 0 1 0 0 0 0 1 1 1]
B1(1,1) = sum(b.*2.^(numel(b)-1:-1:0)) = 135

Using your example:
A1 = [2 3;
4 5];
A2 = [7 6;
2 9];
B=bitshift(A1,6)+A2
Output:
B =
135 198
258 329

I assume the example contains what you want. Simply use math ;)
A1 = [2 3;4,5]
A2=[7 6;2 9]
A1.*2^6+A2
Please be aware that doubles can hold up to 53 bits without precision loss. Recent versions of matlab support uint64. For even longer numbers check vpa, but vpa will result in slow code.

If I understand your example correctly, you only need to bit-shift A1 (i.e. multiply by a power of 2):
M = 5; %// not used actually
N = 6;
B = A1 * 2^N + A2;
In your example, this gives
B =
135 198
258 329

Related

Combine index-based and logical addressing in Matlab

Consider a matrix X. I have to update a submatrix of X, X(row1:row2, col1:col2), with a matrix Z (of size row2-row1+1, col2-col1+1) but only on those positions where a logical matrix L (of size row2-row1+1, col2-col1+1) is true.
E.g. if
X=[ 1 2 3 4 5 6
11 12 13 14 15 16
21 22 23 24 25 26
31 32 33 34 34 36]
Z=[31 41
32 42]
L=[ 1 0
0 1]
row1 = 2; row2 = 3; col1 = 3; col2 = 4
then after the update I should get:
X=[ 1 2 3 4 5 6
11 12 31 14 15 16
21 22 23 42 25 26
31 32 33 34 34 36]
Currently I do the following:
Y = X(row1:row2, col1:col2);
Y(L) = Z(L);
X(row1:row2, col1:col2) = Y;
This code is in a tight loop and according to Matlab's (v2019a) profiler is the main bottleneck of my program. In the real code X is a 2000x1500x3 cube; row1, row2, col1, col2, Z and L change in the loop.
The question is whether it can be rewritten into a single / faster assignment.
Thanks.
Honestly, without seeing your actual code, I get the sense that your solution may be as fast as you can get. The reason I say that is because I tested a few different solutions by creating some random sample data closer to your actual problem. I assumed X is an image of type uint8 with size 2000-by-1500-by-3, Z is size N-by-N (i.e. we will only be modifying the first page of X), L is an N-by-N logical array, and the row and column indices are randomly chosen:
X = randi([0 255], 2000, 1500, 3, 'uint8');
N = 20; % Submatrix size
Z = randi([0 255], N, N, 'uint8');
L = (rand(N, N) > 0.5);
row1 = randi([1 2000-N]);
row2 = row1+N-1
col1 = randi([1 1500-N]);
col2 = col1+N-1;
I then tested 3 different solutions: your original solution, a solution using find and sub2ind to create a linear index for X, and a solution that creates a logical index for X:
% Original solution:
Y = X(row1:row2, col1:col2, 1);
Y(L) = Z(L);
X(row1:row2, col1:col2, 1) = Y;
% Linear index solution:
[rIndex, cIndex] = find(L);
X(sub2ind(size(X), rIndex+row1-1, cIndex+col1-1)) = Z(L);
% Logical index solution
[R, C, ~] = size(X);
fullL = false(R, C);
fullL(row1:row2, col1:col2) = L;
X(fullL) = Z(L);
I tested these repeatedly with randomly-generated sample data using timeit and found that your original solution is consistently the fastest. The linear index solution is very close, but slightly slower. The logical index solution takes more than twice as long.
Let's define some example data:
X = randi(9,5,6);
Y = 10+X;
row1 = 2;
row2 = 4;
col1 = 3;
col2 = 4;
L = logical([0 1; 0 0; 1 1]);
Then:
ind_subm = bsxfun(#plus, (row1:row2).',size(X,1)*((col1:col2)-1));
% linear index for submatrix
ind_subm_masked = ind_subm(L);
% linear index for masked submatrix
X(ind_subm_masked) = Y(ind_subm_masked);
Example results:
X before:
X =
6 2 1 7 9 6
3 3 3 5 5 7
6 3 8 6 5 4
7 4 1 3 3 4
2 5 9 5 5 9
L:
L =
3×2 logical array
0 1
0 0
1 1
X after:
X =
6 2 1 7 9 6
3 3 3 15 5 7
6 3 8 6 5 4
7 4 11 13 3 4
2 5 9 5 5 9

Find duplicates in a matrix

consider a matrix:
a = [1 2
1 3
2 3
4 5
6 1]
I want to find duplicates for every unique element of a and take the rows of them to different matrices. For example here lets say that the answer for number 1 is:
a1 = [1 2
1 3
6 1]
The answer for number 2 is:
a2 = [1 2
2 3]
The answer for number 3 is:
a3 = [1 3
2 3]
and so on for every unique elements of matrix a. Any suggestions?
This will do it:
temp=unique(a);
for k=1:numel(temp)
[r,~]=find(a==temp(k));
assignin('base', ['a' num2str(k)], a(sort(r),:))
end
Results:-
>> a1
a1 =
1 2
1 3
6 1
>> a2
a2 =
1 2
2 3
>> a3
a3 =
1 3
2 3
>> a4
a4 =
4 5
>> a5
a5 =
4 5
>> a6
a6 =
6 1
You can use any to check if any element of a row contains the value you want. This will return a logical array that is true where the row contained the value. You can then use this to grab the relevant rows of a.
result = a(any(a == value, 2), :);
We could create an anonymous function that does this for you.
rows_that_contain_value = #(A, value)A(any(A == value, 2), :);
Then we can use this like this
a = [1 2
1 3
2 3
4 5
6 1]
a1 = rows_that_contain_value(a, 1);
a2 = rows_that_contain_value(a, 2);
a3 = rows_that_contain_value(a, 3);
If we want to do this for all unique values in a, we can do something like the following.
groups = arrayfun(#(x)rows_that_contain_value(a, x), unique(a), 'uniformoutput', 0);

Compare two vectors in MATLAB without using loop

Given two vector a , b of different length in MATLAB, I want the output as follows:
Example :
a = [3 5 10 20 45 80]
b = [3 5 80]
y = [1 1 0 0 0 1]
where y is of length similar to a in which 1's indicate existence of an item in b and 0 its non-existence.
I want to do this without using loops. Thanks
Note that all the numbers in each vector will be repeated only once as they correspond to some ids.
ismember()
Lia = ismember(A,B) returns an array containing 1 (true) where the data in A is found in B. Elsewhere, it returns 0 (false).
a = [3 5 10 20 45 80];
b = [3 5 80];
ismember(a,b)
ans =
1 1 0 0 0 1

creating diagonal matrix with selected elements

I have a 4x5 matrix called A from which I want to select randomly 3 rows, then 4 random columns and then select those elements which coincide in those selected rows and columns so that I have 12 selected elements.Then I want to create a diagonal matrix called B which will have entries either 1 or 0 so that multiplication of that B matrix with reshaped A matrix (20x1) will give me those selected 12 elements of A.
How can I create that B matrix? Here is my code:
A=1:20;
A=reshape(A,4,5);
Mr=4;
Ma=3;
Na=4;
Nr=5;
M=Ma*Mr;
[S1,S2]=size(A);
N=S1*S2;
y2=zeros(size(A));
k1=randperm(S1);
k1=k1(1:Ma);
k2=randperm(S2);
k2=k2(1:Mr);
y2(k1,k2)=A(k1,k2);
It's a little hard to understand what you want and your code isn't much help but I think I've a solution for you.
I create a matrix (vector) of zeros of the same size as A and then use bsxfun to determine the indexes in this vector (which will be the diagonal of B) that should be 1.
>> A = reshape(1:20, 4, 5);
>> R = [1 2 3]; % Random rows
>> C = [2 3 4 5]; % Random columns
>> B = zeros(size(A));
>> B(bsxfun(#plus, C, size(A, 1)*(R-1).')) = 1;
>> B = diag(B(:));
>> V = B*A(:);
>> V = V(V ~= 0)
V =
2
3
4
5
6
7
8
9
10
11
12
13
Note: There is no need for B = diag(B(:)); we could have simply used element by element multiplication in Matlab.
>> V = B(:).*A(:);
>> V = V(V ~= 0)
Note: This may be overly complex or very poorly put together and there is probably a better way of doing it. It's my first real attempt at using bsxfun on my own.
Here is a hack but since you are creating y2 you might as well just use it instead of creating the useless B matrix. The bsxfun answer is much better.
A=1:20;
A=reshape(A,4,5);
Mr=4;
Ma=3;
Na=4;
Nr=5;
M=Ma*Mr;
[S1,S2]=size(A);
N=S1*S2;
y2=zeros(size(A));
k1=randperm(S1);
k1=k1(1:Ma);
k2=randperm(S2);
k2=k2(1:Mr);
y2(k1,k2)=A(k1,k2);
idx = reshape(y2 ~= 0, numel(y2), []);
B = diag(idx);
% "diagonal" matrix 12x20
B = B(all(B==0,2),:) = [];
output = B * A(:)
output =
1
3
4
9
11
12
13
15
16
17
19
20
y2 from example.
y2 =
1 0 9 13 17
0 0 0 0 0
3 0 11 15 19
4 0 12 16 20

Creating Matrix with a loop in Matlab

I want to create a matrix of the following form
Y = [1 x x.^2 x.^3 x.^4 x.^5 ... x.^100]
Let x be a column vector.
or even some more variants such as
Y = [1 x1 x2 x3 (x1).^2 (x2).^2 (x3).^2 (x1.x2) (x2.x3) (x3.x1)]
Let x1,x2 and x3 be column vectors
Let us consider the first one. I tried using something like
Y = [1 : x : x.^100]
But this also didn't work because it means take Y = [1 x 2.*x 3.*x ... x.^100] ?
(ie all values between 1 to x.^100 with difference x)
So, this also cannot be used to generate such a matrix.
Please consider x = [1; 2; 3; 4];
and suggest a way to generate this matrix
Y = [1 1 1 1 1;
1 2 4 8 16;
1 3 9 27 81;
1 4 16 64 256];
without manually having to write
Y = [ones(size(x,1)) x x.^2 x.^3 x.^4]
Use this bsxfun technique -
N = 5; %// Number of columns needed in output
x = [1; 2; 3; 4]; %// or [1:4]'
Y = bsxfun(#power,x,[0:N-1])
Output -
Y =
1 1 1 1 1
1 2 4 8 16
1 3 9 27 81
1 4 16 64 256
If you have x = [1 2; 3 4; 5 6] and you want Y = [1 1 1 2 4; 1 3 9 4 16; 1 5 25 6 36] i.e. Y = [ 1 x1 x1.^2 x2 x2.^2 ] for column vectors x1, x2 ..., you can use this one-liner -
[ones(size(x,1),1) reshape(bsxfun(#power,permute(x,[1 3 2]),1:2),size(x,1),[])]
Using an adapted Version of the code found in Matlabs vander()-Function (which is also to be found in the polyfit-function) one can get a significant speedup compared to Divakars nice and short solution if you use something like this:
N = 5;
x = [1:4]';
V(:,n+1) = ones(length(x),1);
for j = n:-1:1
V(:,j) = x.*V(:,j+1);
end
V = V(:,end:-1:1);
It is about twice as fast for the example given and it gets about 20 times as fast if i set N=50 and x = [1:40]'. Although I state that is not easy to compare the times, just as an option if speed is an issue, you might have a look at this solution.
in octave, broadcasting allows to write
N=5;
x = [1; 2; 3; 4];
y = x.^(0:N-1)
output -
y =
1 1 1 1 1
1 2 4 8 16
1 3 9 27 81
1 4 16 64 256