pmeth 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/pmeth.rb +83 -88
  3. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c65096ac15217bc9e12437449a1b6fa9833f627b
4
- data.tar.gz: a51645f73810ae436fb329d5188fcd8cc5023842
3
+ metadata.gz: c10b7f39e2469c0ecfe087918e1a1bdf0fa9c200
4
+ data.tar.gz: 79da3d0a1648106e7ed3dd0bcbfb44a8964f58a2
5
5
  SHA512:
6
- metadata.gz: b60e083691a3f2e138f12df22ec9fc84605d1ffa47ec0e2c5ade4d3eef383818c97ee0050a7a4582fec3ce7c91fcf7bf048cffdcd3eabb00a01a373be78e4ede
7
- data.tar.gz: f89066070ad87abb955b225f597cf219b5e630267ae172837df870e3da778d420a1d9208ebb5238cc0d75b30d0f561a910daacb7330759ae80b4842c6e358411
6
+ metadata.gz: 4211a9815d11ba335d958b0509902d8aa54a3aca195dff7cb242524da4d4b5fb19ba28697ef21cf4c88f29fb3e17493208b2d0536ab1f5bb012140b3e437d554
7
+ data.tar.gz: eb7d88b8b676d3ae595ef7b564ec80b8acb2461534cb4b6bf4a50abe6828c59411f446b9bc0a25f2d48e5c9e92e0c16065903f74e5f73dd57f2b41e4552df2c4
data/lib/pmeth.rb CHANGED
@@ -1,124 +1,119 @@
1
1
  #encoding: utf-8
2
2
  class PMeth
3
- # Input: An integer you wish to know whether is prime
4
- # Output: true/false
3
+ # Returns true if n is a prime number, false if not
5
4
  def self.prime?(n)
6
5
  for d in 2..(n - 1)
7
6
  if (n % d) == 0
8
- return false
9
- end
7
+ return false
8
+ end
10
9
  end
11
10
  true
12
11
  end
13
12
 
14
- # Input: A permutation array of unique objects
15
- # Output: A random integer that the length of the Input 0 array can be divided by to get another integer (the randomly chosen size of chunks that permutations will be split into, in the recombine/mutate methods)
16
- def self.division(objects) #number of objects must be => 10
17
- x = 1.5
18
- until objects.length/x == (objects.length/x).to_i && x <= objects.length
19
- x = (objects.length/10).to_f + rand(objects.length).to_f
13
+ # Returns a random integer that array can be divided by to get another integer (other than the array length itself)
14
+ def self.division(array)
15
+ x = 1.5 # x assigned a non-integer value to begin with
16
+ if prime?(array.length) # array with prime number of objects is not divisible by any integer other than 1 and itself
17
+ x = 1
18
+ else
19
+ until x > 0 && array.length/x.to_f == (array.length/x.to_f).to_i && Integer === x
20
+ x = rand(array.length)
21
+ end
20
22
  end
21
23
  return x
22
24
  end
23
25
 
