;;;; This is an implementation of the basic AQ algorithm for learning from ;;;; exmples which uses the version-space algorithm to compute stars. The ;;;; file VERSION-SPACE must also be loaded with appropriate language ;;;; specification functions. ;;;; Copyright (c) 1988 by Raymond Joseph Mooney. This program may be freely ;;;; copied, used, or modified provided that this copyright notice is included ;;;; in each copy of this code and parts thereof. ;;;; This version of AQ assumes that events are represented as ordered lists ;;;; of feature values. Complexes are assumed to also be represented in the ;;;; same manner where ? is used as a fetaure value if no restriction is made ;;;; on the value of this feature, i.e. it is not a selector in the complex. ;;;; The files FIGURE-DATA and WEATHER-DATA contain sample datasets. (defparameter *trace-aq* nil) ; AQ produces a trace if this flag is set to T ; One may also want to turn on *trace-vs* (defun aq (examples) ;;; AQ takes a list of examples where an example is a list of either + or - ;;; (indicating the class) and an event description. It returns a cover ;;; (a list of complexes) which covers all of the postive events and none ;;; of the negative ones. (let ((pos-instances nil) (neg-instances nil) (cover nil)(seed nil)(best-complex nil)(delta 0)) ;;; Separate instances into positive and negative ones (dolist (example examples) (cond ((eq (first example) '+) (push (second example) pos-instances)) ((eq (first example) '-) (push (second example) neg-instances)))) ;; Use seeds which are not covered by any previous star until there ;; are no more such seeds. (do ((seed-instances pos-instances)) ((null seed-instances)) (setf seed (pop seed-instances)) ; select a seed from available set (trace-print *trace-aq* "~%~%Seed: ~A" seed) ;; use version-space to generate a star covering this seed but none ;; of the negative examples (version-space (make-examples (list seed) neg-instances)) ;; Pick the best complex in this star and put it in the cover (setf best-complex (select-complex *g* pos-instances)) (trace-print *trace-aq* "~%Best complex: ~A" (format-generalization best-complex)) (push best-complex cover) ;; Remove from the set of possible seeds those which are covered by any ;; complex in the star (setf seed-instances (remove-if #'(lambda (instance) (dolist (complex *g*) (when (match complex instance) (return t)))) seed-instances)) ;; Remove from the set of positive events those covered by the chosen ;; complex (setf pos-instances (remove-if #'(lambda (instance) (match best-complex instance)) pos-instances))) ;; Pick seeds and generate stars until all + events are covered (do nil ((null pos-instances)) (setf seed (first pos-instances)) (trace-print *trace-aq* "~%~%Seed: ~A" seed) (version-space (make-examples (list seed) neg-instances)) (setf best-complex (select-complex *g* pos-instances)) (trace-print *trace-aq* "~%Best complex: ~A" (format-generalization best-complex)) (push best-complex cover) (setf pos-instances (remove-if #'(lambda (instance) (match best-complex instance)) pos-instances)) (incf delta)) ; delta is an estimate of distance from ; the minimal # of complexes (trace-print *trace-aq* "~%~%Cover minimal within ~D complexes" delta) cover)) (defun select-complex (complexes pos-instances) ;;; From a set of complexes select that one which maximizes the number of ;;; positive examples covered and break ties by trying to minimize the ;;; number of selectors in the complex (let ((best-complex nil)(max-matches -1)(match-count 0)) (trace-print *trace-aq* "~%") (dolist (complex complexes best-complex) (setf match-count 0) ;; Count the number of + events the complex covers (dolist (pos-instance pos-instances) (if (match complex pos-instance) (incf match-count))) (trace-print *trace-aq* "~%~A matches ~D instance~:P" (format-generalization complex) match-count) ;; if complex is better than current best complex then make it the new ;; best complex (when (or (> match-count max-matches) (and (= match-count max-matches) (<= (count-selectors complex) (count-selectors best-complex)))) (setf max-matches match-count) (setf best-complex complex))))) (defun count-selectors (complex) ;;; Counts the number of selectors (i.e. non-?'s in the complex) (let ((selector-count 0)) (dolist (feature complex selector-count) (unless (eq feature '?) (incf selector-count)))))