I'm trying to understand this behavior of FindRoot. Consider a sample function (the one I'm actually interested in is far more complicated, but has similar issues) and the following arguments:
crazyFunction[x_, y_] := N@Norm[{x + 2 y}]
yact = RandomReal[{-10, 10}, 2]~Join~{RandomReal[{100, 250}]};
gv = yact + RandomReal[{-.1, .1}, 2]~Join~{RandomReal[{-5, 5}]};
sampledata = crazyFunction[#, {a, b, c}] == crazyFunction[#, yact] & /@
{{1, 2, 3}, {2, 3, 4}, {4, 5, 6}};
Basically, I'm applying the sample function for a particular yact value, at three x values, and setting it equal to the function evaluated with three "unknown" y values {a,b,c}. To solve for the "unknown" values, I used FindRoot with initial guessed value gv randomly perturbed from the actual values:
sol = FindRoot[sampledata, Transpose@{{a, b, c}, gv}, MaxIterations -> 1000]
Note, this likely will throw a warning (* FindRoot::lstol: The line search decreased the step size to within tolerance specified by AccuracyGoal and PrecisionGoal ... *).
To evaluate the quality of the solution, I compare the Norm of the difference between the actual yact and the solved y (normalized to the Norm of yact):
Norm[yact - {a, b, c} /. sol]/Norm[yact]
(* Out[]:= 0.0540657 *)
which isn't a terrible value.
My thinking here is, I have three unknowns -- a, b, and c -- and three different equations for the different x values, so that should be enough to solve the problem. In fact, without three equations FindRoot won't work. I.e.:
FindRoot[sampledata[[1]], Transpose@{{a, b, c}, gv}, MaxIterations -> 1000]
(* FindRoot::nveq: The number of equations does not match the number of variables in... *)
But, if instead of using three, different equations, I simply repeat the same equation three times:
sampledata = Table[crazyFunction[#, {a, b, c}] == crazyFunction[#, yact] &@{1, 2,3}, {3}];
sol = FindRoot[sampledata, Transpose@{{a, b, c}, gv}, MaxIterations -> 1000];
Not only does it not give the lstol warning, but it actually gets a more accurate result! Consider:
dat=Table[yact=RandomReal[{-10,10},2]~Join~{RandomReal[{100,250}]};
gv=yact+RandomReal[{-.1,.1},2]~Join~{RandomReal[{-5,5}]};
sampledata=crazyFunction[#,{a,b,c}]==crazyFunction[#, yact]&/@{{1,2,3},{2,3,4},{4,5,6}};
sol=Quiet@FindRoot[sampledata,Transpose@{{a,b,c},gv},MaxIterations->1000];
Norm[yact-{a,b,c}/.sol]/Norm[yact],{1000}];
datSamedata=Table[
yact=RandomReal[{-10,10},2]~Join~{RandomReal[{100,250}]};
gv=yact+RandomReal[{-.1,.1},2]~Join~{RandomReal[{-5,5}]};
sampledata=Table[crazyFunction[#,{a,b,c}]==crazyFunction[#, yact]&@{1,2,3},{3}];
sol=Quiet@FindRoot[sampledata,Transpose@{{a,b,c},gv},MaxIterations->1000];
Norm[yact-{a,b,c}/.sol]/Norm[yact],{1000}];
Histogram[{dat, datSamedata}, "Log"]

Note the log-binning. Using the same equation three times is far more accurate than using three different equations!
So, my question is: Why is repeating the same equation three times far more accurate than using three different equations?


SeedRandom[3]to your first block of code, then you will consistently generate the lstol error, rather than just "likely" generate it. – Mark McClure Sep 21 '12 at 15:47