complearn 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. data/AUTHORS +13 -0
  2. data/COPYING +340 -0
  3. data/ChangeLog +0 -0
  4. data/INSTALL +231 -0
  5. data/Makefile +352 -0
  6. data/Makefile.am +76 -0
  7. data/Makefile.in +352 -0
  8. data/NEWS +7 -0
  9. data/README +0 -0
  10. data/aclocal.m4 +104 -0
  11. data/bin/Makefile +209 -0
  12. data/bin/Makefile.am +8 -0
  13. data/bin/Makefile.in +209 -0
  14. data/bin/labeltree +68 -0
  15. data/bin/labeltree.in +68 -0
  16. data/bin/makesvm +70 -0
  17. data/bin/makesvm.in +70 -0
  18. data/bin/maketree +98 -0
  19. data/bin/maketree.in +98 -0
  20. data/bin/ncd +43 -0
  21. data/bin/ncd.in +43 -0
  22. data/bin/ncdmatrix +54 -0
  23. data/bin/ncdmatrix.in +54 -0
  24. data/bin/ncdvector +50 -0
  25. data/bin/ncdvector.in +50 -0
  26. data/complearn-0.6.2.gem +0 -0
  27. data/complearn.gemspec +57 -0
  28. data/config.log +597 -0
  29. data/config.status +1082 -0
  30. data/configure +4922 -0
  31. data/configure.ac +91 -0
  32. data/confstat5FpLBf/config.h +65 -0
  33. data/confstat5FpLBf/subs-1.sed +50 -0
  34. data/confstat5FpLBf/subs-2.sed +13 -0
  35. data/confstat5FpLBf/subs.frag +0 -0
  36. data/confstat5FpLBf/subs.sed +59 -0
  37. data/confstat5FpLBf/undefs.sed +24 -0
  38. data/doc/FAQ.txt +67 -0
  39. data/doc/Makefile +286 -0
  40. data/doc/Makefile.am +11 -0
  41. data/doc/Makefile.in +286 -0
  42. data/doc/devguide.txt +15 -0
  43. data/doc/example.complearnrc +14 -0
  44. data/doc/examples.txt +35 -0
  45. data/doc/man/Makefile +255 -0
  46. data/doc/man/Makefile.am +11 -0
  47. data/doc/man/Makefile.in +255 -0
  48. data/doc/man/complearn.5 +91 -0
  49. data/doc/man/labeltree.1 +35 -0
  50. data/doc/man/makesvm.1 +60 -0
  51. data/doc/man/maketree.1 +58 -0
  52. data/doc/man/ncd.1 +51 -0
  53. data/doc/man/ncdmatrix.1 +40 -0
  54. data/doc/man/ncdvector.1 +42 -0
  55. data/doc/readme.txt +101 -0
  56. data/doc/userguide.txt +46 -0
  57. data/examples/genes/blueWhale.txt +1 -0
  58. data/examples/genes/cat.txt +1 -0
  59. data/examples/genes/chimpanzee.txt +1 -0
  60. data/examples/genes/finWhale.txt +1 -0
  61. data/examples/genes/graySeal.txt +1 -0
  62. data/examples/genes/harborSeal.txt +1 -0
  63. data/examples/genes/horse.txt +1 -0
  64. data/examples/genes/human.txt +1 -0
  65. data/examples/genes/mouse.txt +1 -0
  66. data/examples/genes/rat.txt +1 -0
  67. data/ext/Makefile +167 -0
  68. data/ext/Quartet.c +399 -0
  69. data/ext/Quartet.h +62 -0
  70. data/ext/TreeScore.c +244 -0
  71. data/ext/TreeScore.h +3 -0
  72. data/ext/config.h +65 -0
  73. data/ext/config.h.in +64 -0
  74. data/ext/extconf.rb +3 -0
  75. data/ext/lib/CompLearnLib/CLConfig.rb +241 -0
  76. data/ext/lib/CompLearnLib/CompressionObject.rb +59 -0
  77. data/ext/lib/CompLearnLib/CompressionTask.rb +99 -0
  78. data/ext/lib/CompLearnLib/DistMatrix.rb +18 -0
  79. data/ext/lib/CompLearnLib/FoundComp.rb +10 -0
  80. data/ext/lib/CompLearnLib/FoundComp.rb.in +10 -0
  81. data/ext/lib/CompLearnLib/Ncd.rb +248 -0
  82. data/ext/lib/CompLearnLib/RunEnv.rb +150 -0
  83. data/ext/lib/CompLearnLib/Task.rb +39 -0
  84. data/ext/lib/CompLearnLib/TaskMaster.rb +13 -0
  85. data/ext/lib/CompLearnLib/TaskMasterMPI.rb +112 -0
  86. data/ext/lib/CompLearnLib/TaskMasterSingle.rb +39 -0
  87. data/ext/lib/CompLearnLib/Tree.rb +300 -0
  88. data/install-sh +294 -0
  89. data/missing +336 -0
  90. data/mkinstalldirs +111 -0
  91. data/o +24 -0
  92. data/scripts/CompLearn.iss +89 -0
  93. data/scripts/CompLearn.iss.in +89 -0
  94. data/scripts/debian/changelog +6 -0
  95. data/scripts/debian/control +14 -0
  96. data/scripts/makeSetup.sh +23 -0
  97. data/scripts/makeSetup.sh.in +23 -0
  98. data/scripts/makedeb.zsh +46 -0
  99. data/scripts/makedeb.zsh.in +46 -0
  100. data/tests/alltests.rb +2 -0
  101. data/tests/bz2test.rb +516 -0
  102. data/tests/sshagent-test.rb +48 -0
  103. data/tests/tests.rb +275 -0
  104. metadata +164 -0
