Minimum of two multidimensional matrices, with which matrix 'won' (contained the minimum) - matlab

I have two matrices (size 4x4) and I want to find the minimum between the two. For example:
A = [ 3, 2, 4, 5;
1, 2, 0, 6;
9, 8, 5, 4;
0, 1, 0, 3 ];
B = [ 1, 1, 6, 8;
0, 4, 6, 3;
5, 6, 7, 1;
0, 2, 3, 4 ];
Now, if I did a min(A,B) in Octave, it gives me
[ 1, 1, 4, 5;
0, 2, 0, 3;
5, 6, 5, 1;
0, 1, 0, 3 ]
Is there a way to get the matrix that 'won', by which I mean which matrix contained the minimum, in each element-wise comparison?
Like, for the first element of both matrices, matrix B won and so on.
I don't want to loop through the matrices.

You can compare A and B to find out in which matrix the minimum occurred.
With A > B, you will get a matrix containing False if the entry from A was chosen, and True if the entry from B was chosen. By adding 1 to it, you will get 1 if A was chosen and 2 if B was chosen.
>> 1 + (A > B)
ans =
2 2 1 1
2 1 1 2
2 2 1 2
1 1 1 1
Alternatively, you can concatenate A and B to form a 3-dimensional array with dimensions [4, 4, 2], where C(:, :, 1) = A and where C(:, :, 2) = B. Then you can call min on this matrix C along the third axis. When calling min on one matrix, you can get the index of the "winner" directly as a second return value:
>> C = cat(3, A, B);
>> [res, idx] = min(C, [], 3)
res =
1 1 4 5
0 2 0 3
5 6 5 1
0 1 0 3
idx =
2 2 1 1
2 1 1 2
2 2 1 2
1 1 1 1

Related

combinations totaling to sum

