       RE: Struggling with list element assignment in functions

• To: mathgroup at smc.vnet.net
• Subject: [mg45582] RE: [mg45568] Struggling with list element assignment in functions
• From: "Wolf, Hartmut" <Hartmut.Wolf at t-systems.com>
• Date: Fri, 16 Jan 2004 06:04:58 -0500 (EST)
• Sender: owner-wri-mathgroup at wolfram.com

```For aesthetics I have to make two short notes:

>-----Original Message-----
>From: Wolf, Hartmut
To: mathgroup at smc.vnet.net
>Sent: Wednesday, January 14, 2004 1:30 PM
>To: 'mt at 3planes.com'; mathgroup at smc.vnet.net
>Subject: [mg45582] RE: [mg45568] Struggling with list element assignment in
>functions
>
>
>
>>-----Original Message-----
>>From: mt at 3planes.com [mailto:mt at 3planes.com]
To: mathgroup at smc.vnet.net
>>Sent: Wednesday, January 14, 2004 7:26 AM
>>To: mathgroup at smc.vnet.net
>>Subject: [mg45582] [mg45568] Struggling with list element assignment in
>functions
>>
>>
>>For context, I am trying to create a toroidal data structure by
>>causing edges of an array to be copies of
>>rows and columns on the first interior line of the opposite edge.
>>
>>I'm not entirely clear on what Hold does, but it seemed to solve my
>>problem when wrapping the rows of the array:
>>
>>===
>>Attributes[haloarray] = HoldFirst;
>>haloarray[array_]/;MatrixQ[array] := Module[{},
>>		If [Length[array] <4 || Length[array[] ]< 4,
>>			(Print["haloarray: matrix too
>>small"];Return[Null])];
>>	       Map[halo,array];
>>	       array[] = array[[Length[array] - 1]];
>>	       array[[Length[array]]] = array[];
>>	]
>>
>>Attributes[halo] = {};
>>halo[x_]/;MatchQ[x,z_List] := Module[{y},
>>		y = x;
>>		If [Length[x] <4,(Print["halo: list too
>>short"];Return[Null])];
>>    	       y[] = x[[(Length[x] - 1)]];
>>     	       y[[Length[x]]] = x[];
>>	]
>>===
>>so, by putting in the HoldFirst, I could assign directly to the called
>>array in haloarray[] rather than having to copy it twice, to and from
>>a dummy array. Imagine my disappointment, then, in trying to extend
>>this idea to the halo[] routine. This
>>===
>>Attributes[halo] = HoldFirst;
>>halo[x_]/;MatchQ[x,z_List] := Module[{},
>>		If [Length[x] <4,(Print["halo: list too
>>short"];Return[Null])];
>>    	       x[] = x[[(Length[x] - 1)]];
>>    	       x[[Length[x]]] = x[];
>>	]
>>===
>>refuses to do the assignments and yields all sorts of error messages.
>>Any ideas? It's not a showstopper for me but I'd like to know what's
>>up.
>>
>>thanks
>>Michael Tobis
>>http://geosci.uchicago.edu/~tobis
>>
>
>Michael,
>
>perhaps you fell into the error -- so common (in any field) --
>namely of "optimizing before solving the problem".
>
>I assume, you originally wanted to _extend_ your (matrix) data
>periodically by margins to the left and to the right.
>
>Take the one-dimensional case
>
>In:= rr = Range
>Out= {1, 2, 3, 4, 5}
>(our test data)
>
>then there is a function in Mathematica, that does it:
>
>Out= {5, 1, 2, 3, 4, 5, 1}
>
>
>This function also extends to the two-dimensional case. Let's
>again define a test sample:
>
>In:= (tt = Array[CirclePlus, {5, 3}]) // MatrixForm
>
>(I suppress the output here, CirclePlus is only used for
>Now look at
>
>In:= PadRight[tt, {7, 5}, tt, {1, 1}] // MatrixForm
>
>I guess this is your solution.
>
>As PadRight is a built-in, there usually is no need (or
>opportunity) for further optimization.
>
>
>
>
>
>Now let me explain, what went wrong with your attempt. (I drop
>all embellishments here)
>
>In:= Attributes[halo] = HoldAll;
>halo[x_] :=
>  (x[] = x[[(Length[x] - 1)]];
>    x[[Length[x]]] = x[];)
>
>In:= rr = PadRight[Range, 7, 0, 1]
>Out= {0, 1, 2, 3, 4, 5, 0}
>(our test data for this case)
>
>In:= halo[rr]
>In:= rr
>Out= {5, 1, 2, 3, 4, 5, 1}
>
>Ok, halo worked!
>
>What we did, was replace the first and last element by the
>margins of the (true) data kernel. In order to achieve that
>in-place operation, it is necessary to pass the data by a
>symbol (rr here) and hold the argument.
>
>
>Now we try to repeat the trick for the next dimension:
>
>In:=
>(tt0 = PadRight[Array[a, {5, 3}], {7, 5}, 0, {1, 1}]) // MatrixForm
>Out//MatrixForm=
> 0     0        0        0      0
>
> 0  a[1, 1]  a[1, 2]  a[1, 3]   0
>
> 0  a[2, 1]  a[2, 2]  a[2, 3]   0
>
> 0  a[3, 1]  a[3, 2]  a[3, 3]   0
>
> 0  a[4, 1]  a[4, 2]  a[4, 3]   0
>
> 0  a[5, 1]  a[5, 2]  a[5, 3]   0
>
> 0     0        0        0      0
>
>
>
>In:=
>Attributes[haloarray] = HoldFirst;
>haloarray[array_] :=
>  (Map[halo, array];
>    array[] = array[[Length[array] - 1]];
>    array[[Length[array]]] = array[];)
>
>(it doesn't work) The replacement of the rows is the same as
>what we did in the 1-dim case, and indeed, if we drop the line
>Map[halo,array] it works changing the rows.
>
>So we test
>
>In:= Map[halo, tt0]
>
>(doesn't work) Why? Quite simple, Map cannot map halo over a
>symbol, such it has to evaluate its argument, hence we are
>lost (Input condition for halo is now violated).
>
>Normally we now would abandon the Map idea, but for
>illustration, how we can put it further:
>
>In:= Clear[tt1, tt2, tt3, tt4, tt5, tt6, tt7]
>In:=
>tt = Unevaluated /@ {tt1, tt2, tt3, tt4, tt5, tt6, tt7};
>
>We define tt as a list of Symbols. We wrapped them with
>Unevaluated, to stop evaluation of tt for Map.
>
>In:=
>Thread[{tt1, tt2, tt3, tt4, tt5, tt6, tt7} = tt0]

Thread is not needed for Set; also avoid writing the list explicitly:

Evaluate[Evaluate /@ tt] = tt0

>
>This assigns our test data to tt. We cannot see them
>
>In:= tt
>Out=
>{Unevaluated[tt1], Unevaluated[tt2], Unevaluated[tt3],
>Unevaluated[tt4],
>  Unevaluated[tt5], Unevaluated[tt6], Unevaluated[tt7]}
>
>As evaluation stops, but that is exactly what we need for
>haloarray. But it's really there, believe me:
>
>In:= tt2
>Out= {0, a[1, 1], a[1, 2], a[1, 3], 0}
>
>
>In:= haloarray[tt]
>In:= tt
>Out=
>{Unevaluated[tt6], Unevaluated[tt2], Unevaluated[tt3],
>Unevaluated[tt4],
>  Unevaluated[tt5], Unevaluated[tt6], Unevaluated[tt2]}
>
>look close what happend, the rows are right...
>
>...and also the columns
>
>In:= tt2
>Out=
>{a[1, 3], a[1, 1], a[1, 2], a[1, 3], a[1, 1]}
>
>
>To arrive at the desired result we just have to put away the
>wrappers, e.g. like this
>
>In:= (tt = (Evaluate /@ tt)) // MatrixForm
>Out//MatrixForm=
> a[5, 3]  a[5, 1]  a[5, 2]  a[5, 3]  a[5,1]
>
> a[1, 3]  a[1, 1]  a[1, 2]  a[1, 3]  a[1,1]
>
> a[2, 3]  a[2, 1]  a[2, 2]  a[2, 3]  a[2,1]
>
> a[3, 3]  a[3, 1]  a[3, 2]  a[3, 3]  a[3,1]
>
> a[4, 3]  a[4, 1]  a[4, 2]  a[4, 3]  a[4,1]
>
> a[5, 3]  a[5, 1]  a[5, 2]  a[5, 3]  a[5,1]
>
> a[1, 3]  a[1, 1]  a[1, 2]  a[1, 3]  a[1,1]
>
>
>
>But of course the right way to put forth your idea would be:
>
>In:= Clear[haloarray]
>In:=
>(tt0 = PadRight[Array[a, {5, 3}], {7, 5}, 0, {1, 1}]) // MatrixForm
>
>In:=
>Attributes[haloarray] = HoldAll;
>haloarray[array_] := Module[{d1, d2},
>    {d1, d2} = Dimensions[array];
>    array[[All, 1]] = array[[All, d2 - 1]];
>    array[[All, d2]] = array[[All, 2]];
>    array[] = array[[d1 - 1]];
>    array[[d1]] = array[];]
>
>In:= haloarray[tt0]
>In:= tt0
>

more elegant is this:

Attributes[haloarray] = HoldAll;
haloarray[array_] := (
array[[All, 1]] = array[[All, -2]];
array[[All, -1]] = array[[All, 2]];
array[] = array[[-2]];
array[[-1]] = array[];)

>
>