77
$\begingroup$

Is it possible to save a function which was created via Interpolation of some data in such a way that I can use this function in a new Mathematica session without repeated interpolation of the data?

For example, I have some data which I interpolate in the following way:

exampleData={{1,1},{2,3},{3,4},{4,7},{5,5},{6,4},{7,2}};
interPolFunc[x_]:=Interpolation[exampleData,x]

Now one of the following would be nice:

  • a way to save the interpolated function so that it can be used the next time when I work with Mathematica (but I do not want to interpolate the data again, so that I can delete them).
  • the data and Interpolation command are saved in a separated notebook which is executed when I want to use my interPolFunc in another notebook.

Unfortunately I did not find any solution for that. But I hope that some of you have several suggestions!

$\endgroup$
2
  • 11
    $\begingroup$ It's important to know that the internal structure of an Interpolation function is not a very stable format. That is, future versions of Mathematica may use a different structure to store Interpolations which would make your saved Interpolation not work. This is the case between version 7 and version 8 because of improvements made to Interpolation in version 8. $\endgroup$
    – Searke
    Commented Feb 19, 2012 at 2:46
  • $\begingroup$ Thanks for the hint @Searke! I will keep my data in a separate notebook so that I can redo the Interpolation in the case something will be changed at the structure in the future. $\endgroup$
    – partial81
    Commented Feb 20, 2012 at 11:46

4 Answers 4

51
$\begingroup$

You can use DumpSave:

exampleData = {{1, 1}, {2, 3}, {3, 4}, {4, 7}, {5, 5}, {6, 4}, {7, 2}};
interPolFunc[x_] = Interpolation[exampleData, x]

(note the use of Set (=) rather than SetDelayed so as to have the interpolating function evaluated only once; the way you had it, you interpolated each and every time).

DumpSave["~/Desktop/interpol.mx", interPolFunc]

then

Quit[]
DumpGet["~/Desktop/interpol.mx"]
interPolFunc[4]
(*7*)
$\endgroup$
8
  • 27
    $\begingroup$ You forgot the obligatory warning: MX is not cross-architecture. $\endgroup$
    – Szabolcs
    Commented Feb 18, 2012 at 13:36
  • $\begingroup$ Thank you all for your answers. @Szabolcs: Your answer is also very helpful. But @acl made me aware of the use of Set instead of SetDelayed - a nice bonus answer. Therefore, I set his answer as accepted. @J.M. I am not so golden ;-) If I restart mathematica I would have to interpolate the data again. But with acl’s or Szabolcs’ answer I need not to. @acl: By the way: What would you use if you work with Piecewise functions (of in mathematica in-built functions) or with self-created functions (again out of in-built functions), Set or SetDelayed? Is there any suggestion or rule for that? $\endgroup$
    – partial81
    Commented Feb 18, 2012 at 13:48
  • $\begingroup$ thanks. regarding Set or SetDelayed, see for instance mathematica.stackexchange.com/questions/704/… or mathematica.stackexchange.com/questions/96/… but I doubt you need to worry that much about it. $\endgroup$
    – acl
    Commented Feb 18, 2012 at 13:52
  • 1
    $\begingroup$ @partial: I'll put it this way: f[x_] := Sin[x]/(1+x) is fine. g[x_] := Piecewise[{{x, x >= 0}}, 0] is also fine. But, there are situations like h[x_] = D[f, x] that necessitate the use of Set instead of SetDelayed... $\endgroup$ Commented Feb 18, 2012 at 13:56
  • 2
    $\begingroup$ @Leo Only if the other Linux computer runs on the same architecture. If you saved the file on x86_64, you won't be able to load it on 32-bit x86 or on a Raspberry Pi. However, the cross-platform compatibility of MX has improved since I wrote this comment. I believe you will be able to load it on 64-bit macOS or Windows (in the past this was not possible). $\endgroup$
    – Szabolcs
    Commented Sep 3, 2020 at 9:23