How would one go about generating a matrix with all the possible combinations of number totaling to a sum with repetition?
Basically, combinations of x1, x2, x3 such that x1 + x2 + x3 = n.
For example: n =3
0 1 2
0 2 1
1 0 2
1 2 0
1 1 1
Is there simple way of doing this using predefined Matlab functions?
I tried
n=6;
nchoosek(0:n,3)
which gives me
0 1 2
0 1 3
0 1 4
0 1 5
0 1 6
0 2 3
0 2 4
0 2 5
0 2 6
0 3 4
0 3 5
0 3 6
0 4 5
0 4 6
0 5 6
1 2 3
1 2 4
1 2 5
1 2 6
1 3 4
1 3 5
1 3 6
1 4 5
1 4 6
1 5 6
2 3 4
2 3 5
2 3 6
2 4 5
2 4 6
2 5 6
3 4 5
3 4 6
3 5 6
4 5 6
How would one extract all rows that have the total equal to n?
I think linear indexing or find should make it possible, but I don't know how to go about that.
Regards
For concreteness, let's go with your example of 3 values adding up to 6. The standard way to do this is to think of placing 2 'dividers' into a row of 6 identical 'objects': those dividers then divide the objects into 3 groups, and you can read off the length of each group. So all we need to do is enumerate all ways of placing those dividers. You can use nchoosek(1:8, 2) for this: each row of that matrix describes a division, by describing the positions of the 2 dividers amongst the 2 + 6 == 8 objects + dividers.
This is a more efficient approach than enumerating all triples of integers 0-6 and then picking out those that add to the correct total.
I don't really speak MATLAB, so the following is probably unidiomatic (and suggestions to improve it are welcome!), but something like this should work:
% Total we're aiming for.
n = 6;
% Number of pieces to divide that total into.
k = 3;
% All possible placements of internal dividers.
dividers = nchoosek(1:(n+k-1), k-1);
ndividers = size(dividers, 1);
% Add dividers at the beginning and end.
b = cat(2, zeros(ndividers, 1), dividers, (n+k)*ones(ndividers, 1));
% Find distances between dividers.
c = diff(b, 1, 2) - 1
And here are the results, as provided by this site:
c =
0 0 6
0 1 5
0 2 4
0 3 3
0 4 2
0 5 1
0 6 0
1 0 5
1 1 4
1 2 3
1 3 2
1 4 1
1 5 0
2 0 4
2 1 3
2 2 2
2 3 1
2 4 0
3 0 3
3 1 2
3 2 1
3 3 0
4 0 2
4 1 1
4 2 0
5 0 1
5 1 0
6 0 0
Use dec2base to generate all combinations with repetition, and logical indexing to keep only those with the desired sum:
n = 6;
m = 3;
c = dec2base(0:(n+1)^m-1,n+1,m)-'0'; %// generate combinations with repetition
result = c(sum(c,2)==n,:); %// keep those with desired sum. Logical indexing
I believe you are describing permutations of restricted integer partitions, though your example doesn't seem complete. For n=3 into three parts from elements {0, 1, 2} there are two solutions: {0, 1, 2} and {1, 1, 1}. These may further be permuted into:
{{0, 1, 2}, {0, 2, 1}, {1, 0, 2}, {1, 2, 0}, {2, 0, 1}, {2, 1, 0}, {1, 1, 1}}
If this is not what you want you should clarify why these additional orderings are not to be included.
If this understanding is correct you should be able to find a number of resources by searching for that phrase. Some examples:
Elegant Python code for Integer Partitioning
Integer Partition in Java
Algorithm for generating integer partitions
Integer Partition Algorithm by Jerome Kelleher
Integer Partition Algorithm by Daniel Scocco
Fast Algorithms for Generating Integer Partitions (PDF) (looks heavy-duty)
Stony Brook Algorithm Repository - Partitions
As a practical example, using Mathematica one would write:
IntegerPartitions[6, {3}, Range[0, 5]]
Output:
{{5, 1, 0}, {4, 2, 0}, {4, 1, 1}, {3, 3, 0}, {3, 2, 1}, {2, 2, 2}}
These could each then be permuted to produce the other orderings.
It is quite easy to set up a recursive function to generate these partitions by starting with all numbers <= n, then appending values that are <= that value that do not exceed n. This is continued until each list is length p; if the list totals n it is kept; if it does not it is discarded. Again, in Mathematica:
f[n_, p_, c__] /; Length#{c} == p := If[+c == n, {{c}}, {}]
f[n_, p_, c___] := Array[f[n, p, c, #] &, Min[c, n - +c] + 1, 0, Join]
f[6, 3]
Output:
{{2, 2, 2}, {3, 2, 1}, {3, 3, 0}, {4, 1, 1}, {4, 2, 0}, {5, 1, 0}, {6, 0, 0}}
The function nchoosek provides the possible ways of selecting r-1 plus signs in the sum. For example, x1 + x2 + x3 = 5, then two signals must be selected over the sum 1 + 1 + 1 + 1 + 1 = 5. For nonnegative solutions make the transformation yi = x1 + 1, and solves y1+y2+ ... = m + n
The result of nchoosek provides the position of the plus sign.
The remaining of program provides the sum between selected signals.
clear all
close all
clc
% Program that generates the possible distributions
% M objects in r boxes
% Éderson D'Martin Costa
% 12/02/2015
% number of objects
m = 3;
% number of boxes
r = 3;
% total number of possibilities
% C = nchoosek(m+r-1,r-1)
v = 1:m+r-1;
C = nchoosek(v,r-1);
[l,c] = size(C);
Y = zeros(l,c+1);
Y(:,1) = C(:,1);
Y(:,end) = m+r-C(:,end);
for i = r-1:-1:2
Y(:,i) = C(:,i)-C(:,i-1);
end
X = Y-1;
display(X)
% sum(X,2)
As #Mark Dickinson pointed out. I just wanted to give intuitive explanation.
Your problem can be restated as "How many ways can you distribute 3 apples to 3 people"?
Suppose you have 3 people: AA, BB, CC and you want to distribute 3 apple among them. How can you do it?
AA | BB | CC
*** | |
* | * | *
** | * |
........
* -> represent apples.
Now if you think the problem is just selecting two | among 5 positions which we know can be done using 5 choose 2.

Outer product in Matlab?

How to turn two vectors into a matrix of all combinations of their elements?
For example, vectors
>> A=[1;2;3]
A =
1
2
3
>> B=[4;5;6]
B =
4
5
6
Should be turned to
[1, 4; 1, 5; 1, 6; 2, 4; 2, 5; 2, 6; 3, 4; 3, 5; 3, 6]
ans =
1 4
1 5
1 6
2 4
2 5
2 6
3 4
3 5
3 6
I'm sure there is a simpler way of doing this but... meshgrid will get you close and you just need to perform some array manipulation to get your result:
[BA, BB] = meshgrid(A,B);
[BA(:) BB(:)]
An order of magnitude slower than meshgrid, but just to show you a different method:
[kron(A,ones(numel(B),1)), kron(ones(numel(A),1), B)];

MatLab - histc with many edges vector

Consider this :
a = [1 ; 7 ; 13];
edges = [1, 3, 6, 9, 12, 15];
[~, bins] = histc(a, edges)
bins =
1
3
5
Now I would like to have the same output, but with a different "edges" vector for each a value, i.e. a matrix instead of a vector for edges. Exemple :
a = [1 ; 7 ; 13];
edges = [ 1, 3, 6 ; 1, 4, 15 ; 1, 20, 30];
edges =
1 3 6
1 4 15
1 20 30
indexes = theFunctionINeed(a, edges);
indexes =
1 % 1 inside [1, 3, 6]
2 % 7 indide [1, 4, 15]
1 %13 inside [1, 20, 30]
I could do this with histc inside a for loop, by I'm trying to avoid loops.
If you transform your arrays to cell arrays, you can try
a = {1 ; 7 ; 13};
edges = {[ 1, 3, 6 ];[ 1, 4, 15] ; [1, 20, 30]};
[~, indexes] = cellfun(#histc, a, edges,'uniformoutput', false)
This results in
indexes =
[1]
[2]
[1]
~edit~
To transform your matrices into cell arrays you can use num2cell:
a = num2cell(a);
edges = num2cell(edges, 2);
You could also do:
a = [1; 7; 13];
edges = [1 3 6; 1 4 15; 1 20 30];
bins = sum(bsxfun(#ge, a, edges), 2)
The result:
>> bins
bins =
1
2
1

MATLAB: Finding n-th smallest element in per row

I want to find the n-th smallest element for each row in a matrix.
Example:
n = 2
M = [1, 2, 3; 4, 5, 6; 7, 8 9]
Result = [2, 5, 8]
First sort the matrix by the second dimension (i.e. sort every row in ascending order):
n = 2
M = [1, 2, 3; 4, 5, 6; 7, 8 9]
M_SORTED = sort(M,2)
M_SORTED =
1 2 3
4 5 6
7 8 9
The n-th column of the matrix will contain the result:
RESULT = M_SORTED(:, n)
RESULT =
2
5
8

GROUP BY in MATLAB

I want to do what SQL's GROUP BY does in MATLAB. For example,
M = [
1, 5;
2, 5;
3, 5;
1, 6;
2, 6;
1,7 ]
SQL: SELECT MAX(c1), c2 FROM M(c1, c2) GROUP BY 2
Result = [
3, 5;
2, 6;
1, 7]
How can I do this in Matlab?
grpstats in the Statistics Toolbox can do this:
>> [grpstats(M(:,1), M(:,2), {'max'}) unique(M(:,2))]
ans =
3 5
2 6
1 7
If you don't mind doing some preprocessing to get the order (or if the first column is nicely built from 1 to n), you can do it like this:
accumarray([1 2 3 1]',[11 12 13 14]',[],#max)
This will give:
14
12
13
Or in your case:
accumarray(M(:,1),M(:,2),[],#max)
Note the order. The second number for example, will correspond to M(:,1) == 2
I think there is a simple solution to this.
Here is what I tested on Matlab and it worked:
>> M = [
1, 5;
2, 5;
3, 5;
1, 6;
2, 6;
1,7 ];
>> grpstats(M,M(:,2),{'max'})
ans =
3 5
2 6
1 7