24
- # Input 0: A parent permutation array of unique objects
25
- # Input 1: A second parent permutation array of the same unique objects as input 0
26
- # Output: A child permutation array, whose order is a recombination of the parent permutations (the same unique objects ordered differently to either input)
26
+ # Returns a new permutation that has had a randomly sized sub-section re-ordered by shuffle
27
+ def self.chunk_mutate(permutation)
28
+ if prime?(permutation.length) # if there are a prime number of objects in the permutation
29
+ ig = rand(permutation.length)-1 # choose a random object to ignore - to add back at its original index after mutation
30
+ ig_obj = permutation[ig] # save the object
31
+ permutation.delete_at(ig)
32
+ end
33
+ mutant = []
34
+ 1.times do # this is to make use of the redo statement below
35
+ x = 0 # x is the randomly chosen size of chunks that permutation will be split into
36
+ until x > 2 # the chunk to be re-ordered must have at least 2 objects
37
+ x = division(permutation)
38
+ end
39
+ sliced = permutation.each_slice(x).to_a # permutation is sliced into chunks of size x
40
+ e = rand(sliced.length-1) # one of the chunks is chosen at random...
41
+ sliced[e] = sliced[e].shuffle # ... and the objects within are shuffled
42
+ new_perm = sliced.flatten
43
+ if new_perm == permutation # if the size of the chunk to be shuffled is small, there is a chance that it may not be differently ordered by shuffle...
44
+ redo # ... redo is used to ensure that a mutant permutation is created
45
+ end
46
+ if ig != nil
47
+ new_perm.insert(ig, ig_obj)
48
+ end
49
+ mutant << new_perm # the new permutation has been added to an array for access outside the 1.times loop
50
+ end
51
+ return mutant[0] # new_perm
52
+ end
53
+
54
+ # Returns a new permutation where two of the objects have swapped positions (indices)
55
+ def self.swap_mutate(permutation)
56
+ a = b = x = y = 0
57
+ until a != b
58
+ x = rand(permutation.length-1) # randomly choose two indices x and y...
59
+ y = rand(permutation.length-1)
60
+ a = permutation[x] # ... and call the objects at these indices a and b
61
+ b = permutation[y]
62
+ end
63
+ mutant = permutation.dup # create a new permutation...
64
+ mutant[x] = b # ... with object b at index x...
65
+ mutant[y] = a # ... and object a at index y
66
+ return mutant
67
+ end
68
+
69
+ # Returns a permutation whose objects are ordered partly like a_parent permutation, and partly like b_parent permutation
27
70
  def self.recombine(a_parent, b_parent)
28
- kid = []
29
- 1.times do # so we can use redo
30
- x = division(a_parent)
31
- if x == a_parent.length && prime?(x) == false # If a permutation with a non-prime number of objects comes up with x == array length, redo
32
- redo
33
- elsif x == a_parent.length # to compensate for permutations with a prime number of objects:
34
- ig = rand(a_parent.length)-1 # choose a random element of the array to ignore - we add the object at this element back at its original position after recombination
35
- a_parent_reduced = a_parent.dup
36
- b_parent_reduced = b_parent.dup
37
- a_parent_reduced.delete_at(ig)
38
- b_parent_reduced.delete_at(ig)
39
- x = division(a_parent_reduced)
40
- a_parent_sliced = a_parent_reduced.each_slice(x).to_a
71
+ child_permutation = []
72
+ 1.times do # this is to make use of the redo statement below
73
+ x = division(a_parent) # the randomly chosen size of chunks that permutations will be split into
74
+ if prime?(a_parent.length) # to compensate for permutations with a prime number of objects:
75
+ ig = rand(a_parent.length)-1 # choose a random object to ignore - to add back at its original index after mutation
76
+ a_parent_reduced, b_parent_reduced = a_parent.dup, b_parent.dup # then create duplicates of the parent arrays...
77
+ a_parent_reduced.delete_at(ig); b_parent_reduced.delete_at(ig) # .. and remove the ignored object from these duplicates
78
+ x = division(a_parent_reduced) # choose a new chunk size for reduced parent permutations, that no longer have a prime number of objects
79
+ a_parent_sliced = a_parent_reduced.each_slice(x).to_a # slice the reduced parent permutations into chunks of size x
41
80
  b_parent_sliced = b_parent_reduced.each_slice(x).to_a
42
81
  else
43
- a_parent_sliced = a_parent.each_slice(x).to_a
82
+ a_parent_sliced = a_parent.each_slice(x).to_a # if permutation lengths are non-prime, just slice the parent permutations into chunks of size x
44
83
  b_parent_sliced = b_parent.each_slice(x).to_a
45
84
  end
46
- chosen = rand(b_parent_sliced.length)-1 # choose one of the chunks (sub array from a permutation) to keep from b_parent
47
- child = a_parent_sliced.flatten.dup
48
- y = 0
49
- pos_array = []
50
- a_parent_sliced[chosen].each do |object| # place each object in the equivalent a_parent chunk into the position it's corresponding object (from b_parent) occupies in a_parent
51
- chunk = b_parent_sliced[chosen][y] # the equivalent object in the chosen b_parent chunk
52
- pos = a_parent_sliced.flatten.index(chunk) # the position of the b_parent chunk in a_parent
53
- c_pos = a_parent_sliced.flatten.index(object) # the position of the object in a_parent
54
- pos_array << pos
55
- y+=1
85
+ chosen = rand(b_parent_sliced.length)-1 # choose a chunk to have b_parent ordered objects in child permutation
86
+ child = a_parent_sliced.flatten.dup # un-modified child permutation to accept chunk from b_parent (and possibly ignored object)
87
+ a_indices = []
88
+ ### place each object in chosen a_parent chunk into the index it's corresponding object (from b_parent) occupies in a_parent ###
89
+ a_parent_sliced[chosen].each do |i|
90
+ index = a_parent_sliced[chosen].index(i) # the index of each object in the chosen a_parent chunk...
91
+ b_object = b_parent_sliced[chosen][index] # ... the object at that index in the chosen b_parent chunk...
92
+ a_indices << a_parent_sliced.flatten.index(b_object) # ... the index of that object (from b_parent chunk) (INDEX RHO) in a_parent is added to an array
56
93
  end
