【问题标题】:Partial out all but i-th variable in variadic function in ClojureClojure中可变参数函数中除第i个变量外的所有变量
【发布时间】: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


    【解决方案1】:

    您可以定义univariate-in-i,如下所示。 (假设所有其他位置值都定义在某个 var default 中,它是一个向量)

    (fn [i] #(->>
               (assoc default i %)
               (apply f)))
    

    【讨论】:

    • default 这里只是上面的 x 其余参数,对吧?
    • 这很好用:defaultx,但包裹在一个向量中。这对我来说有点难以完全理解,但我会仔细考虑的。我认为这是我正在寻找的答案。谢谢!
    • 诀窍是向量实现了clojure.lang.Associative,这使您可以将i 处的元素换成未应用的参数:)
    【解决方案2】:

    如果你觉得这有点难以理解(在如何实现渐变的上下文中),使用 clojure 实现多变量渐变的另一种变体: 然后,给定f and vector v of a1,....,aN,将区分除 xi 之外的所有变量:

    (defn partial-diff [f v i]
      (let [h 10e-6
            w (update v i + h)]
        (/ (- (apply f w) (apply f v))
           h)))
    
    (defn gradient [f v]
      (map #(partial-diff f v %) (range (count v))))
    

    =>

    (gradient (fn [x y] 
                  (+ (* x x) (* x y y))) [3 3])
    => (15.000009999965867 18.000030000564493)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多