I have given a list of indices, e.g. i = [3 5]
and a vector v = 1:6
. I need a function f
which returns the logical map for the vector v
given the indices i
, e.g.:
f(i, length(v)) = [0 0 1 0 1 0]
Since I will call this function several million times, I would like to make it as fast as possible. Is there a builtin function which performs this task?
In logical indexing, you use a single, logical array for the matrix subscript. MATLAB extracts the matrix elements corresponding to the nonzero values of the logical array. The output is always in the form of a column vector. For example, A(A > 12) extracts all the elements of A that are greater than 12.
In most programming languages, the first element of an array is element 0. In MATLAB, indexes start at 1.
In MATLAB®, there are three primary approaches to accessing array elements based on their location (index) in the array. These approaches are indexing by position, linear indexing, and logical indexing.
MATLAB matches all characters in the name exactly except for the wildcard character * , which can match any one or more characters.
I know I'm late in the game, but I really wanted to find a faster solution which is just as elegant as ismember
. And indeed there is one, that employs the undocumented ismembc
function:
ismembc(v, i)
N = 7;
i = [3 5];
%// slayton's solution
tic
for ii = 1:1e5
clear idx;
idx(N) = false;
idx(i) = true;
end
toc
%// H.Muster's solution
tic
for ii = 1:1e5
v = 1:N;
idx = ismember(v, i);
end
toc
%// Jonas' solution
tic
for ii = 1:1e5
idx = sparse(i, 1, true, N, 1);
end
toc
%// ismembc solution
tic
for ii = 1:1e5
v = 1:N;
idx = ismembc(v, i);
end
toc
Here's what I got:
Elapsed time is 1.482971 seconds.
Elapsed time is 6.369626 seconds.
Elapsed time is 2.039481 seconds.
Elapsed time is 0.776234 seconds.
Amazingly, ismembc
is indeed the fastest!
Edit:
For very large values of N
(i.e. when v
is a large array), the faster solution is actually slayton's (and HebeleHododo's, for that matter). You have quite a variety of strategies to choose from, pick carefully :)
Edit by H.Muster:
Here's are benchmark results including _ismemberoneoutput
:
Slayton's solution:
Elapsed time is 1.075650 seconds.
ismember:
Elapsed time is 3.163412 seconds.
ismembc:
Elapsed time is 0.390953 seconds.
_ismemberoneoutput:
Elapsed time is 0.477098 seconds.
Interestingly, Jonas' solution does not run for me, as I get an Index exceeds matrix dimensions.
error...
Edit by hoogamaphone:
It's worth noting that ismembc
requires both inputs to be numerical, sorted, non-sparse, non-NaN values, which is a detail that could be easily missed in the source documentation.
You can use ismember
i = [3 5];
v = 1:6;
ismember(v,i)
will return
ans =
0 0 1 0 1 0
For a probably faster version, you can try
builtin('_ismemberoneoutput', v, i)
Note that I tested this only for row vectors like specified by you.
Simply create a vector of logical indices and set the desired locations to true/false
idx = false( size( v) );
idx( i ) = true;
This can be wrapped in a function like so:
function idx = getLogicalIdx(size, i)
idx = false(size);
idx(i) = true;
end
If you need a indexing vector of the same size for each of your million operations allocated the vector once and then operate on it each iteration:
idx = false(size(v)); % allocate the vector
while( keepGoing)
idx(i) = true; % set the desired values to true for this iteration
doSomethingWithIndecies(idx);
idx(i) = false; % set indices back to false for next iteration
end
If you really need performance than you can write a mex function to do this for you. Here is a very basic, untested function that I wrote that is about 2x faster than the other methods:
#include <math.h>
#include <matrix.h>
#include <mex.h>
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
double M;
double *in;
M = mxGetScalar(prhs[0]);
in = mxGetPr(prhs[1]);
size_t N = mxGetNumberOfElements(prhs[1]);
plhs[0] = mxCreateLogicalMatrix( M,1 );
mxLogical *out= mxGetLogicals( plhs[0] );
int i, ind;
for (i=0; i<N; i++){
out[ (int)in[i] ] = 1;
}
}
There are several different ways to allocate a vector in matlab. Some are faster than others, see this Undocumented Matlab post for a good summary:
Here are some quick benchmarks comparing the different methods. The last method is by far the fastest but it requires you to use the same size logical indexing vector for each operation.
N = 1000;
ITER = 1e5;
i = randi(5000,100,1);
sz = [N, 1];
fprintf('Create using false()\n');
tic;
for j = 1:ITER
clear idx;
idx = false( N, 1 );
idx(i) = true;
end
toc;
fprintf('Create using indexing\n');
tic;
for j = 1:ITER
clear idx;
idx(N) = false;
idx(i) = true;
end
toc;
fprintf('Create once, update as needed\n');
tic;
idx = false(N,1);
for j = 1:ITER
idx(i) = true;
idx(i) = false;
end
toc;
fprintf('Create using ismembc\n');
a = ones(N,1);
tic;
for j = 1:ITER
idx = ismembc(1:N, i);
end
toc;
I expect that @slayton's solution is fastest. However, here's a one-liner alternative, that may at least save you some memory if the vectors are large.
vecLen = 6;
logicalIdx = sparse(idx,1,true,vecLen,1);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With