Re: an even faster way to normalize a

*To*: mathgroup at smc.vnet.net*Subject*: [mg85680] Re: an even faster way to normalize a*From*: thomas <thomas.muench at gmail.com>*Date*: Tue, 19 Feb 2008 01:56:01 -0500 (EST)*References*: <fp9945$199$1@smc.vnet.net>

Hello Roger, try this: (*Make up some data that includes appropriate outliers*) sum = Table[RandomReal[{-.1, 1.1}, 3], {512}, {512}]; In[225]:= Timing[ res1 = With[{flat = Flatten[sum, 1]}, Partition[(1. - Unitize[Plus @@ ((1 - UnitStep[#] + UnitStep[# - 1]) & /@ Transpose[flat])])*flat, 512]];] Out[225]= {0.094, Null} Compared to your "Map" version: In[215]:= Timing[ res2 = Map[ If[#[[1]] < 0. || #[[1]] > 1. || #[[2]] < 0. || #[[2]] > 1. || #[[3]] < 0. || #[[3]] > 1., {0., 0., 0.}, #] &, sum, {2}];] Out[215]= {0.531, Null} In[193]:= res1 == res2 Out[193]= True How does it work? First, I flatten your 2-D matrix into a 1-D vector with 3 elements each: flat = Flatten[sum, 1] which I then transpose, to get 3 long vectors (1 for each coordinate). I then check each coordinate for "correctness" (with "0" meaning "correct"): (1 - UnitStep[#] + UnitStep[# - 1]) & /@ Transpose[flat] which is: 1-UnitStep[x] is 0 for x >= 0, but 1 for x < 0 UnitStep[x-1] is 0 for x <= 1, but 1 for x > 1 When they are added it is 0 for "correct", and 1 for "incorrect". So you still have 3 long vectors with 0's and 1's. Then, all three coordinate-vectors are added (Plus@@...), so it stays 0 if all three coordinates are correct, and a positive number (1, 2 or 3) otherwise. Unitize[...] brings this back to 1. Then I subtract the result from 1 1.-Unitize[...] (* Note that the whole code becomes about 8x slower when you write "1" instead of "1." That has to do with unpacking packed arrays when you multiply with "flat" later*) so that all 0's become 1 ("correct" values) and all 1's become 0 ("incorrect" values). This is multiplied with your original vector "flat", so that all incorrect values are re-set to 0, and the correct values are not changed. Finally, I bring it back into the original 512x512 shape by partitioning it. thomas On Feb 17, 1:25 pm, congruentialumina... at yahoo.com wrote: > Hello UG: > > I have a 512x512 array of 3-tuples. I want to make any tuple with a > value outside of 0 <--> 1, become {0.,0.,0.}. > > The first version has this loop: > > For[i = 1, i <= graphSize, i++, > For[j = 1, j <= graphSize, j++, > If[((sum[[i, j, 1]] < 0) || (sum[[i, j, 1]] > 1) || > (sum[[i, j, 2]] < 0) || (sum[[i, j, 2]] > 1) || > (sum[[i, j, 3]] < 0) || (sum[[i, j, 3]] > 1)), > sum[[i, j]] = {0., 0., 0.} > ] > ] > ]; > > After scratching my head for a while I came up with this (equivalent) > Map statement. > > sum = Map[ > If[#[[1]] < 0 || #[[1]] > 1 || #[[2]] < 0 || #[[2]] > 1 || #[[3]] < > 0 || #[[3]] > 1, {0., 0., 0.}, #] &, sum, {2}]; > > It is faster but only by about 15%. > > It is unreasonable to believe some other construction can accomplish > this with a bigger payoff? > > Thanks in advance. > > Regards..Roger W.