Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Efficiently Converting Java List to Matlab Matrix

I am calling the Google Protocol Buffers Java API from Matlab. This works pretty well, but I have hit a big performance bottleneck. The bulk of the data are returned as objects of type:

java.util.Collections$UnmodifiableRandomAccessList

They actually contain a list of floats. I need to convert this to a Matlab matrix. The best approach I have found so far is to call:

cell2mat(cell(Q.toArray()))

However, that one line is a huge performance bottleneck in the code.

Note I am aware of the FarSounder Matlab parser generators for the Google Protocol Buffers, unfortunately these are very slow. See below for some rough benchmark speeds for my problem (YMMV). High is good.

  • Farsounder Matlab: 0.03
  • Pure Python: 1
  • Java API called from Matlab (parsing and extracting metadata only): 10
  • Java API called from Matlab (parsing and extracting both metadata and data): 0.25

If it wasn't for the overhead of converting the java.util.Collections$UnmodifiableRandomAccessList to a Matlab matrix, then the approach of calling the Java API from Matlab would look quite promising.

Is there a better way of converting this Java object into a Matlab matrix?

Bear in mind that the method returning this type is in automatically generated code.

like image 803
Andrew McLean Avatar asked Feb 14 '23 00:02

Andrew McLean


2 Answers

You might be best writing a tiny piece of extra java code, like so:

import java.util.List;
import java.util.ListIterator;

class Helper {
    public static float[] toFloatArray(List l) {
        float retValue[] = new float[l.size()];
        ListIterator iterator = l.listIterator();
        for (int idx = 0; idx < retValue.length; ++idx ){
            // List had better contain float values,
            // or else the following line will ClassCastException.
            retValue[idx] = (float) iterator.next();
        }
        return retValue;
    }
}

with which I see:

>> j = java.util.LinkedList;
>> for idx = 1:1e5, j.add(single(idx)); end
>> tic, out = Helper.toFloatArray(j); toc
Elapsed time is 0.006553 seconds.
>> tic, cell2mat(cell(j.toArray)); toc
Elapsed time is 0.305973 seconds.
like image 191
Edric Avatar answered Feb 22 '23 23:02

Edric


In my experience, the most performant solution is write a little set of java helpers, that converts the lists to plain arrays of primitive types. These are well mapped to matrices by matlab.

If the above e.g. gives a an array of java.lang.Floats, the helper could look like this:

public static float[] toFloats(Float[] floats) {
    float[] rv = new float[floats.length];
    for (int i=0; i < floats.length; i++) rv[i] = (float) floats[i];
    return rv;
}

In matlab cell2mat(cell(Q.toArray())) hence would become:

some.package.toFloats(Q.toArray());

Obviously you could modify the helper function to directly take your list as well, avoiding the need for the toArray() call (does this actually make a copy?).

like image 40
sebastian Avatar answered Feb 23 '23 00:02

sebastian