I would like to describe and compare several different ways that one may save a function definition in Mathematica.
First, let me get out of the way how you were defining interPolFunc
incorrectly. First and most importantly, the use of SetDelayed
(:=
) will cause rebuilding of interpolation data every time you call interPolFunc
. Secondly:
Interpolation[{f1, f2, ...}]
constructs an interpolation of the function
values fi, assumed to correspond to x values 1, 2, ...
.
Therefore, you should write:
interPolFunc = Interpolation[exampleData];
The output of which is an InterpolatingFunction
object.
Put
Perhaps the most basic method for saving a function or expression is Put
, also written >>
. There is also PutAppend
(>>>
) which adds to a file rather than replacing it.
expr >> filename
writes expr to a file.
Put[expr1, expr1, ..., "filename"]
writes a sequence of expressions expri to a file.
Let's try it (the normal extension for Mathematica textual files is m
):
interPolFunc >> "interPolFunc-Put.m"
The contents of interPolFunc-Put.m
read:
InterpolatingFunction[{{1, 7}}, {3, 1, 0, {7}, {4}, 0, 0, 0, 0},
{{1, 2, 3, 4, 5, 6, 7}}, {{1}, {3}, {4}, {7}, {5}, {4}, {2}},
{Automatic}]
Put
saves the value
of the expression it is given.
To use this one would use Get
, also written <<
, and =
:
interPolFunc = << "interPolFunc-Put.m" ;
Suppose we have a function that has multiple definition rules and/or depends on additional user functions that we wish to save. Consider this number-of-permutations function nPr
:
nCr[_, 0] = 1;
nCr[n_, n_] = 1;
p : nCr[n_, m_] := p = nCr[n - 1, m] + nCr[n - 1, m - 1]
nPr[n_Integer?Positive, m_Integer?Positive] := nCr[n, m] m!
The Symbol nPr
has no value (technically no OwnValues
rule), therefore nPr >> file
will not work. We can however use Definition
and FullDefinition
in cases such as this.
Definition[nPr] >> "nPr-Definition.m"
The file shows that the line that defines nPr
is saved, but not nCr
:
nPr[(n_Integer)?Positive, (m_Integer)?Positive] := nCr[n, m]*m!
By comparison, using FullDefinition
all definition lines are saved:
FullDefinition[nPr] >> "nPr-FullDefinition.m"
nPr[(n_Integer)?Positive, (m_Integer)?Positive] := nCr[n, m]*m!
nCr[_, 0] = 1
nCr[n_, n_] = 1
p:nCr[n_, m_] := p = nCr[n - 1, m] + nCr[n - 1, m - 1]
Notice in these examples that the lines of code that define the functions are themselves saved, therefore loading the definition is accomplished with a simple Get
:
<< "nPr-FullDefinition.m";
(Though undocumented, Definition
and FullDefinition
support multiple arguments such as Definition[symbol1, symbol2, ...]
. See this for an example.)
Save & DumpSave
There is an aptly named function Save
which automates that last method shown above, but with PutAppend:
Save["filename", symbol]
appends definitions associated with the specified symbol to a file.
- Save uses
FullDefinition
to include subsidiary definitions.
This produces contents identical to nPr-FullDefinition.m
:
Save["nPr-Save.m", nPr]
Save
also automates saving definitions for a list of symbols, symbol names matching a specified pattern, or all symbols in a context. See the documentation for details.
To this point all files created have been in the human readable .m
format. DumpSave
diverges from this, using a platform and version specific binary .mx
format. This format is very fast to load, but with rare exception it should not be used for long term storage or to exchange information between users.
DumpSave["file.mx", symbol]
writes definitions associated with a symbol to a file in internal Mathematica format.
DumpSave
writes out definitions in a binary format that is optimized for input by Mathematica.
Files written by DumpSave
can only be read on the same type of computer system on which they were written.
Another important distinction is that DumpSave
uses Definition
rather than FullDefinition
. If for some reason this behavior is needed for Save
we can use this trick from Janus, leveraging Block
:
Block[{FullDefinition = Definition},
Save["filename.m", expr]
]
The reverse does not appear to be possible with DumpSave
therefore one must give it a list of related symbols explicitly.
Export
It is possible to save to and load other file formats using Export
and Import
.
For example, saving a GZIP compressed .m
file directly:
Export["nPr-Export.m.gz", FullDefinition[nPr], {"GZIP", "Package"}]
Import["nPr-Export.m.gz"]
This performs worse than Save
but the file takes considerably less space.
Performance comparison
For testing, using the definition for nPr
above, I call this:
$RecursionLimit = 15000;
nPr[3000, 150]
Because nCr
uses memoization this creates a large number of definition rules (over 400,000). I then test save and load speed (each done in a separate session):
Save["nPr-Save.m", nPr] // AbsoluteTiming
Put[FullDefinition[nPr], "nPr-FullDefinition.m"] // AbsoluteTiming
DumpSave["nPr-DumpSaveFull.mx", {nPr, nCr}] // AbsoluteTiming
Export["nPr-Export.m.gz", FullDefinition[nPr], {"GZIP", "Package"}] // AbsoluteTiming
{13.6837827, Null}
{9.0355168, Null}
{14.5778338, {nPr, nCr}}
{19.3200270, "nPr-Export.m.gz"}
Load times:
Get["nPr-Save.m"]; // AbsoluteTiming
{3.4281960, Null}
Get["nPr-FullDefinition.m"]; // AbsoluteTiming
{3.4361966, Null}
Get["nPr-DumpSaveFull.mx"]; // AbsoluteTiming
{0.5560318, Null}
Import["nPr-Export.m.gz"]; // AbsoluteTiming
{3.7532147, Null}
Data versus Definitions
The examples above all relate to saving definitions, defined by DownValues
and similar.
If one is saving an expression (data) rather than definitions Export
is handy.
Here is a fine method from David Bailey, streamlined by Szabolcs:
Export["data.mc", Compress[data], "String"]
Uncompress@Import["data.mc", "String"]
This saves very quickly, produces a smaller file, and should be portable between systems. It however does not load as quickly as the "MX"
format.
If loading speed is valued at the expense of platform independence the "MX"
format can also be used for data by using Export
:
Export["data.mx", data, "MX"]
Or combined with compression for smaller files:
Export["data.mx.gz", data, {"GZIP", "MX"}]