57
- if pos_array.include?(nil)
94
+ if a_indices.include?(nil) # TODO unsure why: a_indices sometimes includes nil
58
95
  redo
59
96
  else
60
97
  y = 0
61
- pos_array.each do |pos|
62
- unless b_parent_sliced[chosen].include?(a_parent_sliced[chosen][y])
63
- child[pos] = a_parent_sliced[chosen][y]
64
- child[a_parent_sliced.flatten.index(a_parent_sliced[chosen][y])] = b_parent_sliced[chosen][y] # swapping the positions of objects in chunks from parents, to give their positions in child
98
+ a_indices.each do |ai|
99
+ unless b_parent_sliced[chosen].include?(a_parent_sliced[chosen][y]) # unless the chosen chunk from b_parent includes objects from the chosen a_parent chunk...
100
+ child[ai] = a_parent_sliced[chosen][y] # ... the object from the chosen chunk in parent_a is added to INDEX RHO in child
101
+ chosen_index = a_parent_sliced.flatten.index(a_parent_sliced[chosen][y]) # index of object from a_parent's chosen chunk in a_parent
102
+ child[chosen_index] = b_parent_sliced[chosen][y] # swapping the indices of objects in chunks from parents, to give their indices in child
65
103
  end
66
104
  y+=1
67
105
  end
68
106
  end
69
- if ig != nil
107
+ if ig != nil # if the permutations are a prime number in length, we now add the ignored object from earlier into child
70
108
  if b_parent_sliced[chosen].include?(b_parent[ig]) # add the ignored object from b_parent if it's in the chosen chunk...
71
109
  child.insert(ig, b_parent[ig])
72
110
  else
73
111
  child.insert(ig, a_parent[ig]) # ...otherwise add the ignored object from a_parent
74
112
  end
75
113
  end
76
- if child != child.uniq
77
- redo
78
- end
79
- kid << child # so we can access this outside the loop
80
- end
81
- return kid[0]
82
- end
83
-
84
- # Input: A permutation array of unique objects
85
- # Output: A slightly different permutation array of the same unique objects
86
- def self.mutate(fasta)
87
- mutant = []
88
- 1.times do
89
- x = 0
90
- until x > 2
91
- x = division(fasta)
92
- end
93
- sliced = fasta.each_slice(x).to_a
94
- e = rand(sliced.length-1).to_i
95
- sliced[e] = sliced[e].shuffle
96
- if sliced.flatten == fasta
97
- redo
98
- end
99
- mutant << sliced.flatten
114
+ child_permutation << child # so we can access this outside the loop
100
115
  end
101
- return mutant[0]
116
+ return child_permutation[0]
102
117
  end
103
118
 
104
- # Input: A permutation array of unique objects
105
- # Output: A slightly different permutation array of the same unique objects
106
- def self.mini_mutate(fasta)
107
- a = b = 0
108
- until a != b
109
- a = fasta[rand(fasta.length-1)]
110
- b = fasta[rand(fasta.length-1)]
111
- end
112
- mutant = []
113
- fasta.each do |i|
114
- if i == a
115
- mutant << b
116
- elsif i == b
117
- mutant << a
118
- else
119
- mutant << i
120
- end
121
- end
122
- return mutant
123
- end
124
119
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pmeth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Edward Chalstrey
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-25 00:00:00.000000000 Z
11
+ date: 2014-04-30 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: "Reproduction methods for genetic (and other iterative improvement) algorithms,
14
14
  being used to solve permutation problems, \n where permutations are arrays of unique