Re: problem with RandomInteger

*To*: mathgroup at smc.vnet.net*Subject*: [mg112241] Re: problem with RandomInteger*From*: Mark Adler <madler at alumni.caltech.edu>*Date*: Mon, 6 Sep 2010 04:15:21 -0400 (EDT)*References*: <i5qhhg$pkm$1@smc.vnet.net> <i5vnpi$2c3$1@smc.vnet.net>

So disassembling the compiled code, we start with the example: f1=Compile[{},Module[{l,i,j},l={0,0,0}; i=RandomInteger[{1,3}]; l[[i]]=1; j=RandomInteger[{1,3}]; l[[j]]]]; Table[f1[],{100}]//Mean//N f1//InputForm 0.97 CompiledFunction[{}, {{2, 0, 1}}, {0, 5, 0, 0, 1}, {{1, 7}, {45, {1, 1, 1}, 2, 3, 0}, {7, 1, 0}, {7, 3, 1}, {58, 2, 0, 1, 2}, {7, 1, 0}, {71, 0, 0, 2, 0, 0}, {7, 1, 1}, {7, 3, 3}, {58, 2, 1, 3, 4}, {70, 0, 0, 4, 0, 1}, {2}}, Function[{}, Module[{l, i, j}, l = {0, 0, 0}; i = RandomInteger[{1, 3}]; l[[i]] = 1; j = RandomInteger[{1, 3}]; l[[j]]]], Evaluate] After some experimentation, here is what the compiled function parts mean: Compiled registers for parameters, variables, and return value (part 2): List of {type, rank, register}, where type is 1 for logical, 2 for integer, 3 for real, 4 for complex; rank is the rank of the tensor (0 for scalar). The list will start with the parameters, then any explicit internal variables (e.g. when using Module or Block), and lastly the return value. register is the register number which starts counting at zero for each scalar type and the general tensor type. So the first tensor will be in register 0, and the second tensor will be in register 1, regardless of the types of the tensors (integer, real, etc.). Compiled variables (part 3): Number of each type of register {logicals, integers, reals, complexes, tensors}. (This can be more than the registers defined in part 2, for registers needed internally by the compiled code.) Compiled code (part 4): List of operations, where each operation is a list with an opcode followed by parameters. Here the relevant opcodes are listed, with their parameters after the colon. Opcode 1 starts execution: version number (always {1,7} when compiled by version 7) Opcode 2 ends execution (no parameters) -- returns the register specified in part 2 Opcode 7 initializes an integer register: value, destination integer register Opcode 45 initializes a tensor: initialization packed array, array type (2 integer, 3 real, etc.), length, destination tensor register Opcode 58 is RandomInteger: 2, integer register with imin, integer register with imax, destination integer register (don't know what the 2 means -- it doesn't change for requesting arrays, and the opcode changes for other distributions) Opcode 70 extracts a part: tensor register to index, 0, index register, 0, destination register (I think that the zeros are more generally the rank of the index and the rank of the result) Opcode 71 sets a part: tensor register to index, 0, index register, 0, register with value to assign (same comment on zeros) So now we disassemble (I will use the notation i<n> for integer registers and t<n> for tensor registers: {1, 7}: start {45, {1, 1, 1}, 2, 3, 0}: t0 = {1,1,1} {7, 1, 0}: i0 = 1 {7, 3, 1}: i1 = 3 {58, 2, 0, 1, 2}: i2 = RandomInteger[{i0, i1}] {7, 1, 0}: i0 = 1 {71, 0, 0, 2, 0, 0}: t0[[ i2 ]] = i0 {7, 1, 1}: i1 = 1 {7, 3, 3}: i3 = 3 {58, 2, 1, 3, 4}: i4 = RandomInteger[{i1, i3}] {70, 0, 0, 4, 0, 1}: i1 = t0[[ i4 ]] {2}: return result in i1 (as defined in part 2: {{2, 0, 1}}) Clearly the problem is t0 = {1,1,1}. So the result should always be 1. But wait! It got 0.97 above instead 1, so it *wasn't* always 1. What the heck? So here's the weird part. The compiled function changes after it has been executed! Watch this: f1=Compile[{},Module[{l,i,j},l={0,0,0}; i=RandomInteger[{1,3}]; l[[i]]=1; j=RandomInteger[{1,3}]; l[[j]]]]; f1//InputForm//Print (a=Table[f1[],{100}])//Mean//N f1//InputForm CompiledFunction[{}, {{2, 0, 1}}, {0, 5, 0, 0, 1}, {{1, 7}, {45, {0, 0, 0}, 2, 3, 0}, {7, 1, 0}, {7, 3, 1}, {58, 2, 0, 1, 2}, {7, 1, 0}, {71, 0, 0, 2, 0, 0}, {7, 1, 1}, {7, 3, 3}, {58, 2, 1, 3, 4}, {70, 0, 0, 4, 0, 1}, {2}}, Function[{}, Module[{l, i, j}, l = {0, 0, 0}; i = RandomInteger[{1, 3}]; l[[i]] = 1; j = RandomInteger[{1, 3}]; l[[j]]]], Evaluate] 0.96 CompiledFunction[{}, {{2, 0, 1}}, {0, 5, 0, 0, 1}, {{1, 7}, {45, {1, 1, 1}, 2, 3, 0}, {7, 1, 0}, {7, 3, 1}, {58, 2, 0, 1, 2}, {7, 1, 0}, {71, 0, 0, 2, 0, 0}, {7, 1, 1}, {7, 3, 3}, {58, 2, 1, 3, 4}, {70, 0, 0, 4, 0, 1}, {2}}, Function[{}, Module[{l, i, j}, l = {0, 0, 0}; i = RandomInteger[{1, 3}]; l[[i]] = 1; j = RandomInteger[{1, 3}]; l[[j]]]], Evaluate] So it does seem to be compiling it correctly the first time, assigning {0,0,0} to t0, but during execution the compiled code changes! In the end t0 is set to {1,1,1}. Now watch this (here I extract from the compiled code just the list that t0 is being set to, where the rest of the compiled code isn't changing): f1 = Compile[{}, Module[{l, i, j}, l = {0, 0, 0}; i = RandomInteger[{1, 3}]; l[[i]] = 1; j = RandomInteger[{1, 3}]; l[[j]]]]; f1[[4, 2, 2]] f1[] f1[[4, 2, 2]] f1[] f1[[4, 2, 2]] f1[] f1[[4, 2, 2]] f1[] f1[[4, 2, 2]] f1[] f1[[4, 2, 2]] {0, 0, 0} 1 {0, 1, 0} 0 {0, 1, 0} 1 {1, 1, 0} 1 {1, 1, 1} So it's retaining the value of el across executions in the compiled code itself! This eventually fills up el with ones, resulting in the behavior. Mark