3
$\begingroup$

I need to solve a sequence of equations and I want the starting point of each new FindRoot to be the solution of the earlier FindRoot, increased or decreased by a a bit in the following way:

Some data

d={..,.,...}

Step1: Solve for counter c =100,

 {x100,y100}={x,y}/.FindRoot[{f1(x,y,c,d[[c]])==0,f2(x,y,c,d[[c]])==0},{x,a100},{y,b100}]

Step2: Solve for counter c =99

 {x99,y99}={x,y}/.FindRoot[{f1(x,y,c,d[[c]])==0,f2(x,y,c,d[[c]])==0},{x,a99},{y,b99}]

The starting points $(a100,b100)$ and $(a99,b99)$ are something I find by trial and error.

Step3: For counter c=98,

a98 = x99 + x99-x100;
b98 = y99 + y99-y100;

I know that my roots are monotonic in $c$, therefore I want my new start point to be the previous solution perturbed by how much more or less the previous solution was relative to the solution before that.

Finally when I have all my solutions, I would like to store them as a list so I could do more math with them.

I already know how to use Table and feed in the previous solution as the new start point.

 d = {0.5, 0.4, 0.5, 0.4, 0.5};
sol = {0.9, 0.4};
Table[sol={x,y}/.FindRoot[{x^2+y^2==a,x-y==d[[a]]},{x,sol[[1]]},{y,sol[[2]]}], {a,1,5}]

But I don't know enough about Mathematica Loop commands to figure out how to use the previous solution + the difference between the previous solution and the one before that, as the start point.

Also, I don't know when the counter should stop. I'd like for the counter to stop when the solutions first hit a particular region. For example:

Stop when $-4 <x < y < 0.1$ or if counter $c = 0$. So basically, I'd like my loop stopping condition to be some function of the counter and/or all the roots calculated so far.

Suppose more complicated stopping conditions are hard to figure out, I'd appreciate it if someone to tell me how run a loop with simple stopping conditions like $x<0.1$ unless ofcourse $c=0$.

EDIT(New stuff):Below is an implementation of Kguler's solution method

Ok, following Kgluer's comments, I have tried to mimic what he has suggested and it is sort of working but I am not entirely sure of what's going on and I wanna be absolutely certain that I am error free before I implement it on my actual problem. Ok here goes:

f = Table[{x + y == a*a, x - y == 0}, {a, 1, 5}]

ContourPlot[Evaluate[f], {x, 0, 25}, {y, 0, 25}]

enter image description here

I want to give my FindRoot a start point of $(0,0)$ and a start distance of $(0.5,0.5)$ to look for the first solution when $a=1$. Then when it computes the solution as $(0.5,0.5)$, I want it to look for the next solution, for $a=2$, near the first solution $(0.5,0.5)$+the difference between the first solution and the previous start point$(0.5,0.5)-(0,0)$. So it should look for solutions near $(1,1)$ when $a=2$ and so on and so forth.

The parameter $d$ below is superfluous for this problem but I just threw it in there because in my actual problem, $d$ like data shows up non-trivially.

d = {0, 0, 0, 0, 0};
sol = {0, 0};
add = {0.5, 0.5}
counter = 5;

