0
$\begingroup$

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.)

$\endgroup$
2
  • 5
    $\begingroup$ See "Implementing functions that localize their arguments" in a/567 $\endgroup$
    – Kuba
    Commented Sep 9, 2017 at 20:59
  • $\begingroup$ Thank you very much! This is much easier than my approach. 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$
    – Lars H.
    Commented Sep 9, 2017 at 21:04

0

Browse other questions tagged or ask your own question.