2016-11-02 4 views
0

J'essaye d'écrire un simple modèle d'espace d'état de Markov, qui, comme son nom l'indique, fait un retour en arrière pour prédire l'état suivant.Clojure boucle et récurrence ou réduire dans le modèle d'espace d'état

Voici ce qui est censé être un MWF, mais ce n'est pas parce que je ne peux pas comprendre tout à fait comment je suis censé placer (recur ...) dans le code ci-dessous.

;; 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)])))) 

Mon objectif est de calculer un certain état à dire le temps t=5 dire, dans ce cas, le modèle a besoin de regarder en arrière et de calculer les états t=[0 1 2 3 4] ainsi. Cela devrait, dans mon esprit, se faire bien avec loop/recur mais pourrait également être fait avec reduce peut-être (pas sûr de savoir, encore nouveau pour Clojure). Mon problème est vraiment qu'il devrait utiliser recur à l'intérieur let mais cela ne devrait pas fonctionner étant donné comment loop/recur sont conçus.

Répondre

2

votre tâche est vraiment de générer l'élément suivant basé sur le précédent, en commençant par une graine. En clojure il peut être rempli en utilisant la fonction iterate:

user> (take 10 (iterate #(+ 2 %) 1)) 
(1 3 5 7 9 11 13 15 17 19) 

il vous suffit de définir la fonction de produire la valeur suivante. Il pourrait ressembler à ceci (pas sûr de l'exactitude de l'algorithme de calcul, juste en fonction de ce qui est dans la question):

(defn next-item [[prev-s prev-d :as prev-item]] 
    (let [s (trans-call prev-s prev-d)] 
    [s (dur-call s prev-d)])) 

et maintenant nous allons itérer avec elle, à partir d'une certaine valeur:

user> (take 5 (iterate next-item [3 4])) 
([3 4] [3 3] [3 2] [3 1] [0 0]) 

maintenant votre fonction de test pourrait être mis en œuvre ainsi:

(defn test-fn [t] 
    (when (not (neg? t)) 
    (nth (iterate next-item 
        (let [s (rand-int 3)] 
        [s (rand-int (inc s))])) 
     t))) 

vous pouvez aussi le faire avec la boucle (mais il est encore moins idiomatiques):

(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))))))))) 

ici nous passons tous les résultats accumulés à l'itération suivante de la boucle.

vous pouvez également introduire l'index d'itération de la boucle et juste passer autour du dernier résultat avec elle:

(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))))))) 

et un exemple avec 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)))) 
+0

C'est tout simplement magnifique! Je suppose que ce que je ne comprends pas, c'est quand utiliser 'loop/recur',' réduire' et 'itérer'. Vraisemblablement, on pourrait faire une récursion de cela aussi? Pourquoi pas toi? – Astrid

+1

mis à jour ma réponse avec la solution récursive. Je ne voudrais pas utiliser la récursivité ici, puisque ce cas est si fréquent, qu'il y a une fonction pour cela. De plus, comme il produit un seq paresseux, ses limites d'utilisation sont beaucoup plus larges en général que les simples boucles (enfin, cela dépend toujours de vos besoins) – leetwinski

+0

Je vois, incroyable réponse monsieur. – Astrid