charlie 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. data/History.txt +3 -0
  2. data/Manifest.txt +53 -0
  3. data/README.txt +90 -0
  4. data/Rakefile +43 -0
  5. data/TODO.txt +28 -0
  6. data/data/BENCHMARK +53 -0
  7. data/data/CROSSOVER +49 -0
  8. data/data/GENOTYPE +49 -0
  9. data/data/MUTATION +43 -0
  10. data/data/SELECTION +48 -0
  11. data/data/template.html +34 -0
  12. data/examples/bit.rb +10 -0
  13. data/examples/function_opt_2peak.rb +24 -0
  14. data/examples/function_opt_sombero.rb +38 -0
  15. data/examples/gladiatorial_simple.rb +17 -0
  16. data/examples/gladiatorial_sunburn.rb +89 -0
  17. data/examples/gridwalk.rb +29 -0
  18. data/examples/output/flattened_sombero.html +6400 -0
  19. data/examples/output/flattened_sombero2_.html +3576 -0
  20. data/examples/output/fopt1_dblopt.html +2160 -0
  21. data/examples/output/hill10.html +5816 -0
  22. data/examples/output/hill2.csv +24 -0
  23. data/examples/output/hill2.html +384 -0
  24. data/examples/output/royalroad1_report.html +1076 -0
  25. data/examples/output/royalroad2_report.html +1076 -0
  26. data/examples/output/royalroadquick_report.html +504 -0
  27. data/examples/output/tsp.html +632 -0
  28. data/examples/output/weasel1_report.html +1076 -0
  29. data/examples/output/weasel2_report.html +240 -0
  30. data/examples/royalroad.rb +26 -0
  31. data/examples/royalroad2.rb +18 -0
  32. data/examples/simple_climb_hill2.rb +47 -0
  33. data/examples/tsp.rb +35 -0
  34. data/examples/weasel.rb +36 -0
  35. data/lib/charlie.rb +35 -0
  36. data/lib/charlie/crossover.rb +49 -0
  37. data/lib/charlie/etc/minireport.rb +45 -0
  38. data/lib/charlie/etc/monkey.rb +136 -0
  39. data/lib/charlie/genotype.rb +45 -0
  40. data/lib/charlie/list/list_crossover.rb +30 -0
  41. data/lib/charlie/list/list_genotype.rb +53 -0
  42. data/lib/charlie/list/list_mutate.rb +75 -0
  43. data/lib/charlie/mutate.rb +25 -0
  44. data/lib/charlie/permutation/permutation.rb +47 -0
  45. data/lib/charlie/population.rb +156 -0
  46. data/lib/charlie/selection.rb +162 -0
  47. data/test/t_common.rb +32 -0
  48. data/test/test_basic.rb +32 -0
  49. data/test/test_benchmark.rb +56 -0
  50. data/test/test_cross.rb +28 -0
  51. data/test/test_mutator.rb +44 -0
  52. data/test/test_permutation.rb +23 -0
  53. data/test/test_sel.rb +39 -0
  54. metadata +115 -0
