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 - Filling between two spheres in SphericalPlot3D

Manipulate[ SphericalPlot3D[{1, 2 - n}, {θ, 0, Pi}, {ϕ, 0, 1.5 Pi}, Mesh -> None, PlotPoints -> 15, PlotRange -> {-2.2, 2.2}], {n, 0, 1}] I cant' seem to be able to make a filling between two spheres. I've already tried the obvious Filling -> {1 -> {2}} but Mathematica doesn't seem to like that option. Is there any easy way around this or ... Answer There is no built-in filling in SphericalPlot3D . One option is to use ParametricPlot3D to draw the surfaces between the two shells: Manipulate[ Show[SphericalPlot3D[{1, 2 - n}, {θ, 0, Pi}, {ϕ, 0, 1.5 Pi}, PlotPoints -> 15, PlotRange -> {-2.2, 2.2}], ParametricPlot3D[{ r {Sin[t] Cos[1.5 Pi], Sin[t] Sin[1.5 Pi], Cos[t]}, r {Sin[t] Cos[0 Pi], Sin[t] Sin[0 Pi], Cos[t]}}, {r, 1, 2 - n}, {t, 0, Pi}, PlotStyle -> Yellow, Mesh -> {2, 15}]], {n, 0, 1}]

plotting - Plot 4D data with color as 4th dimension

I have a list of 4D data (x position, y position, amplitude, wavelength). I want to plot x, y, and amplitude on a 3D plot and have the color of the points correspond to the wavelength. I have seen many examples using functions to define color but my wavelength cannot be expressed by an analytic function. Is there a simple way to do this? Answer Here a another possible way to visualize 4D data: data = Flatten[Table[{x, y, x^2 + y^2, Sin[x - y]}, {x, -Pi, Pi,Pi/10}, {y,-Pi,Pi, Pi/10}], 1]; You can use the function Point along with VertexColors . Now the points are places using the first three elements and the color is determined by the fourth. In this case I used Hue, but you can use whatever you prefer. Graphics3D[ Point[data[[All, 1 ;; 3]], VertexColors -> Hue /@ data[[All, 4]]], Axes -> True, BoxRatios -> {1, 1, 1/GoldenRatio}]

plotting - Adding a thick curve to a regionplot

Suppose we have the following simple RegionPlot: f[x_] := 1 - x^2 g[x_] := 1 - 0.5 x^2 RegionPlot[{y < f[x], f[x] < y < g[x], y > g[x]}, {x, 0, 2}, {y, 0, 2}] Now I'm trying to change the curve defined by $y=g[x]$ into a thick black curve, while leaving all other boundaries in the plot unchanged. I've tried adding the region $y=g[x]$ and playing with the plotstyle, which didn't work, and I've tried BoundaryStyle, which changed all the boundaries in the plot. Now I'm kinda out of ideas... Any help would be appreciated! Answer With f[x_] := 1 - x^2 g[x_] := 1 - 0.5 x^2 You can use Epilog to add the thick line: RegionPlot[{y < f[x], f[x] < y < g[x], y > g[x]}, {x, 0, 2}, {y, 0, 2}, PlotPoints -> 50, Epilog -> (Plot[g[x], {x, 0, 2}, PlotStyle -> {Black, Thick}][[1]]), PlotStyle -> {Directive[Yellow, Opacity[0.4]], Directive[Pink, Opacity[0.4]],