# Pass an empty list object into a function and dynamically generate its list elements

I have another question on passing a list which needs to be generated dynamically. (Sorry for posting two questions in one day...) I did some search and found a similar post here, but I think it was for a fixed-length list. I hope I didn't misunderstand it...

Here is my code:

FindRootsOfResult[i_, points_] := Module[{a, c},
Result = 2 E^(2 I \[Pi] w x) (2 + E^(I \[Pi] w x)) ((-100 + 0.55 I) + w)^3 /. x -> i;
a = FindRoot[Result == 0, {w, j}] // Hold;
c = ParallelTable[{Re[(a // ReleaseHold)[[1, 2]] - 100], Im[(a // ReleaseHold)[[1, 2]]]}, {j, 100 - 6, 100 + 6, 0.001}];
c = DeleteDuplicates[c, (Abs[#1[[2]] - #2[[2]]] < 10^-2 &) || Abs[#1[[1]] - #2[[1]]] < 10^-8 &];
points = Join[points, c];
]


What I'm trying to do is to assign a value for the variable x and to pass a list into the FindRootsOfResult function, and then compute the corresponding roots of the function of w in a certain region. Finally I get rid of duplicate roots and save the roots in the list I passed in for further calculation. Since the number of roots in the given region changes for different x, the length of the list should be dynamically changed as well. I use Join in the last line because I'd like to assign many different x, compute the roots, and save all of them in the same list.

A simple example would be

FindRootsOfResult[1/100, ans]


and I expect ans contains all the roots for x=1/100. However Mathematica gives me many error messages like

\$RecursionLimit::reclim: Recursion depth of 256 exceeded. >>
Join::heads: Heads Join and List at positions 1 and 2 are expected to be the same. >>


and the list ans has nothing useful inside. Then I think, OK maybe Mathematica doesn't know that ans should be a list object, so I make ans be an empty list and do it again:

ans = {};
FindRootsOfResult[1/100, ans]


but I still get error messages

Set::shape: Lists {} and {{-1.82878*10^-6,-0.55},{-1.81874*10^-6,-0.55},{-1.80871*10^-6,-0.55},{-1.79868*10^-6,-0.55},{-1.78866*10^-6,-0.55},{-1.77864*10^-6,-0.55},{-1.76862*10^-6,-0.55},<<38>>,{-2.06832*10^-6,-0.55},{-2.05815*10^-6,-0.55},{-2.04798*10^-6,-0.55},{-2.03781*10^-6,-0.55},{-2.02765*10^-6,-0.55},<<344>>} are not the same shape. >>


Now I really don't know why I can't pass a list as I expected. If I execute the commands in FindRootsOfResult line by line manually, it works perfectly. I guess I don't really understand how Mathematica passes list objects. If anyone could give me a brief explanation or any previous discussion, I would so appreciate it!

-
Possibly answered here (duplicate): mathematica.stackexchange.com/a/18737/121 –  Mr.Wizard May 1 '13 at 10:29
@Mr.Wizard, yes I think the concept in your example is the same as here! Thanks for providing this thread. I didn't know this one when I searched related topics. –  Leo Fang May 1 '13 at 17:04

It sounds like you are going about this wrong. You seem to be trying to pass an empty list to a function, and have the function fill up the list, so that you can use the list elsewhere. That's not going to work.

What you do is to build your function and have the function return the list, which you can then use elsewhere. So -- remove points_ from the definition of the function and remove the semicolon from after the definition of c, because c is what you want to return. Now you can call the function with the single argument and its output will be the list c, which you can then keep track of as you will.

-
yes you got what I was trying to do! Thanks. So you're suggesting that use FindRootsOfResult to generate a list directly and assign the list to a name like test=FindRootsOfResult[1/100]? If so, yeah it works! I just wonder if passing a list object is totally forbidden in Mathematica or not, and if not, how to do that? –  Leo Fang Apr 30 '13 at 18:17
It's fine to pass the list in. But you can't pass the list in, change it, and then pass the same variable out again. –  bill s Apr 30 '13 at 18:28
You can do that with the Hold attribute. –  Sjoerd C. de Vries Apr 30 '13 at 21:47
Got it! Thanks Bill & @SjoerdC.deVries –  Leo Fang Apr 30 '13 at 22:19

Bill s' answer is fully correct, but just in case you insist on using a pass by reference, you could do it by adding a single line to your code:

SetAttributes[FindRootsOfResult, HoldRest];
FindRootsOfResult[i_, points_] :=
Module[{a, c},
Result = 2 E^(2 I \[Pi] w x) (2 +
E^(I \[Pi] w x)) ((-100 + 0.55 I) + w)^3 /. x -> i;
a = FindRoot[Result == 0, {w, j}] // Hold;
c = ParallelTable[{Re[(a // ReleaseHold)[[1, 2]] - 100],
Im[(a // ReleaseHold)[[1, 2]]]}, {j, 100 - 6, 100 + 6, 0.001}];
c = DeleteDuplicates[
c, (Abs[#1[[2]] - #2[[2]]] < 10^-2 &) ||
Abs[#1[[1]] - #2[[1]]] < 10^-8 &];
points = Join[points, c];]

ans = {};
FindRootsOfResult[1/100, ans]

ans // Short

{{-1.828775921808301*^-6, -0.5499996481081764}, <<392 >>,
{2.0794240640498174*^-6, -0.5499995919599968}}


You have to realize that normally when you pass a variable in Mathematica it's a pass by value. So, you passed an empty list and not a variable containing an empty list. Using HoldRest you tell Mathematica not to evaluate the second parameter, and hence its name is passed.

Again, there are much better ways to solve your actual problem.

-
I really forgot that it's a pass-by-value in Mathematica...Thanks again for reminding me and showing a working example! –  Leo Fang Apr 30 '13 at 22:21

By the way, I do find a way to avoid passing a list (by reference). Here's my solution:

FindRootsOfResult[i_, points_] := Module[{a, c},
Result = 2 E^(2 I \[Pi] w x) (2 + E^(I \[Pi] w x)) ((-100 + 0.55 I) + w)^3 /. x -> i;
a = FindRoot[Result == 0, {w, j}] // Hold;
c = ParallelTable[{Re[(a // ReleaseHold)[[1, 2]] - 100], Im[(a // ReleaseHold)[[1, 2]]]}, {j, 100 - 6, 100 + 6, 0.001}];
points = DeleteDuplicates[c, (Abs[#1[[2]] - #2[[2]]] < 10^-2 &) || Abs[#1[[1]] - #2[[1]]] < 10^-8 &];
]
{(2 # - 1)/100, ToExpression["test" <> ToString[#]]} & /@ Range[1, 131, 2]
FindRootsOfResult @@@ ({(2 # - 1)/100, ToExpression["test" <> ToString[#]]} & /@ Range[1, 131, 2]);
result = Flatten[ToExpression["test" <> ToString[#]] & /@ Range[1, 131, 2], 1];
ListPlot[result, PlotRange -> {{-4.2, 4.2}, {-4, 0.1}},  PlotMarkers -> Automatic]


What I do here is to generate a lot of variables called test labeled by indices starting from 1, which will also give a corresponding value to x, and apply my FindRootsOfResult function on those stuff. In the end I use Flatten to combine all resulting lists into a single list, and do a ListPlot. As a result, I don't need to pass a "list" (or the reference of a list if you like) into the function; what I pass into is just a variable which will be assigned a list by FindRootsOfResult. It works perfectly.

-