MathGroup Archive 2000

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

Search the Archive

Re: Re: Re: Set in Scan

  • To: mathgroup at smc.vnet.net
  • Subject: [mg22075] Re: [mg22008] Re: [mg21900] Re: [mg21856] Set in Scan
  • From: Hartmut Wolf <hwolf at debis.com>
  • Date: Sat, 12 Feb 2000 04:04:33 -0500 (EST)
  • Organization: debis Systemhaus
  • References: <000001bf73ea$4985a4e0$937227c8@default>
  • Sender: owner-wri-mathgroup at wolfram.com

Tomas Garza schrieb:
> 
> Dear Hartmut,
> 
>                                         ..... However, I'm still
> at a loss concerning the problem of a very long list of fixed-size (not
> necessarily too long, maybe less than 20) lists where the assignment may be
> something which depends on the value of the element to be replaced, e.g.,
> Function[sym,If[sym[[3]] < 0.5, "-XXX-","-YYY-"]], so that it is not
> possible to use
> 
> allv[[All,3]] = k
> 
> since here k would have to be the same for each element of allv. But I can't
> use
> 
> Scan[Function[sym,
>        (#[[3]] = If[#[[3]] < 0.5, "-XXX-", "-YYY-"])&@ Unevaluated[sym],
>        {HoldFirst}],
>      Unevaluated[{v1, v2, v3}]]
> 
> or
> 
> Scan[(#[[3]] = new) &, Unevaluated /@ Hold[v1, v2, v3]]
> 
> as Allan Hayes suggests, since I would have to write explicitly the full
> list {v1, v2,..., vN}, which is out of the question for very large N
> (between 10,000 and 20,000). So far I have been using a ReplaceAll approach
> which is unbelievably slow. I'm sure the Scan approach is much faster,
> but...
> 


Dear Tomas,

... some proposals how to deal with your problem. The best answer
depends a little on how you get at your (many, relatively short) lists. 

Johannes Ludstecks problem originated from his wish to give his (not so
many, yet long) lists *individual* names, but process them effectively
together "in single strokes". For the methods proposed so far it was
neccessary to write down explicit list, like {v1, v2, v3}, which had to
be carefully dealt with as not to get the symbols unevaluated to the lhs
of Set[Part[...],...]

I now show how to extend these methods, in case your are not able (or
simply down like) to write down the explicit List of the symbols. What
we need is a bag, from which we can get at the unevaluated symbols at
will, but have the bag itself evaluated.

So what we need to do in first place, is to put the unevaluated symbols
in that bag. That's the tricky point, but it can be done easily, if you
first define your symbols, put them into the bag, and *then* give them
values. Here is a model for that:

allv = Table[Unique[v], {3}]

{v$5, v$6, v$7}

...these are our symbols, as many as you like. You need not get at them
through Unique, e.g. you could read in a table of names and make them to
symbols.

allvheld = Hold /@ allv
{Hold[v$5], Hold[v$6], Hold[v$7]}

...this is the magic bag. All is save there, e.g. you may take it away
for a walk.

Do[ Evaluate[allv[[i]]] = Table[Random[], {4}], {i, 3}]

...here the symbols get there values, that's your program. We look at
the values:

allv

{{0.166919, 0.200547, 0.974411, 0.131898}, 
 {0.617234, 0.177582, 0.771096, 0.519545}, 
 {0.639894, 0.347534, 0.957892, 0.124675}}

?allv
"Global`allv"
allv = {v$5, v$6, v$7}
 
...we see allv hasn't changed, yet we can't get at its components (the
symbols) because of the recursive evaluation in _Mathematica_.

...for executing our compound assignment, we use our magic bag:

Scan[(#[[3]] = gg[#[[3]]]) &, Apply[Unevaluated, allvheld, {1}]  ]

allv

{{0.166919, 0.200547, gg[0.974411], 0.131898}, 
 {0.617234, 0.177582, gg[0.771096], 0.519545}, 
 {0.639894, 0.347534, gg[0.957892], 0.124675}}

...we applied a trick, to remove the Hold-s:

Apply[Unevaluated, allvheld, {1}]

{Unevaluated[v$5], Unevaluated[v$6], Unevaluated[v$7]}


Of course you can also reach you goal with the held symbols -- I did it
-- but it's more difficult and there is no point in doing that after we
know this trick.

Wrapping head Hold around the symbols in our bag is save, yet not
strickly neccessary. You could also wrap with Unevaluated. Also you need
not to know in advance the number of your symbols you would need, just
generate enough (remark: of course, with some attention we may add
further symbols later). Here a few snapshots:

...

allvkept = Unevaluated /@ allv

{Unevaluated[v$8], ..., Unevaluated[v$12]}

Do[ Evaluate[allv[[i]]] = Table[Random[], {4}], {i, 3}]

allv
{{0.389824, ...}, ..., {..., 0.590491}, v$11, v$12}

...the last two symbols do not have values. Now the final Set:

Off[Part::partd, Set::noval]

Scan[(#[[3]] = hh[#[[3]]]) &, allvkept  ]      (* trompe l'oeil *)

allv
{{0.389824, 0.712106, hh[0.337913], 0.118311}, 
 {0.442732, 0.883199, hh[0.0471863], 0.284335}, 
 {0.821009, 0.347524, hh[0.062472],  0.590491}, v$11, v$12}

On[Part::partd, Set::noval]


However all this is not needed, when you don't reach for individual
names for your lists, if you can hold all data together in a big list,
i.e. your short lists are just elements of it. (You may have got at this
through Map-ping, Table-ing, Array-ing, Append-ing, but not Do-ing.)

 
allv = allv0 = Table[Random[], {3}, {4}]

{{0.289622, 0.158518, 0.627899, 0.486945},
 {0.727602, 0.394153, 0.58083,  0.564662},
 {0.42659, 0.182415, 0.606131, 0.28117}}

You had been frustrated with Set[allv[[All,...]],...]. Well, let's go
back to the days of Version 3. There we had used instead

allv[[Range[3], 3]] = k;

allv

{{0.289622, 0.158518, k, 0.486945},
 {0.727602, 0.394153, k, 0.564662}, 
 {0.42659, 0.182415, k, 0.28117}}

------
allv = allv0

Scan[(allv[[#, 3]] = kk) & , Range[3]]

allv

{{0.289622, 0.158518, kk, 0.486945}, 
 {0.727602, 0.394153, kk, 0.564662}, 
 {0.42659, 0.182415, kk, 0.28117}}

------
allv = allv0

Scan[(allv[[#, 3]] = gg[allv[[#, 3]]]) &, Range[3]]

allv

{{0.289622, 0.158518, gg[0.627899], 0.486945}, 
 {0.727602, 0.394153, gg[0.58083], 0.564662}, 
 {0.42659, 0.182415, gg[0.606131], 0.28117}}

------
allv = allv0

Do[allv[[i, 3]] = gg[allv[[i, 3]]], {i, 3}]

allv

{{0.289622, 0.158518, gg[0.627899], 0.486945}, 
 {0.727602, 0.394153, gg[0.58083], 0.564662}, 
 {0.42659, 0.182415, gg[0.606131], 0.28117}}


Now for version 4:
------
allv = allv0

allv[[All, 3]] = k;

allv

{{0.289622, 0.158518, k, 0.486945}, 
 {0.727602, 0.394153, k, 0.564662}, 
 {0.42659, 0.182415, k, 0.28117}}

...this probably is not well known:

allv[[All, 3]] = {1, 2, 3};

allv

{{0.289622, 0.158518, 1, 0.486945}, 
 {0.727602, 0.394153, 2, 0.564662}, 
 {0.42659, 0.182415, 3, 0.28117}}


allv[[All, 3]] = allv[[All, 3]]^2;

allv

{{0.289622, 0.158518, 1, 0.486945}, 
 {0.727602, 0.394153, 4, 0.564662}, 
 {0.42659, 0.182415, 9, 0.28117}}


Now finally i did some Timing measurements. I measured

t[[4, 1]] = (Scan[(allv[[#, 3]] = allv[[#, 3]]^2 + a) &, Range[8000]] 
        // Timing)[[1, 1]]
t[[4, 2]] = (Do[allv[[i, 3]] = allv[[i, 3]]^2 + b, {i, 8000}] 
        // Timing)[[1, 1]]
t[[4, 3]] = (allv[[All, 3]] = allv[[All, 3]]^2 + c; // Timing)[[1, 1]]

...and got for t

{{2.123, 2.093, 0.06}, {8.012, 7.951, 0.12}, 
 {32.536, 31.946, 0.26}, {132.26, 131.129, 0.501}, {0, 0, 0}}

t[[1,...]] is for n=1000, 2 for 2000, 3 for 4000, 4 for 8000 (as seen
above). 

What is remarkable is the phantastic Performance of
Set[allv[All,...]],...]
Do even is a little bit better than Scan, yet both are somewhat
disappointing.
I guess this is all due to single access times (added up). The observed
complexity is

t[[# + 1, All]]/t[[#, All]] & /@ {1, 2, 3}

{{3.7739, 3.79885, 2.}, {4.06091, 4.01786, 2.16667}, 
 {4.06504, 4.10471, 1.92692}}

So Set[..[[All,..]],...] is seemingly linear O[n] (within the measured
range), and Set[..[[n,..]],...] is seemingly quadratic O[n^2]


What I learnt from this thread is:  strive to use All in any case.
(For Johannes Ludsteck, however it should not make enough a difference
to abandon the
advantage of descriptive access, i.e. through names of symbols.)

Kind regards, Hartmut


  • Prev by Date: Re: Simplifying expressions for use in C programs
  • Next by Date: Partition
  • Previous by thread: Re: Re: Re: Set in Scan
  • Next by thread: Check[] *and* Off[]