I have two matrices filled with 0s and 1s
e.g.
A = [ 0 0 1 0,
1 0 1 0 ]
B = [ 1 1 1 1
0 0 0 0 ]
and I'd like to compared the values form the same position against each other and return a 2x2 matrice
R = [ TP(1) FN(3)
FP(2) TN(2) ]
TP = returns the amount of times A has the value 1, and B has the value 1
FN = returns the amount of times A has the value 0, and B has the value 1
FP = returns the amount of times A has the value 1, and B has the value 0
TN = returns the amount of times A has the value 0, and B has the value 0
How do i get each individual number in A and B?
Approach #1: Comparison based using bsxfun -
pA = [1 0 1 0] %// pattern for A
pB = [1 1 0 0] %// pattern for B
%// Find matches for A against pattern-A and pattern-B for B using bsxfun(#eq.
%// Then, perform AND for detecting combined matches
matches = bsxfun(#eq,A(:),pA) & bsxfun(#eq,B(:),pB)
%// Sum up the matches to give us the desired counts
R = reshape(sum(matches),2,[]).'
Output -
R =
1 3
2 2
Approach #2: Finding decimal numbers -
Step-1: Find decimal numbers corresponding to the combined A's and B's
>> dec_nums = histc(bin2dec(num2str([B(:) A(:)],'%1d')),0:3)
dec_nums =
2
2
3
1
Step-2: Re-order the decimal numbers such that they line up as needed in the problem
>> R = reshape(flipud(dec_nums),2,[])'
R =
1 3
2 2
Use logical operators & and ~ applied on the linearized versions of A and B, and then nnz (or sum) to count the true values:
R = [nnz(A(:)&B(:)) nnz(~A(:)&B(:)); nnz(A(:)&~B(:)) nnz(~A(:)&~B(:))];
Related
let a and b are sequence of k consecutive natural numbers a = (a_i) and b = (b_i). If A an n x n matrix, then A[a,b] (a nontrivial submatrix of A which is obtained from eliminating elements that doesnt belong in rows a and columns b) is called boundary submatrix if
i) a_1 = 1 or a_1 > 1 and A[(a_1 - 1),b] = 0
or
ii) b_1 = 1 or b_1 > 1 and A[a,(b_1 - 1)] = 0
(yes the matrix usually got some zero entries)
what is the easiest code to understand for this case?
I tried to make and array for the sequence using columnk but it seems difficult.
Example for matrix
B =
1 1 1 0
1 2 1 1
0 1 2 2
0 0 3 2
if we pick a = 2,3 and b = 3,4 we get
B(a,b) =
1 1
2 2
and the example of its boundary submatrices of B would be its every principal submatrix, and B([2,3],[2,3]) since B([2,3],1)=0
I have five elements A, B, C, D and E.
The distance between each of the elements is given by the matrix below:
Distances =
[0 5 3 8 15;
5 0 7 5 20;
3 7 0 12 12;
8 5 12 0 8;
7 20 12 8 0]
I want to choose all combinations of elements such that the sum of distances is less than 10.
It can be done recursively by:
First find sets of 2-item eligible combinations.
Then, find sets of 3-item eligible combinations by adding another item to the previously-found eligible 2-item combinations.
Etc.
Doing it by hand for the above example I get the following combinations:
A,
B,
C,
D,
E,
A B,
A C,
A D,
B C,
B D,
D E,
A B C
How would I do this systematically in Octave, if the number of elements is large (say 250)?
Several general points:
Since the original question was tagged with matlab, I will show a solution which I tested there.
This solution uses the functions VChooseK and VChooseKRO found on FEX, which need to be compiled into MEX using an appropriate compiler.
Even though the question talks about distances, and there's little sense in adding up discontinuous paths (i.e. A->C + B->D), since this is not specified explicitly in the question as something invalid, the solution below outputs them as well.
The solution is shown for the example given in the OP. It should be modified slightly to output readable results for 250 nodes, (i.e. change the node "names" from letters to numbers seeing how 26 < 250).
Outputs are currently only printed. Some modifications need to be made (in the form of temporary variables) if further computations are required on the result.
function q41308927
%% Initialization:
nodes = char((0:4) + 'A');
D = [0 5 3 8 15;
5 0 7 5 20;
3 7 0 12 12;
8 5 12 0 8;
7 20 12 8 0];
thresh = 10;
d = triu(D); % The problem is symmetric (undirected), so we only consider the upper half.
% Also keep track of the "letter form":
C = reshape(cellstr(VChooseKRO(nodes,2)), size(D)).'; % "C" for "Combinations"
%{
C =
5×5 cell array
'AA' 'AB' 'AC' 'AD' 'AE'
'BA' 'BB' 'BC' 'BD' 'BE'
'CA' 'CB' 'CC' 'CD' 'CE'
'DA' 'DB' 'DC' 'DD' 'DE'
'EA' 'EB' 'EC' 'ED' 'EE'
%}
C = C(d>0); d = d(d>0);
assert(numel(C) == numel(d)); % This is important to check
%% Find eligible sets of size n
for k = 1:numel(nodes)
if numel(d)<k
break
end
% Enumerate combinations:
C = C(VChooseK(1:numel(C),k));
d = sum(VChooseK(d,k),2);
% Filter combinations:
if any(d < thresh)
C(d >= thresh,:) = [];
d = d(d < thresh);
disp(sortrows(C)); % This is just to show it works like the manual example
else
break
end
end
The output of the above is:
'AB'
'AC'
'AD'
'BC'
'BD'
'DE'
'AB' 'AC'
'AC' 'BD'
This is a plain Octave (or Matlab) solution. The matrix Distances is as in the question. The algorithm builds a 0-1 matrix a in which each column encodes a set with sum of distances less than limit (for example 10).
The matrix a is initialized with identity, because all one-elements subsets are admissible (sum of distances is 0). Then each column is picked c = a(:,m); and the possibility of adding another element is investigated (cand = c; cand(k) = 1; means adding k-th element). Without loss of generality, it is enough to consider adding only the elements after the last current element of the set.
The product cand'*Distances*cand is twice the sum of distances of the candidate set cand. So, if it's less than twice the limit, the column is added: a = [a cand];. At the end, the matrix a is displayed in transposed form, for readability.
limit = 10;
n = length(Distances);
a = eye(n, n);
col1 = 1;
col2 = n;
while (col1 <= col2)
for m = col1:col2
c = a(:,m);
for k = max(find(c>0))+1:n
cand = c;
cand(k) = 1;
if cand'*Distances*cand < 2*limit
a = [a cand];
end
end
end
col1 = col2 + 1;
col2 = length(a);
end
disp(a')
Output:
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1
1 1 0 0 0
1 0 1 0 0
1 0 0 1 0
0 1 1 0 0
0 1 0 1 0
0 0 0 1 1
With a 250 by 250 matrix, the performance will greatly depend on how large limit is. If it is so large that all or most of 2^250 sets qualify, this is going to run out of memory. (2^250 is more than 10^75, so I don't think you'd ever want to see anywhere near that many sets).
And this is to have output in a more readable form:
for m = 1:length(a)
disp(find(a(:,m))')
end
Output:
1
2
3
4
5
1 2
1 3
1 4
2 3
2 4
4 5
I have the following matrix in Matlab:
M = [0 0 1
1 0 0
0 1 0
1 0 0
0 0 1];
Each row has exactly one 1. How can I (without looping) determine a column vector so that the first element is a 2 if there is a 1 in the second column, the second element is a 3 for a one in the third column etc.? The above example should turn into:
M = [ 3
1
2
1
3];
You can actually solve this with simple matrix multiplication.
result = M * (1:size(M, 2)).';
3
1
2
1
3
This works by multiplying your M x 3 matrix with a 3 x 1 array where the elements of the 3x1 are simply [1; 2; 3]. Briefly, for each row of M, element-wise multiplication is performed with the 3 x 1 array. Only the 1's in the row of M will yield anything in the result. Then the result of this element-wise multiplication is summed. Because you only have one "1" per row, the result is going to be the column index where that 1 is located.
So for example for the first row of M.
element_wise_multiplication = [0 0 1] .* [1 2 3]
[0, 0, 3]
sum(element_wise_multiplication)
3
Update
Based on the solutions provided by #reyryeng and #Luis below, I decided to run a comparison to see how the performance of the various methods compared.
To setup the test matrix (M) I created a matrix of the form specified in the original question and varied the number of rows. Which column had the 1 was chosen randomly using randi([1 nCols], size(M, 1)). Execution times were analyzed using timeit.
When run using M of type double (MATLAB's default) you get the following execution times.
If M is a logical, then the matrix multiplication takes a hit due to the fact that it has to be converted to a numerical type prior to matrix multiplication, whereas the other two have a bit of a performance improvement.
Here is the test code that I used.
sizes = round(linspace(100, 100000, 100));
times = zeros(numel(sizes), 3);
for k = 1:numel(sizes)
M = generateM(sizes(k));
times(k,1) = timeit(#()M * (1:size(M, 2)).');
M = generateM(sizes(k));
times(k,2) = timeit(#()max(M, [], 2), 2);
M = generateM(sizes(k));
times(k,3) = timeit(#()find(M.'), 2);
end
figure
plot(range, times / 1000);
legend({'Multiplication', 'Max', 'Find'})
xlabel('Number of rows in M')
ylabel('Execution Time (ms)')
function M = generateM(nRows)
M = zeros(nRows, 3);
col = randi([1 size(M, 2)], 1, size(M, 1));
M(sub2ind(size(M), 1:numel(col), col)) = 1;
end
You can also abuse find and observe the row positions of the transpose of M. You have to transpose the matrix first as find operates in column major order:
M = [0 0 1
1 0 0
0 1 0
1 0 0
0 0 1];
[out,~] = find(M.');
Not sure if this is faster than matrix multiplication though.
Yet another approach: use the second output of max:
[~, result] = max(M.', [], 1);
Or, as suggested by #rayryeng, use max along the second dimension instead of transposing M:
[~, result] = max(M, [], 2);
For
M = [0 0 1
1 0 0
0 1 0
1 0 0
0 0 1];
this gives
result =
3 1 2 1 3
If M contains more than one 1 in a given row, this will give the index of the first such 1.
I have been thinking about a problem for the last few days but as I am a beginner in MATLAB, I have no clue how to solve it. Here is the background. Suppose that you have a symmetric N×N matrix where each element is either 0 or 1, and N = (1,2,...,n).
For example:
A =
0 1 1 0
1 0 0 1
1 0 0 0
0 1 0 0
If A(i,j) == 1, then it is possible to form the pair (i,j) and if A(i,j)==0 then it is NOT possible to form the pair (i,j). For example, (1,2) is a possible pair, as A(1,2)==A(2,1)==1 but (3,4) is NOT a possible pair as A(3,4)==A(4,3)==0.
Here is the problem. Suppose that a member of the set N only can for a pair with at most one other distinct member of the set N (i.e., if 1 forms a pair with 2, then 1 cannot form a pair with 3). How can I find all possible “lists” of possible pairs? In the above example, one “list” would only consist of the pair (1,2). If this pair is formed, then it is not possible to form any other pairs. Another “list” would be: ((1,3),(2,4)). I have searched the forum and found that the latter “list” is the maximal matching that can be found, e.g., by using a bipartite graph approach. However, I am not necessarily only interested to find the maximal matching; I am interested in finding ALL possible “lists” of possible pairs.
Another example:
A =
0 1 1 1
1 0 0 1
1 0 0 0
1 1 0 0
In this example, there are three possible lists:
(1,2)
((1,3),(2,4))
(1,4)
I hope that you can understand my question, and I apologize if am unclear. I appreciate all help I can get. Many thanks!
This might be a fast approach.
Code
%// Given data, A
A =[ 0 1 1 1;
1 0 0 1;
1 0 0 0;
1 1 0 0];
%%// The lists will be stored in 'out' as a cell array and can be accessed as out{1}, out{2}, etc.
out = cell(size(A,1)-1,1);
%%// Code that detects the lists using "selective" diagonals
for k = 1:size(A,1)-1
[x,y] = find(triu(A,k).*(~triu(ones(size(A)),k+1)));
out(k) = {[x y]};
end
out(cellfun('isempty',out))=[]; %%// Remove empty lists
%%// Verification - Print out the lists
for k = 1:numel(out)
disp(out{k})
end
Output
1 2
1 3
2 4
1 4
EDIT 1
Basically I will calculate all the the pairwise indices of the matrix to satisfy the criteria set in the question and then simply map them over the given matrix. The part of finding the "valid" indices is obviously the tedious part in it and in this code with some aggressive approach is expensive too when dealing with input matrices of sizes more than 10.
Code
%// Given data, A
A = [0 1 1 1; 1 0 1 1; 1 1 0 1; 1 1 1 0]
%%// Get all pairwise combinations starting with 1
all_combs = sortrows(perms(1:size(A,1)));
all_combs = all_combs(all_combs(:,1)==1,:);
%%// Get the "valid" indices
all_combs_diff = diff(all_combs,1,2);
valid_ind_mat = all_combs(all(all_combs_diff(:,1:2:end)>0,2),:);
valid_ind_mat = valid_ind_mat(all(diff(valid_ind_mat(:,1:2:end),1,2)>0,2),:);
%%// Map the ones of A onto the valid indices to get the lists in a matrix and then cell array
out_cell = mat2cell(valid_ind_mat,repmat(1,[1 size(valid_ind_mat,1)]),repmat(2,[1 size(valid_ind_mat,2)/2]));
A_masked = A(sub2ind(size(A),valid_ind_mat(:,1:2:end),valid_ind_mat(:,2:2:end)));
out_cell(~A_masked)={[]};
%%// Remove empty lists
out_cell(all(cellfun('isempty',out_cell),2),:)=[];
%%// Verification - Print out the lists
disp('Lists =');
for k1 = 1:size(out_cell,1)
disp(strcat(' List',num2str(k1),':'));
for k2 = 1:size(out_cell,2)
if ~isempty(out_cell{k1,k2})
disp(out_cell{k1,k2})
end
end
end
Output
A =
0 1 1 1
1 0 1 1
1 1 0 1
1 1 1 0
Lists =
List1:
1 2
3 4
List2:
1 3
2 4
List3:
1 4
2 3
I'm sure there's a faster way to do it, but here's the obvious solution:
%// Set top half to 0, and find indices of all remaining 1's
A(triu(A)==1) = 0;
[ii,jj] = find(A);
%// Put these in a matrix for further processing
P = [ii jj];
%// Sort indices into 'lists' of the kind you defined
X = repmat({}, size(P,1),1);
for ii = 1:size(P,1)-1
X{ii}{1} = P(ii,:);
for jj = ii+1:size(P,1)
if ~any(ismember(P(ii,:), P(jj,:)))
X{ii}{end+1} = P(jj,:); end
end
end
I want to create a combination of non-decreasing elements. The combination will be like,
If i=10 and w=5, then the elements of the combination can be any value from 1 to w and the sum will be equal to i.
Possible combinations are like,
1+1+1+1+1+5
1+1+1+1+1+1+4
1+1+1+1+1+1+1+3
1+1+1+1+1+1+1+1+1+1
......
But 1+1+1+7 is not a desired combination because 7 is greater than w
How to get the combinations using MatLab? I need to get the combinations for higher values of i and w like may be i=20 and w=8.
Thank You
You can do it with a recursive function. The following code contains a wrapper function and the recursive function which does the actual work:
function result = partitions(s,M)
%// s: desired sum; M: maximum value
result = partitions_rec(s,1,M,s);
end
function mat = partitions_rec(s,m,M,n)
%// s: desired sum, m: minimum value; M: maximum value; n: number of entries
M = min(M,s);
if s==0
mat = zeros(1,n);
else
mat = [];
for ii = m:M;
aux = partitions_rec(s-ii,ii,M,n-1);
if size(aux,1)
mat = [ mat; ii*ones(size(aux,1),1) aux ];
end
end
end
end
Example:
>> result = partitions(5,3)
ans =
1 1 1 1 1
1 1 1 2 0
1 1 3 0 0
1 2 2 0 0
2 3 0 0 0
A 0 indicates no number. If you want to remove the zeros, you need to put the result in the form of a cell array, where each cell is a vector with nonzero values:
result_cell = arrayfun(#(ii) result(ii, logical(result(ii,:))), 1:size(result,1), 'uniformoutput', 0);
In the example, this would give
>> result_cell{:}
ans =
1 1 1 1 1
ans =
1 1 1 2
ans =
1 1 3
ans =
1 2 2
ans =
2 3