diff --git a/gp.jl b/gp.jl index 99677a2..09e16a9 100644 --- a/gp.jl +++ b/gp.jl @@ -1,23 +1,8 @@ -#= -Objective: Find minimum time vehicle control program -Terminal Set: x (position) - v (velocity) - -1 -Function Set: +, -, *, DIV, GT, ABS -Cost: Time to bring behicle to phase plane origin - averaged over 20 random initial conditions -Gen. Limit: 50 -Pop. Size: 500 -Max Initial Tree Depth: 6 -Init. Method: Ramped half-and-half -Max. Tree depth: 17 -X-Over Prob.: 0.9 -Mutation prob.: 0 -Number of elites: 2 -Selection: Tournament -=# function GT(a,b) + """ + GT function to be used in AST + """ if a > b return 1 else @@ -26,25 +11,106 @@ function GT(a,b) end function DIV(a,b) + """ + Protected division used in AST + """ if abs(b) < 10.0^-10 return 1 else return a/b end end +#= +macro create_function(defs) + for name in eval(defs) + ex = quote + function $(Symbol(name))(x,v) + fs = [:+, :-, :DIV, :GT] + ts = [:x,:v,-1] + return create_single_full_tree(4, fs, ts) + end + end + eval(ex) + end +end +=# + +function create_full_tree(depth, fs, ts) + """ + Creates a single AST with full depth + Inputs + depth Current depth of tree. Initially called from main() with max depth + fs Function Set - Array of allowed functions + ts Terminal Set - Array of allowed terminal values + Output + Full AST of typeof()==Expr + """ -function create_single_full_tree(depth, fs, ts) - # If we are not at the bottom + # If we are at the bottom if depth == 1 + # End of tree, return function with two terminal nodes return Expr(:call, fs[rand(1:length(fs))], ts[rand(1:length(ts))], ts[rand(1:length(ts))]) else - return Expr(:call, fs[rand(1:length(fs))], create_single_full_tree(depth-1, fs, ts), create_single_full_tree(depth-1, fs, ts)) + # Not end of expression, recurively go back through and create functions for each new node + return Expr(:call, fs[rand(1:length(fs))], create_full_tree(depth-1, fs, ts), create_full_tree(depth-1, fs, ts)) end end -function main() - fs = [:+, :-, :DIV, :GT] - ts = [:x, :v, -1] - tst = create_single_full_tree(4, fs, ts) +function create_grow_tree(depth, fs, ts) + if depth == 1 + return Expr(:call, fs[rand(1:length(fs))], ts[rand(1:length(ts))], ts[rand(1:length(ts))]) + else + choice = rand(1:3) + if choice == 1 + return Expr(:call, fs[rand(1:length(fs))], create_grow_tree(depth-1, fs, ts), create_grow_tree(depth-1, fs, ts)) + elseif choice == 2 + return Expr(:call, fs[rand(1:length(fs))], ts[rand(1:length(ts))], create_grow_tree(depth-1, fs, ts)) + else + return Expr(:call, fs[rand(1:length(fs))], create_grow_tree(depth-1, fs, ts), ts[rand(1:length(ts))]) + end + end end -main() + + + +#= +Objective: Find minimum time vehicle control program +Terminal Set: x (position) + v (velocity) + -1 +Function Set: +, -, *, DIV, GT, ABS +Cost: Time to bring behicle to phase plane origin + averaged over 20 random initial conditions +Gen. Limit: 50 +Pop. Size: 500 +Max Initial Tree Depth: 6 +Init. Method: Ramped half-and-half +Max. Tree depth: 17 +X-Over Prob.: 0.9 +Mutation prob.: 0 +Number of elites: 2 +Selection: Tournament +=# + + +# Define x, v as globals because I can't figure out how to get +# around creating expressions and not being able to plug +# x and v into them for the past week + +pop_size = 500 +max_initial_depth = 6 +max_depth = 17 +xover_prob = 0.9 +fs = [:+, :-, :DIV, :GT] +ts = [:x,:v,-1] +xs = rand(1:10,20) +vs = rand(1:10,20) +elites = 2 + +pop0 = [] +for i in 1:pop_size/2 + push!(pop0, create_full_tree(max_initial_depth, fs, ts)) + push!(pop0, create_grow_tree(max_initial_depth, fs, ts)) +end + + diff --git a/gp_module_test.jl b/gp_module_test.jl new file mode 100644 index 0000000..d5af7d3 --- /dev/null +++ b/gp_module_test.jl @@ -0,0 +1,80 @@ +#= +Objective: Find minimum time vehicle control program +Terminal Set: x (position) + v (velocity) + -1 +Function Set: +, -, *, DIV, GT, ABS +Cost: Time to bring behicle to phase plane origin + averaged over 20 random initial conditions +Gen. Limit: 50 +Pop. Size: 500 +Max Initial Tree Depth: 6 +Init. Method: Ramped half-and-half +Max. Tree depth: 17 +X-Over Prob.: 0.9 +Mutation prob.: 0 +Number of elites: 2 +Selection: Tournament +=# +module GP + function GT(a,b) + """ + GT function to be used in AST + """ + if a > b + return 1 + else + return -1 + end + end + + function DIV(a,b) + """ + Protected division used in AST + """ + if abs(b) < 10.0^-10 + return 1 + else + return a/b + end + end + + @eval function create_single_full_tree(depth, fs, ts) + """ + Creates a single AST with full depth + Inputs + depth Current depth of tree. Initially called from main() with max depth + fs Function Set - Array of allowed functions + ts Terminal Set - Array of allowed terminal values + Output + Full AST of typeof()==Expr + """ + # If we are at the bottom + if depth == 1 + # End of tree, return function with two terminal nodes + return Expr(:call, fs[rand(1:length(fs))], ts[rand(1:length(ts))], ts[rand(1:length(ts))]) + else + # Not end of expression, recurively go back through and create functions for each new node + return Expr(:call, fs[rand(1:length(fs))], create_single_full_tree(depth-1, fs, ts), create_single_full_tree(depth-1, fs, ts)) + end + end +end + +function main() + """ + Main function + """ + # Define functional and terminal sets + fs = [:+, :-, :DIV, :GT] + ts = [:x, :v, -1] + # Create the tree + tst = GP.create_single_full_tree(4, fs, ts) + #println(typeof(tst)) + #println(tst) + #println(dump(tst)) + # If I comment these globals, eval cannot find x and v in the scope + GP.x = 1 + GP.v = 1 + #eval(tst) +end +main() diff --git a/test.jl b/test.jl new file mode 100644 index 0000000..fd165be --- /dev/null +++ b/test.jl @@ -0,0 +1,14 @@ +macro create_ast(fns, tms) + return esc(Expr(:call, fns[1], tms[1], tms[2])) +end + +function main() + fns = [:+, :-] + tms = [:x, :y] + tst = @create_ast(fns, tms) + println(tst) + x = 1 + y = 2 + eval(tst) +end +main()