Re: Using Extract where some indices are out of bounds (efficiently)
- To: mathgroup at smc.vnet.net
- Subject: [mg115263] Re: Using Extract where some indices are out of bounds (efficiently)
- From: Ray Koopman <koopman at sfu.ca>
- Date: Thu, 6 Jan 2011 02:01:49 -0500 (EST)
- References: <iev2kf$4mq$1@smc.vnet.net> <ifup7d$cog$1@smc.vnet.net>
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]] ]]]