Tuesday, June 9, 2015

Use Block to Temporarily Block Global Variables

The main Mathematica scoping function to learn is Module. For occasional special purposes, use Block to temporarily store and then restore Global variables, and use With to fix local variables so they can't be accidentally changed inside of With.

Use any Doc Center page for a scratchpad (not Block), since all variable names and values are localized to that page and are automatically cleaned up when you leave the page.

Block does two things:
  1. Temporarily stores a Global variable value and then restore it
  2. Uses a local value for the variable in the Block if you give it one
Here is a step-by-step example of how Block works.

x=17;
Block[{x=4},x^2]
16

x
17

Step
Effect
x = 17;
Variable x is Set to 17 in the Global` Context
Block[{x=4},x^2]
A Block is entered using specifying a local variable with the same name as the Global one (x = 4)
Within Block: x$23 = x
Local, temporary variable x$23 is Set to x’s global value of 17
Within Block: x = 4
Local, temporary variable x is Set to 4
Within Block: x^2
In Power[x, 2] x replaced by 4: Power[x, 2] /. x -> 4
Block returns 4^2 = 16
Locally with Block Power[x, 2] evaluates to 16, which is returned
Block Sets x = x$23 and exits
The Global value of x is restored
x
The Global values of x is called
17
The Global value of x is returned

Typical Uses of Block

Block is used to scope and protect the iterators in Table, Do, Sum, etc. If you write a function with an iterator you can use Block.

More typical uses of Block are to change the value of system environment variables such as decreasing $RecursionLimit or $IterationLimit to prevent infinite looping while you're debugging a function, or increasing them to solve a deeply nested or iterated calculation.

An interesting combinatorial series arises from the number of partitions of integer sets, the Bell number. Pemmaraju and Skiena compute it recursively. To let the function solve for indefinitely large sets, $RecursionLimit is temporarily set to Infinity within the Block and automatically restored to its default value after execution.

Clear[bellB,bellB1];

bellB@n_Integer:=bellB1@n;
bellB1@0=1;(*base case*)

bellB1@n_:=Block[
{$RecursionLimit=Infinity},
bellB1@n=Sum[Binomial[n-1,k]*bellB1@k,{k,0,n-1}] (*memo function*)
]

bellB/@Range@10
{1,2,5,15,52,203,877,4140,21147,115975}

$RecursionLimit

1024

Why Block Might Not Seem to Work

Again, if you understand that Block will 1) temporarily store a Global variable value and then restore it, and 2) use a local value for the variable in the Block only if you give it one, you will understand the following examples. First, we Set x equal to 25 in Global`.

x=25;

Here x isn't scoped and so isn't Blocked; Mathematica can't just assume you wanted it localized.

Block[{},x]
25

Here x is scoped but we didn't assign it a new value. So while its global value of 25 was stored in a temporary variable it was also used in Block.

Block[{x},x]
25

Now we assign a value to x in Block's scope, or in its body. Block works as intended.

Block[{x=5},x]
5

Block[{x},x=5]
5

And x's Global value was restored as Block closed itself out. All is good in the universe :-)

x
25


Block Compared with Module and With

Block and Module let us change scoped variable values in the body of their code.

Block[{x=5},Print@x;x=50;x]
5
50

Module[{x=15},Print@x;x=100;x]
15
100

But With does not; we get an error message. When we try to Set x to 8, Mathematica sees "2 = 8":

With[{x=2},Print@x;x=8;x^2]
2
Set::setraw: Cannot assign to raw object 2. >>
Out[292]= 4

Block and Module immediately use scoped variable values, so here Mathematica sees "5^2 /. 5 -> 6", evaluates 5^2 as 25 and thus sees "25 /. 5 ->6"; there's no x to replace.

Block[{x=5},x^2/.x->6]
25

Module works by creating a special local variable name for each scoped variable. Here, within the Module, x lives on under the new name "x$485":

Module[{x},Print@x]
x$485

