Consider three row vectors in Matlab, A, B, C, each with size 1xJ. I want to construct a matrix D of size Kx2 listing every possible pairs of elements (a,b) such that:
a is an element of A.
b is an element of B.
a-b is an element of C.
a and b are different from Inf, -Inf.
For example,
A=[-3 3 0 Inf -Inf];
B=[-2 2 0 Inf -Inf];
C=[Inf -Inf -1 1 0];
D=[-3 -2; %-3-(-2)=-1
3 2; % 3-2=1
0 0]; % 0-0=0
I would like this code to be efficient, because in my real example I have to repeat it many times.
If J is not too large so that you can afford two intermediate matrices of size up to J×J, this can be done in a vectorized way, which usually means it will be fast:
A = [-3 3 0 Inf -Inf];
B = [-2 2 0 Inf -Inf];
C = [Inf -Inf -1 1 0];
[a, b] = ndgrid(A(~isinf(A)), B(~isinf(B)));
ind = ismember(a-b, C);
result = [a(ind) b(ind)];
This works by generating all pairs that fulfil the individual conditions (such as being finite), and then selecting those pairs that fulfil the joint condition (such as their difference being in a prescribed set of values).
Related
Consider three row vectors in Matlab, A, B, C, each with size 1xJ. I want to construct a matrix D of size Kx3 listing every triplets (a,b,c) such that:
a is the position in A of A(a).
b is the position in B of B(b).
A(a)-B(b) is an element of C.
c is the position in C of A(a)-B(b).
A(a) and B(b) are different from Inf, -Inf.
For example,
A=[-3 3 0 Inf -Inf];
B=[-2 2 0 Inf -Inf];
C=[Inf -Inf -1 1 0];
D=[1 1 3; %-3-(-2)=-1
2 2 4; % 3-2=1
3 3 5]; % 0-0=0
I would like this code to be efficient, because in my real example I have to repeat it many times.
This question relates to my previous question here, but now I'm looking for the positions of the elements.
You can use combvec (or any number of alternatives) to get all pairings of indices a and b for the corresponding arrays A and B. Then it's simply a case of following your criteria
Find the differences
Check which differences are in C
Remove elements you don't care about
Like so:
% Generate all index pairings
D = combvec( 1:numel(A), 1:numel(B) ).';
% Calculate deltas
delta = A(D(:,1)) - B(D(:,2));
delta = delta(:); % make it a column
% Get delta index in C (0 if not present)
[~,D(:,3)] = ismember(delta,C);
% If A or B are inf then the delta is Inf or NaN, remove these
idxRemove = isinf(delta) | isnan(delta) | D(:,3) == 0;
D(idxRemove,:) = [];
For your example, this yields the expected results from the question.
You said that A and B are at most 7 elements long, so you have up to 49 pairings to check. This isn't too bad, but readers should be careful that the pairings can grow quickly for larger inputs.
Suppose I have a IxJ matrix A in Matlab which contains some numbers (possibly, including Inf, -Inf).
For example, for I=3 and J=6, I could have
A= [0 0 Inf -Inf 0 1;
5 4 Inf -Inf 6 5;
Inf -Inf 0 Inf 0 2];
I want to construct a matrix B of size IxJ, such that each row i starts from 1, adds a +1 every time an element of A(i,:) changes, and assigns equal index to equal elements. Two Inf elements have to be treated as equal. Similarly, two -Inf elements have to be treated as equal.
In the example above
B= [1 1 2 3 1 4; %
1 2 3 4 5 1;
1 2 3 1 3 4];
Could you advise on how to proceed?
A simple approach is to use the third output of unique with the 'stable' option for each row:
B = NaN(size(A)); % preallocate
for k = 1:size(A,1)
[~, ~, B(k,:)] = unique(A(k,:), 'stable');
end
This question already has answers here:
Create a zero-filled 2D array with ones at positions indexed by a vector
(4 answers)
Closed 6 years ago.
I have a vector v of size (m,1) whose elements are integers picked from 1:n. I want to create a matrix M of size (m,n) whose elements M(i,j) are 1 if v(i) = j, and are 0 otherwise. I do not want to use loops, and would like to implement this as a simple vector-matrix manipulation only.
So I thought first, to create a matrix with repeated elements
M = v * ones(1,n) % this is a (m,n) matrix of repeated v
For example v=[1,1,3,2]'
m = 4 and n = 3
M =
1 1 1
1 1 1
3 3 3
2 2 2
then I need to create a comparison vector c of size (1,n)
c = 1:n
1 2 3
Then I need to perform a series of logical comparisons
M(1,:)==c % this results in [1,0,0]
.
M(4,:)==c % this results in [0,1,0]
However, I thought it should be possible to perform the last steps of going through each single row in compact matrix notation, but I'm stumped and not knowledgeable enough about indexing.
The end result should be
M =
1 0 0
1 0 0
0 0 1
0 1 0
A very simple call to bsxfun will do the trick:
>> n = 3;
>> v = [1,1,3,2].';
>> M = bsxfun(#eq, v, 1:n)
M =
1 0 0
1 0 0
0 0 1
0 1 0
How the code works is actually quite simple. bsxfun is what is known as the Binary Singleton EXpansion function. What this does is that you provide two arrays / matrices of any size, as long as they are broadcastable. This means that they need to be able to expand in size so that both of them equal in size. In this case, v is your vector of interest and is the first parameter - note that it's transposed. The second parameter is a vector from 1 up to n. What will happen now is the column vector v gets replicated / expands for as many values as there are n and the second vector gets replicated for as many rows as there are in v. We then do an eq / equals operator between these two arrays. This expanded matrix in effect has all 1s in the first column, all 2s in the second column, up until n. By doing an eq between these two matrices, you are in effect determining which values in v are equal to the respective column index.
Here is a detailed time test and breakdown of each function. I placed each implementation into a separate function and I also let n=max(v) so that Luis's first code will work. I used timeit to time each function:
function timing_binary
n = 10000;
v = randi(1000,n,1);
m = numel(v);
function luis_func()
M1 = full(sparse(1:m,v,1));
end
function luis_func2()
%m = numel(v);
%n = 3; %// or compute n automatically as n = max(v);
M2 = zeros(m, n);
M2((1:m).' + (v-1)*m) = 1;
end
function ray_func()
M3 = bsxfun(#eq, v, 1:n);
end
function op_func()
M4= ones(1,m)'*[1:n] == v * ones(1,n);
end
t1 = timeit(#luis_func);
t2 = timeit(#luis_func2);
t3 = timeit(#ray_func);
t4 = timeit(#op_func);
fprintf('Luis Mendo - Sparse: %f\n', t1);
fprintf('Luis Mendo - Indexing: %f\n', t2);
fprintf('rayryeng - bsxfun: %f\n', t3);
fprintf('OP: %f\n', t4);
end
This test assumes n = 10000 and the vector v is a 10000 x 1 vector of randomly distributed integers from 1 up to 1000. BTW, I had to modify Luis's second function so that the indexing will work as the addition requires vectors of compatible dimensions.
Running this code, we get:
>> timing_binary
Luis Mendo - Sparse: 0.015086
Luis Mendo - Indexing: 0.327993
rayryeng - bsxfun: 0.040672
OP: 0.841827
Luis Mendo's sparse code wins (as I expected), followed by bsxfun, followed by indexing and followed by your proposed approach using matrix operations. The timings are in seconds.
Assuming n equals max(v), you can use sparse:
v = [1,1,3,2];
M = full(sparse(1:numel(v),v,1));
What sparse does is build a sparse matrix using the first argument as row indices, the second as column indices, and the third as matrix values. This is then converted into a full matrix with full.
Another approach is to define the matrix containing initially zeros and then use linear indexing to fill in the ones:
v = [1,1,3,2];
m = numel(v);
n = 3; %// or compute n automatically as n = max(v);
M = zeros(m, n);
M((1:m) + (v-1)*m) = 1;
I think I've also found a way to do it, and it would be nice if somebody could tell me which of the methods shown is faster for very large vectors and matrices. The additional method I thought of is the following
M= ones(1,m)'*[1:n] == v * ones(1,n)
I have a cell A in Matlab of dimension 1x3, e.g.
A={{1,2,3,4} {5,6} {7,8,9} }
A contains all the integers from 1 to n in increasing order. In the example n=9. However, the number of elements within each sub-cell can be different. Each sub-cell is non-empty.
Consider the vector B of dimension nx1 containing some integers from 1 to n in increasing order (repetitions are allowed), e.g.
B=[1 1 2 2 4 7 7 8 9]'
I want to construct (without using loops) the vector C of dimension nx1 such that each C(i) tells which sub-cell of A B(i) belongs to. In the example
C=[1 1 1 1 1 3 3 3 3]'
With that structure, A is uniquely determined by the number of elements of each of its cells, and the result can be obtained as
C = sum(bsxfun(#gt, B, cumsum(cellfun(#numel, A))), 2)+1;
I don't know whether it's faster than for loops, but how about
C = arrayfun(#(b) find(cellfun(#(a) any(cell2mat(a) == b), A)), B);
Explanation: pick each element b in B; then pick every sub-cell a in A and check for equality with b, return the index of sub-cell b is a member of.
I have a matrix A of size m x n and another matrix b of size 1 x n (in Matlab).
The matrix b is such that it consists of sequences of 1s, then sequences of 2s, then sequences of 3s, etc. up to some value k.
(For example b = [1 1 1 2 2 2 3 4 4], n = 9)
I want to take A, and for each row in A, choose the max in each segment, zeroing everything else in that subsequence.
So, for example, for a row A = [0 -1 2 3 4 1 3 4 5]) I would get
[0 0 2 0 4 0 3 0 5]
If there are multiple rows in A (m > 1), this should happen for each row.
I can do it easily using for loops, but it works very slowly, because I loop both over m and n.
Is there a "oneliner" to do it in Matlab, or something simple that works fast?
If A is a single row, accumarray can do the job using an ad hoc function:
result = accumarray(b(:), A(:) ,[] , #(x) {x==max(x)});
result = vertcat(result{:}).' .* A;
Not sure how fast this will be, since it uses cells.
If A has several rows, you can use a loop over the rows.