Message Boards Message Boards

0
|
1313 Views
|
5 Replies
|
3 Total Likes
View groups...
Share
Share this post:

Why does nested Integration works for a single function but not for a list of functions ?

Posted 7 months ago

I try to apply nested integration to lists of functions. The code works fine for a single function (not a list), but returns error when trying to calculate the same expression with a list of functions.

A function f[x,args...] is simplified preliminary by defining argument x (let say X={1,2,3,4}) and I obtain a list of functions for given x's. Next step, I define integral functions f2[args...] and f3[args...] and try to compute a nested integration with the list, desiring to obtain a list of result for all x's. May it be done without use of 'Indexed' or calling a part of the function list in general f[[i]] ? I would like to send a list into Nintegrates and obtain list of outputs.

Currently my solution is the following, but I like to avoid use of indexes:

ListExpressions = {x + y + z, 2 x + y + z, 3 x + y + z, 4 x + y + z, 5 x + y + z};
f[x_?NumericQ, y_?NumericQ, z_?NumericQ, KK_?NumericQ] := Evaluate[Indexed[ListExpressions, KK]]
f2[K1_?NumericQ, y_?NumericQ, z_?NumericQ, KK_?NumericQ] := NIntegrate[f[x, y, z, KK], {x, 0, K1}];
f3[K1_?NumericQ, K2_?NumericQ, K3_?NumericQ, KK_?NumericQ] := NIntegrate[f2[K1, y, z, KK], {y, 0, K2}, {z, 0, K3}];
f3[1,1,10,#]&/@Range[5]

Out= {60.,65.,70.,75.,80.}
POSTED BY: Aka Kopejkin
5 Replies

The basic problem

I tried to simplify the question down to the following. My apologies if I oversimplified it. The basic question is why does NIntegrate[] succeed on this:

NIntegrate[{t^2, t^3}, {t, 0, 1}]
{0.333333, 0.25}

But fail on this:

integrand[t_?NumericQ] := {t^2, t^3};
NIntegrate[integrand[t], {t, 0, 1}]

NIntegrate::inum: Integrand integrand[t] is not numerical at {t} = {0.00795732}.

NIntegrate::inum: Integrand integrand[t] is not numerical at {t} = {0.00795732}.

 NIntegrate[integrand[t], {t, 0, 1}]

NIntegrate threads over vectors but does not integrate vector-valued functions

Well, the "why not" question could be answered only by the design team at WRI, but it appears the choice was for NIntegrate to integrate scalar-valued functions only. When the integrand expression is literally a List[], then NIntegrate[] is threaded over the list. It is in effect "listable" over the first argument. NIntegrate will integrate the elements of the list if they are scalar-valued. On the other hand, when the argument has a head other than List, NIntegrate expects the value to be a scalar. If it is not, it complains and gives up.

One may inspect the thread with Trace or TracePrint:

TracePrint[
 NIntegrate[{t, {t^2, t^3}}, {t, 0, 1}],
 TraceDepth -> 2
 ]
 NIntegrate[{t,{t^2,t^3}},{t,0,1}]
  NIntegrate
 {NIntegrate[t,{t,0,1}],NIntegrate[{t^2,t^3},{t,0,1}]}
  List
  NIntegrate[{t^2,t^3},{t,0,1}]
  {NIntegrate[t^2,{t,0,1}],NIntegrate[t^3,{t,0,1}]}
  {0.333333,0.25}
 {0.5,{0.333333,0.25}}  

Out[..]=    
  {0.5, {0.333333, 0.25}}

One might also infer that NIntegrate is evaluated independently on each element of a list from the following:

NIntegrate[{t^2, integrand[t]}, {t, 0, 1}]

NIntegrate::inum: Integrand integrand[t] is not numerical at {t} = {0.00795732}.
NIntegrate::inum: Integrand integrand[t] is not numerical at {t} = {0.00795732}.

{0.333333, NIntegrate[integrand[t], {t, 0, 1}]}

Possible workaround

One may integrate a vector-valued function with NDSolve:

Block[{a = 0, b = 1},
 NDSolveValue[{y'[t] == integrand[t], y[a] == 0 integrand[0]}, 
  y[b], {t, a, b}]
 ]
{0.333333, 0.25}

Well, 0 integrand[0] is a slick way to get a zero vector of the same dimension as integrand[t]. One might prefer to write it explicitly as {0, 0} when it is known that the integrand is of dimension 2, say.

One difference is that NDSolve controls error locally whereas NIntegrate uses a global estimate of the error. Other differences are that NIntegrate has sophisticated handling of singularities and integrates multivariate functions.

POSTED BY: Michael Rogers

This works:

ListExpressions = {x + y + z, 2  x + y + z, 3  x + y + z, 
   4  x + y + z, 5  x + y + z};
g[x_?NumericQ, y_?NumericQ, z_?NumericQ, KK_Integer] = 
  Quiet@ListExpressions[[KK]];
g2[K1_?NumericQ, y_?NumericQ, z_?NumericQ, KK_?NumericQ] := 
  NIntegrate[g[x, y, z, KK], {x, 0, K1}];
g3[K1_?NumericQ, K2_?NumericQ, K3_?NumericQ, KK_?NumericQ] := 
  NIntegrate[g2[K1, y, z, KK], {y, 0, K2}, {z, 0, K3}];
g3[1, 1, 10, #] & /@ Range[5]
POSTED BY: Gianluca Gorni
Posted 7 months ago

Thank you ! My fault, I only mentioned 'Indexed' but in fact I assume: "May it be done without use of 'Indexed' or calling a part of the function list in general f[[i]] ? I would like to send a list to Nintegrates and obtain list of outputs." The post was corrected correspondingly.

POSTED BY: Aka Kopejkin
Posted 7 months ago

I tried to boil your example down to simpler situation. Here is an input that does not work:

Clear[g2, g3];
g2[y_?NumericQ] := NIntegrate[{1}, {x, 0, 1}];
g3[K1_?NumericQ] := NIntegrate[g2[y], {y, 0, K1}];
g3[1]

The following variation does work:

Clear[g2, g3];
g2[y_] := NIntegrate[{1}, {x, 0, 1}];
g3[K1_?NumericQ] := NIntegrate[g2[y], {y, 0, K1}];
g3[1]

and also this

Clear[g3];
g3[K1_?NumericQ] :=
  NIntegrate[NIntegrate[{1}, {x, 0, 1}],
   {y, 0, K1}];
g3[1]

I have no explanation.

POSTED BY: Updating Name
Posted 7 months ago

Michael, thank you for the comprehensive answer.

POSTED BY: Aka Kopejkin
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract