Looking for matrices in matlab - matlab

My problem is as follows:
I have the followings matrices:
0 1
1 1
or
1 1 1
1 1 1
0 1 0
or
1 1 1 0
1 1 1 1
0 1 1 0
And I want to get the following matrices:
0 1
2 1
or
1 1 1
1 1 1
0 2 0
or
1 1 1 0
1 1 1 2
0 3 3 0
What I want is to get the submatrices (or col-vector, or row-vector in case that submatrices are not possible) as large as possible.
I am going to explain clearly:
If the input is the third matrix:
1 1 1 0
1 1 1 1
0 1 1 0
I want to group elements vertically or horizontally, making these submatrices as large as possible. The largest submatrix in this example is:
x x x 0
x x x 1
0 1 1 0
Another possible submatrix, that is also largest is:
1 x x 0
1 x x 1
0 x x 0
Both represented by x.
Then, there are three elements with 1, yet. So I want to group again. Getting the largest submatrices (or sub-vector) again. At that point, depending on the previous move, we will get:
x x x 0
x x x 1
0 y y 0
or
y x x 0
y x x 1
0 x x 0
Represented by y.
Now, we have another element, that has not being grouped, and now we make another group (represented by z):
y x x 0
y x x z
0 x x 0
If now we choose another input, we have the following steps:
0 1
1 1
We have two sub-vector, so we have two possible solutions:
0 1
x x
or
0 x
1 x
And then, depending on the solution chosen, we have the following solution:
0 y
x x
or
0 x
y x
Grouping the other element alone.
Finally, in the second case, we only have one possible solution:
1 1 1
1 1 1
0 1 0
Getting the largest submatrix we have this solution:
x x x
x x x
0 1 0
And then, group the last element alone:
x x x
x x x
0 y 0
Thank you in advance.

It won't be fast, but brute forcing your way through would work (for small problems). Pseudo code like:
A = [1, 0; 1, 1];
B = zeros(size(A));
bCount = 1;
while any(A ~= 0)
globalmax = 0;
for i,j = 1 : sizeOfMatrix
localmax = 0;
for ii,jj = i,j : sizeOfMatrix
if ((ii-i+1) * (jj-j+1) > localmax ... &&
&& all(A(i:ii, j:jj) ~= 0))
localmax = (ii-i+1) * (jj-j+1);
localmaxPoints = [i, ii; j, jj];
end
end
if (localmax > globalmax)
globalmax = localmax;
globalmaxPoints = localmaxPoints;
end
end
A[globalmaxPoints] = 0;
B[globalmaxPoints] = bCount;
bCount = bCount+1;
end
Note this code won't work directly, but it should be easy to fix it.
Obviously the approach it is suitable only for small matrices - too slow for anything large. There are some small optimizations which are trivial, but won't change much.
You require something better to find optimum for a huge matrix. Unless you have some properties in these matrices you could use (for example zeros are only along the edges), you will have to use optimization techniques. You might not get the most optimal solution, but it will be a very good one.

Related

Count the first x integers of a group of values

