5
$\begingroup$

I have a large number of variables/functions with subscripts and use definitions with memoization to avoid recomputing them within a kernel session, but I cannot figure out how to export them all for long-term storage. (Ideally human-readable and in a way that also works when running the code from the command line without the Notebook interface).

I have symbolized the subscripted variables so I can use functions that only operate on symbols (in particular Save, Clear). Below is a minimum working example.

Creating and saving the variables as symbols works fine:


Get["Notation`"]
Symbolize[ParsedBoxWrapper[SubscriptBox["_", "_"]]]

a⎵Subscript⎵1 = 2    
a⎵Subscript⎵test = 3

Names[StringJoin[$Context, "*"]]

Information[a⎵Subscript⎵1, LongForm -> False]
Information[a⎵Subscript⎵test, LongForm -> False]

Information["a⎵Subscript⎵1", 
 LongForm -> False]
Information["a⎵Subscript⎵test", 
 LongForm -> False]

Save[ NotebookDirectory[] <> "test_symbolize_save.m", "`*"]

symbolized variables with subscripts before saving

But when I open a new notebook and load the saved file it loads neither the original variables with subscript (only the internal representation) nor the associated values (even though they are contained in the exported file):


Get["Notation`"]
Symbolize[ParsedBoxWrapper[SubscriptBox["_", "_"]]]

Get[StringJoin[NotebookDirectory[], "test_symbolize_save.m"]]; 

Names[StringJoin[$Context, "*"]]

Information[2, LongForm -> False]
Information[3, LongForm -> False]

Information["a⎵Subscript⎵1", LongForm -> False]
Information["a⎵Subscript⎵test", LongForm -> False]

symbolized variables with subscripts after loading

I entered the subscript via "Ctrl+_" for the first ? calls before exporting and after importing. The RawInputForm of those calls after importing probably points to the underlying issue, as the intended reference to the subscripted variable points to its stored value instead.

Content of the file exported with Save:


a⎵Subscript⎵1 = 2     
a⎵Subscript⎵test = 3

(I also tried DumpSave, and while that saved the variable/function name, it did not save the subscripts and associated values.)

My question: How can I easily and consistently create, export, and import variables/functions with subscripts, so the definitions and computed values are fully restored after import?

I don't have to use symbolize (in fact i never did before), but when I tried Save without symbolizing it did not actually export my variables/functions with subscripts.

$\endgroup$
  • 6
    $\begingroup$ I hate to say it, but I would recommend against using Notation and just stick to one dimensional symbols. There are so fewer headaches... $\endgroup$ – user6014 Oct 30 '18 at 23:57
  • 1
    $\begingroup$ The issue is that the Notation rules weren't saved via Save. How you get that to work I'm not entirely sure, but try exporting the OwnValues, DownValues, and FormatValues explicitly. That will work at minimum. $\endgroup$ – b3m2a1 Oct 31 '18 at 0:12
6
+50
$\begingroup$

You could just save global variables and Subscript:

Save[file, {"`*", "Subscript"}]

If you really want to use the Notation package, then the problem is that the functions that know how to convert back and forth between the symbolized and unsymbolized forms are not being saved. Here are your definitions:

Get["Notation`"]
Symbolize[ParsedBoxWrapper[SubscriptBox["_","_"]]]

Subscript[a, 1] = 2
Subscript[a, test] = 3

2

3

Here is how to save the needed symbols from the notation package:

Block[{NotationBoxTag, Notation`Private`createSymbolizeSingleInstance, 
       MakeExpression, $ContextPath},
SetAttributes[{$ContextPath},Protected];
    Save[
        FileNameJoin[{NotebookDirectory[], "test_symbolize_save.m"}],
        {"`*", NotationMakeBoxes, NotationMakeExpression}
    ]
]

(The above Block is not strictly necessary, but there is no need to save all of the definitions when you are going to reload the Notation package anyway)

Then quit the kernel, and reload:

Get["Notation`"]
Symbolize[ParsedBoxWrapper[SubscriptBox["_","_"]]]

