crossover.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. package gago
  2. import (
  3. "math/rand"
  4. "sort"
  5. )
  6. // Type specific mutations for slices
  7. // CrossUniformFloat64 crossover combines two individuals (the parents) into one
  8. // (the offspring). Each parent's contribution to the Genome is determined by
  9. // the value of a probability p. Each offspring receives a proportion of both of
  10. // it's parents genomes. The new values are located in the hyper-rectangle
  11. // defined between both parent's position in Cartesian space.
  12. func CrossUniformFloat64(p1 []float64, p2 []float64, rng *rand.Rand) (o1 []float64, o2 []float64) {
  13. var gSize = len(p1)
  14. o1 = make([]float64, gSize)
  15. o2 = make([]float64, gSize)
  16. // For every gene pick a random number between 0 and 1
  17. for i := 0; i < gSize; i++ {
  18. var p = rng.Float64()
  19. o1[i] = p*p1[i] + (1-p)*p2[i]
  20. o2[i] = (1-p)*p1[i] + p*p2[i]
  21. }
  22. return o1, o2
  23. }
  24. // Generic mutations for slices
  25. // Contains the deterministic part of the GNX method for testing purposes.
  26. func gnx(p1, p2 Slice, indexes []int) (Slice, Slice) {
  27. var (
  28. n = p1.Len()
  29. o1 = p1.Copy()
  30. o2 = p2.Copy()
  31. toggle = true
  32. )
  33. // Add the first and last indexes
  34. indexes = append([]int{0}, indexes...)
  35. indexes = append(indexes, n)
  36. for i := 0; i < len(indexes)-1; i++ {
  37. if toggle {
  38. o1.Slice(indexes[i], indexes[i+1]).Replace(p1.Slice(indexes[i], indexes[i+1]))
  39. o2.Slice(indexes[i], indexes[i+1]).Replace(p2.Slice(indexes[i], indexes[i+1]))
  40. } else {
  41. o1.Slice(indexes[i], indexes[i+1]).Replace(p2.Slice(indexes[i], indexes[i+1]))
  42. o2.Slice(indexes[i], indexes[i+1]).Replace(p1.Slice(indexes[i], indexes[i+1]))
  43. }
  44. toggle = !toggle // Alternate for the new copying
  45. }
  46. return o1, o2
  47. }
  48. // CrossGNX (Generalized N-point Crossover). An identical point is chosen on
  49. // each parent's genome and the mirroring segments are switched. n determines
  50. // the number of crossovers (aka mirroring segments) to perform. n has to be
  51. // equal or lower than the number of genes in each parent.
  52. func CrossGNX(p1 Slice, p2 Slice, n int, rng *rand.Rand) (o1 Slice, o2 Slice) {
  53. var indexes = randomInts(n, 1, p1.Len(), rng)
  54. sort.Ints(indexes)
  55. return gnx(p1, p2, indexes)
  56. }
  57. // CrossGNXInt calls CrossGNX on two int slices.
  58. func CrossGNXInt(s1 []int, s2 []int, n int, rng *rand.Rand) ([]int, []int) {
  59. var o1, o2 = CrossGNX(IntSlice(s1), IntSlice(s2), n, rng)
  60. return o1.(IntSlice), o2.(IntSlice)
  61. }
  62. // CrossGNXFloat64 calls CrossGNX on two float64 slices.
  63. func CrossGNXFloat64(s1 []float64, s2 []float64, n int, rng *rand.Rand) ([]float64, []float64) {
  64. var o1, o2 = CrossGNX(Float64Slice(s1), Float64Slice(s2), n, rng)
  65. return o1.(Float64Slice), o2.(Float64Slice)
  66. }
  67. // CrossGNXString calls CrossGNX on two string slices.
  68. func CrossGNXString(s1 []string, s2 []string, n int, rng *rand.Rand) ([]string, []string) {
  69. var o1, o2 = CrossGNX(StringSlice(s1), StringSlice(s2), n, rng)
  70. return o1.(StringSlice), o2.(StringSlice)
  71. }
  72. // Contains the deterministic part of the PMX method for testing purposes.
  73. func pmx(p1, p2 Slice, a, b int) (Slice, Slice) {
  74. var (
  75. n = p1.Len()
  76. o1 = p1.Copy()
  77. o2 = p2.Copy()
  78. )
  79. // Create lookup maps to quickly see if a gene has been visited
  80. var (
  81. p1Visited, p2Visited = make(set), make(set)
  82. o1Visited, o2Visited = make(set), make(set)
  83. )
  84. for i := a; i < b; i++ {
  85. p1Visited[p1.At(i)] = true
  86. p2Visited[p2.At(i)] = true
  87. o1Visited[i] = true
  88. o2Visited[i] = true
  89. }
  90. for i := a; i < b; i++ {
  91. // Find the element in the second parent that has not been copied in the first offspring
  92. if !p1Visited[p2.At(i)] {
  93. var j = i
  94. for o1Visited[j] {
  95. j, _ = search(o1.At(j), p2)
  96. }
  97. o1.Set(j, p2.At(i))
  98. o1Visited[j] = true
  99. }
  100. // Find the element in the first parent that has not been copied in the second offspring
  101. if !p2Visited[p1.At(i)] {
  102. var j = i
  103. for o2Visited[j] {
  104. j, _ = search(o2.At(j), p1)
  105. }
  106. o2.Set(j, p1.At(i))
  107. o2Visited[j] = true
  108. }
  109. }
  110. // Fill in the offspring's missing values with the opposite parent's values
  111. for i := 0; i < n; i++ {
  112. if !o1Visited[i] {
  113. o1.Set(i, p2.At(i))
  114. }
  115. if !o2Visited[i] {
  116. o2.Set(i, p1.At(i))
  117. }
  118. }
  119. return o1, o2
  120. }
  121. // CrossPMX (Partially Mapped Crossover). The offsprings are generated by
  122. // copying one of the parents and then copying the other parent's values up to a
  123. // randomly chosen crossover point. Each gene that is replaced is permuted with
  124. // the gene that is copied in the first parent's genome. Two offsprings are
  125. // generated in such a way (because there are two parents). The PMX method
  126. // preserves gene uniqueness.
  127. func CrossPMX(p1 Slice, p2 Slice, rng *rand.Rand) (o1 Slice, o2 Slice) {
  128. var indexes = randomInts(2, 0, p1.Len(), rng)
  129. sort.Ints(indexes)
  130. return pmx(p1, p2, indexes[0], indexes[1])
  131. }
  132. // CrossPMXInt calls CrossPMX on an int slice.
  133. func CrossPMXInt(s1 []int, s2 []int, rng *rand.Rand) ([]int, []int) {
  134. var o1, o2 = CrossPMX(IntSlice(s1), IntSlice(s2), rng)
  135. return o1.(IntSlice), o2.(IntSlice)
  136. }
  137. // CrossPMXFloat64 calls CrossPMX on a float64 slice.
  138. func CrossPMXFloat64(s1 []float64, s2 []float64, rng *rand.Rand) ([]float64, []float64) {
  139. var o1, o2 = CrossPMX(Float64Slice(s1), Float64Slice(s2), rng)
  140. return o1.(Float64Slice), o2.(Float64Slice)
  141. }
  142. // CrossPMXString calls CrossPMX on a string slice.
  143. func CrossPMXString(s1 []string, s2 []string, rng *rand.Rand) ([]string, []string) {
  144. var o1, o2 = CrossPMX(StringSlice(s1), StringSlice(s2), rng)
  145. return o1.(StringSlice), o2.(StringSlice)
  146. }
  147. // Contains the deterministic part of the OX method for testing purposes.
  148. func ox(p1, p2 Slice, a, b int) (Slice, Slice) {
  149. var (
  150. n = p1.Len()
  151. o1 = p1.Copy()
  152. o2 = p2.Copy()
  153. )
  154. // Create lookup maps to quickly see if a gene has been copied from a parent or not
  155. var p1Visited, p2Visited = make(set), make(set)
  156. for i := a; i < b; i++ {
  157. p1Visited[p1.At(i)] = true
  158. p2Visited[p2.At(i)] = true
  159. }
  160. // Keep two indicators to know where to fill the offsprings
  161. var j1, j2 = b, b
  162. for i := b; i < b+n; i++ {
  163. var k = i % n
  164. if !p1Visited[p2.At(k)] {
  165. o1.Set(j1%n, p2.At(k))
  166. j1++
  167. }
  168. if !p2Visited[p1.At(k)] {
  169. o2.Set(j2%n, p1.At(k))
  170. j2++
  171. }
  172. }
  173. return o1, o2
  174. }
  175. // CrossOX (Ordered Crossover). Part of the first parent's genome is copied onto
  176. // the first offspring's genome. Then the second parent's genome is iterated
  177. // over, starting on the right of the part that was copied. Each gene of the
  178. // second parent's genome is copied onto the next blank gene of the first
  179. // offspring's genome if it wasn't already copied from the first parent. The OX
  180. // method preserves gene uniqueness.
  181. func CrossOX(p1 Slice, p2 Slice, rng *rand.Rand) (o1 Slice, o2 Slice) {
  182. var indexes = randomInts(2, 0, p1.Len(), rng)
  183. sort.Ints(indexes)
  184. return ox(p1, p2, indexes[0], indexes[1])
  185. }
  186. // CrossOXInt calls CrossOX on a int slice.
  187. func CrossOXInt(s1 []int, s2 []int, rng *rand.Rand) ([]int, []int) {
  188. var o1, o2 = CrossOX(IntSlice(s1), IntSlice(s2), rng)
  189. return o1.(IntSlice), o2.(IntSlice)
  190. }
  191. // CrossOXFloat64 calls CrossOX on a float64 slice.
  192. func CrossOXFloat64(s1 []float64, s2 []float64, rng *rand.Rand) ([]float64, []float64) {
  193. var o1, o2 = CrossOX(Float64Slice(s1), Float64Slice(s2), rng)
  194. return o1.(Float64Slice), o2.(Float64Slice)
  195. }
  196. // CrossOXString calls CrossOX on a string slice.
  197. func CrossOXString(s1 []string, s2 []string, rng *rand.Rand) ([]string, []string) {
  198. var o1, o2 = CrossOX(StringSlice(s1), StringSlice(s2), rng)
  199. return o1.(StringSlice), o2.(StringSlice)
  200. }
  201. // CrossCX (Cycle Crossover). Cycles between the parents are indentified, they
  202. // are then copied alternatively onto the offsprings. The CX method is
  203. // deterministic and preserves gene uniqueness.
  204. func CrossCX(p1, p2 Slice) (Slice, Slice) {
  205. var (
  206. o1 = p1.Copy()
  207. o2 = p2.Copy()
  208. cycles = getCycles(p1, p2)
  209. toggle = true
  210. )
  211. for i := 0; i < len(cycles); i++ {
  212. for _, j := range cycles[i] {
  213. if toggle {
  214. o1.Set(j, p1.At(j))
  215. o2.Set(j, p2.At(j))
  216. } else {
  217. o2.Set(j, p1.At(j))
  218. o1.Set(j, p2.At(j))
  219. }
  220. }
  221. toggle = !toggle
  222. }
  223. return o1, o2
  224. }
  225. // CrossCXInt calls CrossCX on an int slice.
  226. func CrossCXInt(s1 []int, s2 []int) ([]int, []int) {
  227. var o1, o2 = CrossCX(IntSlice(s1), IntSlice(s2))
  228. return o1.(IntSlice), o2.(IntSlice)
  229. }
  230. // CrossCXFloat64 calls CrossCX on a float64 slice.
  231. func CrossCXFloat64(s1 []float64, s2 []float64) ([]float64, []float64) {
  232. var o1, o2 = CrossCX(Float64Slice(s1), Float64Slice(s2))
  233. return o1.(Float64Slice), o2.(Float64Slice)
  234. }
  235. // CrossCXString calls CrossCX on a string slice.
  236. func CrossCXString(s1 []string, s2 []string) ([]string, []string) {
  237. var o1, o2 = CrossCX(StringSlice(s1), StringSlice(s2))
  238. return o1.(StringSlice), o2.(StringSlice)
  239. }
  240. // CrossERX (Edge Recombination Crossover).
  241. func CrossERX(p1, p2 Slice) (Slice, Slice) {
  242. var (
  243. n = p1.Len()
  244. o1 = p1.Copy()
  245. o2 = p2.Copy()
  246. parents = []Slice{p1, p2}
  247. offsprings = []Slice{o1, o2}
  248. p1Neighbours = getNeighbours(p1)
  249. p2Neighbours = getNeighbours(p2)
  250. pNeighbours = make(map[interface{}]set)
  251. )
  252. // Merge the neighbours of each parent whilst ignoring duplicates
  253. for i := range p1Neighbours {
  254. pNeighbours[i] = union(p1Neighbours[i], p2Neighbours[i])
  255. }
  256. // Hold two copies of the parent neighbours (one for each offspring)
  257. var neighbours = []map[interface{}]set{pNeighbours, nil}
  258. neighbours[1] = make(map[interface{}]set)
  259. for k, v := range pNeighbours {
  260. neighbours[1][k] = v
  261. }
  262. // The first element of each offspring to be the one of the corresponding parent
  263. o1.Set(0, p1.At(0))
  264. o2.Set(0, p2.At(0))
  265. // Delete the neighbour from the adjacency set
  266. for i := range neighbours {
  267. delete(neighbours[i], parents[i].At(0))
  268. for j := range neighbours[i] {
  269. if neighbours[i][j][parents[i].At(0)] {
  270. delete(neighbours[i][j], parents[i].At(0))
  271. }
  272. }
  273. }
  274. for o := range offsprings {
  275. for i := 1; i < n; i++ {
  276. // Find the gene with the least neighbours
  277. var (
  278. j interface{}
  279. min = 5 // There can't be more than 5 neighbours between 2 parents
  280. )
  281. for k, v := range neighbours[o] {
  282. if len(v) < min {
  283. j = k
  284. min = len(v)
  285. }
  286. }
  287. offsprings[o].Set(i, j)
  288. delete(neighbours[o], j)
  289. for k := range neighbours[o] {
  290. if neighbours[o][k][j] {
  291. delete(neighbours[o][k], j)
  292. }
  293. }
  294. }
  295. }
  296. return o1, o2
  297. }
  298. // CrossERXInt calls CrossERX on an int slice.
  299. func CrossERXInt(s1 []int, s2 []int) ([]int, []int) {
  300. var o1, o2 = CrossERX(IntSlice(s1), IntSlice(s2))
  301. return o1.(IntSlice), o2.(IntSlice)
  302. }
  303. // CrossERXFloat64 callsCrossERX on a float64 slice.
  304. func CrossERXFloat64(s1 []float64, s2 []float64) ([]float64, []float64) {
  305. var o1, o2 = CrossERX(Float64Slice(s1), Float64Slice(s2))
  306. return o1.(Float64Slice), o2.(Float64Slice)
  307. }
  308. // CrossERXString calls CrossERX on a string slice.
  309. func CrossERXString(s1 []string, s2 []string) ([]string, []string) {
  310. var o1, o2 = CrossERX(StringSlice(s1), StringSlice(s2))
  311. return o1.(StringSlice), o2.(StringSlice)
  312. }