77
$\begingroup$

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 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"}]
$\endgroup$
3
  • 1
    $\begingroup$ Regarding the last section, it's not from me, and I actually learned it through you ;-) stackoverflow.com/a/6136838/695132 $\endgroup$
    – Szabolcs
    Commented Feb 19, 2012 at 20:09
  • $\begingroup$ @Szabolcs I do recall that answer but I'm giving you credit because I had not seen the form with Export, and testing indicates that it is only marginally slower than BinaryWrite. I should however also give credit to David Bailey. $\endgroup$
    – Mr.Wizard
    Commented Feb 19, 2012 at 21:00
  • 1
    $\begingroup$ @Mr.Wizard +1. I also used this technique (based on Compress) in a number of posts, e.g. here (in a somewhat different form), and more directly, here. I wasn't aware of David's suggestion (missed that post of yours somehow), but he probably found this earlier than me. $\endgroup$ Commented Mar 13, 2012 at 9:41
20
$\begingroup$

Your function, as you wrote it, does re-interpolate every time you call it because a delayed definition was used.

The correct way to write it is

interPolFunc = Interpolation[exampleData]

This (as well as you example) can be saved using Save or DumpSave.

When the function is simply assigned to a variable, as I showed here, it can also be exported for example to WDX and re-used later:

Export["interpolation.wdx", interPolFunc]

interPolFunc = Import["interpolation.wdx"]

(Instead of WDX, or course one can use any other format that can hold arbitrary Mathematica expressions, such as the Package format with the .m extension or .mx files)

InterpolatingFunction objects are just like any other Mathematica expression.

When dealing with very large expressions that are slow to import/export, a good alternative to importing/exporting directly supported formats is

Export["data.mmaz", Compress[expression], "String"]
expression = Uncompress@Import["data.mmaz", "String"]

Compressed strings are quite fast to import or export and unlike MX files, they are cross-platform and cross-version compatible. Note that MX files are not compatible between different platforms or versions of Mathematica.

$\endgroup$
6
  • $\begingroup$ Why should we use WDX rather than .m or .mx? $\endgroup$
    – Mr.Wizard
    Commented Feb 18, 2012 at 13:28
  • $\begingroup$ @Mr.Wizard We could use M or MX if you wish. That's why I said "for example". Any format that can hold Mathematica expressions will do. I typically use Export["data.mmaz", Compress[data], "String"] as the fastest compact cross-platform solution. $\endgroup$
    – Szabolcs
    Commented Feb 18, 2012 at 13:30
  • $\begingroup$ I am encouraging you to extend your answer. Or I'll post. That's a threat. ;^) $\endgroup$
    – Mr.Wizard
    Commented Feb 18, 2012 at 13:31
  • 1
    $\begingroup$ @Mr.Wizard A reason I personally don't like Save and DumpSave for storing data is that the variable names are hard-coded into the file, and are not easy to find out what they are after import. But this is just personal preference, so I didn't mention it in the answer. $\endgroup$
    – Szabolcs
    Commented Feb 18, 2012 at 13:32
  • $\begingroup$ please add the Export["file",Compress[dat],"String"] bit to your answer. I wrote it up for mine but luckily saw your comment before posting it. $\endgroup$
    – acl
    Commented Feb 18, 2012 at 13:37
16
$\begingroup$

If you'd like to keep your function inside the notebook and not to refer to external files, there is another way. This also can come very handy for CDF files. Use Compress to get a string:

exampleData = {{1, 1}, {2, 3}, {3, 4}, {4, 7}, {5, 5}, {6, 4}, {7, 2}};
Compress[Interpolation[exampleData]]

Then use the string to define the function. You now need only that cell. If you restart your session and execute the cell you'll get your function back:

Exit

interPolFunc = Uncompress["1:eJxTTMoPSmNlYGAoFgUSnnklqUUF+\
TmJJZl56W6lecklmfl5aYwgaRYg4ZNZXJLGhMzLBMllsgOJNC4UcRAjkxlEADFDHkgZCLM\
jc1hg0mhEMSeQcCwtyc8FuiMZzXp2TOuZ4HaBTQT5JpMN7i4UDaiGgbWjCTFjCrFgCrFjC\
rESpZEJQwjVtwBbEkCF"]

interPolFunc /@ RandomReal[{1, 7}, 5]
{3.52424, 4.48403, 6.00775, 4.06734, 1.50966}

You can hide it at the end of the document and make it run automatically by selecting it and going Cell >> Cell Properties >> Initialization Cell.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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