MathGroup Archive 2014

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

Search the Archive

Re: Efficient function to accumulate a list of

  • To: mathgroup at smc.vnet.net
  • Subject: [mg132514] Re: Efficient function to accumulate a list of
  • From: Bob Hanlon <hanlonr357 at gmail.com>
  • Date: Fri, 4 Apr 2014 03:57:58 -0400 (EDT)
  • Delivered-to: l-mathgroup@mail-archive0.wolfram.com
  • Delivered-to: l-mathgroup@wolfram.com
  • Delivered-to: mathgroup-outx@smc.vnet.net
  • Delivered-to: mathgroup-newsendx@smc.vnet.net
  • References: <20140403061721.737146A1A@smc.vnet.net>

Your function does not work as described. For comparison with other
approaches, I have simplified it and modified it to do what you described.

Clear[particleToDensity, particleToDensity2, particleToDensity3]

Use Module to localize the transient variable names, delete the unnecessary
Round and If, and use lower case letter to start a user-defined function
(avoid potential future name conflict with built-in functions):

particleToDensity[particles_,
  arrayDimensions_: {144, 300}] :=
 Module[{arr, l, tp},
  arr = ConstantArray[0, arrayDimensions];
  For[l = 1, l <= Length[particles], l++,
   tp = particles[[l]];
   arr[[tp[[2]], tp[[3]]]] += tp[[1]]];
  arr]


Use Map rather than For loop:


particleToDensity2[particles_,
  arrayDimensions_: {144, 300}] :=
 Module[{arr},
  arr = ConstantArray[0, arrayDimensions];
  (arr[[#[[2]], #[[3]]]] += #[[1]]) & /@
   particles;
  arr]


Use SparseArray


particleToDensity3[particles_,
  arrayDimensions_: {144, 300}] :=
 SparseArray[{#[[1, 2]], #[[1, 3]]} -> Total[#[[All, 1]]] & /@
   GatherBy[particles, #[[{2, 3}]] &], arrayDimensions]


data = {{3.6, 7, 4}, {3.4, 8, 6}, {2.1, 7, 4}};


t1 = Timing[arr1 = particleToDensity[data];];

t2 = Timing[arr2 = particleToDensity2[data];];

t3 = Timing[arr3 = particleToDensity3[data];];


Verifying that the arrays are equivalent


arr1 == arr2 == arr3


True


Map is marginally quicker and the sparse array approach is much quicker


{t1[[1]]/t2[[1]], t1[[1]]/t3[[1]]}


{1.03, 2.7}


However, if the array is relatively dense


data = Table[{
    RandomReal[{0, 5}],
    RandomInteger[{1, 144}],
    RandomInteger[{1, 300}]},
   {10000}];


t1 = Timing[arr1 = particleToDensity[data];];

t2 = Timing[arr2 = particleToDensity2[data];];

t3 = Timing[arr3 = particleToDensity3[data];];


Verifying that the arrays are equivalent


arr1 == arr2 == arr3


True


Map is now noticeably quicker but the SparseArray became noticeably slower
than your approach.


{t1[[1]]/t2[[1]], t1[[1]]/t3[[1]]}


{1.3822, 0.7310}



Bob Hanlon


On Thu, Apr 3, 2014 at 2:17 AM, <julian.w.francis at gmail.com> wrote:

> Dear all,
>
> I am struggling with how to convert a list of (value, coords) tuples into
> an array such that the an element in the array should represent the sum of
> all value elements in that list with matching coords, and zero if no
> matches, e.g.
>
> { {3.6, 7,4}, {3,4, 8,6}, {2.1, 7,4} }
>
> if it were a 10X10 element array would become all zero's, except element
> (7,4)->(3.6+2.1) and (8,6)->3.4
>
> I've got some code which does what I want:
>
> ParticleToDensity[particles_] := (
>   arr = ConstantArray[0, {144, 300}];
>   For[l = 1, l < NoParticles, l++,
>    (tp = particles[[l]];
>     If[tp[[2]] != 0,
>      arr[[Round[tp[[3]]], Round[tp[[2]]]]] += tp[[1]]]
>     )];
>   arr)
>
> So, the argument to the function is a list of "particles", and the first
> element of this particle is the value in the array I'd like to accumulate,
> and the next two elements in that particle say where in the array they
> should be accumulated.
>
> It seems to work, but it is slow. I can see that this isn't really the
> Mathematica way of doing things, but I'm struggling to think of a better
> way.
>
> For reference, NoParticles is typically set to something like 10,000, and
> it takes about 0.1 secs to process on my machine. However this needs to be
> done frequently, hence I am hoping for a better way.
>
>
>
> Any help greatly appreciated.
>
> Thanks,
> Julian.
>
>


  • Prev by Date: Re: Solve output depends on previous attempt with bad syntax
  • Next by Date: Re: Solve output depends on previous attempt with bad syntax
  • Previous by thread: Efficient function to accumulate a list of {value,coord} into array
  • Next by thread: Re: Efficient function to accumulate a list of {value,coord} into array