Clojure Training: Recursion for the Hidden Markov Model

I study Clojure and start by copying the functions of a Python program that will create genomic sequences following the (extremely simple) hidden Markov model.

In the beginning, I stuck with my well-known method of sequential programming and used the def keyword many times, thereby solving the problem with many side effects, carrying almost any Clojure concept right in the butt. (although it worked as expected)

Then I tried to convert it to a more functional way using a loop, recur, atom, etc. Now when I run, I get an ArityException, but I cannot read the error message in such a way as to show me which function is calling it.

(defn create-model [name pA pC pG pT pSwitch]
; converts propabilities to cumulative prop and returns a char
  (with-meta
    (fn []
      (let [x (rand)]
        (if (<= x pA)
          \A
          (if (<= x (+ pA pC))
            \C
            (if (<= x (+ pA pC pG))
              \G
              \T)))))                   ; the function object
    {:p-switch pSwitch :name name}))    ; the metadata, used to change model


(defn create-genome [n]
; adds random chars from a model to a string and switches models randomly
  (let [models [(create-model "std" 0.25 0.25 0.25 0.25 0.02) ; standard model, equal props
                (create-model "cpg" 0.1 0.4 0.4 0.1 0.04)]    ; cpg model
        islands (atom 0)                 ; island counter
        m (atom 0)]                      ; model index
    (loop [result (str)]
      (let [model (nth models @m)]
        (when (< (rand) (:p-switch (meta model))) ; random says "switch model!"
;          (swap! m #(mod (inc @m) 2))   ; swap model used in next iteration     
          (swap! m #(mod (inc %) 2))     ; EDIT: correction
          (if (= @m 1)                   ; on switch to model 1, increase island counter
;            (swap! islands #(inc @islands)))) ; EDIT: my try, with error
            (swap! islands inc)))) ;             EDIT: correction
        (if (< (count result) n)         ; repeat until result reaches length n
          (recur (format "%s%c" result (model)))
          result)))))

, (create-genome 1000)

ArityException Wrong number of args (1) passed to: user/create-genome/fn--772  clojure.lang.AFn.throwArity (AFn.java:429)

:

  • (), ?
  • ?

  • ( clojure -newb)? - .
  • # , ? , , :)
+4
3

, , :

#(mod (inc @m) 2)

#(inc @islands)

0-, arity 1.

: #(body) (fn [...] (body)). , . , body % %x, x - , , , x ( , %).

, body , #() , , swap!.

, swap -, , !, ArityException.

, , :

(swap! m #(mod (inc %) 2)) ; will swap value of m to (mod (inc current-value-of-m) 2) internally

(swap! islands inc) ; will swap value of islands to (inc current-value-of-islands) internally

+2

, , : loop ?

- fn , , , . repeatedly, .

, , , format - clojure.string/join, , apply str over .

- , , , , :

(defn make-generator 
  "Takes a probability distribution, in the form of a map 
  from values to the desired likelihood of that value appearing in the output.
  Normalizes the probabilities and returns a nullary producer fn with that distribution."
  [p-distribution]  
  (let[sum-probs (reduce + (vals p-distribution))
       normalized (reduce #(update-in %1 [%2] / sum-probs) p-distribution (keys p-distribution) )]
      (fn [] (reduce 
              #(if (< %1 (val %2)) (reduced (key %2)) (- %1 (val %2))) 
              (rand) 
              normalized))))

(defn markov-chain 
  "Takes a series of states, returns a producer fn.
  Each call, the process changes to the next state in the series with probability :p-switch,
  and produces a value from the :producer of the current state."
  [states]
  (let[cur-state (atom (first states))
       next-states (atom (cycle states))]
    (fn [] 
      (when (< (rand) (:p-switch @cur-state))
        (reset! cur-state (first @next-states))
        (swap! next-states rest))
      ((:producer @cur-state)))))


(def my-states [{:p-switch 0.02 :producer (make-generator {\A 1 \C 1 \G 1 \T 1})  :name "std"}
                {:p-switch 0.04 :producer (make-generator {\A 1 \C 4 \G 4 \T 1})  :name "cpg"}])


(defn create-genome [n]
  (->> my-states
       markov-chain
       (repeatedly n)
       clojure.string/join))

, :

  • let in make-generator , 1.
  • make-generator , reduce. , , 2 . (reduce + [4 5 2 9]) (((4 + 5) + 2) + 9). , if create-model, .
  • markov-chain cur-state next-states, ( cycle) . m models, .
  • when, , , , . : @cur-state .

, , , , , .
, , ( ) . " " , .

+3

, hashtag #.

#(+ %1 %2) (fn [x y] (+ x y)). : #(+ 1 1). . , , , swap! , . , , . , reset!: (reset! an-atom (+ 1 1)). .

:

, . , , :

(swap! m #(mod (inc %) 2)) (swap! m #(mod (inc @m) 2)).

, . - , , , .

+1
source

All Articles