;;; Contains stuff for setting up and running tests for multi-category learning tasks
;;; like soybean disease diagnosis. In comments, *-CATEGORIES refers to the system
;;; dependent function of this form (e.g. ID3-CATEGORIES) *-CATEGORIES for each
;;; domain should set the variable *INSTANCE-TESTER* to define the tester for that
;;; system.

(defvar *instance-tester* nil)

(defun separate-instances (categories num-learn-instances &optional num-test-instances)
  ;;; Separates a list of instances for a set of categories into learning and testing
  ;;; instances to facilitate experimentation in preparation for using *-CATEGORIES
  ;;; and TEST-CATEGORIES.  The variable categories should be bound to a list of
  ;;; category names whose values are a list of instances of that category. The first
  ;;; num-learn-instances of these instances are stored on the LEARN-INSTANCES property
  ;;; to be used for learning and the rest are stored on TEST-INSTANCES for testing.
  
  (dolist (category categories)
    (setf (get category 'learn-instances) 
	  (subseq (eval category) 0 num-learn-instances))
    (if num-test-instances
	(setf (get category 'test-instances)
	  (subseq (eval category) (- (length (eval category)) num-test-instances)))
	(setf (get category 'test-instances)
	  (subseq (eval category) num-learn-instances)))))


(defun test-categories (categories &optional learn-instances?)
  ;;; To be used after *-CATEGORIES in order to test the generalizations learned 
  ;;; on a  set of new instances stored under the TEST-INSTANCES property of each category
  ;;; name in categories.  Reports % correct for each category and overall % correct.

  (let ((percent-sum 0)(percent 0))
    (dolist (category categories)
      (format t "~%~%Testing ~A instances" category)
      (let ((answers (mapcar #'(lambda (instance)
				 (funcall *instance-tester* instance categories))
			     (get category (if learn-instances?
					       'learn-instances
					       'test-instances))))
	    (count 0))
	(format t "~%~A" answers)
	(dolist (answer answers) (if (and (eq (first answer) category)(null (rest answer)))
				     (incf count)))
	(setf percent (* 100 (/ count (length answers))))
	(incf percent-sum percent)
	(format t "~%Percent correct: ~,2F" percent)))
    (format t "~%~%Total percent correct: ~,2F" (/ percent-sum (length categories)))))



