I would like to welcome guest writer Joshua Kaplan, an expert in one of the darkest undocumented corners of Matlab – that of the Java-to-Matlab interface (JMI). Today, Joshua will introduce JMI and its core functionality. Later articles will explore additional aspects of this complex technology.
As you’ve seen many times on this blog before, Matlab can easily call Java. This article explores the dark undocumented territory known as JMI (Java Matlab Interface) that enables calling Matlab from Java. This interface takes the form of a file called jmi.jar that comes with every copy of Matlab released in the past decade. JAR files are essentially a zip file containing Java class files. In this case, several Java classes in jmi.jar enable interaction with Matlab. This post will discuss the most important class: com.mathworks.jmi.Matlab.
Matlab’s dynamic evaluation functions
JMI easily allows calling two built-in Matlab functions: eval and feval. Essentially, eval evaluates any string typed into Matlab’s Command Window, and feval allows calling any function by name and passing in arguments. For example:
>> sqrt(5) ans = 2.2361 >> eval('sqrt(5)') ans = 2.2361 >> feval('sqrt',5) ans = 2.2361 |
The first approach takes the square root of 5 normally by directly calling Matlab’s square root function sqrt. JMI does not enable this direct-invocation approach. Instead, JMI uses the second approach, where eval mimics the first call by evaluating the entire expression inside single quotes. The third option, also used by JMI, is to use feval where the function and arguments are specified separately. While in the above example calling eval and feval is very similar, there are differences. For instance, assignment can be done as x=5 or eval(‘x=5’) but there is no feval equivalent. There are also other eval relatives, such as hgfeval, evalc and evalin, which will not be explained today.
Before we explore com.mathworks.jmi.Matlab, it is important to note a few things: Everything that follows is based on many hours of experimentation and online research and so while I am more or less certain of what I am about to explain, it could be deficient or incorrect in many respects. In fact, this area is so undocumented that an article written in 2002 by one of The MathWorks employees and published in the official newsletter, has been removed from their website a year or two ago.
Secondly, this post is written to satisfy people’s curiosities regarding JMI. If you actually wish to call Matlab from Java, I strongly suggest you use MatlabControl, a user-friendly Java library I have written that wraps JMI. There are many complications that arise with threading, method completion blocking, virtual machine restrictions, and other domains that prevent using JMI directly to be practical and reliable.
com.mathworks.jmi.Matlab class and its mtEval() method
With all of that said, let’s dive in! In the Matlab Command Window type:
methodsview('com.mathworks.jmi.Matlab') |
You will see all of the Matlab class’s numerous methods. Many of the methods have extremely similar names; many others have the same names and just different parameters. In order to call eval and feval we are going to use two of Matlab‘s methods:
public static Object mtEval(String command, int returnCount) public static Object mtFeval(String functionName, Object[] args, int returnCount) |
Since Matlab can call Java, we can experiment with these methods from Matlab. That’s right, we’re about to use Matlab to call Java to call Matlab!
First, let’s import the Java package that contains the Matlab class, to reduce typing:
import com.mathworks.jmi.* |
Now let’s take the square root of 5 like we did above, but this time from Java. Using JMI’s eval-equivalent:
Matlab.mtEval('sqrt(5)',1) |
Here, ‘sqrt(5)’ is what will be passed to eval, and 1 signifies that Matlab should expect one value to be returned. It is important that the second argument be accurate. If instead the call had been:
Matlab.mtEval('sqrt(5)',0) |
Then an empty string (”) will be returned. If instead, 2 or more were passed in:
Matlab.mtEval('sqrt(5)',2) |
Then a Java exception like the one below will occur:
??? Java exception occurred: com.mathworks.jmi.MatlabException: Error using ==> sqrt Too many output arguments. at com.mathworks.jmi.NativeMatlab.SendMatlabMessage(Native Method) at com.mathworks.jmi.NativeMatlab.sendMatlabMessage(NativeMatlab.java:212) at com.mathworks.jmi.MatlabLooper.sendMatlabMessage(MatlabLooper.java:121) at com.mathworks.jmi.Matlab.mtFeval(Matlab.java:1478) at com.mathworks.jmi.Matlab.mtEval(Matlab.java:1439)
Looking at this exception’s stack trace we notice that mtEval() is actually internally calling mtFeval().
com.mathworks.jmi.Matlab class’s mtFeval() method
Now to perform the square root using JMI’s feval-equivalent:
Matlab.mtFeval('sqrt',5,1) |
Here, ‘sqrt’ is the name of the Matlab function to be called, 5 is the argument to the function, and 1 is the expected number of return values. Again, the number of return values. If this number is specified as 0 instead of 1, the function call will still succeed, although not all of the results will necessarily be returned. The second mtFeval() argument, which specifies the arguments to the invoked Matlab function, can take any number of arguments as an array. Therefore the following is acceptable:
Matlab.mtFeval('sqrt',[5 3],1) |
This will return an array containing both of their square roots. Note that although two vales are returned, they are considered as only 1 since it is a single array that is returned.
Multiple Matlab arguments can be specified in mtFeval() using a cell array. For example, consider the following equivalent formats (note the different returned array orientation):
>> min(1:4,2) ans = 1 2 2 2 >> Matlab.mtFeval('min',{1:4,2},1) ans = 1 2 2 2 |
As we observed above, mtEval() is really just calling mtFeval(). This works because eval is a function, so feval can call it. An illustration:
Matlab.mtFeval('eval','sqrt(5)',1) |
com.mathworks.jmi.Matlab class’s mtFevalConsoleOutput() method
Both mtFeval() and mtEval() have allowed us to interact with Matlab, but the effects are not shown in the Command Window. There is a method that will allow us to do this:
public static Object mtFevalConsoleOutput(String functionName, Object[] args, int returnCount) |
mtFevalConsoleOutput() is just liked the mtFeval() command except that its effects will be shown. For instance:
>> Matlab.mtFeval('disp','hi',0); % no visible output >> Matlab.mtFevalConsoleOutput('disp','hi',0); hi |
There is no equivalent mtEvalConsoleOutput() method, but that’s not a problem because we have seen that eval can be accomplished using feval:
>> Matlab.mtFevalConsoleOutput('eval','x=5',0); x = 5 |
Other methods in com.mathworks.jmi.Matlab
There are many more eval and feval methods in the Matlab class. Most of these methods’ names begin with eval or feval instead of mtEval and mtFeval. Many of these methods are asynchronous, which means their effect on Matlab can occur after the method call returns. This is often problematic because if one method call creates a variable which is then used by the next call, there is no guarantee that the first call has completed (or even begun) by the time the second call tries to use the new variable. Unlike mtEval() and mtFeval(), these methods are not static, meaning we must have an instance of the Java class Matlab:
>> proxy = Matlab proxy = com.mathworks.jmi.Matlab@1faf67f0 |
Using this instance we will attempt to assign a variable and then retrieve it into a different variable. The result will be a Java exception indicating that ‘a’ does not currently exist:
>> proxy.evalConsoleOutput('a=5'); b = proxy.mtEval('a',1) ??? Java exception occurred: com.mathworks.jmi.MatlabException: Error using ==> eval Undefined function or variable 'a'. at com.mathworks.jmi.NativeMatlab.SendMatlabMessage(Native Method) at com.mathworks.jmi.NativeMatlab.sendMatlabMessage(NativeMatlab.java:212) at com.mathworks.jmi.MatlabLooper.sendMatlabMessage(MatlabLooper.java:121) at com.mathworks.jmi.Matlab.mtFeval(Matlab.java:1478) at com.mathworks.jmi.Matlab.mtEval(Matlab.java:1439) a = 5 |
If you run the above code you are not guaranteed to get that exception because of the nature of asynchronous method calls. However, this inherent unpredictability makes it difficult to perform almost any sequential action. Therefore, it is best to stick to mtEval, mtFeval, and mtFevalConsoleOutput, where this type of exception will be very remote. (They can still occur, about 1 in 100 times, as to why – I’d love to know as well.)
Two particular methods that may come in handy are mtSet() and mtGet(), which are the Java proxies for the Matlab set and get functions – they accept a Matlab handle (a double value) and a property name (a string) and either set the value or return it. Like Matlab, they also accept an array of property names. This can be used to update Matlab HG handles from within Java code, without needing to pass through an intermediary Matlab eval function:
>> Matlab.mtSet(gcf,'Color','b') >> Matlab.mtGet(gcf,'Color') ans = 0 0 1 >> Matlab.mtGet(gcf,{'Color','Name'}) ans = java.lang.Object[]: [3x1 double] 'My figure' |
Summary
With just eval and feval, an enormous amount of Matlab’s functionality can be accessed from Java. For instance, this allows for creating sophisticated Java GUIs with Swing and then being able to call Matlab code when the user clicks a button or moves a slider.
My next post will be on using MatlabControl to control Matlab from Java from within Matlab. The following post will discuss doing the same, but from a Java program launched outside of Matlab.
Addendum 2016-10-21: In R2016b, MathWorks has finally released a documented connector from Java to the Matlab engine, which should be used in place of JMI where possible.
[…] This post was mentioned on Twitter by michaelbloem. michaelbloem said: I've called Java from Matlab before, but didn't realized you could call Matlab from Java… http://bit.ly/aTVfAD […]
Very useful post. Thank you very much.
I am trying to use jmi to run a large java project from within matlab and I keep running into problems regarding PermGen space
“java.lang.OutOfMemoryError: PermGen space”
Increasing the maximum jvm memory helps to some extent, however, I cannot find a way to directly increase the PermGen space.
Any advice?
Thank you,
Lior
@Lior – you can add -XX:PermSize and -XX:MaxPermSize options to your java.opts file. The default values for these options on WinXP are 32M and 64M.
great tip.
I need to call the eig() function of Matlab from my Java program….how exactly do I do this??
[…] Calling MATLAB from Java is more complicated, but can be done with MATLAB extension, which is sold separately by MathWorks, or using an undocumented mechanism called JMI (Java-to-Matlab Interface) […]
Hi,
Thanks for that very nice post. I am just wondering, is it possible to use Java multi-agent based framework (JADE) with MATLAB/Simulink using JMI? Have anyone done this? Please share me some ideas.
Thanks
@Shantanu – indeed, I have seen several references over the years to people who have used JADE with Matlab and Simulink. Use this link to get started.
Thanks. This was very useful for me. I searched a solution for about 2 months. Now i have the solution.
You are Great!!!
@Vincenzo – I’m glad you like it
Hi,
Thanks for the post. I need to call a Matlab script with input arguments of different types (large matrices of different sizes) through Matlab.mtFevalConsoleOutput. Also, the Matlab script accepts only double matrices, not cell arrays. Can you please advise?
[…] dedicated and documented MEX functions; in Java this can be done using the undocumented/unsupported JMI (Java-Matlab Interface) package. Note that using standard Java Threads without Matlab synchronization is fully supported; it is […]
I need to call the main() function of Matlab and pass one input image to that main function from my Java program.
And how I can Exactly do that in proper manner..??
If someone know, please help me….
Hello,
Great read i was just wondering is there a way to convert the responses from Object to double to string.
For eg. I was working on ADFTest the other day and the values it returned were of Object type and i could not cast it to say double/string.
Your help would be much appreciated.
Thanks.
@Hardik – Objects cannot directly be converted into double/string in general. For example, how would you convert a “house” object into double? – there is no generic way to do that. The object would need to contain internal methods (functions) that provide double/string representations of the object. For strings, the customary method for this is the toString() method in Java Objects and char() in Matlab Objects. Refer to your object’s documentation to see which of its methods might help you.
If jmi is used,do we require Matlab then? And do all functionalities available inside Matlab can be accessed using jmi?
JMI is just a connector from Java to Matlab, it is not the Matlab engine. You still need the Matlab engine in order to do any Matlab processing with JMI.
Note that in R2016b, MathWorks has finally released a documented connector from Java to the Matlab engine, which should be used in place of JMI where possible: http://www.mathworks.com/help/matlab/matlab-engine-api-for-java.html
Hello,
In relation to your last answer, is it necessary to have R2016b installed? I have R2013b so I don’t have that: matlabroot/extern/engines/java/jar/engine.jar
Is there any solution apart from installing R2016b?
@Sergio – you only need R2016b if you want to use the new (documented) Matlab engine interface.
If you have R2016a or earlier you can use the undocumented JMI interface, as explained in the post above (and its followup posts).
Very useful post! I’ll be using this in one of my current projects.
BTW, it looks like the “MatlabControl” link in the fifth paragraph is broken. It’s pointing to googlecode.com, which is defunct. Could you update the link to MatlabControl’s current home?
@Andrew – I fixed the MatlabControl link to its new home on GitHub
Hi Yair
It’s a very nice post. I was able to run a Matlab script from within a Java class with
in the matlab console!
but I couldn’t get it run a function with input and/or output arguments, actually it doesn’t even compile because it either can’t call the function with the argument list or it can’t convert the return type (java.lang.Object) into the assignee (int) type – and won’t cast to an explicit cast. As all of your example invocations of Matlab.mtEval and Matlab.mtFeval are obviously examples run on Matlab console and not on a JVM, I was wondering if this is possible at all!!??
I have matlab 7.6.0 (2008a) and jdk/jvm 1.6.0 (both Matlab and compiler)
thx
PS: the code snippet:
Hi Yair
What is the point of invoking matlab functions by a java-matlab connector from inside the matlab console like in all of your examples????? From inside a java class – where this all actually would make a sense – not much works as described above. I can mtEval a script but when it comes to invoking a function with input and/or return arguments, the only thing which works half way is this:
but it returns a java.lang.Object and when I call getClass on it, I receive [D No clue what it is and how to convert it into a nummerical value!?
Can you please help.
again this DOESN’T even compile:
@Peyman – running a Java object that calls Matlab from within Matlab is an easy way to debug Java programs that will later be deployed outside Matlab.
[D
means aDouble
array. See here and here. To get a more human-readable string (‘double[]’ in your case), useclassName = hObject.getClass.getCanonicalName()
.Ok, I see. I could figure out that it was a
double[]
by callingobj.getClass().getSimpleName()
.Thank you very much Yair for these great posts and answering instantly!!
Hello, thanks for all your work that has been immensely useful for those working in the Matlab environment.
I have been trying to replace matlabcontrol with the official java matlab engine but faced a problem. In my case I want to invoke a matlab function by a java class that is instantiated within matlab. However, when the class tries to access the matlab engine the following exception is thrown:
Initializing MATLAB Engine API from MATLAB is not supported.
Can you confirm that the supported Matlab java interface does not allow connecting to a Matlab session where the java class was launched? This would then be a case where unfortunately the official interface does not replace matlabcontrol… Many thanks!
@Francisco – this is one of those cases where you should ask MathWorks support. After all, you’re trying to use a supported Matlab functionality when you encountered this limitation. Maybe MathWorks will be able to resolve your problem. Alternatively, you could post your query on Matlab Answers. If you discover a workaround, please post it here in a follow-up comment.