Combinations from a given set without repetition - matlab

Suppose I have a matrix defined as follows
M = [C1 C2 C3 C4]
Where the C's are column vectors
I want some efficient (i.e. no for loops) way of producing A vector such that
ResultVec = [C1 C2;
C1 C3;
C1 C4;
C2 C3;
C2 C4;
C3 C4]
Thanks in advance!

That is, what nchoosek does:
M = [ 1 2 3 4 ];
R = nchoosek(M,2);
returns:
R =
1 2
1 3
1 4
2 3
2 4
3 4
I don't know if it's your intention but nchoosek is Matlabs implementation of The number of k-combinations from a given set S of n elements without repetition (Wikipedia)
The function nchoosek is performance wise not very efficient though. But there are equivalents on File Exchange, which are much(!!) faster and doing the same.
Just to make it clear, it's not just working for the fairly simple example above, and is not returning any indices. It directly transforms the matrix as desired.
M = [ 21 42 123 17 ];
returns:
R =
21 42
21 123
21 17
42 123
42 17
123 17

This is the simplest way I've come up with:
n = size(M, 2);
[j, i] = ind2sub([n n], find(~triu(ones(n))));
ResultVec = M(:, [i j]);
ResultVec = reshape(ResultVec, [], 2)

Related

how to multiply each element of A as a scalar to B