data = NestWhileList[{#[[1]] + 1,{x, y} = {x, y} /.
  FindRoot[{x + y == #[[1]]*#[[1]], x - y == d[[#[[1]]]]}, {x, #[[2]][[1]] + #[[3]]  [[1]]}, {y, \#[[2]][[2]] + #[[3]][[2]]}],
{x - #[[2]][[1]], y - #[[2]][[2]]}} &,{1, sol, add},Not[2 < #[[2]][[2]] < #[[2]][[1]] < 3] &, 2, counter]

This code gives the following output.

{{1, {0, 0}, {0.5, 0.5}}, {2, {0.5, 0.5}, {0.5, 0.5}}, {3, {2., 2.}, {1.5, 1.5}}, {4, {4.5, 4.5}, {2.5, 2.5}}, {5, {8., 8.}, {3.5, 3.5}}, {6, {12.5, 12.5}, {4.5, 4.5}}}

So it looks like it is doing what I want it to do.. but I still don't fully understand many thing. Like what would change if I altered the 4th input of NestWhileList from 2 to 3? Or how NestWhileList test function knows to look at the counter. I am sure there are more things I don't understand so any help with writing good code and explanations will be greatly appreciated. Thanks.

$\endgroup$
4
  • $\begingroup$ Did you check the "while" constructs (NestWhileList, While, etc)? $\endgroup$ Sep 14, 2012 at 2:54
  • 1
    $\begingroup$ is this answer to a related question useful? $\endgroup$
    – kglr
    Sep 14, 2012 at 4:48
  • $\begingroup$ Thanks belisarius. I had been trying to get While, NestWhileList etc to work but it wasn't until Kguler's response did I realize that NestWhiileList allows for the use of all the output previously generated. $\endgroup$
    – Amatya
    Sep 14, 2012 at 20:20
  • $\begingroup$ @Amatya, I added a short update that deals with your second question. Pls check if it works as intended. $\endgroup$
    – kglr
    Sep 15, 2012 at 1:14

1 Answer 1

6
$\begingroup$

NestWhile and NestWhileList are the built-in functions that feature arguments that can be used to capture your requirements (looping until a condition is satisfied where the condition can depend on values in previous iterations).

The following is a simple version of the problem checking a stopping condition that depends only on the values in the current iteration. By using the 2nd and 4th arguments you can make the stopping condition depend on the values from any number of previous iterations.

 d = {0.5, 0.4, 0.5, 0.4, 0.5, 0.5, 0.4, 0.5, 0.5, 0.4, 0.5, 0.5, 0.4, 0.5, 0.5, 0.4, 0.5, 0.5, 0.4};
sol = {0.9, 0.4};
counter = 20;
NestWhileList[{#[[1]] + 1, 
  FindRoot[{x^2 + y^2 == #[[1]], x - y == d[[#[[1]]]]}, 
     {x, #[[2]][[1]]}, {y, #[[2]][[2]]}][[All, 2]]} &, 
  {1, sol}, 
  Not[2 < #[[2]][[2]] < #[[2]][[1]] < 3] &, 
  {1, 1}, 
  counter]

gives

{{1, {0.9, 0.4}}, {2, {0.911438, 0.411438}}, {3, {1.1798, 0.779796}}, 
 {4, {1.44896, 0.948958}}, {5, {1.6, 1.2}}, {6, {1.81125, 1.31125}}, 
 {7, {1.96391, 1.46391}}, {8, {2.06011, 1.66011}}, {9, {2.23431,   1.73431}}, 
{10, {2.35654, 1.85654}}, {11, {2.42711, 2.02711}}}

while, with smaller value for counter

counter = 5;
NestWhileList[{#[[1]] + 1, 
   FindRoot[{x^2 + y^2 == #[[1]],  x - y == d[[#[[1]]]]},
     {x, #[[2]][[1]]}, {y, #[[2]][[2]]}][[All, 2]]} &,
  {1, sol}, 
  Not[2 < #[[2]][[2]] < #[[2]][[1]] < 3] &, 
  {1, 1}, 
  counter]

iteration stops before the condition is satisfied and you get

 {{1, {0.9, 0.4}}, {2, {0.911438, 0.411438}}, 
  {3, {1.1798, 0.779796}}, {4, {1.44896, 0.948958}}, 
  {5, {1.6, 1.2}}, {6, {1.81125, 1.31125}}}

If you need only the last element of the list you can use NestWhile instead:

counter = 20;
NestWhile[{#[[1]] + 1, 
  FindRoot[{x^2 + y^2 == #[[1]], x - y == d[[#[[1]]]]},
    {x, #[[2]][[1]]}, {y, #[[2]][[2]]}][[All, 2]]} &,
  {1, sol}, 
  Not[2 < #[[2]][[2]] < #[[2]][[1]] < 3] &, 
  {1, 1},
  counter]

to get

 {11, {2.42711, 2.02711}}

EDIT: You can also use While to get the same results as above:

results = {{1, sol}};
i = 1;
While[Not[i > counter || (2 < sol[[2]] < sol[[1]] < 3)],
 sol =FindRoot[{x^2 + y^2 == i, x - y == d[[i]]},{x, sol[[1]]}, {y, sol[[2]]}][[All, 2]];
 i++; AppendTo[results, {i, sol}];]; 
results

UPDATE: Using the 4th argument of NestWhile to use the result history in the stopping test:

First, a modification of OP's second example that works as intended:

 data = NestWhileList[{#[[1]] +  1, 
      {x, y} = {x, y} /. 
      FindRoot[{x + y == #[[1]]*#[[1]], 
         x - y ==   d[[#[[1]]]]}, {x, #[[2]][[1]] + #[[3]][[1]]}, 
      {y, #[[2]][[2]] + #[[3]][[2]]}], 
      {x - #[[2]][[1]],  y - #[[2]][[2]]}} &,
 {1, sol, add}, 
 (Not[5 < {##}[[-1, 2, 2]] <= {##}[[-1, 2, 1]] < 10]) &, 
 2, 
 counter]

gives

 {{1, {0.5, 0}, {0.5, 0.5}}, {2, {0.5, 0.5}, {0., 0.5}},
  {3, {2.,  2.}, {1.5, 1.5}}, {4, {4.5, 4.5}, {2.5, 2.5}},
  {5, {8., 8.}, {3.5, 3.5}}}

In

 NestWhile[func, expr, test, k]

(start stopping test after k iterations, and test using the last k values), the expected argument pattern for the pure function test is that of the SlotSequence (##) object that keeps the k-long list of results. Using the compound expression

(Print[{##}]; Not[5 < {##}[[-1, 2, 2]] <= {##}[[-1, 2, 1]] < 10]) &

as your test function you can see its content and structure.

enter image description here

$\endgroup$
3
  • $\begingroup$ Hey Kguler,Thanks a lot. I understand in principle that if I set the fourth parameter in NestWhileList to be 2 then that enables me to use the previous 2 solutions in my "test" or also in the body of the "function" inside NestWhileList. However...I don't know how NestWhileList stores the previous 2 solutions and what I should refer to them as so I can call them inside my FindRoot. Can you please tell me how I do this? I've tried all combinations of #[[4]] or #[[4]][[2]] and all manners of things but I can't get it to work. The examples on the Wolfram website are too cryptic for a beginner. $\endgroup$
    – Amatya
    Sep 14, 2012 at 8:40
  • $\begingroup$ you get some hints onthe structure of what is stored by adding Print[{##}]; as part of the third argument: (Print[{##}];testfunction[...])&. You can also put the SlotSequence (##) that holds the current values of what is stored inside a list and give it a name: say, storedstuff={##}; also as part of the third argument. Then you can use storedstuff and its parts as you wish anywhere. Hope this helps. I will try to update my answer with an example of how to use the previous iteration results. BTW, I agree with you - related material in the docs could use more detailed usage examples. $\endgroup$
    – kglr
    Sep 14, 2012 at 11:19
  • $\begingroup$ Kguler, Thank you! Now I understand. awesome! $\endgroup$
    – Amatya
    Sep 15, 2012 at 20:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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