Skip to main content

performance tuning - Integration strategies for oscillatory multidimensional function


I am seeking to integrate a highly oscillatory, multidimensional function. I am currently using NIntegrate's QuasiMonteCarlo approach. However, this is time-consuming and, given my current resources, not very accurate. How can I obtain more reliable estimates of the beasty integral given below? As the function itself will be integrated at a later stage, I am also interested in speeding up the function evaluation.


The integral to be solved:


fun[r_?NumericQ, d_?NumericQ, c_, opts:OptionsPattern[]]:=
NIntegrate[
Cos[(c (d^2+r^2-2 d r Cos[ta] - 3 ((-r+d Cos[ta]) Cos[tb]+d Cos[a] Sin[ta] Sin[tb])^2)) / Abs[d^2+r^2-2 d r Cos[ta]]^(5/2)]
Cos[(c (d^2+r^2+2 d r Cos[ta] - 3 ((r+d Cos[ta]) Cos[tb]+d Cos[a] Sin[ta] Sin[tb])^2)) / Abs[d^2+r^2+2 d r Cos[ta]]^(5/2)]

* Sin[ta]*Sin[tb]/(2*Pi),
{ta,0,Pi},
{tb,0,Pi/2},
{a,0,Pi},
Evaluate@FilterRules[{opts},Options[NIntegrate]]
]

Typically, $d$ = 2, $r$ is in the range from 0 to Infinity (with the small values and $r$=$d$ posing problems), and $c$ is in the range from 100 to 3000. A typical function call is:


AbsoluteTiming[fun[3, 2, 400, Method -> "QuasiMonteCarlo", PrecisionGoal -> 6, 
MaxPoints -> 40000000]]

(* -> {102.3215798,-0.00442278} *)

This issues a NIntegrate::maxp warning and indicates an error estimate of 0.00011. Using the default strategy I obtain:


AbsoluteTiming[
fun[3, 2, 400, MaxRecursion -> 20, Method -> {GlobalAdaptive, MaxErrorIncreases -> 10000}]]
(* -> {9.3912165,-0.00439357} *)

and a NIntegrate::eincr warning. Estimated error: 0.0369.


How to proceed from here? Thank you for your help.



Answer




Since no comment or answer has given as of the time I saw this post, and I don't have enough reputations to leave a comment, let me give a quick answer I used to solve the same kind of problems. I'm sure there must be a better way to do it with Mathematica, so this is just a beginning.


To evaluate an N-dimensional integral with a highly oscillatory integrand (which may peak at a particular small region in the N-dimensional space), I think all built-in methods and strategies of NIntegrate are not applicable. They are either super slow, or give a very inaccurate result which is easy to be proven wrong. Particularly, although to my knowledge Monte Carlo seems to be the best candidate for integrating a general multi-dimensional function (i.e., not knowing the symmetries in the integration region, so can't further simplify it and/or attack it with other strategies designed for special purposes), only when the integrand is smooth enough can Monte Carlo give a relatively good estimate and fast convergence. As a result, I would suggest using so-called "importance-sampling" Monte Carlo, which is not provided in built-in functions yet. (That's odd!)


Fortunately, Thomas Hahn (the author of FormCalc, FeynArts, etc.) has implemented this kind of algorithm in Mathematica (and C/C++ and Fortran as well). It's called the Cuba library. It provides both importance sampling and stratified sampling algorithms, and also the mixture of both. It is still being developed and under maintenance, so at least it works with Mathematica 8. Particularly, I would suggest using its Vegas routine, which is exactly designed for evaluating multi-dimensional integral, to solve your problem. Since it has a good user manual, I would simply refer you to that without further explanation.


However, if you don't mind doing the integral with C/C++, I would say that the Vegas routine provided in the GNU Scientific Library (GSL) converges way faster than the Cuba library does. Not sure why, maybe it has to do with the MathLink interface. Anyway, this is beyond the scope of this site.


Comments

Popular posts from this blog

functions - Get leading series expansion term?

Given a function f[x] , I would like to have a function leadingSeries that returns just the leading term in the series around x=0 . For example: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x)] x and leadingSeries[(1/x + 2 + (1 - 1/x^3)/4)/(4 + x)] -(1/(16 x^3)) Is there such a function in Mathematica? Or maybe one can implement it efficiently? EDIT I finally went with the following implementation, based on Carl Woll 's answer: lds[ex_,x_]:=( (ex/.x->(x+O[x]^2))/.SeriesData[U_,Z_,L_List,Mi_,Ma_,De_]:>SeriesData[U,Z,{L[[1]]},Mi,Mi+1,De]//Quiet//Normal) The advantage is, that this one also properly works with functions whose leading term is a constant: lds[Exp[x],x] 1 Answer Update 1 Updated to eliminate SeriesData and to not return additional terms Perhaps you could use: leadingSeries[expr_, x_] := Normal[expr /. x->(x+O[x]^2) /. a_List :> Take[a, 1]] Then for your examples: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x), x] leadingSeries[Exp[x], x] leadingSeries[(1/x + 2 + (1 - 1/x...

How to thread a list

I have data in format data = {{a1, a2}, {b1, b2}, {c1, c2}, {d1, d2}} Tableform: I want to thread it to : tdata = {{{a1, b1}, {a2, b2}}, {{a1, c1}, {a2, c2}}, {{a1, d1}, {a2, d2}}} Tableform: And I would like to do better then pseudofunction[n_] := Transpose[{data2[[1]], data2[[n]]}]; SetAttributes[pseudofunction, Listable]; Range[2, 4] // pseudofunction Here is my benchmark data, where data3 is normal sample of real data. data3 = Drop[ExcelWorkBook[[Column1 ;; Column4]], None, 1]; data2 = {a #, b #, c #, d #} & /@ Range[1, 10^5]; data = RandomReal[{0, 1}, {10^6, 4}]; Here is my benchmark code kptnw[list_] := Transpose[{Table[First@#, {Length@# - 1}], Rest@#}, {3, 1, 2}] &@list kptnw2[list_] := Transpose[{ConstantArray[First@#, Length@# - 1], Rest@#}, {3, 1, 2}] &@list OleksandrR[list_] := Flatten[Outer[List, List@First[list], Rest[list], 1], {{2}, {1, 4}}] paradox2[list_] := Partition[Riffle[list[[1]], #], 2] & /@ Drop[list, 1] RM[list_] := FoldList[Transpose[{First@li...

front end - keyboard shortcut to invoke Insert new matrix

I frequently need to type in some matrices, and the menu command Insert > Table/Matrix > New... allows matrices with lines drawn between columns and rows, which is very helpful. I would like to make a keyboard shortcut for it, but cannot find the relevant frontend token command (4209405) for it. Since the FullForm[] and InputForm[] of matrices with lines drawn between rows and columns is the same as those without lines, it's hard to do this via 3rd party system-wide text expanders (e.g. autohotkey or atext on mac). How does one assign a keyboard shortcut for the menu item Insert > Table/Matrix > New... , preferably using only mathematica? Thanks! Answer In the MenuSetup.tr (for linux located in the $InstallationDirectory/SystemFiles/FrontEnd/TextResources/X/ directory), I changed the line MenuItem["&New...", "CreateGridBoxDialog"] to read MenuItem["&New...", "CreateGridBoxDialog", MenuKey["m", Modifiers-...