given a vector and matrix A and B, how to multiply each element of A as a scalar to B then add up each of the new matrix, without using a for loop.
What i mean is:
A = [1;2;3]
B = [1 2;3 4 ;5 6]
C = (A(1) * B) + (A(2) * B) + (A(3) * B)
ans =
6 12
18 24
30 36
C = sum(C)
C =
54 72
but I can't do it manually because the vector is too long.
You can use the following command:
sum(reshape(sum(B(:)*A.',2),size(B)))
Explanation:
B(:)*A'
Flatten out B and multiply each element of it with each element of A.
sum(B(:)*A.',2)
Sum across the 'A' dimension (rows).
reshape(sum(B(:)*A.',2),size(B))
Reshape to get back to the original dimensions of B.
sum(reshape(sum(B(:)*A.',2),size(B)))
Sum across the columns as you wanted.
Edit
Suggestion from #verbatros which work when A is row vector as well:
sum(reshape(sum(B(:)*A(:).',2),size(B)))
Very easy:
A = [1;2;3]
B = [1 2;3 4 ;5 6]
C = sum (A(:)) .* sum (B)
C =
54 72

Transforming two matrices into one matrix using binary numbers

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

Performing a function on each matrix value

I am currently experimenting with Matlab functions. Basically I am trying to perform a function on each value found in a matrix such as the following simple example:
k = [1:100];
p = [45 60 98 100; 46 65 98 20; 47 65 96 50];
p(find(p)) = getSum(k, find(p), find(p) + 1);
function x = getSum(k, f, g, h)
x = sum(k(f:g));
end
Why the corresponding output matrix values are all 3, in other words why all indices are depending on the first calculated sum?
The output is the following:
p =
3 3 3 3
3 3 3 3
3 3 3 3
f:g returns the value between f(1,1) and g(1,1), so 1:2.
find(p) returns the indices of non zero values. Since all values are non-zero, you get all indices.
So if we break down the statement p(find(p)) = getSum(k, find(p), fin(p) + 1)
We get
find(p) = 1:12
We then get
f = 1:12 and g = 2:13 which lead to k = 1:2 (as explained above)
finally sum(1:2) = 3
And this value is apply over p(1:12), which is the same as p(:,:) (all the matrix)

How to take outer product of more than two matrices in one shot, in matlab?

I want to compute y = a⊗a⊗a, where a is a n-by-1 vector, and ⊗ is the outer product operator. In this case y should be an n-by-n-by-n tensor.
If y = a⊗a, it is easy. I simply do:
y = a * a'
But what to do in the first case? How do I compute this outer product efficiently in MATLAB if there are more than two vectors?
In a multi-dimensional (tensor) case of y = u⊗v, I believe that you need to shift the dimensions of the second operand like so:
v_t = permute(v, circshift(1:(ndims(u) + ndims(v)), [0, ndims(u)]));
and then multiply them with bsxfun:
y = bsxfun(#times, u, v_t);
The regular matrix multiplication is defined only for vector and 2-D matrices, so we couldn't use it in the general case.
Also note that this computation still fails if the second operand is a 1-D vector, because ndims returns 2 instead of 1 for vectors. For this purpose, lets define our own function that counts dimensions:
my_ndims = #(x)(isvector(x) + ~isvector(x) * ndims(x));
To complete the answer, you can define a new function (e.g. an anonymous function), like so:
outprod = #(u, v)bsxfun(#times, u, permute(v, circshift(1:(my_ndims(u) + my_ndims(v)), [0, my_ndims(u)])));
and then use it as many times as you want. For example, y = a×a×a would be computed like so:
y = outprod(outprod(a, a), a);
Of course, you can write a better function that takes a variable number of arguments to save you some typing. Something along these lines:
function y = outprod(u, varargin)
my_ndims = #(x)(isvector(x) + ~isvector(x) * ndims(x));
y = u;
for k = 1:numel(varargin)
v = varargin{k};
v_t = permute(v, circshift(1:(my_ndims(y) + my_ndims(v)),[0, my_ndims(y)]));
y = bsxfun(#times, y, v_t);
end
I hope I got the math right!
You can use as well the kron function:
kron(a * a', a)
or when four outer (kronecker tensor) products needed:
kron(kron(a * a', a), a)
and so on. The last one gives you a m x n matrix, where m = n * n * n.
If adding dimensions is desired as going on with the products, you may use the reshape function:
reshape(kron(a * a', a), [n, n, n])
or
reshape(kron(kron(a * a', a), a), [n, n, n, n])
and so on. The last one gives you a n x n x n x n tensor.
The problem with using kron as in a previous solution is that it throws off canonical indexing of the outerproduct.
Instead, ndgrid is ideal for this scenario:
a = [1; 2; 3];
b = [4; 5];
c = [6; 7; 8; 9];
[xx, yy, zz] = ndgrid(1:length(a), 1:length(b), 1:length(c));
% desired outerproduct
M = a(xx) .* b(yy) .* c(zz);
On paper, we can check that the desired solution M is the datacube:
M(:,:,1) = | M(:,:,2) = | M(:,:,3) = | M(:,:,4) =
| | |
24 30 | 28 35 | 32 40 | 36 45
48 60 | 56 70 | 64 80 | 72 90
72 90 | 84 105 | 96 120 | 108 135
Using the Kronecker product approach
M2 = reshape(kron(a * b', c), [length(a), length(b), length(c)]);
we would get:
M2(:,:,1) = | M2(:,:,2) = | M2(:,:,3) = | M2(:,:,4) =
| | |
24 36 | 64 84 | 30 45 | 80 105
28 48 | 72 96 | 35 60 | 90 120
32 56 | 72 108 | 40 70 | 90 135
Datacube M2 has the same elements as M, but these elements are rearranged. This is because kron(a * b', c) does not contain the slices of M in contiguous blocks to facilitate direct application of the reshape function. To compute outerproduct this way, we would need to apply a rearrangement operation/function (determinable, but labrious and time consuming) to the elements of kron(a * b', c).
A further advantage of using ndgrid is that it generalizes easily to higher orders.

MATLAB sorting two vectors by value

This is a fairly simple task I want to perform, but I can't seem to figure out a way to do it. I've tried sortrows, reshaping, and other solutions, but none of them do exactly what I want.
Essentially, I have two vectors from the same range of values, of unequal lengths. Some of the values are equal, some are not. E.g.
A = [1 5 20 30 53 70 92]
B = [2 3 4 16 20 30 60 95 100]
What I want to do is add "NaNs" to each vector to "stand in" for the values in the other vector that aren't shared. So, I want them to look like:
A = [1 NaN NaN NaN 5 NaN 20 30 53 NaN 70 92 NaN NaN]
B = [NaN 2 3 4 NaN 16 20 30 NaN 60 NaN NaN 95 100]
Some method by which the vector will have placeholders for the value of the other vector.
Do I combine the vectors, sort it, then somehow search and replace all values from the other vector with NaNs? That seems like a bit of a clunky solution, though not impossible. I feel like there is some more elegant way to accomplish this that I am missing.
Thanks!
Here is one solution using a simple map:
A = [1 5 20 30 53 70 92]
B = [2 3 4 16 20 30 60 95 100]
% map all A and B elements
% use 1 for A and 2 for B
map = zeros(max([A,B]),1);
map(A) = 1;
map(B) = bitor(map(B), 2);
% find the values present in either A, or B
[~,~,j] = find(map);
AA = nan(size(j));
BB = nan(size(j));
AA(bitand(j,1)~=0) = A;
BB(bitand(j,2)~=0) = B;
Comparison with Rodys solution shows this method is a bit faster:
A = unique(randi(10000, 1000, 1));
B = unique(randi(10000, 1000, 1));
tic;
for i=1:1000
map=zeros(10000,1);
map(A) = 1;
map(B) = bitor(map(B), 2);
[~,~,j] = find(map);
AA = nan(size(j));
BB = nan(size(j));
AA(bitand(j,1)~=0) = A;
BB(bitand(j,2)~=0) = B;
end
toc
tic
for i=1:1000
C = union(A,B);
Ap = NaN(size(C));
Ap(ismember(C,A)) = A;
Bp = NaN(size(C));
Bp(ismember(C,B)) = B;
end
toc
isequalwithequalnans(BB, Bp)
isequalwithequalnans(AA, Ap)
Elapsed time is 0.283828 seconds.
Elapsed time is 0.457204 seconds.
ans =
1
ans =
1
Well, here's one way:
% union of sets A and B
C = union(A,B);
% initialize new sets, check membership, and
% assign old values when applicable
Ap = NaN(size(C)); Ap(ismember(C,A)) = A;
Bp = NaN(size(C)); Bp(ismember(C,B)) = B;
Note that union gets rid of repititions. In case you want to keep all repetitions, use a manual sort and the second output of ismember:
% combine and sort, KEEPING repetitions
C = sort([A B]);
% initialize new sets, check membership, and
% assign old values when applicable
Ap = NaN(size(C)); Bp = NaN(size(C));
[I,Ab] = ismember(C,A); [I,Bb] = ismember(C,B);
Ap(I) = A(Ab(I)); Bp(I) = B(Bb(I));