JMI – Java-to-Matlab Interface

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.

Categories: Guest bloggers, High risk of breaking in future versions, Java, Undocumented feature

Tags: , , ,

Bookmark and SharePrint Print

25 Responses to JMI – Java-to-Matlab Interface

  1. Pingback: Tweets that mention JMI - Java-to-Matlab Interface | Undocumented Matlab -- Topsy.com

  2. Lior says:

    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

  3. Jeet says:

    I need to call the eig() function of Matlab from my Java program….how exactly do I do this??

  4. Pingback: MATLAB | Thermal Vision Research

  5. shantanu says:

    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

  6. Vincenzo says:

    Thanks. This was very useful for me. I searched a solution for about 2 months. Now i have the solution.
    You are Great!!!

  7. Baba says:

    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?

  8. Pingback: Explicit multi-threading in Matlab – part 1 | Undocumented Matlab

  9. Ramlal Chaudhari says:

    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….

  10. Hardik says:

    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.

  11. Anonymous says:

    If jmi is used,do we require Matlab then? And do all functionalities available inside Matlab can be accessed using jmi?

  12. 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?

  13. Peyman says:

    Hi Yair
    It’s a very nice post. I was able to run a Matlab script from within a Java class with

    import com.mathworks.jmi.*
    ...
    Matlab.mtEval("someScript");
    ...

    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:

    import com.mathworks.jmi.*;
    import java.util.LinkedList;
     
    public class MatlabRunner implements Runnable{
        public LinkedList rrIntervals;
     
        public MatlabRunner(LinkedList list) {
            this.rrIntervals = list;
        }
     
        @Override
        public void run() {
            System.out.println("running the matlab runner...");
            long t0 = System.nanoTime();
            int isTrigger = 0;
     
            while(isTrigger == 0) {
                try {
                    isTrigger = (int) Matlab.mtEval("waitTrigger(ioObj, address)", 1);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
     
            long t1 = System.nanoTime();
            long elapsedTime = (long) ((t1 - t0) / 1000);
            System.out.println("elapse time = " + elapsedTime);
     
            this.rrIntervals.remove();
            this.rrIntervals.add(elapsedTime);
        }
    }
  14. Peyman says:

    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:

    Matlab.mtEval("functionWithInputAndReturnValue(3, 5)", 1);

    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:

    Object isTrigger = new Object();
            int[] args = new int[2];
            args[0] = 3;
            args[1] = 5;
            try {
                isTrigger = Matlab.mtFeval("functionWithInputAndReturnValue", args, 1);
            } catch (Exception e) {
                e.printStackTrace();
            }
    • @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 a Double array. See here and here. To get a more human-readable string (‘double[]’ in your case), use className = hObject.getClass.getCanonicalName().

    • Peyman says:

      Ok, I see. I could figure out that it was a double[] by calling obj.getClass().getSimpleName().
      Thank you very much Yair for these great posts and answering instantly!!

Leave a Reply

Your email address will not be published. Required fields are marked *