jinni 0.1.1 → 0.3.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.
- checksums.yaml +4 -4
- data/README.md +65 -11
- data/lib/jinni/creature.rb +7 -2
- data/lib/jinni/eigenclass.rb +1 -1
- data/lib/jinni/genepool.rb +45 -0
- data/lib/jinni/numeric.rb +0 -1
- data/lib/jinni/version.rb +1 -1
- data/lib/jinni.rb +21 -17
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ee683454b13cb220e37262246b93ab743e790172
|
4
|
+
data.tar.gz: f387a3ff296f2ccb871c0b20da61fda5b2792055
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cc062f3fae19de17af17a78882fcf1c41d5d11f77ceadffb414f8cee299ae3524732dbc4bde8805b7a8f20549dd24f8d8c58e95dd0b158c5c618dab222f3191c
|
7
|
+
data.tar.gz: 86b8614b1b9a6cdde555b647a7ad34a11a806cc541ccc2922a301e1b3ba8726d3200e5bbb8329e1c8494ee47a25ab03ca2819285e226696be9ee1511960fcfd3
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
# Jinni []()
|
1
|
+
# Jinni [](https://rubygems.org/gems/jinni)
|
2
2
|
|
3
|
-
unconventional genetics, aggressively metaprogrammed
|
3
|
+
unconventional genetics, aggressively metaprogrammed. Pronounced like `genie`.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -17,9 +17,9 @@ Or install it yourself as:
|
|
17
17
|
$ gem install jinni
|
18
18
|
|
19
19
|
|
20
|
-
##
|
20
|
+
## Quick-Start
|
21
21
|
|
22
|
-
###
|
22
|
+
### Make a class
|
23
23
|
|
24
24
|
class Fish < Jinni::Creature
|
25
25
|
# attr_genetic name, min, max
|
@@ -29,29 +29,83 @@ Or install it yourself as:
|
|
29
29
|
|
30
30
|
# must return a fixnum
|
31
31
|
def fitness
|
32
|
-
|
32
|
+
@pointiness + (@speed_in_knots / @mass_in_kilos )
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
|
36
|
+
### Have an offspring
|
37
|
+
|
38
|
+
bill = Fish.random_new
|
39
|
+
ted = Fish.random_new
|
40
|
+
|
41
|
+
child = bill << ted
|
42
|
+
|
43
|
+
### Put some creatures in a genepool
|
44
|
+
|
45
|
+
fishes = Genepool.new
|
37
46
|
10.times { fishes.push(Fish.random_new) } # `random_new` respects min and max
|
38
47
|
|
39
|
-
###
|
48
|
+
### have some more offspring
|
40
49
|
|
41
50
|
bill = fishes[0]
|
42
51
|
ted = fishes[1]
|
43
52
|
|
44
53
|
child = bill << ted
|
45
54
|
|
46
|
-
###
|
47
|
-
|
48
|
-
this here doesn't work:
|
55
|
+
### Start a whole new generation
|
49
56
|
|
50
|
-
generation =
|
57
|
+
generation = fishes.generate(10)
|
51
58
|
fishes << generation
|
52
59
|
|
53
60
|
### todo: something mutations something, also make it faster
|
54
61
|
|
62
|
+
## API
|
63
|
+
|
64
|
+
### creatures : instance
|
65
|
+
|
66
|
+
Jinni adds the following public instance methods to your creatures:
|
67
|
+
|
68
|
+
#### fitness()
|
69
|
+
you should override this function with something sensible for your class. It returns `0.0` by default, but any float will do.
|
70
|
+
#### genes()
|
71
|
+
genes is a getter method that returns the genetic attributes available to your instance.
|
72
|
+
#### mutate(rate = 0.01)
|
73
|
+
mutate returns a slightly mutated object. Each bit in the original dna has a `rate` chance of flipping.
|
74
|
+
#### <<(object) / cross(object)
|
75
|
+
<< is the basic method used to cross two objects. It splits the dna strands of the input objects into random chunks, and then they randomly swap.
|
76
|
+
#### to_binary()
|
77
|
+
to_binary returns the binary dna strand that represents the object.
|
78
|
+
|
79
|
+
### creatures : class
|
80
|
+
|
81
|
+
Jinni adds the following public class methods to your creature class:
|
82
|
+
|
83
|
+
#### attr_genetic(:name, min, max)
|
84
|
+
use this method in your class to declare your genetic attributes.
|
85
|
+
#### random_new()
|
86
|
+
random_new initializes an object with attributes randomly assigned from within your declared range.
|
87
|
+
#### new_from_binary()
|
88
|
+
use this method to initialize an object from an arbitrary binary string.
|
89
|
+
|
90
|
+
### numeric
|
91
|
+
|
92
|
+
Jinni also monkeypatches the following methods into Numeric:
|
93
|
+
|
94
|
+
#### to_binary()
|
95
|
+
utility method to convert a numeric into a binary string.
|
96
|
+
#### bits()
|
97
|
+
utility method to return the number of bits that the binary representation of the number requires
|
98
|
+
|
99
|
+
### genepool
|
100
|
+
|
101
|
+
Jinni creates a class, Genepool which inherits from Array. Genepool has the following instance methods:
|
102
|
+
|
103
|
+
#### generate(n, mutationRate = 0.01, quality = :fitness)
|
104
|
+
use this method to create a new generation of `n` creatures based on a genepool. it uses weighted roulette wheel selection to simulate the effects of genetic fitness, then crosses the selected objects together.
|
105
|
+
#### roulette(n, quality = :fitness)
|
106
|
+
this utility method uses weighted roulette wheel selection to choose `n` objects from your gene pool influenced by fitness. It does not cross them.
|
107
|
+
#### average(quality = :fitness)
|
108
|
+
this method returns the mean of one quality through a collection of objects. It's very useful for watching your generations increase in fitness.
|
55
109
|
|
56
110
|
## Contributing
|
57
111
|
|
data/lib/jinni/creature.rb
CHANGED
@@ -14,6 +14,12 @@ module Jinni
|
|
14
14
|
@@genes
|
15
15
|
end
|
16
16
|
|
17
|
+
def mutate(rate = 0.01)
|
18
|
+
binary = self.to_binary
|
19
|
+
newBinary = binary.chars.map { |bit| bit == "0" ? "1" : "0" if rand < rate }
|
20
|
+
return self.class.new_from_binary newBinary
|
21
|
+
end
|
22
|
+
|
17
23
|
# this is Where It Happens
|
18
24
|
# usage:
|
19
25
|
# child = bill << ted
|
@@ -49,7 +55,6 @@ module Jinni
|
|
49
55
|
|
50
56
|
# generic initialize from hash, called by the others
|
51
57
|
def initialize(hash)
|
52
|
-
puts hash
|
53
58
|
hash.each_pair do |gene, value|
|
54
59
|
instance_variable_set( "@#{gene}", value )
|
55
60
|
end
|
@@ -76,12 +81,12 @@ module Jinni
|
|
76
81
|
start = 0
|
77
82
|
@@genes.each_pair do |gene, range|
|
78
83
|
binary_chunk = binary[start..(start = start + range.bits - 1)]
|
84
|
+
break if binary_chunk.class != String
|
79
85
|
offset = binary_chunk.to_i(2)
|
80
86
|
value = self.class.send("#{gene}_min") + offset
|
81
87
|
start += 1
|
82
88
|
params[gene] = value
|
83
89
|
end
|
84
|
-
puts params
|
85
90
|
params
|
86
91
|
end
|
87
92
|
|
data/lib/jinni/eigenclass.rb
CHANGED
@@ -0,0 +1,45 @@
|
|
1
|
+
class Genepool < Array
|
2
|
+
def roulette(n, quality = :fitness)
|
3
|
+
scratch = self.clone
|
4
|
+
|
5
|
+
probabilities = scratch.map { |creature| creature.send(quality) }
|
6
|
+
selected = []
|
7
|
+
|
8
|
+
n.times do
|
9
|
+
r, inc = rand * probabilities.max, 0 # pick a random number and select the individual
|
10
|
+
# corresponding to that roulette-wheel area
|
11
|
+
scratch.each_index do |i|
|
12
|
+
if r < (inc += probabilities[i])
|
13
|
+
selected << scratch[i]
|
14
|
+
# make selection not pick sample twice
|
15
|
+
# scratch.delete_at i
|
16
|
+
# probabilities.delete_at i
|
17
|
+
break
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
return selected
|
22
|
+
end
|
23
|
+
|
24
|
+
def generate(n, mutationRate = 0.01, quality = :fitness)
|
25
|
+
scratch = self.clone
|
26
|
+
|
27
|
+
pool = scratch.roulette(n * 2, quality)
|
28
|
+
|
29
|
+
generation = Genepool.new
|
30
|
+
|
31
|
+
pool.each_slice(2) do |pair|
|
32
|
+
child = pair[0] << pair[1]
|
33
|
+
# child = child.mutate if mutationRate > 0
|
34
|
+
generation << child
|
35
|
+
end
|
36
|
+
|
37
|
+
return generation
|
38
|
+
end
|
39
|
+
|
40
|
+
def average(quality = :fitness)
|
41
|
+
self.map {|f| f.send(quality)}.inject{ |sum, n| sum + n }.to_f / self.length
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
data/lib/jinni/numeric.rb
CHANGED
data/lib/jinni/version.rb
CHANGED
data/lib/jinni.rb
CHANGED
@@ -1,26 +1,30 @@
|
|
1
1
|
require 'pry'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
require_relative 'jinni/version'
|
4
|
+
require_relative 'jinni/creature'
|
5
|
+
require_relative 'jinni/eigenclass'
|
6
|
+
require_relative 'jinni/numeric'
|
7
|
+
require_relative 'jinni/genepool'
|
11
8
|
|
12
9
|
class Fish < Jinni::Creature
|
13
|
-
attr_genetic
|
14
|
-
attr_genetic :
|
15
|
-
attr_genetic :
|
16
|
-
attr_genetic :
|
17
|
-
|
18
|
-
|
10
|
+
# attr_genetic name, min, max
|
11
|
+
attr_genetic :pointiness, 0, 2
|
12
|
+
attr_genetic :mass_in_kilos, 10, 100
|
13
|
+
attr_genetic :speed_in_knots, 8, 12
|
14
|
+
|
15
|
+
# must return a fixnum
|
16
|
+
def fitness
|
17
|
+
@pointiness.to_f * (@speed_in_knots.to_f / @mass_in_kilos.to_f )
|
18
|
+
end
|
19
19
|
end
|
20
20
|
|
21
|
-
|
22
|
-
|
21
|
+
fishes = Genepool.new
|
22
|
+
100.times { fishes << Fish.random_new } # `random_new` respects min and max
|
23
23
|
|
24
|
-
|
24
|
+
newGen = fishes.generate(1000)
|
25
25
|
|
26
26
|
binding.pry
|
27
|
+
|
28
|
+
puts 'end'
|
29
|
+
|
30
|
+
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jinni
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Monks
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-05-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -56,6 +56,7 @@ files:
|
|
56
56
|
- lib/jinni.rb
|
57
57
|
- lib/jinni/creature.rb
|
58
58
|
- lib/jinni/eigenclass.rb
|
59
|
+
- lib/jinni/genepool.rb
|
59
60
|
- lib/jinni/numeric.rb
|
60
61
|
- lib/jinni/version.rb
|
61
62
|
homepage: http://github.com/amonks/jinni
|