help-octave
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: multi-dimensional logical index assignment?


From: michaell
Subject: Re: multi-dimensional logical index assignment?
Date: Mon, 4 May 2020 15:05:31 -0500 (CDT)

mmuetzel wrote
> Am 02. Mai 2020 um 21:43 Uhr schrieb "Markus Mützel":
>> Am 02. Mai 2020 um 19:36 Uhr schrieb "Nicholas Jankowski":
>> > I'm trying to do a 3+ dimensional version of what is shown here:
>> >
>> https://stackoverflow.com/questions/18129298/how-to-use-double-indexing-to-redefine-matrix-values
>>  
>> >  
>> > and the syntax eludes me. The example shown is clear enough for a 2D
>> matrix, e.g.,:
>> >  
>> > >> A = [1 2; 3 4];
>> > >> A(2,:)((A(2,:)>3)) = 0
>> > error: () must be followed by . or close the index chain
>> > >> A(2,A(2,:)>3) = 0
>> > A =
>> >    1   2
>> >    3   0
>> > 
>> > but if I have a 3D array and I want to change the values of 'page' 2
>> based on the values of 'page' 4, can that be done in a similar one line
>> assignment without using an intermediate variable?  e.g., 
>> > 
>> > >> a = rand(2,3,4);
>> > >> a(:,:,4)>0.5
>> > ans =
>> >   1  1  1
>> >   1  1  0
>> > >> a(:,:,2)(a(:,:,4)>0.5) = 0
>> > error: () must be followed by . or close the index chain
>> > >> a((a(:,:,4)<0.5),2) = 0
>> > error: Invalid resizing operation or ambiguous assignment to an
>> out-of-bounds array element
>> >  
>> > I feel like I'm missing something obvious. 
>> 
>> I think the problem here is that it is not possible to combine logical
>> indexing with subscript indexing.
>>
>> Maybe converting both to linear indices could do the trick:
>> 
>> a = rand (2, 3, 4);
>> sz_a = size (a);
>> 
>> src_pg = 4;
>> target_pg = 2;
>> a(find (a(:,:,src_pg)<0.5) + (target_pg-1)*prod (sz_a(1:2))) = 0;
>> 
>> 
>> "find" effectively converts the logical indices to linear indices. The
>> rest is an offset to index into the second page.
> 
> I couldn't stop thinking about this problem because I don't like to use
> "find" if it can be avoided.
> Turns out that it *is* possible to combine logical and subscript indexing
> (and this is something I use quite often).
> The problem is however, that Octave (and Matlab) don't understand that you
> want to apply the logical index to several dimensions.
> So what it effectively does is:
> a = rand (2,3,4);
> idx = a(:,:,4) < 4;
> a(idx(:),:) = 0;  # This indexing fails because idx has more elements than
> size(a,1)
> 
> The following few lines are probably much more efficient than the approach
> with "find" if you do the reshape assignments in-place:
> a = rand (2,3,4);
> sz_a = size (a);
> a = reshape (a, prod (sz_a(1:2)), sz_a(3));
> a(a(:,4)<0.5,2) = 0;
> a = reshape (a, sz_a);
> 
> HTH,
> Markus

It is possible in a one-liner -- you just have to expand the logical
indices:
a((a(:,:,4)>.5)&shiftdim(1:size(a,3)==2,-1))=0
This will work also for the general case where you fix a middle dimension,
or if you fix multiple dimensions -- then you just use another logical AND.
But for very large objects, it will definitely be more efficient to use find
-- here octave will test also the first, third and fourth pages whether the
(expanded) index array is true, which the other solutions don't.

Michael 



--
Sent from: https://octave.1599824.n4.nabble.com/Octave-General-f1599825.html



reply via email to

[Prev in Thread] Current Thread [Next in Thread]