Get[FileNameJoin[{NotebookDirectory[], "test_symbolize_save.m"}]];

Subscript[a, 1]
Subscript[a, test]

2

3

Here are the contents of the saved file:

Import[FileNameJoin[{NotebookDirectory[], "test_symbolize_save.m"}], "String"]
a⎵Subscript⎵1 = 2  
a⎵Subscript⎵test = 3
Attributes[Notation`NotationMakeBoxes] = {HoldAllComplete}

Notation`NotationMakeBoxes[HoldPattern[Notation`ParsedBoxWrapper][
      Notation`Private`boxes__], Notation`Private`anyForm_] := 
    TemplateBox[{Notation`Private`boxes}, "NotationTemplateTag"]

Notation`NotationMakeBoxes[a⎵Subscript⎵1, 
      StandardForm] /; MemberQ[$ContextPath, "Global`"] := 
    SubscriptBox["a", "1"]

Notation`NotationMakeBoxes[a⎵Subscript⎵test, 
      StandardForm] /; MemberQ[$ContextPath, "Global`"] := 
    SubscriptBox["a", "test"]

Notation`NotationMakeBoxes /: Notation`NotationMakeBoxes::usage = 
     "NotationMakeBoxes is a private version of MakeBoxes."

Notation`NotationMakeExpression[TagBox[Notation`Private`boxes_, 
      Notation`NotationBoxTag, Notation`Private`opts___], 
     Notation`Private`anyForm_] := HoldComplete[Notation`ParsedBoxWrapper[
      Notation`Private`boxes]]

Notation`NotationMakeExpression[TagBox[Notation`Private`boxes_, 
      "NotationTemplateTag", Notation`Private`opts___], 
     Notation`Private`anyForm_] := HoldComplete[Notation`ParsedBoxWrapper[
      Notation`Private`boxes]]

Notation`NotationMakeExpression[SubscriptBox["a", "1"], StandardForm] /; 
     MemberQ[$ContextPath, "Global`"] := HoldComplete[
     a⎵Subscript⎵1]

Notation`NotationMakeExpression[SubscriptBox["a", "test"], StandardForm] /; 
     MemberQ[$ContextPath, "Global`"] := HoldComplete[
     a⎵Subscript⎵test]

Notation`NotationMakeExpression[Notation`Private`matchedBoxes:
       SubscriptBox[_, _], StandardForm] /; MemberQ[$ContextPath, 
      "Global`"] := (Notation`Private`createSymbolizeSingleInstance[
      Notation`Private`matchedBoxes, "Global`"]; 
     MakeExpression[Notation`Private`matchedBoxes, StandardForm])

Notation`NotationMakeExpression /: Notation`NotationMakeExpression::usage = 
     "NotationMakeExpression is a private version of MakeExpression."
$\endgroup$
  • $\begingroup$ Is it possible to use DumpSave instead of Save? I tried Block[{NotationBoxTag, Notation`Private`createSymbolizeSingleInstance, MakeExpression, $ContextPath}, SetAttributes[{$ContextPath}, Protected]; DumpSave[FileNameJoin[{NotebookDirectory[], "test_symbolize_save.mx"}], {"Global`", NotationMakeBoxes, NotationMakeExpression}]] but it causes Syntax::sntxi: Incomplete expression; more input is needed . warning, which I don't quite understand. Tested in v11.2. BTW, v9 spits out ToExpression::esntx warning in addition. $\endgroup$ – xzczd Nov 11 '18 at 10:01
  • 1
    $\begingroup$ @xzczd If you want to use DumpSave, then there is no need to make the file readable. So, don't use Block, and it should work. $\endgroup$ – Carl Woll Nov 11 '18 at 19:56
  • $\begingroup$ just for clarity, when you say to remove Block, that includes the first argument of it I presume (what is under culry brackets)? If I do that, I get an error message of the form:List::cxt: Invalid context specified at position 1 in {*,NotationMakeBoxes,NotationMakeExpression}. A context must consist of valid symbol names separated by and ending with . $\endgroup$ – Patrick.B Feb 1 at 15:23

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.