Re: Re: Re: Set in Scan

• To: mathgroup at smc.vnet.net
• Subject: [mg22045] Re: [mg22008] Re: [mg21900] Re: [mg21856] Set in Scan
• From: Hartmut Wolf <hwolf at debis.com>
• Date: Fri, 11 Feb 2000 02:38:25 -0500 (EST)
• References: <200002100725.CAA05624@smc.vnet.net>
• Sender: owner-wri-mathgroup at wolfram.com

```Dear Tomas,

Tomas Garza schrieb:
>
> It looks as if the suggested approach of Hartmut Wolf's - as well as Jens
> Peer Kuska's - to this problem works fine and is extremely efficient.
> However, suppose that instead of having a few possibly very long lists {v1,
> v2, v3} one has a large number N - perhaps of the order of tens of
> thousands - of such lists, which need not be too long. The procedure would
> have to be modified

In fact! This is a different problem, and it's for this one indeed, that
the second proposal I made -- as Allan Hayes did -- comes to full
strength. Perhaps you might go back in this thread to Allan's answer, to
see that the elements of the compound object, the lists v<i> even need
not be of same length, *however* all v<i> must be long enough to at
least include the replace position, else nothing will be replaced at
all.

To do the replacement only in those sublists being long enough would
again consitute another problem.

>                 ... in order to use some symbol like allv = {v1, v2,..., vN}
> in Scan, instead of writing the complete list with all individual v's, as
> used by Hartmut and Jens:
>
> Scan[Function[sym, sym[[3]] = "-XXX-", {HoldFirst}],
>    Unevaluated[{v1, v2, v3}]]
>
> However, if I write
>
> Scan[Function[sym, sym[[3]] = "-XXX-", {HoldFirst}],
>    Unevaluated[allv]]
>
> nothing happens.

It can't, because Unevaluated reaches to Scan (i.e. to it's procedural
machinery) the unevaluated symbol allv, and if you scan a symbol nothing
happens. Scan doesn't even look at the Head of an expression, even be it
Hold -- as Allan noticed -- instead it feeds on the elements, yet there
are none in this case. It's only that

OwnValues[allv]

{HoldPattern[allv] :>
{{0.308624, 0.0113816, 0.452114, 0.100156},
{0.368705, 0.44588, 0.878839, 0.736246},
{0.71764, 0.18652, 0.667573, 0.338795}}}

has such elements.

>              ... And the second suggestion by Hartmut is unusable in case
> 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-"]].
>

Well again this is not quite the same problem, but there is a natural
extending solution:

Scan[Function[sym,
sym[[3]] = If[sym[[3]] < 0.5, "-XXX-", "-YYY-"], {HoldFirst}],
Unevaluated[{v1, v2, v3}]]

{v1, v2, v3}

{{0.308624, 0.0113816, "-XXX-", 0.100156},
{0.368705, 0.44588, "-YYY-", 0.736246},
{0.71764, 0.18652, "-YYY-", 0.338795}}

> Any suggestions?
>

More along the lines of this discussion you would like to try

Scan[Function[sym,
(#[[3]] = If[#[[3]] < 0.5, "-XXX-", "-YYY-"])&@ Unevaluated[sym],
{HoldFirst}],
Unevaluated[{v1, v2, v3}]]

Or the somewhat more obfuscated

Scan[Evaluate,
Scan[((#[[3]] = If[#[[3]] < 0.5, "-XXX-", "-YYY-"])&
@Unevaluated[#])&,
Unevaluated /@ Unevaluated[{v1, v2, v3}]]]

no Hold attributes in. This even works when you replace the outer Scan
(to get the replaced elements evaluated) by Map although the inner Scan
doesn't return anything.
I guess this is neither a bug nor any intended use (of Map), but a
consequence of the requirement that repeated Scans should be possible.
This example at least is an argument that they should!

When had I looked for a solution to the problem posed originally by
Johannes Ludsteck that ideom Unevaluated /@ Unevaluated[{v1,v1,v3}] came
up to my mind shortly after I had sent off my reply

Scan[(#[[3]] = -the new value-)&, Unevaluated /@ Unevaluated[{v1, v2,
v3}]]

... only to then learn from Allan Hayes

Scan[(#[[3]] = -the new value-)&, Unevaluated /@ Hold[v1, v2, v3]]

At the time of my reply I had no time for measurement and guessed the
time complexity to be O[constant].

Now I did some comparitative measurements, each with a new kernel, so
having the same memory and history conditions:

---------
In[1]:= {v1, v2, v3} = Table[Random[], {3}, {1000000}];
In[2]:=
Scan[Function[sym, sym[[3]] = "-XXX-", {HoldFirst}],
Unevaluated[{v1, v2, v3}]] // Timing
Out[2]=
{1.071 Second, Null}

In[3]:= Take[#, 4] & /@ {v1, v2, v3}
Out[3]=
{{0.675382, 0.55102, "-XXX-", 0.633244}, {0.422611, 0.715315, "-XXX-",
0.426188}, {0.011633, 0.223577, "-XXX-", 0.240954}}

---------
In[1]:= {v1, v2, v3} = Table[Random[], {3}, {1000000}];
In[2]:=
Scan[Function[sym, sym[[3]] = "-YYY-"],
Unevaluated /@ Unevaluated[{v1, v2, v3}]] // Timing
Out[2]=
{1.062 Second, Null}

In[3]:= Take[#, 4] & /@ {v1, v2, v3}
Out[3]=
{{0.974173, 0.96568, "-YYY-", 0.747727}, {0.910969, 0.312475, "-YYY-",
0.34289}, {0.729062, 0.611829, "-YYY-", 0.437515}}

---------
In[1]:= {v1, v2, v3} = Table[Random[], {3}, {1000000}];
In[2]:=
Scan[(#[[3]] = "-ZZZ-") &, Unevaluated /@ Hold[v1, v2, v3]] // Timing
Out[2]=
{1.062 Second, Null}
In[3]:=
Take[#, 4] & /@ {v1, v2, v3}
Out[3]=
{{0.921074, 0.870566, "-ZZZ-", 0.553795}, {0.198232, 0.688503, "-ZZZ-",
0.372325}, {0.799497, 0.21537, "-ZZZ-", 0.0673068}}

plus yet another variant

In[1]:= Clear[f]; Attributes[f] = {HoldFirst};
In[2]:= f[sym_] := (sym[[3]] = "-WWW-")
In[3]:= {v1, v2, v3} = Table[Random[], {3}, {1000000}];
In[4]:=
Scan[f, Hold[v1, v2, v3]] // Timing
Out[4]=
{1.032 Second, Null}
In[5]:=
Take[#, 4] & /@ {v1, v2, v3}
Out[5]=
{{0.422896, 0.178604, "-WWW-", 0.193691}, {0.184583, 0.524976, "-WWW-",
0.370107}, {0.592243, 0.952171, "-WWW-", 0.79216}}

All four perform the same and are O[x], when x is the length of the
lists!

I admit, I don't understand that. The Question is: what did we measure?
The Performance of the functions? -- obviously not. The performance of
Scan (through a list of three elements)? -- probably not. Seems just to
be the time of accessing the 3rd element of a list. See

In[1]:= {v1, v2, v3} = Table[Random[], {3}, {1000000}];
In[2]:=
{v1[[3]], v2[[3]], v3[[3]]} // Timing
Out[2]=
{0. Second, {0.969595, 0.192005, 0.637547}}
In[3]:=
{v1[[3]] = "-UUU-", v2[[3]] = "-UUU-", v3[[3]] = "-UUU-"} // Timing
Out[3]=
{1.052 Second, {"-UUU-", "-UUU-", "-UUU-"}}

So it's Set[Part[...],...] which is not O[constant]

Kind regards,  Hartmut

------------------------------------------------------------
P.S.: I used the same values for allv, v<i> as before, see:

> Hartmut Wolf wrote:
>
> > Johannes Ludsteck schrieb:
> > >
> > > Dear MathGroup members
> > >
> > > I have to do replacements in very long lists. An efficient way to do
> > > this is to use
> > >
> > > x[[index]]=newElement.
> > >
> > > This, however, doesn't work if I want to do replacements for a set of
> > > lists. If I try to replace the third element in the lists v1,
> > v2 and v3 by
> > > typing
> > >
> > > Scan[#[[3]] = newElement &, {v1,v2,v3}]
> > > I get the error message
> > > Set::setps: #1 in assignment of part is not a symbol.
> > >
> >
> > Hallo Johannes,
> >
> > the problem with your expression is to get the symbols v1,...
> > unevaluated into the lhs of Set. There are two points where evaluation
> > occurs, first at the rhs of Scan (or Map) where the list {v1,v2,v3} and
> > then recursively v1,... are evaluated. You can suppress that by wrapping
> > the list with Unevaluated. The second is the evaluation of #1 before
> > Function inserts the argument at the lhs of Set. This can be avoided by
> > specifing the argument HoldFirst for evaluation of Function:
> >
> > In[8]:= allv = {v1, v2, v3} = Table[Random[], {3}, {4}]
> > Out[8]=
> > {{0.308624, 0.0113816, 0.452114, 0.100156},
> >  {0.368705, 0.44588, 0.878839, 0.736246},
> >  {0.71764, 0.18652, 0.667573, 0.338795}}
> >
> > In[9]:=
> > Scan[Function[sym, sym[[3]] = "-XXX-", {HoldFirst}],
> >   Unevaluated[{v1, v2, v3}]]
> >
> > In[10]:= {v1, v2, v3}
> > Out[10]=
> > {{0.308624, 0.0113816, "-XXX-", 0.100156},
> >  {0.368705, 0.44588, "-XXX-", 0.736246},
> >  {0.71764, 0.18652, "-XXX-", 0.338795}}
> >
> > Yet another idea would be to use the compound object allv (see above),
> > and then
>
> > In[11]:= allv[[All, 2]] = "-YYY-"
> > Out[11]= "-YYY-"
> >
> > In[14]:= allv
> > Out[14]=
> > {{0.308624, "-YYY-", 0.452114, 0.100156},
> >  {0.368705, "-YYY-", 0.878839, 0.736246},
> >  {0.71764, "-YYY-", 0.667573, 0.338795}}
> >
> > Of course the values of v1,... are not affected, but perhaps you may
> > dispense with them alltogether, or use them only for access or display
> > purposes:
> >
> > In[15]:= Clear[v1, v2, v3]
> > In[16]:=
> > v1 := allv[[1]]; v2 := allv[[2]]; v3 := allv[[3]]
> >
> > In[17]:= {v1, v2, v3}
> > Out[17]=
> > {{0.308624, "-YYY-", 0.452114, 0.100156},
> >  {0.368705, "-YYY-", 0.878839, 0.736246},
> >  {0.71764, "-YYY-", 0.667573, 0.338795}}

```

• Prev by Date: Finding parts of Equations...
• Next by Date: Re: Re: Re: Set in Scan
• Previous by thread: Re: Re: Re: Set in Scan
• Next by thread: Re: Re: Re: Set in Scan