This will be easier if you use a utility to insert a new subtree at a 
particular position in an existing subtree -- that is, to return a new subtree 
with the insertion. Then to do mutation just use this utility to insert a newly 
generated subtree at some randomly chosen index.

Following is code for an insertion utility using the zip library. I'm still 
using Clojure 1.1 and I gather that a few of the things I'm using here have 
been moved or renamed in 1.2, but the same basic idea should work. 

FWIW this is a modified version of the mutation code in my PushGP genetic 
programming system (http://hampshire.edu/lspector/clojush/), changed to count 
only whole s-expressions or atoms that are not in function position as "points" 
and hence as candidates for mutation. My Push language has a more liberal 
syntax, there's no function position as such, and any place can be mutated... 
But if you're evolving standard lisp s-expressions then I think the following 
is what you want.

(ns gp
  (:require [clojure.zip :as zip]
            [clojure.contrib.math :as math]
            [clojure.contrib.seq-utils :as seq-utils]))

(defn insert-code-at-point
  "Returns a copy of tree with the subtree formerly indexed by                  
                                       
point-index (in a depth-first traversal) replaced by new-subtree.               
                                       
Only whole s-expressions and atoms not in function position are counted         
                                       
as points. If index is too high then take it modulo the total number            
                                       
of points."
  [tree point-index new-subtree]
  (let [index (mod (math/abs point-index) (count (seq-utils/flatten tree)))
        zipper (zip/seq-zip tree)]
    (loop [z zipper i index]
      (if (zero? i)
        (zip/root (zip/replace z new-subtree))
        (if (seq? (zip/node z))
          (recur (zip/next (zip/next z)) (dec i))
          (recur (zip/next z) (dec i)))))))

;; show how it works on a range of indices                                      
                                       
(dotimes [i 10]
  (println (insert-code-at-point '(+ (* x y) (/ z w))
                                 i
                                 '(- a b))))

 -Lee


On May 22, 2010, at 9:35 PM, krsnewwave wrote:

> Hello everyone!
> 
> I am having trouble with genetic programming. I am trying to construct
> a random population of trees representing functions. The following is
> how I do my random trees:
> 
> (defn makerandomtree-10
> [pc maxdepth maxwidth fpx ppx]
> (if-let [output
>  (if (and (< (rand) fpx) (> maxdepth 0))
>    (let [head (nth operations (rand-int (count operations)))
>         children (doall (loop[function (list)
>                       width maxwidth]
>                     (if (pos? width)
>                       (recur (concat function
>                         (list (makerandomtree-10 pc (dec maxdepth)
>                           (+ 2 (rand-int (- maxwidth 1))) fpx ppx)))
>                         (dec width))
>                       function)))]
>       (concat (list head) children))
>    (if (and (< (rand) ppx) (>= pc 0))
>       (nth parameters (rand-int (count parameters)))
>       (rand-int 100)))]
> output
> ))
> 
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> 
> And it works. The thing that doesn't work is mutation. I have already
> done 10 versions of this, and all doesn't work good enough. The
> following is the thing that works the best, but not really good
> enough.
> 
> (defn mutate-5
> "chooses a node changes that"
> [function pc maxwidth pchange]
> (if (< (rand) pchange)
>    (let [output (makerandomtree-10 pc 3 maxwidth 0.5 0.6)]
>       (if (seq? output) output (list output)))
>    ;mutate the children of root
>    ;declare an empty accumulator list, with root as its head
>       (let [head (list (first function))
>             children (loop [acc(list)
>                             walker (next function)] (println "----------") 
> (println
> walker) (println "-----ACC-----") (println acc)
>                       (if (not walker)
>                           acc
>                           (if (or (seq? (first function)) (contains? (set 
> operations)
> (first function)))
>                                 (recur (concat acc (mutate-5 walker pc 
> maxwidth pchange))
>                                   (next walker))
>                                 (if (< (rand) pchange)
>                                   (if (some (set parameters) walker)
>                                       (recur (concat acc (list (nth 
> parameters (rand-int (count
> parameters)))))
>                                               (if (seq? walker) (next walker) 
> nil))
>                                       (recur (concat acc (list (rand-int 
> 100)))
>                                               (if (seq? walker) (next walker) 
> nil)))
>                                   (recur acc (if (seq? walker) (next walker) 
> nil))))
>                        ))]
>               (concat head (list children)))))
> 
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> 
> 
> I am sorry that it is somewhat obfuscated. As you can see, I am a
> newbie to clojure, and to functional programming in general.
> 
> -- 
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with your 
> first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en

--
Lee Spector, Professor of Computer Science
School of Cognitive Science, Hampshire College
893 West Street, Amherst, MA 01002-3359
lspec...@hampshire.edu, http://hampshire.edu/lspector/
Phone: 413-559-5352, Fax: 413-559-5438

Check out Genetic Programming and Evolvable Machines:
http://www.springer.com/10710 - http://gpemjournal.blogspot.com/

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to