Prev: London Computational Knowledge Summit
Next: DynamicModule not saving reliably a variable between
From: ap on 17 Apr 2010 06:02 Dear group, I just wanted to check that I'm correct in thinking that I cannot use Nest or Fold to iterate a function, where that function has a HoldFirst attribute set that allows it to modify the global variable (parameter) passed to it. As a test case / example I define a function which modifies a global variable (a list) by setting the 2nd element to a random integer, and returns the modified list, as follows: SetAttributes[f,HoldFirst] f[var_] := {var[[2]] = RandomInteger[ {0,Length[var]} ], var}[[2]] Then if I simply do mylist=Range[10] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} I get f[mylist] {1, 8, 3, 4, 5, 6, 7, 8, 9, 10} as expected. However, if I try to Nest this function to apply it iteratively (as an alternative to a For or Do loop), as follows: Nest[f, mylist, 3] I get Set::setps: {1,2,3,4,5,6,7,8,9,10} in the part assignment is not a symbol. >> In other words, Nest seems not to respect the HoldFirst attribute of f. Instead, the list is passed by value and the resulting attempted assignment of the random integer fails. The same behaviour results from Fold if I slightly modify f to make it a function of two variables. Is this correct? And if so, is the best alternative simply to use a loop? That's easy enough, but I was just trying to be as 'functional' and hence efficient as possible, as this kind of modification of a global variable is a key step in my algorithm and needs to be as fast as possible. I have an alternative implementation where instead of trying to modify the list I Join existing parts of it with the relevant modified element, but this appears to be ~25% slower than a simple Do loop to modify the list.
From: Bill Rowe on 18 Apr 2010 05:57 On 4/17/10 at 6:03 AM, arno.proeme(a)gmail.com (ap) wrote: >I just wanted to check that I'm correct in thinking that I cannot >use Nest or Fold to iterate a function, where that function has a >HoldFirst attribute set that allows it to modify the global variable >(parameter) passed to it. As a test case / example I define a >function which modifies a global variable (a list) by setting the >2nd element to a random integer, and returns the modified list, as >follows: >SetAttributes[f,HoldFirst] f[var_] := {var[[2]] = RandomInteger[ >{0,Length[var]} ], var}[[2]] >Then if I simply do >mylist=Range[10] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} >I get >f[mylist] {1, 8, 3, 4, 5, 6, 7, 8, 9, 10} >as expected. However, if I try to Nest this function to apply it >iteratively (as an alternative to a For or Do loop), as follows: >Nest[f, mylist, 3] >I get >Set::setps: {1,2,3,4,5,6,7,8,9,10} in the part assignment is not a >symbol. >> I get the same error when I use your code and do: f[Range(a)10] So, problem is Nest evaluates the first time to a list of numbers and operates on this list rather than the global variable that has been modified. And since your f will not work with this type of list the error message gets generated. That is I see the problem as being using the syntax var[[2]]=RandomInteger to change the second value. >In other words, Nest seems not to respect the HoldFirst attribute of >f. Instead, the list is passed by value and the resulting attempted >assignment of the random integer fails. The same behaviour results >from Fold if I slightly modify f to make it a function of two >variables. This sounds like another way to describe the situation. And when I think about this, I don't see how Nest could work differently. If Nest doesn't evaluate its argument, how can the next iteration evaluate correctly? I don't understand why you create a local copy of the global variable you want to change. Instead of writing f as you did why not write it as: f:=(myList[[2]]=RandomInteger[Length(a)myList];myList) that is write f to operate directly on the global variable to be modified rather than to operate on a local copy of that variable. If I write f in this fashion then Nest[f,myList,3] works as expected with no error messages. But frankly, the entire idea of modify global variables in this manner strikes me as being unwise. I see result as being code that will be difficult to maintain and debug.
From: Ray Koopman on 18 Apr 2010 05:57 On Apr 17, 3:02 am, ap <arno.pro...(a)gmail.com> wrote: > Dear group, > > I just wanted to check that I'm correct in thinking that I cannot use > Nest or Fold to iterate a function, where that function has a > HoldFirst attribute set that allows it to modify the global variable > (parameter) passed to it. > As a test case / example I define a function which modifies a global > variable (a list) by setting the 2nd element to a random integer, and > returns the modified list, as follows: > > SetAttributes[f,HoldFirst] > f[var_] := {var[[2]] = RandomInteger[ {0,Length[var]} ], var}[[2]] > > Then if I simply do > > mylist=Range[10] > {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} > > I get > > f[mylist] > {1, 8, 3, 4, 5, 6, 7, 8, 9, 10} > > as expected. > However, if I try to Nest this function to apply it iteratively (as an > alternative to a For or Do loop), as follows: > > Nest[f, mylist, 3] > > I get > > Set::setps: {1,2,3,4,5,6,7,8,9,10} in the part assignment is not a > symbol. >> > > In other words, Nest seems not to respect the HoldFirst attribute of > f. Instead, the list is passed by value and the resulting attempted > assignment of the random integer fails. The same behaviour results > from Fold if I slightly modify f to make it a function of two > variables. > > Is this correct? And if so, is the best alternative simply to use a > loop? That's easy enough, but I was just trying to be as 'functional' > and hence efficient as possible, as this kind of modification of a > global variable is a key step in my algorithm and needs to be as fast > as possible. I have an alternative implementation where instead of > trying to modify the list I Join existing parts of it with the > relevant modified element, but this appears to be ~25% slower than a > simple Do loop to modify the list. Use MapAt: In[1]:= g[var_] := MapAt[Random[Integer,{0,Length(a)var}]&,var,2] In[2]:= mylist = Range(a)10 Out[2]= {1,2,3,4,5,6,7,8,9,10} In[3]:= g[mylist] Out[3]= {1,9,3,4,5,6,7,8,9,10} In[4]:= Nest[g,mylist,3] Out[4]= {1,6,3,4,5,6,7,8,9,10}
From: Bob Hanlon on 18 Apr 2010 05:59 mylist = Range[10]; SetAttributes[{f, f1, f2}, HoldFirst]; f[var_] := Module[{x = var}, {x[[2]] = RandomInteger[{0, Length[x]}], x}[[2]]]; Nest[f, mylist, 3] {1,4,3,4,5,6,7,8,9,10} f1[var_] := Module[{x = var}, x[[2]] = RandomInteger[{0, Length[x]}]; x]; Nest[f1, mylist, 3] {1,1,3,4,5,6,7,8,9,10} f2[var_] := ReplacePart[var, 2 -> RandomInteger[{0, Length[var]}]]; Nest[f2, mylist, 3] {1,6,3,4,5,6,7,8,9,10} Bob Hanlon ---- ap <arno.proeme(a)gmail.com> wrote: ============= Dear group, I just wanted to check that I'm correct in thinking that I cannot use Nest or Fold to iterate a function, where that function has a HoldFirst attribute set that allows it to modify the global variable (parameter) passed to it. As a test case / example I define a function which modifies a global variable (a list) by setting the 2nd element to a random integer, and returns the modified list, as follows: SetAttributes[f,HoldFirst] f[var_] := {var[[2]] = RandomInteger[ {0,Length[var]} ], var}[[2]] Then if I simply do mylist=Range[10] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} I get f[mylist] {1, 8, 3, 4, 5, 6, 7, 8, 9, 10} as expected. However, if I try to Nest this function to apply it iteratively (as an alternative to a For or Do loop), as follows: Nest[f, mylist, 3] I get Set::setps: {1,2,3,4,5,6,7,8,9,10} in the part assignment is not a symbol. >> In other words, Nest seems not to respect the HoldFirst attribute of f. Instead, the list is passed by value and the resulting attempted assignment of the random integer fails. The same behaviour results from Fold if I slightly modify f to make it a function of two variables. Is this correct? And if so, is the best alternative simply to use a loop? That's easy enough, but I was just trying to be as 'functional' and hence efficient as possible, as this kind of modification of a global variable is a key step in my algorithm and needs to be as fast as possible. I have an alternative implementation where instead of trying to modify the list I Join existing parts of it with the relevant modified element, but this appears to be ~25% slower than a simple Do loop to modify the list.
From: Leonid Shifrin on 19 Apr 2010 02:48 Hi Arno, My understanding is that indeed, Nest and Fold do not respect the Hold Attributes in the way you outlined. Here is my guess for what's happening: the behavior that you observed is probably just a consequence of the way they (Nest and Fold) work (are implemented): first your function is computed (iterated) by Nest or Fold, and then that result is copied to whatever internal storage Nest or Fold is using to keep the intermediate result of a given iteration. In other words, what you get as an input for the next iteration is already a result stored in that internal storage rather than your initial variable. And when this result is supplied to you for the next iteration, it gets evaluated, so probably what you get is a fully evaluated copy rather than a reference to that storage. This copy is immutable, so you get the error when attempting to modify it. This scenario is just my speculation, any part of it may be wrong. Now, one of the main goals of functional style is to work on immutable structures, so this behavior seems consistent with that ideology. Whenever you use Hold attributes to implement pass-by-reference and in-place modifications, you already step outside of the functional programming paradigm. So I would not hesitate to use loops - in your situation this seems totally appropriate. As far as efficiency is concerned, functional programming is efficient in Mathematica simply because it allows to work with large pieces at once, pushing more operations into the kernel and by-passing the main evaluation loop for many small parts of your expression. In most cases, loops are associated with breaking expression into pieces, and that is what makes them inefficient. In some cases however, loops can be used to the same effect, and then they are no less efficient than functional programming. For your problem in particular, loops should be totally fine. In the case of lists, you may also save a little (like 25 %) by wrapping your values in HoldComplete rather than List, since then no UpValues lookup will take place. Hope this helps. Regards, Leonid On Sat, Apr 17, 2010 at 3:03 AM, ap <arno.proeme(a)gmail.com> wrote: > Dear group, > > I just wanted to check that I'm correct in thinking that I cannot use > Nest or Fold to iterate a function, where that function has a > HoldFirst attribute set that allows it to modify the global variable > (parameter) passed to it. > As a test case / example I define a function which modifies a global > variable (a list) by setting the 2nd element to a random integer, and > returns the modified list, as follows: > > SetAttributes[f,HoldFirst] > f[var_] := {var[[2]] = RandomInteger[ {0,Length[var]} ], var}[[2]] > > Then if I simply do > > mylist=Range[10] > {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} > > I get > > f[mylist] > {1, 8, 3, 4, 5, 6, 7, 8, 9, 10} > > as expected. > However, if I try to Nest this function to apply it iteratively (as an > alternative to a For or Do loop), as follows: > > Nest[f, mylist, 3] > > I get > > Set::setps: {1,2,3,4,5,6,7,8,9,10} in the part assignment is not a > symbol. >> > > In other words, Nest seems not to respect the HoldFirst attribute of > f. Instead, the list is passed by value and the resulting attempted > assignment of the random integer fails. The same behaviour results > from Fold if I slightly modify f to make it a function of two > variables. > > Is this correct? And if so, is the best alternative simply to use a > loop? That's easy enough, but I was just trying to be as 'functional' > and hence efficient as possible, as this kind of modification of a > global variable is a key step in my algorithm and needs to be as fast > as possible. I have an alternative implementation where instead of > trying to modify the list I Join existing parts of it with the > relevant modified element, but this appears to be ~25% slower than a > simple Do loop to modify the list. > >
|
Next
|
Last
Pages: 1 2 Prev: London Computational Knowledge Summit Next: DynamicModule not saving reliably a variable between |