Skip to main content

programming - Is the sharing of variables in Module/Block within Compile documented behavior?


Today I noticed something, I think for the first time.


When used inside Compile variable values within Module (and Block) are sequentially shared:


Compile[{}, Module[{a = 7, b = a}, b + 1] ][]



8

Compare the behavior outside of Compile:


Module[{a = 7, b = a}, b + 1]


1 + a




  • Is this documented behavior or just a happy accident?




  • If undocumented can it be relied upon or should this "trick" be avoided?





Answer



If you look at the generated code (CompilePrint, for example), the procedure is as follows:



  • All the program's constants are placed into separate registers (regardless of their location in the program, they can be in the r.h.s.of variable initialization in scoping constructs, or they can be statements in their bodies. Actually, same constants found in different part of a program share the same register).


  • The variables initialized by Module are placed into separate registers, one by one. This seems quite natural. There is no real need for Compile to actually implement nested scoping where one and the same variable can be shadowed and take another value in some inner block of code. So, it simply assigns different registers for different Module variables - which mimics what Module is doing in the top-level code where it does not really implement nested scoping a-la C, but generates unique symbols, which emulate it.

  • The binding semantics for nested scoping seems to be the same as for the top-level, in that the variables in code are bound to the smallest (innermost) scope containing that piece of code.

  • It looks like, for the purposes of Compile, Block and Module are the same (this refers to cases where the code can be fully compiled without callbacks to MainEvaluate. If such callbacks are present, Block may behave differently from Module, if it is a part of the top-level code executed in a callback). In other words, Compile does not implement dynamic scoping (except via callbacks to the main evaluator), and Block variables are also bound lexically.


Here is what CompilePrint gives for your example:


cmp = Compile[{}, Module[{a = 7, b = a}, b + 1]];
Needs["CompiledFunctionTools`"];

CompilePrint[cmp]



      No argument
5 Integer registers
Underflow checking off
Overflow checking off
Integer overflow checking on
RuntimeAttributes -> {}

I0 = 7
I3 = 1

Result = I4

1 I1 = I0
2 I2 = I1
3 I4 = I2 + I3
4 Return

and here is a more complicated example including nested Module-s and local variable naming conflicts:


cmp3 = 
Compile[{},

Module[{a = 7, b = a},
b = a + b;
Module[{b = b, a = b + 2}, a + b + 1]]];
CompilePrint[cmp3]


No argument
8 Integer registers
Underflow checking off
Overflow checking off

Integer overflow checking on
RuntimeAttributes -> {}

I4 = 2
I0 = 7
I6 = 1
Result = I7

1 I1 = I0
2 I2 = I1

3 I3 = I1 + I2
4 I2 = I3
5 I3 = I2
6 I5 = I3 + I4
7 I7 = I5 + I3 + I6
8 Return

Analyzing the register allocations in these examples confirms the procedure I suggested above. Given this, it looks like the effect you have noticed can be relied upon (but this has a status of an educated guess only).


Comments

Popular posts from this blog

plotting - How to draw lines between specified dots on ListPlot?

I would like to create a plot where I have unconnected dots and some connected. So far, I have figured out how to draw the dots. My code is the following: ListPlot[{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4,13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full] I have thought using ListLinePlot command, but I don't know how to specify to the command to draw only selected lines between the dots. Do have any suggestions/hints on how to do that? Thank you. Answer One possibility would be to use Epilog with Line : ListPlot[ {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4, 13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full, Epilog -> { Line[ ...

calculus and analysis - Integral of the Sinc product

Let us consider the following integral $$ B_n = \int_0^\infty \prod_{k=1,3,5,\dots}^n\frac{\sin (x/k)}{x/k}dx $$ By definition, Sinc[x] == Sin[x]/x , therefore B[n_?OddQ] := Integrate[Product[Sinc[x/k], {k, 1, n, 2}], {x, 0, Infinity}] B /@ Range[1, 13, 2] {Pi/2, Pi/2, Pi/2, Pi/2, Pi/2, Pi/2, Pi/2} OK, everything is fine. But... B[15] 467807924713440738696537864469 Pi/935615849440640907310521750000 What's going on? Answer As Eckhard wrote in comments B[n] is the n-th Borwein integral . (The letter B was not accidental :) ) This funny properties of Borwein integrals is related to the Fourier transform of Sinc function FourierTransform[Sinc[x], x, k] 1/2 Sqrt[Pi/2] (Sign[1 - k] + Sign[1 + k]) Plot[%, {k, -2, 2}, Filling -> 0] which is the box function. The result is $\pi/2$ while the sum $$ 1/3+1/5+\dots+1/n $$ B_n = \frac{\pi}{2} - \pi \bigg(\sum_{k=3,5,\ldots}^n\frac{1}{k} -1\biggr)^\frac{n-1}{2}\prod_{k=3,5,\dots}^n\frac{k}{k-1}. $$ For $n=15$ it is equal to $$ \frac{46780...

list manipulation - Selecting multiple columns from a matrix?

Sample data: data = { {{2013, 1, 1}, 24.13, 167.67, 231.82}, {{2013, 1, 2}, 32.15, 170.92, 225.99}, {{2013, 1, 3}, 35.43, 172.68, 221.67}, {{2013, 1, 4}, 36.73, 173.05, 218.32}, {{2013, 1, 5}, 58.19, 165.96, 197.05}, {{2013, 1, 6}, 69.99, 163.50, 187.52}, {{2013, 1, 7}, 71.37, 154.21, 175.58}, {{2013, 1, 8}, 72.51, 149.66, 163.25}}; I want a DateListPlot with three graphs, so for a matrix formed by columns 1 and 2, one for columns 1 and 3, and 1 for columns 1 and 4. At the moment I'm using this code: data2 = Transpose[{data[[All, 1]], data[[All, 2]]}]; data3 = Transpose[{data[[All, 1]], data[[All, 3]]}]; data4 = Transpose[{data[[All, 1]], data[[All, 4]]}]; DateListPlot[{data2, data3, data4}, Joined -> True, Filling -> {3 -> {1}}] but I have a hunch that this can be done more efficiently. I don't like the Transpose s in particular. Any ideas? edit (for extra credit) What if I need to multiply the second column by 2, which in my solution is simp...