2010-09-27 8 views
8

Kann dieser Java-Code in Clojure-Code übersetzt werden, der so schnell oder fast so schnell ist?Java-Code in schnellen Clojure-Code umwandeln

Ich konnte einfachere Funktionen wie das Hinzufügen von zwei Arrays zu vernünftigen Geschwindigkeiten mit Typhinweis bekommen, aber ich konnte Clojure nicht dazu bringen, das zu tun, was die unten genannten Funktionen in einer vernünftigen Zeitspanne tun Java-Interop- oder Incanter-Matrizen und Verwendung von funktionalen oder imperativen Stilen.

Fehle ich etwas über Typ Hinting oder ist es am besten, so etwas in Java zu tun?

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; 
} 

Antwort

5

mit der clojure 1.3 Zweig beginnend zur Zeit auf Github können Sie use primitives as arguments to functions und kehrt von Funktionen. Sie müssen auch keine Tipp-Nummer-Primitiven mehr eingeben. Es sollte wirklich diese Art von Code viel schneller und viel eleganter erscheinen lassen.

In Typ Hinting könnten Sie gegen die Tatsache, dass (< = Clojure 1.2) alle Funktion Argumente wurden boxed.

+0

Was das genau bedeutet, dass die Funktionsargumente sind eingerahmt? Ich konnte Clojure-Code bekommen, der zwei 2d-Java-Arrays hinzufügt, um ziemlich nah an den nativen Geschwindigkeiten zu laufen. Wie ich es jetzt verstehe, zieht die Funktion Zahlen aus Java ein, fügt sie in clojure hinzu und drückt dann das Ergebnis zurück in ein Java-Array, und der Typ deutet dort auf die Clojure-Java-Interaktionen hin. Aber meine clojure-Versionen des Java-Codes tun dasselbe, nur dass es mehr Operationen in clojure gibt, bevor ich die Dinge zurück nach Java schiebe. Aber ich verstehe nicht, warum die zusätzlichen Operationen die Dinge so viel langsamer machen würden. – 2daaa

+0

Wenn ich Funktionsaufruf sage, beziehe ich mich darauf, eine Clojure-Funktion aufzurufen. Wenn Sie (my-function 42 :-P) ausführen, ist die Zahl 42 eine Integer-Klasseninstanz und kein primitives int, selbst wenn Sie es eingeben. Auch der Rückgabetyp eines Clojure-Funktionsaufrufs ist immer ein Objekt und niemals ein Primitiv (vor Clojure 1.3). Der Übergang zu Clojure-Funktion 1.3 kann eine Null von der Laufzeit einiger stark numerischer Funktionen abbrechen. –

+0

Ohne Typhinweis, wie würden Sie mit gemischten Sammlungen umgehen? –

3

Das andere Stück, das helfen wird (auch in 1.3) ist statische Funktionsverknüpfung, die einige Funktionsaufrufe so schnell wie Methodenaufrufe machen wird (dies wird auch in dem von Arthur geposteten Link beschrieben).

Es wird immer noch schwierig sein, diesen Code in wirklich idiomatischer Weise (dh mit der Funktion "map" höherer Ordnung) für jetzt bei voller Java-Leistung zu schreiben, da Funktionen höherer Ordnung nicht in der Lage sind, statisch zu verwenden Verknüpfung, aber (schamlose Werbung Warnung) ist dies etwas, Rich-Hickey beheben will:

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

+0

wäre es wirklich schön, Funktionen auf Primitiven abzubilden. –

+0

statische Funktionen sind eine Voraussetzung für die Verwendung von Primaten als Argumente oder Rückgabetypen. –

+0

wie sie derzeit implementiert werden, stimmt das. Rich hat während des SF-Meetups eine Unterscheidung getroffen und festgestellt, dass sie auf der JVM-Ebene nicht streng gekoppelt sind - es klingt, als ob die primitive Unterstützung, die er implementiert, irgendwann nicht fest mit statischen Funktionen gekoppelt ist. – tvachon

8

Versuchen Sie folgendes in Clojure 1.3 (Master-Zweig):

(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

Ich habe versucht, ein Array zu erstellen: (Def A (In-Array (Karte Doppel-Array (Map # (wiederholen L% 1) (Bereich L))))), und dann Ihre Grad2-Funktion: (Zeit (grad2 A 1 1)) aber es bricht einfach ab und ich sehe keine Stack-Spur aus irgendeinem Grund. – 2daaa