I am trying to write a simple program - perform f1 as long as t is smaller than 800. t is declared in a list. The problem is easy, but difficult to explain, so I'll give You my code:

a = {t -> 120};
f1[{x_, y_}] := {x + t, y + t} /. a;
NestWhile[f1[#] &; a = a /. Rule[t, _] :> Rule[t, f1[#][[1]] &], {100, 100}, (t /. a) <= 800]

ReplaceAll::reps: {{t->(f1[Slot[<<1>>]][[1]]&)}>=800} is neither a list of replacement rules nor a valid dispatch table, and so cannot be used for replacing. >>

After each calculation step I want to change replacement rule in a list. Desired output should be {880, 880}. Any idea how to make it work? I know it sounds like a stupid example, but if can fix that, I can also fix problem with my original functions.

  • 1
    $\begingroup$ As a first observation, the condition t /. a <= 800 in my opinion should read (t /. a) <= 800. Secondly it is not clear to me what is the function to be nested. It appears you are trying to nest a replacement rule. $\endgroup$ – Peltio Nov 18 '13 at 15:51
  • $\begingroup$ 1. My bad, I'll correct that. 2.If nesting a replacement rule means updating the value assigned to t after each step, than yes $\endgroup$ – Wojciech Nov 18 '13 at 15:55
  • 2
    $\begingroup$ I remember the other post where you wanted to update a replacement rule but... is it really necessary? Would you not be better off with a more straightforward approach as in f[{{x_, y_}, t_}] := {{x + t, y + t}, x + t}; NestList[f, {{100, 100}, 120}, 10], for example? $\endgroup$ – Peltio Nov 18 '13 at 16:11
  • $\begingroup$ As I am just beginning with Mathematica, I may be prone to sticking with certain ideas, which may not be the best ones. Changing a replacement rule over an iteration process was so far my best idea to solve my problem, but I'll try it with t inside the function. Thanks for advice! $\endgroup$ – Wojciech Nov 18 '13 at 16:18
  • 2
    $\begingroup$ The first argument of Nest must be a function. This function may have side effect and change global variables, but it still must be a function. This is why your example fails. The last argument of NestWhile also needs to be a function. $\endgroup$ – Szabolcs Nov 18 '13 at 16:52

I find, when using iterators such a NestList, that it is a good idea to preserve the full state of the iteration at each step. Applying that principle to your calculation, I came up with this:

f1[{{x_, y_}, r_}] := Module[{v}, {v = {x + t, y + t} /. r, t -> v[[1]]}]
First @ NestWhile[f1, {{100, 100}, t -> 120}, #[[1, 1]] <= 800 &]

{880, 880}


Since Wojciech Sitkiewicz has opened up his question to allow other iterators than NestList, I suggest a very simple approach using While.

f1[{x_, y_}] := Module[{bn}, bn = {x + t, y + t} /. a; a = t -> bn[[1]]; bn]
a = t -> 120; pair = {100, 100};
While[(pair = f1[pair])[[1]] <= 800]

{880, 880}


Since function f1 in my question operated on a list consisting of two variables, changing it into a nested list may not always be convenient, while it may force changes in other parts of the program. I forgot to stress it in the question, nevertheless I allowed myself to modify m_goldberg's solution a little bit, so that f1 argument form remains the same as in question.

a = {t -> 120};
f1[{x_, y_}] := Module[{bn}, bn = {x + t, y + t} /. a;
a = a /. Rule[t, _] :> Rule[t, bn[[1]]]; bn]

Catch[Nest[If[#[[1]] > 800, Throw[#], f1[#]] &, {100, 100}, 5]]

{880, 880}

I asked about NestWhile[], but it seems one can solve this problem also using Nest[], Catch[] and Throw[]. The only flaw of this solution is that one have to predict (more or less) how many Nest operations will be executed before Throw is encountered. I'm not sure whether it is the best way to solve this in Mathematica, but so far for me it's working.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.