# ContourPlot3D using a Matlab function through MATLink

I have a Matlab function which accepts a 3 dimensional vector and returns a single number. I want to use this through MATLink to make a 3d plot.

A unit sphere:

ContourPlot3D[
Norm[{x, y, z}, 2]^2 == 1, {x, -1, 1}, {y, -1, 1}, {z, -1, 1}]


I now want to replace the Norm with my function:

myfunc= MFunction["myfunc"];
ContourPlot3D[myfunc[{x, y, z}] == 1, {x, -1, 1}, {y, -1, 1}, {z, -1, 1}]


but I get errors:

MSet::unsupp: Unsupported data type. The expression "x" can't be converted. MFunction::args: The arguments at positions {1} to "myfunc" could not be translated to MATLAB....

I am fairly certain I'm missing something obvious but I this is my first time with MATLink.

• The problem is that the symbolic expression {x,y,z} is passed to myfunc before the values of x,y,z are substituted in. Symbols can't be transferred no MATLAB, only numbers can. So you get an error: The expression "x" can't be converted. The solution is to use a wrapper function which will only evaluated for numerical vectors. Unfortunately I don't have time to write an answer right now, but I'll do it a few hours later (or more likely someone else will do it sooner). I just wanted to point you to the solution beforehand. – Szabolcs Jan 30 '14 at 17:04
• That would be extremely helpful, thanks. I'll try to find information on it, in case I can do it myself as well. – asdfa Jan 30 '14 at 18:37

The problem is that the symbolic vector {x,y,z} is passed to the function before the values for x, y and z are substituted. Symbols cannot be transferred to MATLAB, so you get an error:

In[1]:= Needs["MATLink"]

In[2]:= OpenMATLAB[]

In[3]:= norm = MFunction["norm"]
Out[3]= MFunction["norm"]

In[4]:= norm[{x, y, z}]

During evaluation of In[4]:= MSet::unsupp: Unsupported data type. The expression "x" can't be converted.

During evaluation of In[4]:= MFunction::args: The arguments at positions {1} to "norm" could not be translated to MATLAB.

Out[4]= \$Failed


If you use explicit numbers, all is fine:

In[5]:= norm[{1, 2, 3}]
Out[5]= 3.74166


You can use a wrapper function to prevent Mathematica from attempting to evaluate norm[{x,y,z}]. This is a very typical situation in Mathematica and it's not specific to MATLink. See here for more information.

So let's make the wrapper function:

Clear[norm2]
norm2[x_?(VectorQ[#, NumericQ] &)] := norm[x]


Now norm2 will only evaluate when supplied with numerical arguments, and we can avoid the error messages:

In[8]:= norm2[{x, y, z}]
Out[8]= norm2[{x, y, z}]

In[9]:= norm2[{3, 2, 1}]
Out[9]= 3.74166


The ContourPlot3D will work as well, with one big caveat:

ContourPlot3D[
norm2[{x, y, z}] == 1, {x, -1.1, 1.1}, {y, -1.1, 1.1}, {z, -1.1, 1.1}, MaxRecursion -> 0, PlotPoints -> 5]


You need to reduce the number of evaluations it does so significantly that the quality of the output will suffer a lot. Otherwise it will take a very long time to evaluate. With the default options, ContourPlot3D would do about half a million evaluations for this plot. Unfortunately MFunction is not very fast at the moment, so you won't be able to complete more than a few hundred evaluations in a reasonable amount of time.

The reason for the bad performance is that there is a constant overhead to every call to an MFunction. This overhead is due to limitations (and bugs :-( ) of the MATLAB Engine API that MATLink uses to communicate with MATLAB. The overhead is considerably worse on Mac/Linux than on Windows, primarily because of the low quality implementation of the MATLAB Engine on these platforms.

As of 2014 January a rewrite of MATLink is in progress. The next version will use a different way to communicate with MATLAB (the MEX API) and will significantly reduce this overhead, making these types of applications much more feasible.

This performance issue is not always a problem, but ContourPlot3D being a 3D plotting function it needs to make a very large number of evaluations (many more than a 1D or a 2D one would), so the performance problem is particularly apparent here.

As a workaround you could consider generating a large number of points (Tuples[Range[-1.1, 1.1, 0.01], 3]), and sending them all at once to MATLAB for processing, then sending all the result back in one go and using ListContourPlot3D[..., Contours -> {1}]` on them.

• @Szablocs I did the same but did not post due to this timing issue. Its better to get the performance related explanation from the developer himself. I am really looking forward to the update of MATLink when the communication overhead becomes really negligible. It is already a great tool but with such an update MATLink will be a killer app. – PlatoManiac Jan 30 '14 at 20:07
• That was very helpful, thanks! Your work helped a likely publication for tomorrow, thanks a bunch again. – asdfa Jan 30 '14 at 20:34