;; TRAINING BIAS #4: Prefer codes with more colors. ;; Specifically, for a code of length N, the probability that a randomly ;; chosen code has K different colors is: ;; p(+ | K) = (K/N) * (2/(N+1)) ;; So: ;; p(+ | N) = 2 / (N+1) ;; p(+ | 1) = 2 / (N(N+1)) ;; Codes consistent with this probability distribution are ;; generated by randomly generating a number in the range ;; [0,1], and using the cumulative probability distribution ;; function to map this probability to a number of colors in [1,N]. ;; ;; Note that this bias is only meaningful when there are at ;; least as many colors as pegs. ;; ;; Negative instances are generated by using the inverse ;; cumulative probability distribution function (i.e., using ;; (1-p) for each probability. (defun train-bias4-pos (&optional (colors *colors*) (code-length *code-length*)) (setf numcolors (bias4-colors code-length t)) (train-bias-flag colors code-length #'(lambda (code flag) (check-train-bias4 code flag numcolors)) t)) (defun train-bias4-neg (&optional (colors *colors*) (code-length *code-length*)) (setf numcolors (bias4-colors code-length nil)) (train-bias-flag colors code-length #'(lambda (code flag) (check-train-bias4 code flag numcolors)) nil)) (defun bias4-colors (code-length posflag) (let ((p (random 1.0)) (cumprob 0) (pnext 0) (norm (* (/ 1 code-length) (/ 2 (+ 1 code-length))))) (if posflag (loop for i from code-length downto 1 do (progn (setf pnext (* i norm)) (incf cumprob pnext) (if (> cumprob p) (return-from bias4-colors i)))) (loop for i from 1 to code-length do (progn (setf pnext (* i norm)) (incf cumprob pnext) (if (> cumprob p) (return-from bias4-colors i))))))) (defun check-train-bias4 (code flag numcolors &aux (colors nil)) (loop for c in code do (setf colors (adjoin c colors))) (if flag (eq (length colors) numcolors) (not (eq (length colors) numcolors))))