This can be done without using any Mathematica features. You can keep the matrix as a global variable on the C++ side. You will have a function for initializing it, a function for destroying it, and a function for the distance calculation. Then just call the initializer and cleanup function manually from Mathematica when you need to.
Note: Storing a large matrix as std::vector< std::vector<...> >
in C++ is not a good idea if you need performance. Write your own class instead which stores the matrix as a flat array and indexes into it as i*n + j
or similar.
If you need very good performance, do not use MathLink. Use LibraryLink instead. With LibraryLink, you can use "constant passing" for tensors: you can pass a Mathematica matrix to C++ without making an in-memory copy of it (and have read-only access on the C++ side). See "Memory management of MTensors" in the LibraryLink documentation.
Since version 10, LibraryLink also provides "managed library expressions" (see again the LibraryLink tutorial). These make it possible to have C-side data structures which get destroyed automatically once Mathematica no longer holds references to them. This might simplify the first type of solution I mentioned where you have an initializer function and a cleanup function for the matrix. It will ensure that the cleanup function gets called automatically once there's no Mathematica side reference to the matrix.
Also take a look at my package LTemplate
which makes it easier to write this sort of code with managed library expressions.
With LTemplate the solution would look something like this (sorry for not testing this, I must leave in minutes):
The template:
template = LClass["Distance",
{LFun["setMatrix", {Integer}, "Void"],
LFun["dist", {{Real, 1, "Constant"}, {Real, 1, "Constant"}}, Real]}
];
C++ code:
class Distance {
YourMatrixType m; // may even be an mma::RealMatrixRef, i.e. an MTensor
public:
~Distance() { /* must clean up m if already initialized */ }
void setMatrix(mint i) { /* initialize m */ }
double dist(mma::RealTensorRef v1, mma::RealTensorRef v2) const {
// compute distance between v1 and v2 based on m
}
};
Now in Mathematica:
CompileTemplate[template]
obj = Make["Distance"]
obj@"setMatrix"[i]
obj@"dist"[v1, v2]
When there's no more references held by Mathematica to obj
(e.g. you do obj =.
and it's not stored in Out[...]
either) then the destructor will automatically be called and the matrix m
is freed.
SparseArray
and also setting$HistoryLength
to zero. $\endgroup$ – Edmund Dec 12 '15 at 13:10$HistoryLength
thing is always a good tip. $\endgroup$ – tortortor Dec 12 '15 at 17:32