Re: Using Extract where some indices are out of bounds (efficiently)
- To: mathgroup at smc.vnet.net
- Subject: [mg115296] Re: Using Extract where some indices are out of bounds (efficiently)
- From: Ray Koopman <koopman at sfu.ca>
- Date: Fri, 7 Jan 2011 04:07:15 -0500 (EST)
- References: <iev2kf$4mq$1@smc.vnet.net> <ifup7d$cog$1@smc.vnet.net> <ig3pco$ja9$1@smc.vnet.net>
On Jan 5, 11:01 pm, Ray Koopman <koop... at sfu.ca> wrote: > On Jan 4, 1:28 am, Ray Koopman <koop... at sfu.ca> wrote: >> On Dec 23 2010, 12:52 am, Julian Francis <julian.w.fran... at gmail.com> >> wrote: >>> Dear all, >>> >>> How can I arrange to use Extract to extract values from an array; >>> but where some of the indices may be out of bounds, in which case >>> they should be simply ignored? >>> >>> I wrote a simple arrayInBounds function, and then did a Select on >>> that to retrieve only the indices which are in bounds, which are >>> then fed into Extract. Whilst this works it seems to lead to a >>> 150* reduction in speed. >>> >>> FYI: >>> My arrayInBounds function looks like this: >>> >>> arrayInBounds[array_, index_] := >>> If[index == {}, True, >>> First[index] > 0 && First[index] < Length[array] && >>> arrayInBounds[array[[1]], Rest[index]]] >>> >>> My support functions for the test are: >>> >>> disks = Table[ >>> Transpose[Position[DiskMatrix[r, 2*(r + 1) + 1], 1]], {r, 1, 30}]; >>> >>> positions[x_, y_, r_] := Transpose[{ >>> disks[[r, 1]] + y - (r + 2), >>> disks[[r, 2]] + x - (r + 2)}] >>> >>> My timing tests are: >>> >>> In[291]:= Timing[lists=Table[Extract[image,Select[positions[x,y, >>> 10],arrayInBounds[image,#]&]], >>> {y,11,64-11}, >>> {x,11,64-11}];] >>> Out[291]= {17.175,Null} >>> In[292]:= Timing[lists2=Table[Extract[image,positions[x,y,10]], >>> {y,11,64-11}, >>> {x,11,64-11}];] >>> Out[292]= {0.094,Null} >>> In[293]:= lists==lists2 >>> Out[293]= True >>> >>> image is assumed to be an array of at least 64*64. >>> >>> In this particular case, the bounds are setup so that the checking >>> serves no purpose and can be eliminated, but I've only done this to >>> show the speed comparison with the no bounds checking comparison. >>> The speed difference is a factor of over 150! This seems surprising >>> to me. Is there a better way? >>> >>> I don't think I can reformulate it using partitions, or the standard >>> imagefilter functions, because in general the functions positions >>> will be giving a complicated list of coordinates which doesn't >>> naturally fit into a square kernel. >>> >>> Any help greatly appreciated. >>> >>> Thanks, >>> Julian. >> >> Is this the sort of thing you're looking for? >> >> myExtract[array_,indices_] := With[{m = Dimensions@array}, Extract[ >> array, Select[indices, And@@Positive@# && And@@Thread[# <= m]&]]] >> >> a = Array[FromDigits@{##}&,{2,3,4}] >> >> {{{111,112,113,114},{121,122,123,124},{131,132,133,134}}, >> {{211,212,213,214},{221,222,223,224},{231,232,233,234}}} >> >> myExtract[a,{{0,1,2},{1,2,3},{2,3,4},{3,4,5}}] >> >> {123,234} >> >> myExtract[a[[2,2]],Transpose@{Range[0,5]}] >> >> {221,222,223,224} >> > If the array from which you are extracting elements is two-dimensional > and square then this will be much faster than my previous suggestion: > > myExtract2[array_,indices_] := With[{m = Length@array}, > Extract[array, Part[indices, > SparseArray[Times@@UnitStep[(#-1)*(m-#)&@Transpose@indices]] /. > SparseArray[_,_,_,d_] :> Flatten@d[[2,2]] ]]] To remove the restriction on myExtract2 to two-dimensional square arrays, just change Length@array to Dimensions@array. This will make it as general as myExtract, without slowing it for two-dimensional square arrays.