;;; macro stuff
;; general macos
(defmacro o (x) 
  "print a named value;
   e.g. (let ((a 22)) (o a)) ==>  [a]=[22]"
  `(progn (format t "[~a]=[~a] " (quote ,x) ,x) ,x))

(defmacro oo (&rest l)
  "print a list of names values;
   e.g. (let ((aa 22) (b 33)) (oo a b)) ==> [a]=22;[b]=[33]"
  `(progn ,@(mapcar #'(lambda(x) `(o ,x)) l) (terpri)))
 
(defmacro inc>     (new-relation old) 
  `(if (> ,new ,old) (setf ,old ,new)))

(defmacro inc< (new old) 
  `(if (< ,new ,old) (setf ,old ,new)))

(defmacro doitems ((one n list &optional out) &body body )
  `(let ((,n 0))
    (dolist (,one ,list ,out)  (incf ,n) ,@body)))

(defmacro doitems1 ((one n list &optional out) &body body )
  `(let ((,n 1))
    (dolist (,one ,list ,out)  (incf ,n) ,@body)))

;;; lib stuff
(defmacro inca (key l &optional (inc 1))
  `(if (cdr (assoc ,key ,l))
    (setf 
     (cdr (assoc ,key ,l))
     (+ ,inc (cdr (assoc ,key ,l))))
    (push (cons ,key ,inc) ,l)))

(defun hkeys (h)
  (let (out)
    (maphash #'(lambda (k v) (push k out)) h)
    out))

(defun hshow (h &optional (header ""))
  (terpri)
  (maphash #'(lambda (k v) (format t "~a~a = ~a~%" header k v)) h)
  t)

;; misc



(defun ?elt (choices)
  (elt choices (floor (random (length choices)))))

(defun ?quantity (min max)
  (if (> min max)
      (?quantity max min)    
      (+ min (random (+ 1 (- max min))))))

(defun sum (l)
  (let ((s 0))
    (dolist (x l s) 
      (incf s x))))

(defun countlist (l)
  (let (out)
    (doitems (one n l (reverse out))
	     (push (cons (1- n) one) out))))

(defstruct counts
  class sample frequency)

(defun h2l (h)
  (let (all)
  (labels ((keep (k v) 
	     (push (make-counts :class    (second  k)
				:sample   (fourth k)
				:frequency v)
		   all)))
    (maphash #'keep h)
    all)))

 ;;;; nearest neighbor stuff

(defun distance1 (x y col max)
  "in this system, all ranges are numbered 1..N and '0'
  denotes a wild card"
  (cond ((zerop x) (?QUANTITY 0 10));;BUG? should this be 1..10
	((zerop y) (?QUANTITY 0 10))
	((numericp col) (- x y))
	((eql x y)  0)
	(t          max)))

(defun distance (l1 l2 max &optional (cols (rel-columns *the-relation*)))
  "Returns a number 0..1"
  (let ((sum 0))
    (mapc #'(lambda (one two col)
	      (let* ((delta (distance1 one two col max))
		     (pow   (expt delta 2)))
		(incf sum pow)))
	    l1 l2 cols)
    (/ (sqrt sum) max)))