这个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;
}
答案 0 :(得分:8)
在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))
答案 1 :(得分:5)
从当前在github上的clojure 1.3分支开始,您可以use primitives as arguments to functions并从函数返回。您也将不再需要键入提示编号基元。它应该能够更快地暗示这种类型的代码并且看起来更优雅。
在类型提示中,你可能会遇到(&lt; = clojure 1.2)所有函数参数被装箱的事实。
答案 2 :(得分:3)
另一个有帮助的部分(也在1.3中)是静态函数链接,这将使一些函数调用与方法调用一样快(这也在Arthur发布的链接中描述)。
现在仍然很难以真正惯用的方式编写此代码(即使用“map”高阶函数),因为高阶函数将无法使用静态链接,但是(无耻的插头警告)这是Rich Hickey想要纠正的事情: