pmeth 0.0.2 → 0.0.3

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 (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