2
$\begingroup$

I'm having some syntax problems with finding a fit to an equation that doesn't have an analytical expression for it's integral. Because I think the problem is one of syntax, I am substituting a simple polynomial function and test data in place of my more complicated model and real data.

ClearAll[x, y, a, b, c, T, z, data, data2, X]

y = a*x^2 + b*x + c[T];

c[T_?NumericQ] := 
Piecewise[{{0, T == 1}, {1, T == 2}, {-1, T == 3}, {Indeterminate, 
 True}}];

z[X_?NumericQ, T_?NumericQ] := NIntegrate[y, {x, 0, X}];

data2={{0, 1, 0.0178038}, {1, 1, 1.34999}, {2, 1, 6.6659}, {3, 1, 
17.979}, {4, 1, 37.409}, {0, 2, 0.0432301}, {1, 2, 2.28057}, {2, 2, 
8.66741}, {3, 2, 21.0094}, {4, 2, 41.3772}, {0, 3, 0.000201272}, {1,
3, 0.309374}, {2, 3, 4.62384}, {3, 3, 14.9498}, {4, 3, 33.4167}};

FindFit[data2, z[X, T], {{a, 1}, {b, 2}}, {X, T}]

Results in the error message

NIntegrate::inumr: The integrand b x+a x^2+c[T] has evaluated to non-numerical values     for all sampling points in the region with boundaries {{0,1.}}. >>

NIntegrate::inumr: The integrand b x+a x^2+c[T] has evaluated to non-numerical values for all sampling points in the region with boundaries {{0,2.}}. >>

NIntegrate::inumr: The integrand b x+a x^2+c[T] has evaluated to non-numerical values for all sampling points in the region with boundaries {{0,3.}}. >>

General::stop: Further output of NIntegrate::inumr will be suppressed during this calculation. >>

FindFit::nrlnum: The function value {-0.0178038,-1.34999+NIntegrate[y,{x,0.,1.}],-6.6659+NIntegrate[y,{x,0.,2.}],-17.979+NIntegrate[y,{x,0.,3.}],<<8>>,-4.62384+NIntegrate[y,{x,0.,2.}],-14.9498+NIntegrate[y,{x,0.,3.}],-33.4167+NIntegrate[y,{x,0.,4.}]} is not a list of real numbers with dimensions {15} at {a,b} = {1.,2.}. >>

Because this is just a simple polynomial, I can use Integrate instead and then there is no problem

FindFit[data2, Integrate[y, {x, 0, X}], {{a, 1}, {b, 2}}, {X, T}] 

returns

{a -> 1.01625, b -> 1.96484}

I would appreciate any help in fixing my code. I looked around for other examples of people having a similar problem but they were all related to needing to use "?NumericQ" to delay the evaluation of NIntegrate until after numeric values were passed into it.

Am I using "?NumericQ" correctly? The error message about the integrand evaluating to a non-numerical value makes me think that it is still trying to evaluate NIntegrate without applying the values for X and T.

$\endgroup$
  • $\begingroup$ (1) You want to also define (and use) y as a function of the various parameters. See the response posted by @Oska. $\endgroup$ – Daniel Lichtblau Dec 9 '14 at 15:30
  • $\begingroup$ (2) (Note to readers) While a tad more effort could have been extended to understand the error message, the post shows reasonable work, an effort to "do things right", and a reasonably posed question. Not sure why it got a down vote or several votes to close. Is this really readily found in the documentation? $\endgroup$ – Daniel Lichtblau Dec 9 '14 at 15:33
  • $\begingroup$ Thanks @Daniel Lichtblau. I did try to do the right thing and learn from earlier posts before posting my own problem. Looking at the answers from Öskå and Michael E2, I can understand if some more experienced users found the problem to be obvious but after reading through both some Wolfram support articles and some past postings here with similar sounding titles it was not obvious to me. $\endgroup$ – Pete in Perth Dec 10 '14 at 3:26
