我开始学习Clojure,并试图实现一些基本的数值微分函数。我试图创建一个接受n变量函数的gradient
函数以及评估它的点。为了以“功能性”的风格做到这一点,我想实现渐变作为单变量衍生物的map
。Clojure中部分输出变量函数中的第i个变量
1-可变衍生物的功能是简单的:
(defn derivative
"Numerical derivative of a univariate function."
[f x]
(let [eps 10e-6] ; Fix epsilon, just for starters.
; Centered derivative is [f(x+e) - f(x-e)]/(2e)
(/ (- (f (+ x eps)) (f (- x eps))) (* 2 eps))))
我想设计沿着这些线的梯度:
(defn gradient
"Numerical gradient of a multivariate function."
[f & x]
(let [varity-index (range (count x))
univariate-in-i (fn [i] (_?_))] ; Creates a univariate fn
; of x_i (other x's fixed)
;; For each i = 0, ... n-1:
;; (1) Get univariate function of x_i
;; (2) Take derivative of that function
;; Gradient is sequence of those univariate derivatives.
(map derivative (map univariate-in-i varity-index) x)))
所以,gradient
具有可变的元数(可以接受任何#的x's)以及x的计数顺序。函数univariate-in-i
采用索引i = 0, 1, ... n-1
,并通过将除x_i
以外的所有变量进行部分分解来返回1变量函数。例如,你会得到:
#(f x_0 x_1 ... x_i-1 % x_i+1 ... x_n)
^
(x_i still variable)
map
在varity-index
-ping这个功能可以让你的1变量函数在每个x_i
序列,然后map
-ping derivative
对这些让你衍生物的序列中的每个x_i
这是我们想要的渐变。
我的问题是:我不确定实施univariate-in-i
的好方法是什么。我基本上需要填写f
中的x的值,除了某些特定的地方(即,放置上面的%
),但是以编程方式。我对技术比解决方案更感兴趣(即我知道如何计算渐变,我试图学习函数式编程和惯用的Clojure)。因此,我想忠于将梯度视为一维导出函数的分布图的策略。但是如果有更好的“功能”方法,请告诉我。如果可能的话,我宁愿不求助于宏。
在此先感谢!
更新:
使用下面ANKUR的回答,梯度功能我得到的是:
(defn gradient
"Numerical gradient of a multivariate function."
[f & x]
(let [varity-index (range (count x))
x-vec (vec x)
univariate-in-i
(fn [i] #(->> (assoc x-vec i %) (apply f)))]
(map derivative (map univariate-in-i varity-index) x)))
这不正是我所希望的,而且似乎非常简洁和实用。
'default'这里只是上面的'x' rest参数吧? – dfreeman 2013-03-18 17:21:52
这很好用:'default'是'x',但是包裹在一个向量中对我来说完全理解有点微妙,但我会通过它来思考。我认为这是我正在寻找的答案。谢谢! – Carl 2013-03-18 17:39:37
诀窍是向量实现'clojure.lang.Associative',这就是允许你在'i'处换掉元素的非应用参数:) – dfreeman 2013-03-18 17:50:48