p;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; K-means and Gaussian Mixture estimation with EM
;; Yann LeCun, April 2004, November 2005.

(libload "libimage/pnm")
(libload "libimage/image-io")
(libload "gaussian")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; load the tiles into global vairable matrix "data".
(de load-data ()
  (setq data (load-matrix "tiles.mat")))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; This function takes an NxM matrix "x" containing
;; N data vectors of dimension M, and a KxM matrix "m"
;; which on input contains K initial prototype vectors. 
;; The function runs the K-means algorithm on the data until 
;; convergence. Upon completion, "m" contains the K prototypes
;; calculated by K-means.
(de k-means (x m)
  (error "you must implement this function")
  ())


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; create an array of k Gaussians of dimension n
(de make-aray-of-gaussians (k n)
  (let ((g (array k)))
    (idx-bloop ((g g)) (g (new gaussian n)))
    g))


;; This function run EM on a gaussian mixture model
;; with K components.  "x" is an NxM matrix "x" containing
;; N data vectors of dimension M, "g" is an array of Gaussian 
;; objects, and "w" is K-dimensional vector containing
;; the initial mixture weights. On output, "g", and "w" will 
;; contain the updated Gaussians, and mixture weights of the
;; mixture of gaussians. The function returns the
;; negative log-likelihood of the data given the model.
(de mog-em (x g w)
  (error "you must implement this function")
  (let* ((k (idx-dim g 0))
	 (n (idx-dim x 0))
	 (r (matrix n k))
	 (neg-log-likelihood 0)
	 (converged t))
    (while (not converged)
      (mog-e x g w r)
      (mog-m x g w r)
      (setq neg-log-likelihood (mog-nll x g w))
      (setq converged (you-must-put-some-code-here)))
    neg-log-likelihood))


;; This is the E-step of EM
;; "r" is the matrix of responsabilities.
(de mog-e (x g w r) 
  (error "you must implement this function")
  ())

;; This is the M-step of EM
;; "r" is the matrix of responsabilities.
(de mog-m (x g w r) 
  (error "you must implement this function")
  ())

;; Return the negative log-likelihood of the data in x
;; given the Gaussian mixture models in g and the
;; weights w.
(de mog-nll (x g w)
  (error "you must implement this function")
  ())


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; turn a bunch of tiles into an image.
(de tiles-to-image (in out)
  (for (i 0 (1- (idx-dim in 0)))
       (for (j 0 (1- (idx-dim in 1)))
	    (idx-copy
	     (select in 0 (+ (* i (idx-dim in 1)) j))
	     (narrow (narrow out 0 8 (* i 8)) 1 8 (* j 8))))))


;; break an image into 8x8 tiles. This is the
;; function that was used to produce tiles.mat.
;; You do not need to run this function as tiles.mat
;; is provided in this directory.
(de image-to-tiles (infile outfile)
  (let* ((th 8)
	 (tw 8)
	 (raw (image-read-ubim infile))
	 (raw-h (idx-dim raw 0))
	 (raw-w (idx-dim raw 1))
	 (sh (div raw-h th))
	 (sw (div raw-w tw))
	 (in (narrow (narrow raw 0 (* th sh) 0) 1 (* tw sw) 0))
	 (out (matrix (* sh sw) (* th tw)))
	 (k 0))
    (for (i 0 (1- sh)) 
	 (for (j 0 (1- sw))
	      (copy-matrix (narrow (narrow in 0 th (* th i)) 1 tw (* tw j))
			   (select out 0 k))
	      (incr k)))
    (save-matrix out outfile)
    out))


