【发布时间】:2013-03-18 16:42:14
【问题描述】:
我开始学习 Clojure,并试图实现一些基本的数值导数函数以供练习。我正在尝试创建一个 gradient 函数,该函数接受一个 n 变量函数以及评估它的点。为了以“函数式”风格执行此操作,我想将渐变实现为 1 变量导数的 map。
一元导数函数很简单:
(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 具有可变的 arity(可以接受任何 # 个 x),以及 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-ping 这个函数在varity-index 上为您提供每个x_i 中的1 变量函数序列,然后map-ping derivative 在这些上为您提供每个@ 中的导数序列987654335@,也就是我们想要的渐变。
我的问题是:我不确定实现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)))
这正是我所希望的,并且看起来非常简洁和实用。
【问题讨论】:
标签: clojure