How to use a variable in a function that can't be clobbered by variable name collision?
How to use a variable in a function that can't be clobbered by variable name collision?
Not really sure what the right question to ask is. But here's what I'm having trouble with:
ClearAll[Evaluate[Context <> "*"]]
klDivergence[d1_, d2_] := NExpectation[Log[ PDF[d1, x]/PDF[d2, x] ], x [Distributed] d1]
d1 = NormalDistribution[0, 1];
d2 = NormalDistribution[5, 1];
klDivergence[d1, d2]
x=0
klDivergence[d1, d2]
The first call to klDivergence works fine. The second one gives me an error or warning "NIntegrate::itraw: Raw object 0 cannot be used as an iterator."
What's the right way to code this, so that I can have a variable of integration inside my function that is not affected by external code?
2 Answers
2
Localize x
in a Module
:
x
Module
klDivergence[d1_, d2_] := Module[x,
NExpectation[Log[PDF[d1, x]/PDF[d2, x]], x [Distributed] d1]]
With[x, ...]
One could also use
[FormalX]
as in klDivergence[d1_, d2_] := NExpectation[ Log[PDF[d1, [FormalX]]/ PDF[d2, [FormalX]]], [FormalX] [Distributed] d1]
. It cannot be overwritten because it is Protected
. Comes close to With[x, ...]
, doesn't it?– Henrik Schumacher
Sep 1 at 17:23
[FormalX]
klDivergence[d1_, d2_] := NExpectation[ Log[PDF[d1, [FormalX]]/ PDF[d2, [FormalX]]], [FormalX] [Distributed] d1]
Protected
With[x, ...]
@HenrikSchumacher It can be overwritten with
Block[[FormalX] = 1,...]
.– Michael E2
Sep 1 at 18:18
Block[[FormalX] = 1,...]
@MichaelE2 Oha, you're right! Okay, a further reason not to use it. =D
– Henrik Schumacher
Sep 1 at 18:20
John Doty's Module
method is used a lot. Alternatively, some internal functions use K[n]
, where n
is an integer chosen to make K[n]
unique, especially for the dummy variable of integration or summation. Something like the following effectively carries this out:
Module
K[n]
n
K[n]
klDivergence[d1_, d2_] :=
With[serno = Max@0, Cases[d1, d2, K[n_Integer] :> n, Infinity] + 1,
NExpectation[Log[PDF[d1, K[serno]]/PDF[d2, K[serno]]],
K[serno] [Distributed] d1]
];
However K
is not Protected
, so the usage is not foolproof. A user can assign a definition to K
and mess the function up; it would also mess up internal functions that use K
. So if what's good enough for Wolfram is good enough for you, you have a solution.
K
Protected
K
K
A little safer would be to Block
K
.
Block
K
klDivergence[d1_, d2_] := Block[K,
With[serno = Max@0, Cases[d1, d2, K[n_Integer] :> n, Infinity] + 1,
NExpectation[Log[PDF[d1, K[serno]]/PDF[d2, K[serno]]],
K[serno] [Distributed] d1]
]];
This would block any user definition of K
while NExpectation
is being computed. That's probably okay in this use-case, as well as most use cases; however, to block a user's definition from working does seem like a hole for a potential bug to creep through. Of course a user should not be assigning values to K
; that explicit advice is kept from users (i.e., it is not found in the documentation, at least not easily), but it is implied by the advice, "you should always choose names for your own variables that start with lowercase letters."
K
NExpectation
K
Another method used sometimes is to create one's own, perhaps Private`
, context; for example, foo`x
or foo`Private`x
:
Private`
foo`x
foo`Private`x
klDivergence[d1_, d2_] := Block[foo`x,
NExpectation[Log[PDF[d1, foo`x]/PDF[d2, foo`x]],
foo`x [Distributed] d1]
];
Thanks for contributing an answer to Mathematica Stack Exchange!
But avoid …
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
But avoid …
To learn more, see our tips on writing great answers.
Required, but never shown
Required, but never shown
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
A minor oversight in the language is that
With[x, ...]
is not allowed. It would be nice to be able to immutably localize a free variable, thus also protecting it from clobberage inside the function.– John Doty
Sep 1 at 16:30