data/History.txt ADDED
@@ -0,0 +1,3 @@
1
+ == 0.5.0 / 2007-12-19
2
+ * First release.
3
+
data/Manifest.txt ADDED
@@ -0,0 +1,53 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ TODO.txt
6
+ data/BENCHMARK
7
+ data/CROSSOVER
8
+ data/GENOTYPE
9
+ data/MUTATION
10
+ data/SELECTION
11
+ data/template.html
12
+ examples/bit.rb
13
+ examples/function_opt_2peak.rb
14
+ examples/function_opt_sombero.rb
15
+ examples/gladiatorial_simple.rb
16
+ examples/gladiatorial_sunburn.rb
17
+ examples/gridwalk.rb
18
+ examples/output/flattened_sombero.html
19
+ examples/output/flattened_sombero2_.html
20
+ examples/output/fopt1_dblopt.html
21
+ examples/output/hill10.html
22
+ examples/output/hill2.csv
23
+ examples/output/hill2.html
24
+ examples/output/royalroad1_report.html
25
+ examples/output/royalroad2_report.html
26
+ examples/output/royalroadquick_report.html
27
+ examples/output/tsp.html
28
+ examples/output/weasel1_report.html
29
+ examples/output/weasel2_report.html
30
+ examples/royalroad.rb
31
+ examples/royalroad2.rb
32
+ examples/simple_climb_hill2.rb
33
+ examples/tsp.rb
34
+ examples/weasel.rb
35
+ lib/charlie.rb
36
+ lib/charlie/crossover.rb
37
+ lib/charlie/etc/minireport.rb
38
+ lib/charlie/etc/monkey.rb
39
+ lib/charlie/genotype.rb
40
+ lib/charlie/list/list_crossover.rb
41
+ lib/charlie/list/list_genotype.rb
42
+ lib/charlie/list/list_mutate.rb
43
+ lib/charlie/mutate.rb
44
+ lib/charlie/permutation/permutation.rb
45
+ lib/charlie/population.rb
46
+ lib/charlie/selection.rb
47
+ test/t_common.rb
48
+ test/test_basic.rb
49
+ test/test_benchmark.rb
50
+ test/test_cross.rb
51
+ test/test_mutator.rb
52
+ test/test_permutation.rb
53
+ test/test_sel.rb
data/README.txt ADDED
@@ -0,0 +1,90 @@
1
+ Charlie
2
+
3
+ * http://rubyforge.org/projects/charlie/
4
+ * http://charlie.rubyforge.org
5
+ * mailto:sander.land+ruby@gmail.com
6
+
7
+ == DESCRIPTION:
8
+ Charlie is a library for genetic algorithms. It allows you to easily create
9
+ and run genetic algorithms. You can choose selection, crossover or mutation
10
+ strategies from either built-in options or simply write your own.
11
+ It also includes methods that can be used to compare several of these
12
+ strategies, generating reports with statistics that can be used to determine
13
+ which one to use in future problems.
14
+
15
+ == EXAMPLES:
16
+ This example finds the binary representation of the number 512.
17
+ require 'rubygems'
18
+ require 'charlie'
19
+ class Find512 < BitStringGenotype(10) # choose a genotype, in this case a list of 10 bits represents a solution
20
+ # Define a fitness function. This one returns minus the offset to the best solution, so a higher number is better.
21
+ # Usually, you won't know the best solution, and will define this as some value that needs to be maximized.
22
+ def fitness
23
+ # Use the 'genes' function to retrieve the array of bits representing this solution.
24
+ -(genes.map(&:to_s).join.to_i(2) - 512).abs
25
+ end
26
+ end
27
+ # Finally, create an instance of a population (with the default size of 20) and let it run for the default number of 100 generations.
28
+ Population.new(Find512).evolve_on_console
29
+
30
+ This example solves RubyQuiz #142.
31
+
32
+ require 'rubygems'
33
+ require 'charlie'
34
+ N=5
35
+ CITIES = (0...N).map{|i| (0...N).map{|j| [i,j] } }.inject{|a,b|a+b}
36
+
37
+ class TSP < PermutationGenotype(CITIES.size)
38
+ def fitness
39
+ d=0
40
+ (genes + [genes[0]]).each_cons(2){|a,b|
41
+ a,b=CITIES[a],CITIES[b]
42
+ d += Math.sqrt( (a[0]-b[0])**2 + (a[1]-b[1])**2 )
43
+ }
44
+ -d # lower distance -> higher fitness.
45
+ end
46
+ end
47
+ pop = Population.new(TSP,20).evolve_on_console(50)
48
+
49
+ == INSTALL:
50
+
51
+ * sudo gem install charlie
52
+
53
+ == Documentation
54
+ Because of the high amount of metaprogramming used in the package, the rdoc documentation is incomplete and also contains some non-existent functions.
55
+
56
+ The following pages contain overviews of the most important parts, including pointers to the appropriate pages of the documentation.
57
+ * Genotypes[link:files/data/GENOTYPE.html]
58
+ * Selection[link:files/data/SELECTION.html]
59
+ * Crossover[link:files/data/CROSSOVER.html]
60
+ * Mutation[link:files/data/MUTATION.html]
61
+ * Benchmarking[link:files/data/BENCHMARK.html]
62
+
63
+ Also see the 'examples' directory for several examples, where most of the functionality is used.
64
+
65
+
66
+
67
+ == LICENSE:
68
+
69
+ (The MIT License)
70
+
71
+ Copyright (c) 2007 Sander Land
72
+
73
+ Permission is hereby granted, free of charge, to any person obtaining
74
+ a copy of this software and associated documentation files (the
75
+ "Software"), to deal in the Software without restriction, including
76
+ without limitation the rights to use, copy, modify, merge, publish,
77
+ distribute, sublicense, and/or sell copies of the Software, and to
78
+ permit persons to whom the Software is furnished to do so, subject to
79
+ the following conditions:
80
+
81
+ The above copyright notice and this permission notice shall be
82
+ included in all copies or substantial portions of the Software.
83
+
84
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
85
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
86
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
87
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
88
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
89
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
90
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,43 @@
1
+
2
+ require 'rubygems'
3
+ require 'hoe'
4
+
5
+ $LOAD_PATH.unshift './lib'
6
+
7
+ require 'charlie'
8
+
9
+ Hoe.new('charlie', Charlie::VERSION) do |p|
10
+ p.rubyforge_name = 'charlie'
11
+ p.url = 'http://charlie.rubyforge.org'
12
+
13
+ p.author = 'Sander Land'
14
+ p.email = 'sander.land+ruby@gmail.com'
15
+
16
+ p.summary = 'A genetic algorithms library for Ruby.'
17
+ p.description = p.paragraphs_of('README.txt', 2..3).join("\n\n")
18
+
19
+
20
+ p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
21
+
22
+ #p.test_globs ['test/test_all.rb'] # removed test_all, because rake now does that anyway
23
+ p.clean_globs = ['test/output/*','./**/*~'] # Remove this on "rake clean" : test output and kate backups
24
+
25
+ p.rdoc_pattern = /^lib|\.txt$|^data\/[A-Z]+$/
26
+ p.remote_rdoc_dir = '' # Release to root
27
+ end
28
+
29
+ task :build_manifest do |t|
30
+ require 'find'
31
+ paths = []
32
+ Find.find(".") do |path|
33
+ next if File.directory?(path)
34
+ next if path =~ /\.svn/ # no svn
35
+ next if path =~ /~$/ # no kate backups
36
+ paths << path.sub(%r{^\./}, '')
37
+ end
38
+ File.open("Manifest.txt", "w") do |f|
39
+ f.puts paths.sort.join("\n")
40
+ end
41
+ end
42
+
43
+
data/TODO.txt ADDED
@@ -0,0 +1,28 @@
1
+ This is my todo list. Contributions and suggestions don't have to be restricted to these things in any way.
2
+
3
+ === Small stuff
4
+ * fix the initialize call in Genotype#from_genes
5
+ * clean up PCross, PMutate
6
+ * n-point crossover for lists
7
+
8
+ === Bigger stuff
9
+ * Better crossover and/or mutation operators for permutations. Especially something useful for TSP. (http://en.wikipedia.org/wiki/Edge_recombination_operator ?)
10
+ * More builtin genotypes:
11
+ 1. Tree-based, extending into genetic programming.
12
+ 2. Graphs / adjacency matrix.
13
+ 3. Neural networks.
14
+ 4. selection algorithms.
15
+ * Extend benchmarking options:
16
+ 1. Compare several generation/population size settings. Especially both of them together while keeping the number of fitness evaluations roughly constant.
17
+ 2. Detailed stats for use in comparing a small number of strategies? Including population stats for every generation and run, graphs?
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+
data/data/BENCHMARK ADDED
@@ -0,0 +1,53 @@
1
+ == Benchmark documentation
2
+ Population#benchmark can compare several selection, crossover and mutation methods and give a report comparing their
3
+ performance, both for convergence and speed.
4
+
5
+ The call to the function is:
6
+
7
+ Population.benchmark(genotype_class,html_output_file,csv_output_file=nil) {
8
+ selection RandomSelection, TournamentSelection(3)
9
+ crossover SinglePointCrossover
10
+ mutator ListMutator(
11
+ }
12
+
13
+ * +genotype_class+ is simply your genotype class.
14
+ * +html_output_file+ is an output file where a large report with several tables of statistics will be written. Pass nil for no output file of this type.
15
+ * +csv_output_file+ is an output file where the raw data (the maximum fitness value for each run) will be written. Pass nil or omit parameter for no output file of this type.
16
+
17
+
18
+
19
+ In the block you can call several functions to specify the parameters of the benchmark.
20
+ This is sometimes refered to as a DSL. As inaccurate as that term may be, I'll still use it here.
21
+
22
+
23
+ === Benchmark DSL documentation (also see StrategiesDSL)
24
+ In the block you must call the following functions:
25
+
26
+ ==== selection(*s_args)
27
+ Will cause each of the selection modules in +s_args+ to be tested.
28
+ ==== crossover(*c_args)
29
+ Will cause each of the crossover modules in +c_args+ to be tested.
30
+ ==== mutator(*m_args)
31
+ Will cause each of the mutation modules in +m_args+ to be tested.
32
+
33
+
34
+ If you want to test the module that is already included without repeating it, just pass Module.new as one of the arguments (or Module.new{self.name='default'} for something more descriptive).
35
+
36
+
37
+ You can also call the following functions to change some other settings:
38
+
39
+ ==== self.generations = g
40
+ Changes the number of generations in each test to +g+. Default is 50.
41
+
42
+ ==== self.population_size = s
43
+ Changes the population size in each test to +g+. Default is 20.
44
+
45
+ ==== self.repeat = r
46
+ Changes the number of times each test will be repeated to +r+. Default is 10, a higher number here will take longer to
47
+ complete, but will improve the accuracy of the results.
48
+
49
+
50
+
51
+
52
+
53
+
data/data/CROSSOVER ADDED
@@ -0,0 +1,49 @@
1
+ == Crossover documentation
2
+ A crossover operator combines two parents to generate one or (usually) two children.
3
+
4
+ The crossover operator should be defined as a +cross+ method in the metaclass of your genotype class.
5
+ class Example < Genotype
6
+ ...
7
+ class << self
8
+ def cross(parent1,parent2)
9
+ # generate children.
10
+ end
11
+ end
12
+ use NullCrossover # or include some builtin operator
13
+ end
14
+ Also see the Genotype#from_genes function, which can be useful for generating children after extracting and recombining the parents' genes.
15
+
16
+ The builtin crossover operators are implemented as modules which should be included in the metaclass.
17
+ Using the Class#use keyword does this automatically.
18
+
19
+ == General Crossovers
20
+ === NullCrossover
21
+ Just returns copies of the two parents, i.e. performs no crossover at all.
22
+
23
+ == List-based Crossovers
24
+ These crossovers can be used for all list- and string-based genotypes.
25
+
26
+ === SinglePointCrossover
27
+ Standard single point crossover. Returns two children.
28
+
29
+ === UniformCrossover
30
+ Standard uniform crossover.Returns two children.
31
+
32
+
33
+ == Specialized Crossovers
34
+ === For PermutationGenotype
35
+ PermutationCrossover is a partial preservation crossover for permutations.
36
+ It is fairly destructive, which can lead to poor performance.
37
+
38
+
39
+ == Meta-crossovers
40
+ These functions take one or more crossover modules and generate a new crossover module.
41
+
42
+ === SingleChild(crossover) (#SingleChild)
43
+ Applies an arbitrary crossover and returns a random child.
44
+
45
+ === PCross(p,crossover,othercrossover=NullCrossover)
46
+ Applies an arbitrary crossover with probability p, and another crossover with probability 1-p.
47
+
48
+
49
+
data/data/GENOTYPE ADDED
@@ -0,0 +1,49 @@
1
+ == Genotype documentation
2
+ The genotype, aka genome, aka chromosomes is a simple representation of a solution to your problem.
3
+ This is usually an array of numbers or bits.
4
+
5
+ === Creating your own.
6
+ If you are creating your own genotype, just inherit from the base Genotype class.
7
+ You should initialize an instance in the +initialize+ method, and make sure the +genes+ and +genes=+ functions work properly.
8
+
9
+ The base class includes NullCrossover, NullMutator and Elitism(ScaledRouletteSelection(),1) by default.
10
+
11
+ All of the other genotypes described here inherit the base class, and its associated selection/crossover/mutation operators, unless
12
+ otherwise indicated.
13
+
14
+ === List-based genotypes (file)[link:files/lib/charlie/list/list_genotype_rb.html]
15
+ All of these genotypes are based on arrays and can use the list-based crossover and mutation operators.
16
+ They are all generated dynamically by functions, and should be used like:
17
+
18
+ class MyGenotype < FloatListGenotype(5)
19
+ def fitness
20
+ ...
21
+ end
22
+ end
23
+
24
+
25
+ ==== FloatListGenotype(n,range=0..1)
26
+ Genotype of +n+ floats in the range +range+.
27
+
28
+ Includes <tt>ListMutator()</tt> (with default parameters :expected_n[3], :uniform[ 0.25 ]) and <tt>SinglePointCrossover</tt> by default.
29
+
30
+ ==== BitStringGenotype(n)
31
+ Genotype of +n+ bits. +genes+ returns an array of 0/1, +to_s+ returns a string.
32
+
33
+ Includes <tt>ListMutator(:expected_n[3],:flip), SinglePointCrossover</tt> by default.
34
+
35
+ ==== StringGenotype(n,elements)
36
+ Genotype of +n+ elements (not necessarily chars).
37
+
38
+ Includes <tt>ListMutator(:expected_n[2],:replace[*elements]), SinglePointCrossover</tt> by default.
39
+
40
+ === Specialized genotypes
41
+ These genotypes have their own crossover and mutation operators.
42
+
43
+ ==== PermutationGenotype(n,elements=0...n) (file)[link:files/lib/charlie/permutation/permutation_rb.html]
44
+ Genotype for permutations. Includes PermutationMutator and PermutationCrossover by default.
45
+
46
+
47
+
48
+
49
+
data/data/MUTATION ADDED
@@ -0,0 +1,43 @@
1
+ == Mutation documentation
2
+ A mutation operator mutates a single instance in place.
3
+
4
+
5
+
6
+ The mutation operator should be defined as a +mutate!+ method in your genotype class.
7
+ class Example < Genotype
8
+ def mutate!
9
+ # apply mutation here.
10
+ end
11
+ use NullMutator # or include some builtin operator
12
+ end
13
+
14
+ The non-destructive counterpart +mutate+ is defined automatically by Genotype#mutate.
15
+
16
+ == General Mutators
17
+ === NullMutator
18
+ Just returns self
19
+
20
+ == List-based Mutators
21
+ These crossovers can be used for all list- and string-based genotypes.
22
+
23
+ === ListMutator(strategy=:expected_n ,point_mutator=:uniform)
24
+ Generates a wide variety of mutators for lists, strings and bitstrings.
25
+
26
+ * strategy can be a proc or one of the MutationStrategies : single point, multi-point and probabilistic.
27
+ * point_mutator can be a proc or one of the PointMutators : bit flipping, replacing elements, or adding some offset.
28
+ See the documentation of list_mutate.rb[link:files/lib/charlie/list/list_mutate_rb.html] for more info on these.
29
+
30
+ Both of these parameters use Symbol#[] in the examples. <tt>:replace['a','b']</tt> is simply equivalent to <tt>[:replace,'a','b']</tt>
31
+
32
+ == Specialized Mutators
33
+ === For PermutationGenotype
34
+ PermutationMutator is a transposition mutator for permutations.
35
+
36
+ == Meta-mutators
37
+ These functions take one or more mutator modules and generate a new mutator module.
38
+
39
+ === PMutate(p,mutator,othermutator=NullMutator)
40
+ Applies an arbitrary mutator with probability p, and another mutator with probability 1-p.
41
+
42
+
43
+
data/data/SELECTION ADDED
@@ -0,0 +1,48 @@
1
+ == Selection documentation
2
+ A selection operator generates the new generation from the old.
3
+
4
+
5
+
6
+ The selection strategy should be defined as a +next_generation+ method in the metaclass of your genotype class.
7
+ class Example < Genotype
8
+ ...
9
+ class << self
10
+ def next_generation(population)
11
+ # select parents and yield(parent1,parent2) them to the crossover and mutation operator. Create an array from several of these calls to get the next generation.
12
+ end
13
+ end
14
+ use RouletteSelection # or include some builtin operator
15
+ end
16
+
17
+
18
+ == Fitness-based selection strategies
19
+ These strategies work with genotype classes which define a +fitness+ function. The +fitness+ function should return a number, higher fitness means better and more likely to be selected. All except RouletteSelection can handle negative fitness values.
20
+
21
+ * RandomSelection
22
+ * TruncationSelection(best=0.3)
23
+ * BestOnlySelection
24
+ * RouletteSelection
25
+ * ScaledRouletteSelection(&block)
26
+ * TournamentSelection(group_size=4,n_times=nil)
27
+
28
+ The documentation for selection_rb[link:files/lib/charlie/selection_rb.html] contains explanations for most of these.
29
+
30
+ === Meta-selection
31
+ ==== Elitism(selection,n=1)
32
+ Generates a module which applies elitism to some selection strategy. This:
33
+ * saves the best +n+ solutions
34
+ * applies the selection
35
+ * replaces the last +n+ individuals in the new population with the best +n+ of the old population (unless the newer individual has higher fitness).
36
+ This ensures the maximum fitness can never decrease.
37
+
38
+
39
+
40
+ == Co-evolutionary selection strategies
41
+ These strategies work with genotype classes which define a <tt>fight(other)</tt> function.
42
+ This function should return true if the instance defeats +other+ in a 'fight'.
43
+
44
+ * GladiatorialSelection
45
+
46
+ Because there is no way to determine who is the actual best individual, using Population#benchmark
47
+ for comparing strategies for convergence speed, etc.
48
+ is not possible. Defining a fitness function as some statistic you want to track and then using benchmark should be possible, but is untested.