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[[1]] ]< 4, >> (Print["haloarray: matrix too >>small"];Return[Null])]; >> Map[halo,array]; >> array[[1]] = array[[Length[array] - 1]]; >> array[[Length[array]]] = array[[2]]; >> ] >> >>Attributes[halo] = {}; >>halo[x_]/;MatchQ[x,z_List] := Module[{y}, >> y = x; >> If [Length[x] <4,(Print["halo: list too >>short"];Return[Null])]; >> y[[1]] = x[[(Length[x] - 1)]]; >> y[[Length[x]]] = x[[2]]; >> ] >>=== >>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[[1]] = x[[(Length[x] - 1)]]; >> x[[Length[x]]] = x[[2]]; >> ] >>=== >>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[26]:= rr = Range[5] >Out[26]= {1, 2, 3, 4, 5} >(our test data) > >then there is a function in Mathematica, that does it: > >In[28]:= PadRight[rr, 7, rr, 1] >Out[28]= {5, 1, 2, 3, 4, 5, 1} > > >This function also extends to the two-dimensional case. Let's >again define a test sample: > >In[30]:= (tt = Array[CirclePlus, {5, 3}]) // MatrixForm > >(I suppress the output here, CirclePlus is only used for >illustration and easy reading) >Now look at > >In[32]:= 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[33]:= Attributes[halo] = HoldAll; >halo[x_] := > (x[[1]] = x[[(Length[x] - 1)]]; > x[[Length[x]]] = x[[2]];) > >In[35]:= rr = PadRight[Range[5], 7, 0, 1] >Out[35]= {0, 1, 2, 3, 4, 5, 0} >(our test data for this case) > >In[36]:= halo[rr] >In[37]:= rr >Out[37]= {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[38]:= >(tt0 = PadRight[Array[a, {5, 3}], {7, 5}, 0, {1, 1}]) // MatrixForm >Out[38]//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 > > >What you proposed effectively was this: > >In[39]:= >Attributes[haloarray] = HoldFirst; >haloarray[array_] := > (Map[halo, array]; > array[[1]] = array[[Length[array] - 1]]; > array[[Length[array]]] = array[[2]];) > >(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[46]:= 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[49]:= Clear[tt1, tt2, tt3, tt4, tt5, tt6, tt7] >In[50]:= >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[51]:= >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[52]:= tt >Out[52]= >{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[53]:= tt2 >Out[53]= {0, a[1, 1], a[1, 2], a[1, 3], 0} > > >In[54]:= haloarray[tt] >In[55]:= tt >Out[55]= >{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[57]:= tt2 >Out[57]= >{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[58]:= (tt = (Evaluate /@ tt)) // MatrixForm >Out[58]//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[81]:= Clear[haloarray] >In[82]:= >(tt0 = PadRight[Array[a, {5, 3}], {7, 5}, 0, {1, 1}]) // MatrixForm > >In[83]:= >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[[1]] = array[[d1 - 1]]; > array[[d1]] = array[[2]];] > >In[85]:= haloarray[tt0] >In[86]:= tt0 > more elegant is this: Attributes[haloarray] = HoldAll; haloarray[array_] := ( array[[All, 1]] = array[[All, -2]]; array[[All, -1]] = array[[All, 2]]; array[[1]] = array[[-2]]; array[[-1]] = array[[2]];) > > >Nonetheless I recommend PadRight. > Still do -- Hartmut