         b (frequencies V)
         n (apply merge-with + (map #(hash-map [%1 %2] 1) U V))
         N (count U)
-        ;; TODO: Use a fmap.
         norm_n (into {} (map (fn[[k v]] [k (/ v N)]) n))
         cells (keys norm_n)]
     (reduce + (map

                                    (* N N))))))
               cells))))

;TODO: write this!
(defn expected_mututal_information
  [U V]
   (let [a (frequencies U)
        b (frequencies V)
        n (apply merge-with + (map #(hash-map [%1 %2] 1) U V))
        N (count U)
        ;; TODO: Use a fmap.
        norm_n (into {} (map (fn[[k v]] [k (/ v N)]) n))
        cells (keys norm_n)]
(reduce + (map
            (fn [[i j]]

              (/
               (* (factorial (a i)) (factorial (b j)) (factorial (- N (a i))) (factorial (- N (b j))))
               (* (factorial N) (n [i j])
              )
               cells))))

; Adjusted Mutual Information (AMI) is an adjustment of the Mutual Information (MI) score to account for chance.
; AMI(U, V) = [MI(U, V) - E(MI(U, V))] / [max(H(U), H(V)) - E(MI(U, V))]

;TODO move this to a util NS? Or find a better implementation
(defn factorial
  [x]
  (println x)
    (if (zero? x)
      1
      (loop [n x f 1]
        (if (= n 1)
            f
            (recur (dec n) (* f n))))))

; The Mutual Information is a measure of the similarity between two labels of the same data.
; Where P(i) is the probability of a random sample occurring in cluster U_i and P'(j) is the probability of a random sample
