Clojure 循环并在状态 space 模型中重复出现或减少
Clojure loop and recur or reduce in state space model
我正在尝试编写一个简单的马尔可夫状态 space 模型,顾名思义,它会反复回顾一个步骤以预测下一个状态。
这应该是一个 MWE,虽然它不是因为我不太清楚我应该如何在下面的代码中放置 (recur ... )
。
;; helper function
(defn dur-call
[S D]
(if (< 1 D)
(- D 1)
(rand-int S)))
;; helper function
(defn trans-call
[S D]
(if (< 1 D)
S
(rand-int 3)))
;; state space model
(defn test-func
[t]
(loop
[S (rand-int 3)]
(if (<= t 0)
[S (rand-int (+ S 1))]
(let [pastS (first (test-func (- t 1)))
pastD (second (test-func (- t 1)))
S (trans-call pastS pastD)]
(recur ...?)
[S (dur-call S pastD)]))))
我的目标是在说时间 t=5
计算一些状态,在这种情况下,模型需要回顾并计算状态 t=[0 1 2 3 4]
。在我看来,这应该用 loop/recur
很好地完成,但也可以用 reduce
完成(不确定如何,对 Clojure 来说仍然是新手)。我的问题确实是,它似乎必须在 let
中使用 recur
,但考虑到 loop/recur
的设计方式,这应该行不通。
你的任务实际上是根据前一个项目生成下一个项目,从一些种子开始。在 clojure 中,它可以通过使用 iterate
函数来实现:
user> (take 10 (iterate #(+ 2 %) 1))
(1 3 5 7 9 11 13 15 17 19)
您只需定义生成下一个值的函数。它可能看起来像这样(不确定计算算法的正确性,只是根据问题中的内容):
(defn next-item [[prev-s prev-d :as prev-item]]
(let [s (trans-call prev-s prev-d)]
[s (dur-call s prev-d)]))
现在让我们从某个值开始对其进行迭代:
user> (take 5 (iterate next-item [3 4]))
([3 4] [3 3] [3 2] [3 1] [0 0])
现在你的测试函数可以这样实现了:
(defn test-fn [t]
(when (not (neg? t))
(nth (iterate next-item
(let [s (rand-int 3)]
[s (rand-int (inc s))]))
t)))
你也可以用循环来做(但它仍然不那么惯用):
(defn test-fn-2 [t]
(when (not (neg? t))
(let [s (rand-int 3)
d (rand-int (inc s))]
(loop [results [[s d]]]
(if (< t (count results))
(peek results)
(recur (conj results (next-item (peek results)))))))))
这里我们将所有累积的结果传递给循环的下一次迭代。
你也可以引入循环的迭代索引,并只传递最后一个结果:
(defn test-fn-3 [t]
(when (not (neg? t))
(let [s (rand-int 3)
d (rand-int (inc s))]
(loop [result [s d] i 0]
(if (= i t)
result
(recur (next-item result) (inc i)))))))
还有一个 reduce
的例子:
(defn test-fn-4 [t]
(when (not (neg? t))
(reduce (fn [prev _] (next-item prev))
(let [s (rand-int 3)
d (rand-int (inc s))]
[s d])
(range t))))
我正在尝试编写一个简单的马尔可夫状态 space 模型,顾名思义,它会反复回顾一个步骤以预测下一个状态。
这应该是一个 MWE,虽然它不是因为我不太清楚我应该如何在下面的代码中放置 (recur ... )
。
;; helper function
(defn dur-call
[S D]
(if (< 1 D)
(- D 1)
(rand-int S)))
;; helper function
(defn trans-call
[S D]
(if (< 1 D)
S
(rand-int 3)))
;; state space model
(defn test-func
[t]
(loop
[S (rand-int 3)]
(if (<= t 0)
[S (rand-int (+ S 1))]
(let [pastS (first (test-func (- t 1)))
pastD (second (test-func (- t 1)))
S (trans-call pastS pastD)]
(recur ...?)
[S (dur-call S pastD)]))))
我的目标是在说时间 t=5
计算一些状态,在这种情况下,模型需要回顾并计算状态 t=[0 1 2 3 4]
。在我看来,这应该用 loop/recur
很好地完成,但也可以用 reduce
完成(不确定如何,对 Clojure 来说仍然是新手)。我的问题确实是,它似乎必须在 let
中使用 recur
,但考虑到 loop/recur
的设计方式,这应该行不通。
你的任务实际上是根据前一个项目生成下一个项目,从一些种子开始。在 clojure 中,它可以通过使用 iterate
函数来实现:
user> (take 10 (iterate #(+ 2 %) 1))
(1 3 5 7 9 11 13 15 17 19)
您只需定义生成下一个值的函数。它可能看起来像这样(不确定计算算法的正确性,只是根据问题中的内容):
(defn next-item [[prev-s prev-d :as prev-item]]
(let [s (trans-call prev-s prev-d)]
[s (dur-call s prev-d)]))
现在让我们从某个值开始对其进行迭代:
user> (take 5 (iterate next-item [3 4]))
([3 4] [3 3] [3 2] [3 1] [0 0])
现在你的测试函数可以这样实现了:
(defn test-fn [t]
(when (not (neg? t))
(nth (iterate next-item
(let [s (rand-int 3)]
[s (rand-int (inc s))]))
t)))
你也可以用循环来做(但它仍然不那么惯用):
(defn test-fn-2 [t]
(when (not (neg? t))
(let [s (rand-int 3)
d (rand-int (inc s))]
(loop [results [[s d]]]
(if (< t (count results))
(peek results)
(recur (conj results (next-item (peek results)))))))))
这里我们将所有累积的结果传递给循环的下一次迭代。
你也可以引入循环的迭代索引,并只传递最后一个结果:
(defn test-fn-3 [t]
(when (not (neg? t))
(let [s (rand-int 3)
d (rand-int (inc s))]
(loop [result [s d] i 0]
(if (= i t)
result
(recur (next-item result) (inc i)))))))
还有一个 reduce
的例子:
(defn test-fn-4 [t]
(when (not (neg? t))
(reduce (fn [prev _] (next-item prev))
(let [s (rand-int 3)
d (rand-int (inc s))]
[s d])
(range t))))