# Does logical indexing have a direct inverse?

28 visualizzazioni (ultimi 30 giorni)
Michael il 10 Dic 2012
Commentato: Rik il 10 Nov 2023
Say I have some region-of-interest filter X, and I use B = A(X~=0) to only extract the values of A where X~=0, is it then possible to retrieve A from B and X?
I'm trying to think of a clever way to do it but coming up a little short!
Thanks for any suggestions,
Mike
##### 1 CommentoMostra -1 commenti meno recentiNascondi -1 commenti meno recenti
Martin Herrerias Azcue il 8 Nov 2019
Modificato: Martin Herrerias Azcue il 8 Nov 2019
I come accross the same problem often enough that I wrote a function for it. It's really a matter of OCD, but I find:
A = revertfilter(B,f);
cleaner than:
A = zeros(size(B),'like',B);
A(f) = B;
Hope it helps.
function A = revertfilter(B,filter,dim,missing)
% A = REVERTFILTER(B,FILTER,DIM,MISSING) - Revert logical-indexing of A by FILTER upon dimension
% DIM, filling any ~FILTER slices with MISSING.
%
% E.g. if B = C(:,:,FILTER,:), A = REVERTFILTER(B,FILTER,3,NaN) will return a size(C) array,
% such that all C(:,:,FILTER,:) == A(:,:,FILTER,:), and for which all A(:,:,~FILTER,:) == NaN.
%
% A = REVERTFILTER(B,FILTER,[],MISSING) - Revert logical-indexing B = A(FILTER), setting the size
% of A from FILTER. For this to work DIM must be missing/empty, and nnz(FILTER) == numel(B).
%
% E.g. C = rand(1,2,3); FILTER = C > 0.5; B = C(FILTER); A = REVERTFILTER(B,FILTER)
% (c) copyleft, Martin Herrerías 2019
if nargin < 3, dim = []; end
if nargin < 4, missing = 0; end
assert(islogical(filter),'REVERSEFILTER only works for logical indexing');
if isnumeric(B), missing = double(missing);
elseif islogical(B), missing = missing > 0;
else
assert(isequal(class(B),class(missing),'Class of MISSING must match B'));
end
if nnz(filter) == numel(B) && isempty(dim)
A = emptyarray(size(filter),missing,B(1));
A(filter) = B;
elseif isvector(filter)
if isempty(dim)
if size(filter,2) > 1, dim = 2; else, dim = 1; end
end
assert(size(B,dim) == nnz(filter),'nnz(FILTER) ~= size(B,DIM)');
sz = size(B);
sz(dim) = numel(filter);
A = emptyarray(sz,missing,B(1));
% Place enough colons before and after dim for A(..,filter,..) = B to work
args = [repmat({':'},1,dim-1),{filter},repmat({':'},1,numel(sz)-dim)];
A(args{:}) = B;
else
error('Unrecognized syntax/arguments');
end
end
function A = emptyarray(sz,missing,b)
% Not sure if this is worth the trouble: it might just be faster to use repmat(missing,sz),
% the idea is that the type of A is still set, whenever possible, by B
if isnan(missing), A = NaN(sz,'like',b); return; end
switch missing
case 0, A = zeros(sz,'like',b);
case 1, A = ones(sz,'like',b);
case true, A = true(sz);
case false, A = false(sz);
case Inf, A = Inf(sz,'like',b);
case -Inf, A = -Inf(sz,'like',b);
otherwise, A = zeros(sz,'like',b); A(:) = missing;
end
end

Accedi per commentare.

### Risposte (5)

Sean il 10 Dic 2012
I.e:
A(X~=0) = B
?
##### 2 CommentiMostra NessunoNascondi Nessuno
Michael il 10 Dic 2012
That looks the same as my forward problem, I'm looking for A = [matlab operation](B).
Sean il 10 Dic 2012
No, the location data is required and it comes from X.
Also, you will never know about the values in A that were not extracted from X or the size of A. Thus you need the index to go in reverse.

Accedi per commentare.

Walter Roberson il 10 Dic 2012
No, it is not possible.
Suppose for example X was a matrix the same size as A, and is 1 for the top-left quadrant and 0 elsewhere. B = A(X~=0) would then retrieve values from the top left quadrant and would have no information about anything elsewhere in A. X also has no information about anything in A. Therefore, if you have only X and B, you cannot reconstruct the information that was in the other three quadrants of A.
My guess about what you actually want to do is:
A(X ~= 0) = B;
##### 0 CommentiMostra -2 commenti meno recentiNascondi -2 commenti meno recenti

Accedi per commentare.

Matt Fig il 10 Dic 2012
Modificato: Matt Fig il 10 Dic 2012
Simple example:
A = randperm(4);
X = [0 1 0 1]
B = A(X~=0)
clear A
Now just look at X and B. By looking at just those two arrays, it is not even in principle possible to tell exactly what A was! This despite the fact that we know all of the elments of A! In a more general case, the problem is only worse. If you, as a human being, cannot tell what the original A was with such a simple example, how in the world could MATLAB tell?
##### 0 CommentiMostra -2 commenti meno recentiNascondi -2 commenti meno recenti

Accedi per commentare.

Image Analyst il 10 Dic 2012
Michael: As the others have said, you can't get back ALL of a from only the part you extracted - you'd need the complete a to do that. However you extracted a chunk of "a" into a 1D column vector, and it is possible to put that back into a 2D reconstructed "a" where the extracted part is the same, but the unextracted part is zero (or any other number you want). Here's some demo code. See if it's what you were thinking.
% Generate sample data.
a = magic(8)
% Make x a mask in the upper left quadrant.
x = false(size(a)); % Initialize.
x(1:4, 1:4) = true % Mask of upper left quadrant
% Extract masked a into b.
b = a(x~=0) % This will be a 16 by 1 column vector.
% We can't get back ALL of a, without using a, but we CAN get back the a that we extracted
% back into the original 2D shape with zeros (or any constant) elsewhere.
a_reconstructed = zeros(size(x)); % Initialize a new "a" with 2D matrix of 0's.
% Find the linear indices that we used to extract elements of a.
linearIndexes = find(x~=0)
% Use them to assign those elements of a reconstructed a
% from the elements in b.
a_reconstructed(linearIndexes) = b(:)
##### 0 CommentiMostra -2 commenti meno recentiNascondi -2 commenti meno recenti

Accedi per commentare.

Chibuzo il 10 Nov 2023
I believe the best approach will be to use set difference function, setdiff(A, B). For example: Given some indices of a vector A, you want to select other entries of A not included in the given indices.
A = randi([1, 15], 1, 10)
A = 1×10
15 9 6 10 10 14 2 6 2 13
indices = [2, 4, 7, 1]
indices = 1×4
2 4 7 1
A1 = A(indices)
A1 = 1×4
9 10 2 15
A2 = A(setdiff(1:length(A), indices))
A2 = 1×6
6 10 14 6 2 13
##### 3 CommentiMostra 1 commento meno recenteNascondi 1 commento meno recente
Chibuzo il 10 Nov 2023
Ok. Have you checked the sparse() and full() function? Sparse() removes 0's and squeezes. And full() returns the full matrix given a sparse matrix. You can condition you matrix accordingly to make this work.
Rik il 10 Nov 2023
Changing between sparse and full is a completely different operation, since the underlying mathematical object doesn't change, just how it is stored in memory. That is why it is possible to go back and forth between the two without issue.
This problem however, is completely different.
There really only is a solution in the trivial case that X contains only true, or in the case that all arrays are empty.

Accedi per commentare.

### Categorie

Scopri di più su Loops and Conditional Statements in Help Center e File Exchange

### Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by