             [anglican.infcomp.network :refer :all]
             [anglican.inference :refer [infer]]
             [anglican.stat :refer [empirical-distribution collect-predicts collect-by collect-results]]
-            [helpers.gmm :refer [normalize]])
+            [helpers.gmm :refer [normalize]]
+            [rhizome.viz]
+            [clojure.string])
   (:use [anglican emit runtime]
         [gorilla-plot core]))
 
 (anglican.infcomp.core/reset-infcomp-addressing-scheme!)
 ;; @@
 ;; =>
-;;; {"type":"html","content":"<span class='clj-unkown'>#function[anglican.infcomp.core/reset-infcomp-addressing-scheme!$fn--26285$fn--26286]</span>","value":"#function[anglican.infcomp.core/reset-infcomp-addressing-scheme!$fn--26285$fn--26286]"}
+;;; {"type":"html","content":"<span class='clj-unkown'>#function[anglican.infcomp.core/reset-infcomp-addressing-scheme!$fn--26362$fn--26363]</span>","value":"#function[anglican.infcomp.core/reset-infcomp-addressing-scheme!$fn--26362$fn--26363]"}
+;; <=
+
+;; **
+;;; ## PDFA object
+;; **
+
+;; @@
+(defm new-pdfa [alphabet K transition emissiondist]
+  (let [alphabet (map str (seq alphabet))
+
+        states (range K)
+
+        edges (into {} (map (fn [state]
+                              [state (into {} (map #(vector % (transition state %))
+                                                   alphabet))])
+                            states))
+
+        probs (into {} (map (fn [state]
+                              [state (into {} (map (fn [[symbol prob]]
+                                                     [(str symbol) prob])
+                                                   (:categories (emissiondist state))))])
+                            states))]
+    {:edges edges
+     :probs probs}))
+;; @@
+;; =>
+;;; {"type":"html","content":"<span class='clj-var'>#&#x27;pdfa/new-pdfa</span>","value":"#'pdfa/new-pdfa"}
+;; <=
+
+;; @@
+(defn pdfa-states [pdfa]
+  (keys (:edges pdfa)))
+
+(defn pdfa-edges [pdfa]
+  (let [t (:edges pdfa)]
+    (into {} (map (fn [state]
+                    [state (vec (set (vals (get t state))))])
+                  (keys t)))))
+;; @@
+;; =>
+;;; {"type":"html","content":"<span class='clj-var'>#&#x27;pdfa/pdfa-edges</span>","value":"#'pdfa/pdfa-edges"}
+;; <=
+
+;; @@
+(defn pdfa-node->descriptor [pdfa]
+   (fn [node]
+     {:label (str node)}))
+
+(defn pdfa-edge->descriptor [pdfa]
+  (fn [state nextstate]
+    (let [edges (get-in pdfa [:edges state])
+          probs (get-in pdfa [:probs state])
+          
+          emissions (filter #(= nextstate (get edges %))
+                            (keys edges))
+          probs (into {}
+                      (map #(vector % (get probs %))
+                           emissions))]
+      {:label (clojure.string/join "|" (map #(format "%.3f%s"(get probs %) %)
+                                            emissions))})))
+;; @@
+;; =>
+;;; {"type":"html","content":"<span class='clj-var'>#&#x27;pdfa/pdfa-edge-&gt;descriptor</span>","value":"#'pdfa/pdfa-edge->descriptor"}
+;; <=
+
+;; @@
+(defn view-pdfa [pdfa]
+  (rhizome.viz/view-graph (pdfa-states pdfa)
+                          (pdfa-edges pdfa)
+                          :node->descriptor (pdfa-node->descriptor pdfa)
+                          :edge->descriptor (pdfa-edge->descriptor pdfa)))
+;; @@
+;; =>
+;;; {"type":"html","content":"<span class='clj-var'>#&#x27;pdfa/view-pdfa</span>","value":"#'pdfa/view-pdfa"}
 ;; <=
 
 ;; **


;; @@
(def test-observations
  (combine-observes-fn (sample-observes-from-prior pdfa [(repeat 10 nil) alphabet])))
test-observations
;; @@
;; =>
;;; {"type":"list-like","open":"<span class='clj-lazy-seq'>(</span>","close":"<span class='clj-lazy-seq'>)</span>","separator":" ","items":[{"type":"html","content":"<span class='clj-long'>4</span>","value":"4"},{"type":"html","content":"<span class='clj-long'>3</span>","value":"3"},{"type":"html","content":"<span class='clj-long'>1</span>","value":"1"},{"type":"html","content":"<span class='clj-long'>3</span>","value":"3"},{"type":"html","content":"<span class='clj-long'>3</span>","value":"3"},{"type":"html","content":"<span class='clj-long'>4</span>","value":"4"},{"type":"html","content":"<span class='clj-long'>3</span>","value":"3"},{"type":"html","content":"<span class='clj-long'>0</span>","value":"0"},{"type":"html","content":"<span class='clj-long'>3</span>","value":"3"},{"type":"html","content":"<span class='clj-long'>2</span>","value":"2"}],"value":"(4 3 1 3 3 4 3 0 3 2)"}
;; <=

;; **

;; **

;; @@
; Pfau, D., Bartlett, N., & Wood, F. (2011). Probabilistic Deterministic Infinite Automata. In Advances in Neural Information Processing Systems (pp. 1930–1938)
(with-primitive-procedures [normalize]
  (defquery pdfa [observedsequence alphabet]
    (let [K (sample (uniform-discrete 1 5))
          emissionprior (fn [] (normalize (repeatedly (count alphabet) (fn [] (sample (uniform-continuous 0 1))))))
          emissiondist (mem (fn [state] (categorical (zipmap alphabet (emissionprior))))) ; \pi

          transitiondist (discrete (repeat K 1))
          transition (mem (fn [state symbol] (sample transitiondist))) ; \delta
          ]
      
      (loop [obs observedsequence
             state [0]]
        (if (not (empty? obs))
