RE: Struggling with list element assignment in functions
- To: mathgroup at smc.vnet.net
- Subject: [mg45581] 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:57 -0500 (EST)
- Sender: owner-wri-mathgroup at wolfram.com
>-----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: [mg45581] [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 evaluattion of tt for Map. In[51]:= Thread[{tt1, tt2, tt3, tt4, tt5, tt6, tt7} = 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 Nonetheless I recommend PadRight. -- Hartmut Wolf