2 comments:

  1. Your explanation was pleasantly clear. It clears up a lot. May I ask you for an explanation about this topic? I wanted to write a function that test if a function is even or odd. I end up writing a piece of code that seems to work but I don’t really know how. The 2nd line is the difficult one. I don’t quite get why have to be this way.

    polyTest[exp_]:=
    Module[{f},Activate@Inactive[SetDelayed][f[x_],exp];
    Which[
    f[x]===f[-x],Print["is even"],
    -f[x]===f[-x],Print["is odd"],
    True,Print["Nor even, nor odd"]
    ]]

    Applying this function to an expression will look like:

    polyTest[1/2 (E^x+E^-x)]

    I previously wrote a more simple but (to me) clear code to do the same. But then I thought and if I write it as a function of Mathematica? What gave rise to this matter.

    f[x_]:=1/2 (E^x-E^-x);
    Which[
    f[x]===f[-x],Print[f[x]," is Even"],
    -f[x]===f[-x],Print[f[x]," is Odd"],
    True,Print[f[x],"Nor even, nor odd"]
    ]
    ClearAll[f]

    Investigating I found that the 1st code could be called “nested scoping constructs”. My solution was an adaptation from various examples from mathematica.stackexchange.com, specifically at: https://mathematica.stackexchange.com/questions/180544/assign-a-function-within-a-function/

    If you find some time for this, I will appreciate it, but even if not, this article is a thumb up.

    Thank you.

    ReplyDelete
    Replies
    1. Dear Fernando, I am not sure your solutions have to do with scoping. Scoping is automatic with SetDelayed and Pattern (e.g. f@x_:= x^2. For compound expressions it is good form to use Module or the more specialized Block or With.

      I am not clear on why the Activate@Inactivate piece is required, but it does seem to be. Perhaps you can explain that. See some explorations below (you'll have to Evaluate the code).

      Best,

      Kris

      Fernando - Even/Odd Function test

      polyTest[exp_] := Module[{f}, Activate@Inactive[SetDelayed][f[x_], exp];
      Which[f[x] === f[-x], Print["is even"], -f[x] === f[-x], Print["is odd"],
      True, Print["Nor even, nor odd"]]]

      Does it work without Activate@Inactivate?

      polyTest2[exp_] := Module[{f}, SetDelayed[f[x_], exp];
      Which[f[x] === f[-x], Print["is even"], -f[x] === f[-x], Print["is odd"],
      True, Print["Nor even, nor odd"]]
      ]

      A simple intuitive test

      polyTest /@ {x^2, x^3}

      Omitting Activate@Inactivate fails - why?

      polyTest2 /@ {x^2, x^3}

      Again, failure

      polyTest2[1/2 (E^x + E^-x)]

      Again, success

      polyTest[1/2 (E^x - E^-x)]

      polyTest2[(E^x + E^-x)] // Trace

      The documentation doesn't explain how SameQ tests for equivalence other than syntactical equivalence. Reduce fails (see below).

      -(E^x + E^-x) === (E^x + E^-x)

      polyTest[(E^x + E^-x)] // Trace

      (E^x + E^-x) == -(E^x + E^-x)

      Reduce[(E^x + E^-x) == -(E^x + E^-x), x, Reals] // Trace

      Reduce[(E^x - E^-x) == -(E^x + E^-x), x, Reals] // Trace

      Plot[{E^x, E^-x}, {x, -2, 2}]

      Plot[(E^x + E^-x), {x, -2, 2}, AxesOrigin -> {0, 0}]

      Plot[(E^x - E^-x), {x, -2, 2}, AxesOrigin -> {0, 0}]

      Plot[-(E^x + E^-x), {x, -2, 2}]

      Your simpler function seems to work.

      f2[x_] := 1/2 (E^x - E^-x);
      Which[f2[x] === f2[-x], Print[f2[x], " is Even"], -f2[x] === f2[-x],
      Print[f2[x], " is Odd"], True, Print[f2[x], "Nor even, nor odd"]]

      f2[x_] := x^2; f3@x_ := x^3;
      Which[f2[x] === f2[-x], Print[f2[x], " is Even"], -f2[x] === f2[-x],
      Print[f2[x], " is Odd"], True, Print[f2[x], "Nor even, nor odd"]];
      Which[f3[x] === f3[-x], Print[f3[x], " is Even"], -f3[x] === f3[-x],
      Print[f3[x], " is Odd"], True, Print[f3[x], "Nor even, nor odd"]];

      Remove[f, f2, f3, polyTest, polyTest2]

      Delete