4
$\begingroup$

Too long for a comment:

ClearAll[x, y, a, b, c, T, z, data2, X]
y[a_, b_, x_, T_] := a*x^2 + b*x + c[T]; 
c[T_?NumericQ] := Piecewise[{{0, T == 1}, {1, T == 2}, {-1, T == 3}, {Indeterminate, True}}];
z[X_?NumericQ, T_?NumericQ, a_?NumericQ, b_?NumericQ] := NIntegrate[y[a, b, x, T], {x, 0, X}];
data2 = {{0, 1, 0.0178038}, {1, 1, 1.34999}, {2, 1, 6.6659}, {3, 1, 17.979},
         {4, 1, 37.409}, {0, 2, 0.0432301}, {1, 2, 2.28057}, {2, 2, 8.66741}, 
         {3, 2, 21.0094}, {4, 2, 41.3772}, {0, 3, 0.000201272}, {1, 3, 0.309374}, 
         {2, 3, 4.62384}, {3, 3, 14.9498}, {4, 3, 33.4167}};
FindFit[data2, z[X, T, a, b], {{a, 1}, {b, 2}}, {X, T}]

For both Integrate and NIntegrate it gives:

{a -> 1.01625, b -> 1.96485}
$\endgroup$
  • 2
    $\begingroup$ For the version with NIntegrate, it's probably a good idea to put ?NumericQ on a_ and b_, too. Then Quiet can be dropped, and the user would still see any important errors and warnings (e.g. convergence problems for different data and/or model). $\endgroup$ – Michael E2 Dec 9 '14 at 18:50
  • $\begingroup$ @MichaelE2 You are right, I was feeling lazy and I didn't try to improve it, thank you. $\endgroup$ – Öskå Dec 9 '14 at 19:14
  • $\begingroup$ Yeah, I sometimes feel the same way. :) $\endgroup$ – Michael E2 Dec 9 '14 at 19:30
  • $\begingroup$ Thank you very much to both Öskå for showing me how to modify my code and to Michael E2 for explaining where I went wrong and why Öskå's code works while mine didn't. $\endgroup$ – Pete in Perth Dec 10 '14 at 2:15
6
$\begingroup$

On the borderline of comment and answer:

I've found it helpful to read the error messages carefully. They contain important information specific to your problem. These are telling you that b x+a x^2+c[T] is not a number when a number is substituted for x. In particular, a and b are nonnumeric symbols. It's complicated why the symbol T is present -- it certainly suggests that ?NumericQ might have failed (it didn't) -- so skip that for now. It's enough to notice that the integral is being called on nonnumeric a and b. Evidently, they, too, need to be protected by ?NumericQ.

To do that, you need to make the model and the user functions it calls depend on all the variables and parameters, including a and b. (See Öskå's answer.) One of the trickier things in programming to understand is the scope of symbols. In this case, the issue is that global symbols and function parameters with the same name are in fact different. Even experienced programmers are tempted to use a global symbol instead of a parameter -- who wants to type all those function arguments every time? But it is a bug waiting to happen. Maybe it will, maybe it won't. An experienced programmer can often predict when it is safe, but the bug is still lurking. In your case, the main culprit is y, which contains the global symbols a, b, c and T. (Again see Öskå's answer.) Now the T shows up in the error message because of this. In the OP's definition of z, T is a parameter. Its value is substituted for any symbol T that appears in the unevaluated right-hand side NIntegrate[y, {x, 0, X}]. But there are no T in the RHS. After parameter substitution, the RHS is evaluated and then y is evaluated. The T shows up at that time, too late for the substitution.

The advice about explicitly including all symbols on which a function depends as arguments of the function has been given many times by many people. The one I remember best is Issue with scope of variables

$\endgroup$
  • $\begingroup$ Thank you @Michael E2 for explaining both Öskå's code and where I went wrong. $\endgroup$ – Pete in Perth Dec 10 '14 at 3:29

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.