RE: strange behavior
- To: mathgroup at smc.vnet.net
- Subject: [mg27196] RE: [mg27158] strange behavior
- From: "Wolf, Hartmut" <Hartmut.Wolf at t-systems.de>
- Date: Fri, 9 Feb 2001 03:10:41 -0500 (EST)
- Sender: owner-wri-mathgroup at wolfram.com
Please look below for my answer: -----Original Message----- From: Otto Linsuain [mailto:linsuain+ at andrew.cmu.edu] To: mathgroup at smc.vnet.net Subject: [mg27196] [mg27158] strange behavior Hi all. I have a little problem using Thread and MapThread, and although I have found a way around it, I am still unhappy with it being there in the first place. I have a function (call it myF ) that takes as arguments FOUR vectors of equal length (doesn't matter what length) -by vector I mean a List of numbers with the simplest structure possible {x1, x2, ..... xN}- and gives out a number. The only operations involved in getting the number are addition, subtraction, multiplication and division. So I do convolutions of one list with another, and things like that (although I don't use ListConvolve). I want to map this function over a bunch of lists in the following way: For argument #1 I always want the same list xList={x1, x2, .....xN} For argument #2 I have the list: yList={{a1,a2,...aN}, {b1,b2,...bN}} and I want to apply the function first to the x's as argument #1 with the a's as argument #2, and then to the x's as argument #1, with the b's as argument #2. So far so good, and only need to map over the second argument. For argument #3 I have many lists. More exactly, I have a list consisting of two NxN matrices: cList={ { {Ca11,Ca12, ...Ca1N},{Ca21,Ca22, ...Ca2N},...{CaN1,Ca12, ...CaNN} }, { {Cb11,Cb12, ...Cb1N},{Cb21,Cb22, ...Cb2N},...{CbN1,Cb12, ...CbNN} } } similarly for argument #4 lList={ { {La11,La12, ...La1N},{La21,La22, ...La2N},...{LaN1,La12, ...LaNN} }, { {Lb11,Lb12, ...Lb1N},{Lb21,Lb22, ...Lb2N},...{LbN1,Lb12, ...LbNN} } } when I use the a's for argument #2 I want to go through and use the first row in the Ca's for argument #3, and the first row in the La's for argument #4, then the second row of each, etc Notice that I don't want all the combination between the cList and the lList. When I am done with that I go to the b's for argument #2, then I want to use the first rows of Cb and Lb for arguments #3 and #4, then their second rows, etc. This is what I do: MapThread[ myF[xList,#1,#2,#3]&, {yList, cList, lList} ] this uses first the first Parts of yList, cList and lList, and then their second Parts. This produces { myF[ xList, {a1,a2,....aN}, matrix of Ca's, matrix of La's], myF[xlIst, {b1,b2,..bN}, matrix of Cb's, matrix of Lb's]} So far so good. Now I just need to Thread over the last two arguments: Map[ Thread[#, List,-2]&, MapThread[ myF[xList,#1,#2,#3]&, {yList, cList, lList} ] ] This threads the function myF over those arguments just the way I wanted AS LONG AS the function myF has not been defined. The minute I define the function myF to do what I want it to do (to combine the four vectors in a certain way and produce a number) it threads in a different way. Namely it threads as if using the Transpose of the lists cList and lList. One solution is to use the Transpose in the first place, so when they get Transposed again it would be just fine, but this is still puzzling. Any ideas on what is going on and suggestions on how to fix it (Transposing big matrices is a little slow) would be appreciated. Otto Linsuain. ---------------------------------------------------- Dear Otto, My Mathematica Version here (still) is In[1]:= {$Version, $ReleaseNumber} Out[1]= {"4.0 for Microsoft Windows (April 21, 1999)", 0} First of all let me define the test data In[2] := xList = Array[x, {3}]; In[3] := yList = Array[#, {3}] & /@ {a, b}; In[4] := cList = Array[#, {3, 3}] & /@ {Ca, Cb}; In[5] := lList = Array[#, {3, 3}] & /@ {La, Lb}; A simple solution I found for your problem including Thread (there are possible lots of them) is: In[23] := MapThread[Thread[myF[xList, #1, #2, #3], List, -2] &, {yList, cList, lList}] However it shares the problems of your solution. The answer seems to be given be the observation In[34]:= Attributes[Thread] Out[34]= {Protected} No Hold being part of that, so your function might evaluate prematurely before Threading comes into effect. (You may observe that by carefully looking at a trace of your evaluation!) Anyways, you certainly may circumvent that problem if you do: In[25]:= With[{myF = Last[#2] &}, MapThread[ Thread[Hold[myF][xList, #1, #2, #3 ], List, -2] &, {yList, cList, lList}]] // ReleaseHold Out[25]= {{a[3], a[3], a[3]}, {b[3], b[3], b[3]}} In[26]:= With[{myF = Last[#4] &}, MapThread[ Thread[Hold[myF][xList, #1, #2, #3 ], List, -2] &, {yList, cList, lList}]] // ReleaseHold Out[26]= {{La[1, 3], La[2, 3], La[3, 3]}, {Lb[1, 3], Lb[2, 3], Lb[3, 3]}} which in both cases I consider to be the right answer. (And your solution -- of course! -- gives the same.) Mine also works well, when only temporaryly holding myF: In[27]:= With[{myF = Last[#2] &}, MapThread[ Thread[Unevaluated[myF[xList, #1, #2, #3 ]], List, -2] &, {yList, cList, lList}]] Out[27]= {{a[3], a[3], a[3]}, {b[3], b[3], b[3]}} In[28]:= With[{myF = Last[#4] &}, MapThread[ Thread[Unevaluated[myF[xList, #1, #2, #3 ]], List, -2] &, {yList, cList, lList}]] Out[28]= {{La[1, 3], La[2, 3], La[3, 3]}, {Lb[1, 3], Lb[2, 3], Lb[3, 3]}} Since your solution involves Thread twice, you have to protect it with a double shield: In[32]:= With[{myF = Last[#2] &}, Map[Thread[#, List, -2] &, MapThread[ Function[Unevaluated[Unevaluated[myF[xList, #1, #2, #3]]]], {yList, cList, lList}]] ] Out[32]= {{a[3], a[3], a[3]}, {b[3], b[3], b[3]}} In[34]:= With[{myF = Last[#4] &}, Map[Thread[#, List, -2] &, MapThread[ Function[Unevaluated[Unevaluated[myF[xList, #1, #2, #3]]]], {yList, cList, lList}]] ] Out[34]= {{La[1, 3], La[2, 3], La[3, 3]}, {Lb[1, 3], Lb[2, 3], Lb[3, 3]}} Now, why do I only need the "single shield"? The reason is simple: the first argument of MapThread is a (here a pure) function which evaluates to itself, so it can be map-threaded, contrary to Thread whose argument is a function application !!! This reminds me at my first steps with Mathematica, where I discovered that things which don't work with Thread, do so with MapThread. I think this is the explanation. -- Hartmut