2016-04-06 2 views
2

Я использовал py4j для создания удобной библиотеки Python для менее удобной библиотеки Java. По большей части это был легкий ветерок, а py4j - отличный инструмент. Тем не менее, я столкнулся с проблемой при отправке матриц между Python и Java.Использование py4j для отправки матриц из Python в Java как int [] [] arrays

В частности, у меня есть статическая функция в Java, который принимает в качестве своих аргументов, целой матрица:

public class MyClass { 
    // ... 
    public static MyObject create(int[][] matrix) { 
     // ... 
    } 
} 

я хотел бы быть в состоянии назвать это из Py4j так:

def create_java_object(numpy_matrix): 
    # <code here checks that numpy_matrix is a (3 x n) integer matrix> 
    # ... 
    return java_instance.jvm.my.namespace.MyClass.create(numpy_matrix) 

Это не работает, что не удивительно, и не работает, если numpy_matrix вместо этого преобразуется в список простых списков python. Я ожидал, что решение было бы построить массив Java и передавать данные через до вызова функции:

def create_java_object(numpy_matrix): 
    # <code here checks that numpy_matrix is a (3 x n) integer matrix> 
    # ... 
    java_matrix = java_instance.new_array(java_instance.jvm.int, 3, n) 
    for i in range(numpy_matrix.shape[1]): 
     java_matrix[0][i] = int(numpy_matrix[0, i]) 
     java_matrix[1][i] = int(numpy_matrix[1, i]) 
     java_matrix[2][i] = int(numpy_matrix[2, i]) 
    return java_instance.jvm.my.namespace.MyClass.create(java_matrix) 

Теперь этот код работает правильно. Однако для этого требуется примерно две минуты. Матрицы, с которыми я работаю, кстати, имеют порядок (3 х ~ 300 000) элементов.

Есть ли канонический способ сделать это в Py4j, который не требует невероятного количества времени для преобразования матрицы? Я не возражаю, что это займет секунду или два, но это слишком медленно. Если Py4j не настроен для такого общения, существует ли библиотека взаимодействия Java для Python?

Примечание: Библиотека Java обрабатывает матрицу int[][] как неизменяемый массив; т. е. он никогда не пытается его модифицировать.

ответ

3

Я нашел решение для этого конкретного случая, который работает; хотя это не очень элегантно:

Py4j поддерживает эффективную передачу объекта Python bytearray в Java как массив byte[]. Я работал над проблемой, изменяя исходную библиотеку и свой код Python.

Новый код Java:

public class MyClass { 
    // ... 
    public static MyObject create(int[][] matrix) { 
     // ... 
    } 
    public static MyObject createFromPy4j(byte[] data) { 
     java.nio.ByteBuffer buf = java.nio.ByteBuffer.wrap(data); 
     int n = buf.getInt(), m = buf.getInt(); 
     int[][] matrix = new int[n][m]; 
     for (int i = 0; i < n; ++i) 
     for (int j = 0; j < m; ++j) 
      matrix[i][j] = buf.getInt(); 
     return MyClass.create(matrix); 
    } 
} 

Новый код Python:

def create_java_object(numpy_matrix): 
    header = array.array('i', list(numpy_matrix.shape)) 
    body = array.array('i', numpy_matrix.flatten().tolist()); 
    if sys.byteorder != 'big': 
     header.byteswap() 
     body.byteswap() 
    buf = bytearray(header.tostring() + body.tostring()) 
    return java_instance.jvm.my.namespace.MyClass.createFromPy4j(buf) 

Это работает в течение нескольких секунд, а не за несколько минут.

+0

Это будет работать только для 2D-матриц? Как сохранить длину формы в качестве первого значения, чтобы вы могли отправить матрицу любой формы? – crockpotveggies

 Смежные вопросы

  • Нет связанных вопросов^_^