@@ -0,0 +1,150 @@
1
+ module MRunEnv
2
+ require 'CompLearnLib/CLConfig'
3
+
4
+ # For now, use these paths
5
+ class MPIRunner
6
+ @@MPIRUBY='mpi_ruby'
7
+
8
+ @@MPIRUN='mpirun'
9
+ @@MPILAMBOOT='lamboot'
10
+ @@MPIWIPE='wipe'
11
+ @@MPIHALT='lamhalt'
12
+
13
+ end
14
+
15
+ # Change this by setting OUTPUTDIR in your shell environment
16
+ class DirNames
17
+ def DirNames.outputDir()
18
+ ENV['OUTPUTDIR'] || "/ufs/cilibrar/src/rubyquart/results"
19
+ end
20
+ end
21
+
22
+ class RunEnv
23
+ @@TMPDIR="/tmp"
24
+
25
+ @tmpCounter = 0
26
+ def RunEnv.getTemporaryFilename()
27
+ fname = format("%s/tmp-%05d.dat", @@TMPDIR, @tmpCounter)
28
+ @tmpCounter += 1
29
+ at_exit { File.exist?(fname) && File.unlink(fname) }
30
+ fname
31
+ end
32
+ def RunEnv.getTemporaryFilenames(howMany)
33
+ results = [ ]
34
+ howMany.times { results << RunEnv.getTemporaryFilename() }
35
+ results
36
+ end
37
+ def RunEnv.zrand(n)
38
+ rand(n)
39
+ end
40
+ def RunEnv.dirsInDir(dirname)
41
+ dirs = [ ]
42
+ for f in Dir.entries(dirname)
43
+ dirs << f if File.ftype(dirname+"/"+f)=='directory' && f != '.' && f != '..'
44
+ end
45
+ dirs.sort
46
+ end
47
+ def RunEnv.filesInDir(dirname)
48
+ files = [ ]
49
+ for f in Dir.entries(dirname)
50
+ files << f if File.ftype(dirname+"/"+f)=='file'
51
+ end
52
+ files.sort
53
+ end
54
+ end
55
+
56
+ class MPIRunner
57
+ def MPIRunner.getGoodHostsFile()
58
+ unless defined?(@hostFilename)
59
+ @hostFilename = SSHAgent.writeGoodHostFile
60
+ end
61
+ @hostFilename
62
+ end
63
+ def MPIRunner.rebootMPI()
64
+ MPIRunner.haltMPI
65
+ MPIRunner.bootMPI
66
+ end
67
+ def MPIRunner.bootMPI()
68
+ MPIRunner.getGoodHostsFile
69
+ result = `#{@@MPILAMBOOT} -x -v -s #{@hostFilename}`
70
+ puts result
71
+ @lamRunning = true
72
+ end
73
+ def MPIRunner.lamRunning?()
74
+ defined?(@lamRunning) && @lamRunning
75
+ end
76
+ def MPIRunner.haltMPI()
77
+ MPIRunner.getGoodHostsFile
78
+ #result = `#{@@MPIHALT}`
79
+ result = `#{@@MPIWIPE} -v #{@hostFilename}`
80
+ SSHAgent.runEverywhere('"killall mpi_ruby;killall lamboot;killall lamd"')
81
+ @lamRunning = false
82
+ end
83
+ def MPIRunner.stopMPIRubyScript()
84
+ #Process.kill(9, pid)
85
+ MPIRunner.haltMPI()
86
+ end
87
+ def MPIRunner.runMPIRubyScript(scriptArray) # returns PID of controller
88
+ scriptName = scriptArray[0]
89
+ scriptArgs = (scriptArray[1..-1]).join(' ')
90
+ puts "Running script #{scriptName} on #{`hostname`}"
91
+ MPIRunner.bootMPI unless lamRunning?
92
+ # res = fork()
93
+ # if (res)
94
+ # res
95
+ # else
96
+ exec("#{@@MPIRUN} C #{@@MPIRUBY} #{scriptName} #{scriptArgs}")
97
+ # end
98
+ end
99
+ end
100
+
101
+ class SSHAgent
102
+ def SSHAgent.isRunning?()
103
+ SSHAgent.checkHost(SSHAgent.primaryHost)
104
+ end
105
+ def SSHAgent.checkHost(hostname)
106
+ puts "Checking #{hostname}"
107
+ result = `unset DISPLAY ; setsid ssh #{hostname} hostname -s`
108
+ result.gsub!(/\s/,'')
109
+ hostname == result
110
+ end
111
+ def SSHAgent.primaryHost()
112
+ CLConfig.getDefaultConfig().hosts[0]
113
+ end
114
+ def SSHAgent.runAt(cmd, h)
115
+ if (h == 'dorado')
116
+ puts "Skipping running #{cmd} on dorado"
117
+ else
118
+ `unset DISPLAY ; setsid ssh #{h} #{cmd}`
119
+ end
120
+ end
121
+ def SSHAgent.runEverywhere(cmd)
122
+ [SSHAgent.primaryHost(), SSHAgent.helperHosts()].flatten.each { |h|
123
+ SSHAgent.runAt(cmd, h)
124
+ }
125
+ end
126
+ def SSHAgent.helperHosts()
127
+ CLConfig.getDefaultConfig().hosts[1..-1]
128
+ end
129
+ def SSHAgent.liveHosts()
130
+ unless SSHAgent.isRunning?
131
+ puts "Sorry, you forgot to start ssh-agent or run ssh-add"
132
+ exit(1)
133
+ end
134
+ alive = [ ]
135
+ SSHAgent.helperHosts.each { |h| alive << h if SSHAgent.checkHost(h) }
136
+ alive
137
+ end
138
+ def SSHAgent.writeGoodHostFile() # returns filename of new hosts file
139
+ cfg = CLConfig.getDefaultConfig
140
+ fname = RunEnv.getTemporaryFilename()
141
+ f = File.open(fname, "wb")
142
+ cfg.hosts.each { |h|
143
+ f.write("#{h}\n")
144
+ }
145
+ f.close
146
+ fname
147
+ end
148
+ end
149
+
150
+ end
@@ -0,0 +1,39 @@
1
+
2
+ require 'CompLearnLib/TaskMaster'
3
+
4
+ module MTask
5
+
6
+ class Task
7
+
8
+ attr_reader :tid, :sentTime
9
+
10
+ def aboutToSend()
11
+ @sentTime = time
12
+ end
13
+
14
+ def setTid(ntid)
15
+ @tid = ntid
16
+ end
17
+
18
+ def reply(result)
19
+ TaskMaster.reply(self,result)
20
+ end
21
+
22
+ def fetch(key)
23
+ TaskMaster.fetch(key)
24
+ end
25
+
26
+ def execute()
27
+ reply(nil)
28
+ end
29
+
30
+ end
31
+
32
+ class Store
33
+ attr_reader :key, :val
34
+ def initialize(ukey, uval)
35
+ @key,@val = ukey,uval
36
+ end
37
+ end
38
+
39
+ end
@@ -0,0 +1,13 @@
1
+ #
2
+ # TaskMaster
3
+ #
4
+ # TaskMaster superclass
5
+
6
+ require 'CompLearnLib/CLConfig'
7
+
8
+ if CLConfig.getDefaultConfig().isSingleProcess? || !defined?(MPI)
9
+ require 'CompLearnLib/TaskMasterSingle'
10
+ else
11
+ require 'CompLearnLib/TaskMasterMPI'
12
+ end
13
+
@@ -0,0 +1,112 @@
1
+
2
+ unless defined?(MPI)
3
+ puts "Sorry, you seem to have started an MPIRuby script using"
4
+ puts "the wrong ruby interpretter. Please try again something"
5
+ puts "like ruby parbegin.rb yourScriptName.rb"
6
+ exit 1
7
+ end
8
+
9
+ class ExitMsg
10
+ end
11
+
12
+ class TaskMaster
13
+
14
+ @@haveInitted = false
15
+
16
+ @cbs = { }
17
+ @free = [ ]
18
+ @slaves = [ ]
19
+ @tasks = { }
20
+ @maxTid = 0
21
+ @storage = { }
22
+
23
+ def TaskMaster.fetch(key)
24
+ @storage[key]
25
+ end
26
+
27
+ def TaskMaster.doMasterInit()
28
+ return if @@haveInitted
29
+ @@haveInitted = true
30
+ sz = MPI::Comm::WORLD.size()
31
+ puts "Starting calculation with #{sz} nodes"
32
+ Kernel.at_exit() {
33
+ exitmsg = ExitMsg.new
34
+ @slaves.each { |n|
35
+ MPI::Comm::WORLD.send(exitmsg, n, 0)
36
+ }
37
+ }
38
+ sz.times { |i| @free << i unless i == 0 }
39
+ @slaves = @free.clone
40
+ end
41
+
42
+ def TaskMaster.doSlaveLoop()
43
+ Process.setpriority(Process::PRIO_PROCESS, Process.pid, 19)
44
+ while true
45
+ task,status = MPI::Comm::WORLD.recv(0, 0)
46
+ if task.is_a?(ExitMsg)
47
+ exit(0)
48
+ end
49
+ if task.is_a?(Task)
50
+ task.execute()
51
+ end
52
+ if task.is_a?(Store)
53
+ @storage[task.key] = task.val
54
+ end
55
+ end
56
+ end
57
+
58
+ def TaskMaster.init()
59
+ if (MPI::Comm::WORLD.rank() == 0)
60
+ TaskMaster.doMasterInit()
61
+ else
62
+ TaskMaster.doSlaveLoop()
63
+ end
64
+ end
65
+
66
+ def TaskMaster.getFreeSlave()
67
+ waitForSlave() if @free.size == 0
68
+ nextSlave = @free.shift
69
+ nextSlave
70
+ end
71
+
72
+ def TaskMaster.waitForReply()
73
+ TaskMaster.waitForSlave()
74
+ end
75
+
76
+ def TaskMaster.reply(task, result)
77
+ MPI::Comm::WORLD.send([task.tid, result], 0, 0)
78
+ end
79
+
80
+ def TaskMaster.handleReply(reply, status)
81
+ tid,obj = reply
82
+ if @cbs[tid]
83
+ @cbs[tid].call(obj, @tasks[tid], status.source)
84
+ @cbs[tid] = nil
85
+ end
86
+ @tasks[tid] = nil
87
+ @free << status.source
88
+ end
89
+
90
+ def TaskMaster.waitForSlave()
91
+ reply, status = MPI::Comm::WORLD.recv(MPI::Comm::ANY_SOURCE, 0)
92
+ TaskMaster.handleReply(reply,status)
93
+ end
94
+
95
+ def TaskMaster.storeEverywhere(key, val)
96
+ @slaves.each { |n|
97
+ MPI::Comm::WORLD.send(Store.new(key,val), n, 0)
98
+ }
99
+ end
100
+
101
+ def TaskMaster.enqueue(t, &cb)
102
+ @maxTid += 1
103
+ t.setTid(@maxTid)
104
+ @cbs[t.tid] = cb
105
+ @tasks[t.tid] = t
106
+ nextFreeSlave = TaskMaster.getFreeSlave
107
+ m = Marshal.dump(t)
108
+ MPI::Comm::WORLD.send(t, nextFreeSlave, 0)
109
+ end
110
+
111
+ end
112
+
@@ -0,0 +1,39 @@
1
+
2
+ class TaskMaster
3
+
4
+ @lastReply = nil
5
+ @storage = { }
6
+
7
+ def TaskMaster.reply(t,reply)
8
+ @lastReply = reply
9
+ end
10
+
11
+ def TaskMaster.storeEverywhere(key, val)
12
+ @storage[key.clone] = val.clone
13
+ end
14
+
15
+ def TaskMaster.fetch(key)
16
+ @storage[key]
17
+ end
18
+
19
+ def TaskMaster.doMasterInit()
20
+ end
21
+
22
+ def TaskMaster.init()
23
+ end
24
+
25
+ def TaskMaster.waitForReply()
26
+ TaskMaster.waitForSlave()
27
+ end
28
+ def TaskMaster.waitForSlave()
29
+ end
30
+
31
+ def TaskMaster.handleReply(reply, status)
32
+ end
33
+
34
+ def TaskMaster.enqueue(t, &cb)
35
+ t.execute()
36
+ cb.call(@lastReply, t, 0)
37
+ end
38
+ end
39
+
@@ -0,0 +1,300 @@
1
+ require 'CompLearnLib/Task'
2
+ require 'CompLearnLib/RunEnv.rb'
3
+ require 'CompLearnLib/CLConfig.rb'
4
+ include MRunEnv
5
+ include MTask
6
+
7
+ module MTree
8
+
9
+ class TreeTask < Task
10
+ def initialize(tree, tries, penalty)
11
+ @tree, @tries, @penalty = tree, tries, penalty
12
+ end
13
+ def execute()
14
+ dm = fetch('dm')
15
+ ts = TreeScore.makeFullList(dm)
16
+ ts.penalty = @penalty
17
+ best, bestscore = nil, nil
18
+ @tries.times {
19
+ maybe = @tree.clone
20
+ maybe.mutateComplex
21
+ score = ts.score(maybe)
22
+ if (best == nil || bestscore < score)
23
+ best = maybe
24
+ bestscore = score
25
+ end
26
+ }
27
+ reply([best, bestscore])
28
+ end
29
+ end
30
+
31
+ class Tree
32
+ # consists of 2n - 2 nodes: n species followed by n-2 kernel nodes
33
+ attr_reader :edges
34
+ def initialize()
35
+ @edges = [ ]
36
+ @spm = nil
37
+ end
38
+ def clone()
39
+ t = Tree.new
40
+ t.copyEdges(self)
41
+ t
42
+ end
43
+ def <=>(other)
44
+ res = @edges.size - other.edges.size
45
+ return res unless res == 0
46
+ @edges.each_index { |i|
47
+ res = @edges[i].size - other.edges[i].size
48
+ return res unless res == 0
49
+ @edges[i].each_index { |j|
50
+ res = @edges[i][j] - other.edges[i][j]
51
+ return res unless res == 0
52
+ }
53
+ }
54
+ 0
55
+ end
56
+ def copyEdges(t)
57
+ @edges = [ ]
58
+ t.edges.each_index { |i|
59
+ @edges[i] = t.edges[i].clone
60
+ }
61
+ @spm = nil
62
+ end
63
+ def makeName(i, names)
64
+ if (i < names.size)
65
+ return names[i].gsub(/[.].*/,'')
66
+ else
67
+ return CLConfig.getDefaultConfig.internalNodePrefix() + (i - names.size).to_s
68
+ end
69
+ end
70
+ def toDotString(names, title, desc)
71
+ result = "/* #{desc} */\ngraph #{title} {\n"
72
+ @edges.each_index { |i|
73
+ @edges[i].each { |j|
74
+ result += "#{makeName(i,names)} -- #{makeName(j,names)}\n"
75
+ }
76
+ }
77
+ result += "}\n"
78
+ result
79
+ end
80
+ def to_s()
81
+ result = ""
82
+ @edges.each_index { |i|
83
+ result += "#{i}->"+@edges[i].join(",")+"\n"
84
+ }
85
+ result
86
+ end
87
+ def Tree.randomTree(species)
88
+ raise "Not enough species" unless (species >= 3)
89
+ result = Tree.new
90
+ k = species - 2
91
+ nodes = species+k
92
+ (k-1).times { |i|
93
+ n = nil
94
+ begin
95
+ n = RunEnv.zrand(i+1) + species
96
+ end until result.getNeighborCount(n) <= 2
97
+ result.connect(i+species+1,n)
98
+ }
99
+ species.times { |i|
100
+ n = nil
101
+ begin
102
+ n = RunEnv.zrand(k) + species
103
+ end until result.getNeighborCount(n) <= 2
104
+ result.connect(i,n)
105
+ }
106
+ result
107
+ end
108
+ def calculateSPMFor(n)
109
+ @spm[n] = [ ]
110
+ curspm = @spm[n]
111
+ curspm[n] = n
112
+ visitted = { }
113
+ border = { n => true }
114
+ begin
115
+ border.each_key { |z|
116
+ visitted[z] = true
117
+ border.delete(z)
118
+ getNeighbors(z).each { |m|
119
+ unless visitted[m]
120
+ border[m] = true
121
+ curspm[m] = z
122
+ end
123
+ }
124
+ }
125
+ end until visitted.size == @edges.size
126
+ end
127
+ def calculateSPM()
128
+ @spm = [ ]
129
+ @edges.each_index { |n| calculateSPMFor(n) }
130
+ end
131
+ def findPath(a,b)
132
+ calculateSPM() unless @spm
133
+ path = [ ]
134
+ curspm = @spm[b]
135
+ cur = a
136
+ while (cur != b)
137
+ path << cur
138
+ cur = curspm[cur]
139
+ end
140
+ path << cur
141
+ path
142
+ end
143
+ def getNodeCount()
144
+ @edges.size
145
+ end
146
+ def getSpeciesCount()
147
+ (getNodeCount()+2) / 2
148
+ end
149
+ def getKernelCount()
150
+ getSpeciesCount() - 2
151
+ end
152
+ def isSpecies?(node)
153
+ getNeighborCount(node) == 1
154
+ end
155
+ def isKernel?(node)
156
+ getNeighborCount(node) == 3
157
+ end
158
+ def getNeighbors(node)
159
+ @edges[node]
160
+ end
161
+ def randomNeighbor(node)
162
+ @edges[node][RunEnv.zrand(@edges[node].size)]
163
+ end
164
+ def getNeighborCount(node)
165
+ return 0 unless @edges[node]
166
+ @edges[node].size
167
+ end
168
+ def connected?(a,b)
169
+ @edges[a] && @edges[a].include?(b)
170
+ end
171
+ def disconnect(a,b)
172
+ @edges[a].delete(b)
173
+ @edges[b].delete(a)
174
+ @edges[a] = nil if @edges[a].size == 0
175
+ @edges[b] = nil if @edges[b].size == 0
176
+ @spm = nil
177
+ end
178
+ def connect(a,b)
179
+ @edges[a] = [ ] unless @edges[a]
180
+ @edges[b] = [ ] unless @edges[b]
181
+ @edges[a] << b
182
+ @edges[b] << a
183
+ @edges[a].sort!
184
+ @edges[b].sort!
185
+ @spm = nil
186
+ end
187
+ def randomSpeciesNode()
188
+ n = nil
189
+ begin
190
+ n = randomNode()
191
+ end until isSpecies?(n)
192
+ n
193
+ end
194
+ def randomSpeciesNodes(count)
195
+ raise "Not enough species nodes" unless getSpeciesCount() >= count
196
+ res = { }
197
+ begin
198
+ res[randomSpeciesNode()] = true
199
+ end until res.size == count
200
+ res.keys
201
+ end
202
+ def randomNode()
203
+ RunEnv.zrand(getNodeCount())
204
+ end
205
+ def randomNodes(count)
206
+ raise "Not enough nodes" unless getNodeCount() >= count
207
+ res = { }
208
+ begin
209
+ res[randomNode()] = true
210
+ end until res.size == count
211
+ res.keys
212
+ end
213
+ def randomKernelNodes(count)
214
+ raise "Not enough kernel nodes" unless getKernelCount() >= count
215
+ res = { }
216
+ begin
217
+ res[randomKernelNode()] = true
218
+ end until res.size == count
219
+ res.keys
220
+ end
221
+ def mutateSpecies()
222
+ begin
223
+ a,b = randomSpeciesNodes(2)
224
+ na,nb = getNeighbors(a)[0],getNeighbors(b)[0]
225
+ end until na != nb
226
+ disconnect(a,na)
227
+ disconnect(b,nb)
228
+ connect(a,nb)
229
+ connect(b,na)
230
+ end
231
+
232
+ def mutateSubtreeInterchange()
233
+ p = nil
234
+ begin
235
+ a,b = randomKernelNodes(2)
236
+ p = findPath(a,b)
237
+ end until (p.size > 3)
238
+ na,nb = p[1],p[-2]
239
+ disconnect(a,na)
240
+ disconnect(b,nb)
241
+ connect(a,nb)
242
+ connect(b,na)
243
+ end
244
+
245
+ def mutateSubtreeTransfer()
246
+ begin
247
+ k1, k2 = randomNode, randomKernelNode()
248
+ p = findPath(k1,k2)
249
+ end until p.size > 2
250
+ i1 = p[1]
251
+ disconnect(k1,i1)
252
+ ms = getNeighbors(i1)
253
+ m1,m2,m3 = ms[0],ms[1],nil
254
+ begin
255
+ m3 = randomNeighbor(k2)
256
+ end until m3 != p[-2]
257
+ [[m1,i1], [m2,i1], [m3,k2]].each { |a| disconnect(a[0],a[1]) }
258
+ [[m1,m2], [k2,i1], [m3,i1], [k1,i1]].each { |a| connect(a[0],a[1]) }
259
+ end
260
+
261
+ def randomKernelNode()
262
+ n = nil
263
+ begin
264
+ n = randomNode()
265
+ end until isKernel?(n)
266
+ n
267
+ end
268
+
269
+ def mutateRandom()
270
+ begin
271
+ c = RunEnv.zrand(3)
272
+ end while c == 1 && getNodeCount <= 10
273
+ case c
274
+ when 0 then mutateSpecies
275
+ when 1 then mutateSubtreeInterchange
276
+ when 2 then mutateSubtreeTransfer
277
+ end
278
+ end
279
+
280
+ def mutateComplex()
281
+ orig = clone()
282
+ begin
283
+ mutateRandom
284
+ end while RunEnv.zrand(0) < 0.5 || (orig <=> self) == 0
285
+ end
286
+
287
+ def verifyTree()
288
+ oldNeighborCount = 0
289
+ @edges.each_index { |i|
290
+ s = @edges[i].size
291
+ return false if s != 1 && s != 3
292
+ oldNeighborCount = s if (s > oldNeighborCount)
293
+ return false if s < oldNeighborCount
294
+ }
295
+ return true
296
+ end
297
+ private :calculateSPM, :calculateSPMFor
298
+ end
299
+
300
+ end