2010-09-27 12 views
8

¿Se puede traducir este código Java a código Clojure que sea tan rápido o casi tan rápido?Convertir código Java en código Clojure rápido

He podido obtener funciones más simples como agregar dos matrices para ejecutar a velocidades razonables con insinuación de tipo, pero no pude hacer que Clojure hiciera lo que las siguientes funciones hacen en un tiempo razonable usando cualquiera Matrices Java interop o Incanter y utilizando estilos funcionales o imperativos.

¿Me falta algo sobre el tipo de alusión o es simplemente lo mejor para hacer este tipo de cosas en 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; 
} 

Respuesta

5

empezando por la rama 1.3 clojure actualmente en github que pueda use primitives as arguments to functions y retornos de funciones. Tampoco tendrá que escribir las primitivas del número de sugerencia. Realmente debería hacer sugerencias sobre este tipo de código mucho más rápido y parecer mucho más elegante.

En este tipo dando a entender que podría funcionar con el hecho de que (= < clojure 1.2) todos los argumentos de la función fueron encajonados.

+0

¿Qué quiere decir exactamente que el que los argumentos de la función están enmarcados? Pude obtener código clojure que agrega dos arreglos java 2d para correr bastante cerca de las velocidades nativas. Tal como lo entiendo ahora, la función extrae números de java, los agrega en clojure, y luego empuja el resultado de regreso a una matriz java, y el tipo apunta allí para las interacciones de clojure a java. Pero mis versiones de clojure del código java hacen lo mismo, solo que hay más operaciones en clojure antes de volver a enviar las cosas a Java. Pero no entiendo por qué las operaciones adicionales harían las cosas mucho más lentas. – 2daaa

+0

Cuando digo llamada de función, me refiero a llamar a una función clojure. si ejecuta (my-function 42 :-P) el número 42 es una instancia de clase Integer y no una int primitiva, incluso si escribe insinuación. también el tipo de retorno de una llamada de función clojure es siempre un Objeto y nunca una primitiva (antes de clojure 1.3) La transición a clojure 1.3 puede caer un cero desde el tiempo de ejecución de algunas funciones muy numéricas. –

+0

Sin sugerencias tipográficas, ¿cómo trataría con las colecciones mix-type? –

3

La otra pieza que ayudará (también en 1.3) es la vinculación de funciones estáticas, que hará que algunas llamadas a funciones sean tan rápidas como las llamadas a métodos (esto también se describe en el enlace publicado por Arthur).

Todavía será difícil escribir este código de una manera verdaderamente idiomática (es decir, usando la función de orden superior "mapa") por ahora con un rendimiento completo de java, ya que las funciones de orden superior no podrán usar estática la vinculación, pero (descarada testigo de control) esto es algo Rich Hickey quiere rectificar:

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

+0

sería realmente bueno mapear funciones en primitivas. –

+0

funciones estáticas son un requisito previo para utilizar primativos como argumentos o tipos de devolución. –

+0

la forma en que se están implementando actualmente, eso es cierto. Rich hizo una distinción durante el encuentro de SF, señalando que a nivel JVM, no están estrictamente acoplados, parece que el soporte primitivo que está implementando puede en algún momento no estar estrechamente acoplado con funciones estáticas. – tvachon

8

intente lo siguiente en clojure 1.3 (rama principal):

(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)) 
+0

He intentado crear una matriz: (def A (en-array (mapa doble-array (mapa # (repetir L% 1) (rango L))))), y luego su función grad2: (tiempo (grad2 A 1 1))) pero simplemente aborta y no veo ningún rastro de pila por alguna razón. – 2daaa

Cuestiones relacionadas