Превращение кода Java в быстрый код Clojure - PullRequest
8 голосов
/ 28 сентября 2010

Может ли этот Java-код быть переведен в код Clojure, который такой же быстрый или почти такой же быстрый?

Мне удалось получить более простые функции, такие как добавление двух массивов для работы на разумных скоростях с подсказкой типов, но я не мог заставить Clojure делать то, что перечисленные ниже функции вообще, за разумное времяиспользуя Java Interop или матрицы Incanter и используя либо функциональные, либо императивные стили.

Я что-то упускаю из-за подсказок по типу или лучше всего делать такие вещи в Java?

static double[][] grad2_stencil= { {0,0,-1,0,0}, 
                             {0,0,16,0,0}, 
                             {-1,16,-60,16,-1}, 
                             {0,0,16,0,0}, 
                             {0,0,-1,0,0} };

public static double grad2(double[][] array, int x, int y){
    double temp=0;
    int L=array.length;
    for(int i=0; i<5; i++){
        for(int j=0; j<5; j++){
            temp+=array[((x+i-2)%L+L)%L][((y+j-2)%L+L)%L]*grad2_stencil[i][j];
        }
    }
    return temp/12.0;
}

public static double[][] grad2_field(double[][] arr){
    int L=arr.length;
    double[][] result=new double[L][L];

    for(int i=0; i<L; i++){
        for(int j=0; j<L; j++){
            result[i][j]=grad2(arr, i, j);
        }
    }

    return result;
}

Ответы [ 3 ]

8 голосов
/ 28 сентября 2010

Попробуйте следующее в clojure 1.3 (основная ветка):

(def ^"[[D" grad2-stencil
  (into-array (Class/forName "[D")
    (map double-array 
      [[ 0   0  -1  0  0 ] 
       [ 0   0  16  0  0 ]
       [-1  16 -60 16 -1 ] 
       [ 0   0  16  0  0 ] 
       [ 0   0  -1  0  0 ]])))

(defn ^:static idx ^long [^long x ^long i ^long L]
  (-> x
    (+ i)
    (- 2)
    (mod L)
    (+ L)
    (mod L)))

(defn ^:static grad2 ^double [^doubles arr ^long x ^long y]
  (let [L (alength arr)
        temp (loop [i 0 j 0 temp 0.0]
               (if (< i 5) 
                 (let [a (idx x i L)
                       b (idx y j L)
                       temp (double (* (aget arr a b) 
                                      (aget grad2-stencil i j)))]
                   (if (< j 4)
                     (recur i (inc j) temp)
                     (recur (inc i) 0 temp)))
                 temp))]
    (/ temp 12.0)))

(defn ^:static grad2-field ^"[[D" [^"[[D" arr]
  (let [result (make-array Double/TYPE (alength arr) (alength arr))]
    (loop [i 0 j 0]
      (when (< i 5)
        (aset result (grad2 arr i j) i j)
        (if (< j 4)
          (recur i (inc j))
          (recur (inc i) 0))))
    result))
5 голосов
/ 28 сентября 2010

начиная с ветки clojure 1.3, в настоящее время находящейся на github, вы можете использовать примитивы в качестве аргументов для функций и возвращаться из функций.Вам также больше не придется вводить примитивы с номерами подсказок.Это действительно должно сделать подсказки такого типа намного быстрее и выглядеть более элегантно.

При подсказке типа вы можете столкнуться с тем фактом, что (<= clojure 1.2) все <b>аргументы функции были упакованы .

3 голосов
/ 28 сентября 2010

Другая часть, которая поможет (также в 1.3) - это статическое связывание функций, которое будет выполнять некоторые вызовы функций так же быстро, как вызовы методов (это также описано в ссылке, опубликованной Артуром).

По-прежнему будет трудно написать этот код по-настоящему идиоматическим способом (т. Е. Используя функцию «map» высшего порядка) на данный момент с полной производительностью Java, поскольку функции более высокого порядка не смогутиспользуйте статическое связывание, но (бесстыдное предупреждение о штекере) Рич Хики хочет исправить это:

http://combinate.us/clojure/2010/09/27/clojure/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...