1

I am working on fairly large Mathematica projects and the problem arises that I have to intermittently check numerical results but want to easily revert to having all my constructs in analytical form.

The code is fairly fluid I don't want to use scoping constructs everywhere as they add work overhead. Is there an easy way for identifying and clearing all assignments that are numerical?

EDIT: I really do know that scoping is the way to do this correctly ;-). However, for my workflow I am really just looking for a dirty trick to nix all numerical assignments after the fact instead of having the foresight to put down a Block.

Timo
  • 4,246
  • 6
  • 29
  • 42

2 Answers2

2

If your assignments are on the top level, you can use something like this:

a = 1;
b = c;
d = 3;
e = d + b;

Cases[DownValues[In],
   HoldPattern[lhs_ = rhs_?NumericQ] | 
   HoldPattern[(lhs_ = rhs_?NumericQ;)] :> Unset[lhs],
3]

This will work if you have a sufficient history length $HistoryLength (defaults to infinity). Note however that, in the above example, e was assigned 3+c, and 3 here was not undone. So, the problem is really ambiguous in formulation, because some numbers could make it into definitions. One way to avoid this is to use SetDelayed for assignments, rather than Set.

Another alternative would be to analyze the names in say Global' context (if that is the context where your symbols live), and then say OwnValues and DownValues of the symbols, in a fashion similar to the above, and remove definitions with purely numerical r.h.s.

But IMO neither of these approaches are robust. I'd still use scoping constructs and try to isolate numerics. One possibility is to wrap you final code in Block, and assign numerical values inside this Block. This seems a much cleaner approach. The work overhead is minimal - you just have to remember which symbols you want to assign the values to. Block will automatically ensure that outside it, the symbols will have no definitions.

EDIT

Yet another possibility is to use local rules. For example, one could define rule[a] = a->1; rule[d]=d->3 instead of the assignments above. You could then apply these rules, extracting them as say DownValues[rule][[All, 2]], whenever you want to test with some numerical arguments.

Leonid Shifrin
  • 22,449
  • 4
  • 68
  • 100
  • This is almost exactly what I'm looking for. I'm very judicious with using SetDelayed specifically for the purpose of having completely analytical constructs from which I make numerical copies. It hadn't occurred to me to use DownValues[In]. This is a list of all the input lines I assume. If so this will probably not work for assignments that I make with Get, correct? I'll try to look at parsing the rules in the Global context, is there an easy listing of them somewhere? – Timo Apr 14 '11 at 13:50
  • You can get these rules by something like `Map[ToExpression[#,InputForm,DownValues]&,Names["Global'"]]`, or the same for `OwnValues` (be sure to not copy directly, I changed the context separator sign to a single quote). After that, you can use `Cases` on these rules in a fashion similar to my code above. As for assignments made with `Get`, they are indeed not reflected in `In`. So, inspecting the `Global'` names seems more robust, but using `Block` or local rules is IMO still more robust. – Leonid Shifrin Apr 14 '11 at 14:22
  • I just had an idea about using a separate (private?) sub-context for all the numerical assignments. Is it possible to set contexts up in such a way that I can e.g. switch the notebooks context to Global'numeric when I want to do numerical evaluations and to Global'analytic when I want to do the analytic stuff? – Timo Apr 14 '11 at 19:08
1

Building on Andrew Moylan's solution, one can construct a Block like function that would takes rules:

SetAttributes[BlockRules, HoldRest]

BlockRules[rules_, expr_] := 
 Block @@ Append[Apply[Set, Hold@rules, {2}], Unevaluated[expr]]

You can then save your numeric rules in a variable, and use BlockRules[ savedrules, code ], or even define a function that would apply a fixed set of rules, kind of like so:

In[76]:= NumericCheck = 
  Function[body, BlockRules[{a -> 3, b -> 2`}, body], HoldAll];

In[78]:= a + b // NumericCheck

Out[78]= 5.

EDIT In response to Timo's comment, it might be possible to use NotebookEvaluate (new in 8) to achieve the requested effect.

SetAttributes[BlockRules, HoldRest]
BlockRules[rules_, expr_] := 
 Block @@ Append[Apply[Set, Hold@rules, {2}], Unevaluated[expr]]

nb = CreateDocument[{ExpressionCell[
     Defer[Plot[Sin[a x], {x, 0, 2 Pi}]], "Input"],
    ExpressionCell[Defer[Integrate[Sin[a x^2], {x, 0, 2 Pi}]], 
     "Input"]}];
BlockRules[{a -> 4}, NotebookEvaluate[nb, InsertResults -> "True"];]

As the result of this evaluation you get a notebook with your commands evaluated when a was locally set to 4. In order to take it further, you would have to take the notebook with your code, open a new notebook, evaluate Notebooks[] to identify the notebook of interest and then do :

BlockRules[variablerules, 
 NotebookEvaluate[NotebookPut[NotebookGet[nbobj]], 
  InsertResults -> "True"]]

I hope you can make this idea work.

enter image description here

Community
  • 1
  • 1
Sasha
  • 5,935
  • 1
  • 25
  • 33
  • This a nice idea but it has the same problem as scoping in that I have to write //NumericCheck lots and lots of times, in addition to having different sets of numerical values so different versions of NumericCheck which I have to change by hand, etc. etc. I'm looking for a simple way to either switch on numerical values or not, maybe context switching is the real solution. – Timo Apr 14 '11 at 19:04
  • @Timo You can use the fact that notebooks are also expression to achieve this effect without much of manual labor, I hope. Please see the updated to my response above. – Sasha Apr 14 '11 at 19:42