Re: Using Extract where some indices are out of bounds (efficiently)
- To: mathgroup at smc.vnet.net
- Subject: [mg115219] Re: Using Extract where some indices are out of bounds (efficiently)
- From: Ray Koopman <koopman at sfu.ca>
- Date: Tue, 4 Jan 2011 04:28:24 -0500 (EST)
- References: <iev2kf$4mq$1@smc.vnet.net>
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}