MathGroup Archive 2010

[Date Index] [Thread Index] [Author Index]

Search the Archive

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


  • Prev by Date: Re: FindRoots?
  • Next by Date: Re: FindRoots?
  • Previous by thread: Re: problem with RandomInteger
  • Next by thread: Re: problem with RandomInteger