I have noticed that there are functions in Mathematica that are ignoring already set parameters. I.e. Plot
:
x=2;Plot[x^2,{x,0,2}]
produces a Plot, although x is set to 2.
On the other hand, some functions do not work this way, I.e. Integrate
:
x=2;Integrate[x^2,{x,0,2}]
produces an error ("Invalid integration variable or limit(s) in {2,0,2}"). Here Mathematica replaced x by 2 before the integration.
For some of my own functions I want to mimic the behavior of Plot, not having to bother if a Symbol already has a value.
My Question is: How to achieve this? How to make this as fail-safe as possible (with reasonable effort)?
What I've done so far:
As an example I tried to make a function myInt
, that makes x=2;myInt[x,{x,0,2}]
work similar as Plot (integrating while ignoring that x is set). I tried to find an answer how to achieve this by using GeneralUtilities`PrintDefinitions
on Plot
and Integrate
and some other functions, to see where the difference in behavior comes from, but had no success.
I searched the documentation center and found the promising Unevaluated
in combination with the Attribute HoldAll
, and naively tried
SetAttributes[myInt,HoldAll];
myInt[expr_,{var_,limit1_,limit2_}]:=Integrate[
Unevaluated[expr],{Unevaluated[var],limit1,limit2}
];
As an example I tried
(*In*) x=2;myInt[x^2,{x,0,b}]
(*Out*) 4b
This is not the expected output b^3/3
. Trying to see what went wrong, I used Trace
on that use of myInt
. Actually there one can see that Mathematica does the following step
Integrate[Unevaluated[x^2],{Unevaluated[x],0,b}]
Integrate[x^2,{Unevaluated[x],0,b}]
Then evaluates the x inside the integral to 2 and integrates with respect to Unevaluated[x], which is not inside the Integral anymore, yielding 4b. Due to this unsatisfactory behavior, I constructed a more complicated function:
SetAttributes[myInt2,HoldAll];
myInt2[expr_,{var_,limit1_,limit2_}]:=Module[
{exprI}
,
exprI=Function[{varI},
Evaluate[ReleaseHold[
ReplaceAll[Hold[expr],HoldPattern[var]->varI]
]]
];
(*what I actually want to do comes here, i.e.*)
Integrate[exprI[varI],{varI,limit1,limit2}]
];
As a quick check I tried myInt2
on the somewhat more complicated Log[x]^3
:
(*In*) myInt2[Log[x]^3,{x,0,2}]==Integrate[Log[x]^3,{x,0,2}]
(*Out*) True
and
x=2;
AbsoluteTiming[Integrate[Log[x]^3,{x,0,2}]]
AbsoluteTiming[myInt2[Log[x]^3,{x,0,2}]]
Remove[x];
AbsoluteTiming[Integrate[Log[x]^3,{x,0,2}]]
The first Integrate
fails with an error, as expected and shown above. myInt2
works and shows the same result as the last line (for completeness: 2 (-6+(-3+Log[2]) Log[2]^2+Log[64])
)
Most of the time myInt2
is slower than Integrate
, but I think this is caused by the localization of variables and additional steps Mathematica has to perform. That's OK for me (Nevertheless, improving execution speed is always nice). But I have concerns, that expressions that contain i.e. Hold
(or similar) break the desired behavior, since I use Evaluate
and ReleaseHold
in my definition of myInt2
.
Did I achieve a method to mimic the behavior of Plot
, concerning variables that were used somewhere in my code before?
To me it seems so, but it looks and feels very clumsy. Is there a better way of doing this (or even better: is there a built-in method to do so, that I did not found, or a much simpler way I just did not thought of?)
Is the way I constructed myInt2
fail-safe, so that I can use such a construction for more complicated functions?
I don't think so, but right now I have no example for this at hand. Sorry!
Maybe someone has more elaborate ideas on how to do this and I would be happy if you share your thoughts/improvements with me. Maybe a separate Context inside the Module
(or a Block
), like in Leonid Shifrin's Answer to this question, could be used for this purpose?
(PS: This is my first post here and I'm no native speaker. If my grammar is bad, something is unclear or formatting is poor, please let me know and I'll try to correct it or explain better. I tried to be as detailed as possible.)
myInt3[expr_, {var_, limit1_, limit2_}] := Block[ {var}, Integrate[expr, {var, limit1, limit2}]]
works as expected. I did not find this great answer when I searched for possible solutions $\endgroup$