I want to get the count starting from 1, of the number of occurrences of Y until its subsequent value is N. A simple example table can be found below, I've added an additional column called expected output to highlight what I'm trying to achieve.
tab:([]x:`N`N`Y`N`N`Y`Y`Y`N`N`Y`Y`Y;expected_output:0 0 1 0 0 1 2 3 0 0 1 2 3)
I have been playing around with the idea of trying to use cut (granted that I can find the correct indexes) I could split the table up, get the count of each list, then piece it all back together somehow e.g.
0 2 3 5 8 10 cut tab
Approach without scan, not as neat as terry's but should be faster on larger tab.
q)update o:{a+r-maxs differ[x]*r:sums a:`Y=x}x from tab
x expected_output o
-------------------
N 0 0
N 0 0
Y 1 1
N 0 0
N 0 0
Y 1 1
Y 2 2
Y 3 3
N 0 0
N 0 0
Y 1 1
Y 2 2
Y 3 3
One approach using scan
q)update c:0{y*x+y}\x=`Y from tab
x expected_output c
-------------------
N 0 0
N 0 0
Y 1 1
N 0 0
N 0 0
Y 1 1
Y 2 2
Y 3 3
N 0 0
N 0 0
Y 1 1
Y 2 2
Y 3 3
Essentially a modified version of sums which resets the counter back to zero (using zero/false multiplication) whenever the next boolean is zero

How to permute elements of a vector by another vector to obtain a matrix of permutations

I want to obtain all the possible permutations of one vector elements by another vector elements. For example one vector is A=[0 0 0 0] and another is B=[1 1]. I want to replace the elements of A by B to obtain all the permutations in a matrix like this [1 1 0 0; 1 0 1 0; 1 0 0 1; 0 1 1 0; 0 1 0 1; 0 0 1 1]. The length of real A is big and I should be able to choose the length of B_max and to obtain all the permutations of A with B=[1], [1 1], [1 1 1],..., B_max.
Thanks a lot
Actually, since A and B are always defined, respectively, as a vector of zeros and a vector of ones, this computation is much easier than you may think. The only constraints you should respect concerns B, which shoud not be empty and it's elements cannot be greater than or equal to the number of elements in A... because after that threshold A will become a vector of ones and calculating its permutations will be just a waste of CPU cycles.
Here is the core function of the script, which undertakes the creation of the unique permutations of 0 and 1 given the target vector X:
function p = uperms(X)
n = numel(X);
k = sum(X);
c = nchoosek(1:n,k);
m = size(c,1);
p = zeros(m,n);
p(repmat((1-m:0)',1,k) + m*c) = 1;
end
And here is the full code:
clear();
clc();
% Define the main parameter: the number of elements in A...
A_len = 4;
% Compute the elements of B accordingly...
B_len = A_len - 1;
B_seq = 1:B_len;
% Compute the possible mixtures of A and B...
X = tril(ones(A_len));
X = X(B_seq,:);
% Compute the unique permutations...
p = [];
for i = B_seq
p = [p; uperms(X(i,:).')];
end
Output for A_len = 4:
p =
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
1 1 0 0
1 0 1 0
1 0 0 1
0 1 1 0
0 1 0 1
0 0 1 1
1 1 1 0
1 1 0 1
1 0 1 1
0 1 1 1

Acces 3D Matrix with 2D index and 1D vector

I have a 3D matrix A (size m*n*k) where m=latitude, n*longitude and k=time.
I want only specific values from first and second dimension, specified by a logical matrix B (size m*n), and I want only the timesteps specified by vector C (size k).
In the end this should become a 2D matrix D, since the first two dimesions will colapse to one.
What is the most easy approach to do this?
And also is it possible to combine logical with linear indizes here? For example B is logical and C is linear?
Sample code with rand:
A=rand(10,10,10);
B=randi([0 1], 10,10);
C=randi([0 1], 10,1);
D=A(B,C) %This would be my approach which doesnt work. The size of D should be sum(B)*sum(c)
Another example without rand:
A=reshape([1:27],3,3,3);
B=logical([1,0,0;1,0,0;0,0,0]);
C=(1,3); %get data from timestep 1 and 5
D=A(B,C);%What I want to do, but doesnÄt work that way
D=[1,19;2,20];%Result should look like this! First dimension is now all data from dimesion 1 and 2. New dimesion 2 is now the time.
A = rand(4,4,4);
B = randi([0 1], 4,4)
B =
1 1 0 1
1 0 1 1
0 0 1 0
1 0 1 1
>> C = randi([0 1],1,1,4);
>> C(:)
ans =
0
1
1
0
Then use bsxfun or implicit expansion expansion whith .* if newer Matlab version to generate a matrix of logical for you given coordinates.
>> idx = logical(bsxfun(#times,B,C))
idx(:,:,1) =
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
idx(:,:,2) =
1 1 0 1
1 0 1 1
0 0 1 0
1 0 1 1
idx(:,:,3) =
1 1 0 1
1 0 1 1
0 0 1 0
1 0 1 1
idx(:,:,4) =
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
Then your output is D = A(idx). However, note that this D is now an Nx1 array. Where N is number of true elements is B times number of true elements in C. 10x True in B and 2x True in C:
>> size(D)
ans =
20 1
An easy way to do it is to first reshape A into an m*n-by-k matrix, then do your indexing:
result = reshape(A, [], size(A, 3));
result = result(B, C);
In this case C can be either a logical vector or vector of indices.

How to generate a vector that orthogonal to other vectors?

I have a matrix A which is
A=[1 0 0 1 0;
0 1 1 0 0;
0 0 1 1 0;
1 1 1 0 0]
And a given vector v=[ 0 0 1 1 0] which has two elements one. I have to change the position of element one such that the new vector v is orthogonal to all the rows in the matrix A.
How can I do it in Matlab?
To verify the correct answer, just check gfrank([A;v_new]) is 5 (i.e v_new=[0 1 0 0 1]).
Note that: Two vectors uand v whose dot product is u.v=0 (i.e., the vectors are perpendicular) are said to be orthogonal.
As AVK also mentioned in the comments, v_new = [0 1 0 0 1] is not orthogonal to all rows of A.
Explanation:-
A=[1 0 0 1 0;
0 1 1 0 0;
0 0 1 1 0;
1 1 1 0 0]
For A(1,:).*v = 0 to A(4,:).*v = 0,
0 x x 0 x % elements of v so that it's orthagonal to the 1st row of A
x 0 0 x x % -------------------------------------------- 2nd row of A
x x 0 0 x % -------------------------------------------- 3rd row of A
0 0 0 x x % -------------------------------------------- 4th row of A
where 0 represents the terms which have to be 0 and x represents the terms which can be either 0 or 1.
If you look as a whole, first 4 columns of v have to be zero so that the output is orthagonal to all rows of A. The 5th column can either be zero or 1.
So,
v_new can either be: v_new = [0 0 0 0 1] or v_new = [0 0 0 0 0]
From above explanation, you can also see that [0 1 0 0 1] is not orthagonal to 2nd and 4th row of A
Solution:-
To find v_new, you can use null function as: v_new = null(A).'
which gives: v_new = [0 0 0 0 1] for which gfrank([A;v_new]) also gives 5.
Maybe this will help you see the orthogonality between two vectors in N dimension.
N=100;
B1 = ones(1,N);
B2 = -1*ones(1,N/2);
B2 = [ones(1,N/2) B2];
B2 = transpose(B2);
B3 = dot(B1,B2);
The above code generates two vectors in N dimension. To check for orthogonality just transpose one of the vectors and multiply with the other one. You should get zero if they are Orthogonal.
The example I used makes sure that I get zero indeed.

Finding X binary numbers with n non-zero digits for large X. - Matlab

Is there a more efficient method for generating X binary numbers (that have n non-zero digits) for a range of 1 to N? I have developed the following solution:
Totalcombos = nchoosek(N,n);
floor = floor(log2(Totalcombos));
L = 2.^floor;
NumElem = 2^N-1;
i=0;
x=1;
%Creates Index combination LUT
while 1
%Produces Binary from 1 : NumElem
binNum= de2bi(x,N,'right-msb')';
x=x+1;
%Finds number of bits in each binary number
NumOfBits = sum(binNum);
%Creates a matrix of binary numbers from 1:NumElem with n 1's
if NumOfBits == n
i=i+1;
ISmatrixShapes{i} = binNum(:,:);
end
if i==L
break
end
end
ISmatrixShape2=cell2mat(ISmatrixShapes);
ISmatrixShape=ISmatrixShape2(:,1:L)';
Is there a way to generate these values without a massive number of loop iterations?
This generates all N-digit binary numbers that have n ones and N-n zeros:
N = 5;
n = 3;
ind = nchoosek(1:N, n);
S = size(ind,1);
result = zeros(S,N);
result(bsxfun(#plus, (ind-1)*S, (1:S).')) = 1;
It works by generating all combinations of n positions of ones out of the N possible positions (nchoosek line), and then filling those values with 1 using linear indexing (bsxfun line).
The result in this example is
result =
1 1 1 0 0
1 1 0 1 0
1 1 0 0 1
1 0 1 1 0
1 0 1 0 1
1 0 0 1 1
0 1 1 1 0
0 1 1 0 1
0 1 0 1 1
0 0 1 1 1
Another, less efficient approach is to generate all permutations of a vector containing n ones and N-n zeros, and then removing duplicates:
result = unique(perms([ones(1,n) zeros(1,N-n)]), 'rows');