Sometimes I do it this way:
Block[{NIntegrate, x, y, z},
intfunc[z_] = NIntegrate[integrand, {x, -5, 5}, {y, -10, 1000}];
];
intfunc[7.]
(* 3.5009*10^7 *)
It's not a great general programmatic way to go, but in the middle of solving a problem, in which I have constructed an expression integrand
, this is to me an easy way. Blocking x
, y
, and z
should be unnecessary (or else integrand
could not depend on them), but sometimes I'm over-cautious.
Update: Explanation
The problem has three aspects: (1) to get the code for integrand
to evaluate (2) before the pattern named z
is evaluated (3) without NIntegrate
evaluating, all during the evaluation of Set
or SetDelayed
. I'll say something about the optional ?NumericQ
at the end.
There are various ways to address this. One way is to go around the problem entirely and use functions that have all parameters as arguments. This is a better way to write a program. This is the workaround the OP points out in the question (and repeated by Bob Hanlon).
But there are ways to address the problem directly. Block
, as in
Block[{NIntegrate}, code]
blocks the evaluation of NIntegrate
during the execution of code
. Basically, the symbol is temporarily cleared of all its values and attributes. So when the code
intfunc[z_] = NIntegrate[integrand, {x, -5, 5}, {y, -10, 1000}];
is evaluated, all the arguments of NIntegrate
are evaluated, and the definition becomes
intfunc[z_] = NIntegrate[<fn expr in x,y,z>, {x, -5, 5}, {y, -10, 1000}];
where <fn expr in x,y,z>
represents the value of integrand
; and that is what intfunc[z_]
is set to be equal to.
Another solution is substitution, which I skipped because I thought someone had already suggested it; e.g.,
intfunc[z0_] := NIntegrate[integrand /. z -> z0, {x, -5, 5}, {y, -10, 1000}];
The overhead from ?NumericQ
is negligible. It could be quite desirable to use intfunc[z0_?NumericQ]...
in the definitions above, especially if intfunc[z]
is to be passed to another solver.
Why doesn't this work, with or without NumericQ
?
intfunc[z_] := NIntegrate[integrand, {x, -5, 5}, {y, -10, 1000}];
Inspecting the DownValues
of intfunc
will help the explanation:
DownValues[intfunc]
(* {HoldPattern[intfunc[z_]] :> NIntegrate[integrand, {x, -5, 5}, {y, -10, 1000}]} *)
SetDelayed
created a rewrite rule that replaces all instances of the symbol z
in the literal, unevaluated expression NIntegrate[integrand, {x, -5, 5}, {y, -10, 1000}]
by the argument to intfunc
. There are no instances of z
in that code. So both of these calls,
intfunc[7.]
intfunc[10.]
result in the same thing
NIntegrate[integrand, {x, -5, 5}, {y, -10, 1000}]
which is then evaluated. At this point integrand
is evaluated by NIntegrate
and the symbolic z
shows up. In @march's suggestion
intfunc[z0_] := Block[{z = z0}, NIntegrate[ ... ]]
the value of z
would be equal to the value of the argument z0
; if numeric, the evaluation of NIntegrate
would proceed with no other difficulties except those posed by a pesky integrand.
As a final remark, the OP's actual expression for integrand
is certainly pesky. IMO the integrand itself is the only reason that NIntegrate
is slow.
intfunc[z0_] := Block[{z = z0}, NIntegrate[ ... ]]
$\endgroup$