Bug introduced in 3.0, persisting through 13.1.
Preamble: I submitted this bug to [email protected] and it was acknowledged. I assume it will be fixed eventually. In the meantime I'd like to understand what's going on so I can have a better idea as to how concerned I should be about other code I've written that might be subject to the same or a similar issue.
I present a toy example that illustrates the bug. In the toy example I don't really need the compiled version because the uncompiled version runs faster, but my actual applications are much larger and more complicated and the compiled version runs faster.
Here is the uncompiled version that works correctly:
fun = Function[{},
FoldList[
RandomChoice[{{1, 0}, {0, 1}}[[#1]]*#2 -> {1, 2}] &,
RandomChoice[{1, 1} -> {1, 2}],
{{1, 1}, {1, 1}}
]
];
fun[]
returns either {1,1,1}
or {2,2,2}
with equal probability as the following usage indicates:
KeySort@Counts@Table[fun[], 100]
(* <|{1, 1, 1} -> 52, {2, 2, 2} -> 48|> *)
The problem comes when the function is compiled, either explicitly or implicitly. To illustrate the effect of implicit compilation consider the following:
KeySort@Counts@Table[fun[], 250]
(* <|{1, 1, 1} -> 62, {1, 2, 2} -> 51, {2, 1, 1} -> 70, {2, 2, 2} -> 67|> *)
We see that erroneous output is produced. We can replicate this behavior by explicitly compiling the function:
cf = Compile[{},
FoldList[
RandomChoice[{{1, 0}, {0, 1}}[[#1]]*#2 -> {1, 2}] &,
RandomChoice[{1, 1} -> {1, 2}],
{{1, 1}, {1, 1}}
]
];
SeedRandom[1];
cf[]
(* {1, 2, 2} *)
I have two questions: (1) What is going on? and (2) Why?
I don't know how to read the byte code in compiled functions, but the following indicates the presence of an extra call to RandomChoice
:
Position[cf, "RandomChoiceWeights"]
(* {{6, 2, 2}, {6, 12, 2}, {6, 17, 2}} *)
So how the heck does Compile
go about introducing this extra call? And how should I think about other uses of Compile
that involve randomness? I just don't have a sense for how bad this might be. I'd like the answer to be "Oh this isn't bad at all because it's triggered by this very specific thing that doesn't apply to anything else."
Any thoughts would be appreciated.
Update
FunctionCompile does not suffer from the bug.
fc = FunctionCompile[
Function[{},
FoldList[
RandomChoice[{{1, 0}, {0, 1}}[[#1]]*#2 -> {1, 2}] &,
RandomChoice[{1, 1} -> {1, 2}],
{{1, 1}, {1, 1}}
]
]
]
KeySort@Counts@Table[fc[], 250]
(* <|{1, 1, 1} -> 129, {2, 2, 2} -> 121|> *)
CompilePrint[]
is the usual method for peering into a compiled function. $\endgroup$Random[Integer, {1,2}]
instead ofRandomChoice
): i.sstatic.net/hvWsv.png v2 is not influenced, butList
is not compilable at that time: i.sstatic.net/NFxPA.png $\endgroup$