MathGroup Archive 2008

[Date Index] [Thread Index] [Author Index]

Search the Archive

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.



  • Prev by Date: Re: Re: Re: mathematica 64-bit for ms windows
  • Next by Date: Re: Re: "Assuming"
  • Previous by thread: Re: an even faster way to normalize a
  • Next by thread: C++ const and mathlink