ga_test.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. package gago
  2. import (
  3. "errors"
  4. "math"
  5. "testing"
  6. "time"
  7. )
  8. func TestValidationSuccess(t *testing.T) {
  9. var err = ga.Validate()
  10. if err != nil {
  11. t.Error("GA parameters are invalid")
  12. }
  13. }
  14. func TestValidationGenomeFactory(t *testing.T) {
  15. var genomeFactory = ga.GenomeFactory
  16. ga.GenomeFactory = nil
  17. if ga.Validate() == nil {
  18. t.Error("Nil GenomeFactory should return an error")
  19. }
  20. ga.GenomeFactory = genomeFactory
  21. }
  22. func TestValidationNPopulations(t *testing.T) {
  23. var nPops = ga.NPops
  24. ga.NPops = -1
  25. if ga.Validate() == nil {
  26. t.Error("Invalid number of Populations should return an error")
  27. }
  28. ga.NPops = nPops
  29. }
  30. func TestValidationNIndividuals(t *testing.T) {
  31. var popSize = ga.PopSize
  32. ga.PopSize = -1
  33. if ga.Validate() == nil {
  34. t.Error("Invalid number of Individuals should return an error")
  35. }
  36. ga.PopSize = popSize
  37. }
  38. func TestValidationModel(t *testing.T) {
  39. var model = ga.Model
  40. // Check nil model raises error
  41. ga.Model = nil
  42. if ga.Validate() == nil {
  43. t.Error("Nil Model should return an error")
  44. }
  45. // Check invalid model raises error
  46. ga.Model = ModGenerational{
  47. Selector: SelTournament{
  48. NContestants: 3,
  49. },
  50. MutRate: -1,
  51. }
  52. if ga.Validate() == nil {
  53. t.Error("Invalid Model should return an error")
  54. }
  55. ga.Model = model
  56. }
  57. func TestValidationMigFrequency(t *testing.T) {
  58. var (
  59. migrator = ga.Migrator
  60. migFrequency = ga.MigFrequency
  61. )
  62. ga.Migrator = MigRing{}
  63. ga.MigFrequency = 0
  64. if ga.Validate() == nil {
  65. t.Error("Invalid MigFrequency should return an error")
  66. }
  67. ga.Migrator = migrator
  68. ga.MigFrequency = migFrequency
  69. }
  70. func TestValidationSpeciator(t *testing.T) {
  71. var speciator = ga.Speciator
  72. ga.Speciator = SpecFitnessInterval{0}
  73. if ga.Validate() == nil {
  74. t.Error("Invalid Speciator should return an error")
  75. }
  76. ga.Speciator = speciator
  77. }
  78. func TestApplyWithSpeciator(t *testing.T) {
  79. var speciator = ga.Speciator
  80. ga.Speciator = SpecFitnessInterval{4}
  81. if ga.Enhance() != nil {
  82. t.Error("Calling Apply with a valid Speciator should not return an error")
  83. }
  84. ga.Speciator = speciator
  85. }
  86. func TestRandomNumberGenerators(t *testing.T) {
  87. for i, pop1 := range ga.Populations {
  88. for j, pop2 := range ga.Populations {
  89. if i != j && &pop1.rng == &pop2.rng {
  90. t.Error("Population should not share random number generators")
  91. }
  92. }
  93. }
  94. }
  95. func TestBest(t *testing.T) {
  96. for _, pop := range ga.Populations {
  97. for _, indi := range pop.Individuals {
  98. if ga.Best.Fitness > indi.Fitness {
  99. t.Error("The current best individual is not the overall best")
  100. }
  101. }
  102. }
  103. }
  104. func TestFindBest(t *testing.T) {
  105. // Check sure the findBest method works as expected
  106. var fitness = ga.Populations[0].Individuals[0].Fitness
  107. ga.Populations[0].Individuals[0].Fitness = math.Inf(-1)
  108. ga.findBest()
  109. if ga.Best.Fitness != math.Inf(-1) {
  110. t.Error("findBest didn't work")
  111. }
  112. ga.Populations[0].Individuals[0].Fitness = fitness
  113. // Check the best individual doesn't a share a pointer with anyone
  114. fitness = ga.Best.Fitness
  115. ga.Best.Fitness = 42
  116. if ga.Populations[0].Individuals[0].Fitness == 42 {
  117. t.Error("Best individual shares a pointer with an individual in the populations")
  118. }
  119. ga.Best.Fitness = fitness
  120. }
  121. // TestDuration verifies the sum of the duration of each population is higher
  122. // the actual duration. This is due to the fact that each population runs on a
  123. // separate core.
  124. func TestDuration(t *testing.T) {
  125. var totalDuration time.Duration
  126. for _, pop := range ga.Populations {
  127. totalDuration += pop.Age
  128. }
  129. if totalDuration < ga.Age {
  130. t.Error("Inefficient parallelism")
  131. }
  132. }
  133. func TestSpeciateEvolveMerge(t *testing.T) {
  134. var (
  135. rng = newRandomNumberGenerator()
  136. testCases = []struct {
  137. pop Population
  138. speciator Speciator
  139. model Model
  140. err error
  141. }{
  142. {
  143. pop: Population{
  144. ID: "42",
  145. rng: rng,
  146. Individuals: Individuals{
  147. Individual{Fitness: 0},
  148. Individual{Fitness: 1},
  149. Individual{Fitness: 2},
  150. Individual{Fitness: 3},
  151. Individual{Fitness: 4},
  152. },
  153. },
  154. speciator: SpecFitnessInterval{3},
  155. model: ModIdentity{},
  156. err: nil,
  157. },
  158. {
  159. pop: Population{
  160. ID: "42",
  161. rng: rng,
  162. Individuals: Individuals{
  163. Individual{Fitness: 0},
  164. Individual{Fitness: 1},
  165. Individual{Fitness: 2},
  166. },
  167. },
  168. speciator: SpecFitnessInterval{4},
  169. model: ModIdentity{},
  170. err: errors.New("Invalid speciator"),
  171. },
  172. {
  173. pop: Population{
  174. ID: "42",
  175. rng: rng,
  176. Individuals: Individuals{
  177. Individual{Fitness: 0},
  178. Individual{Fitness: 1},
  179. Individual{Fitness: 2},
  180. Individual{Fitness: 3},
  181. Individual{Fitness: 4},
  182. },
  183. },
  184. speciator: SpecFitnessInterval{3},
  185. model: ModGenerational{
  186. Selector: SelTournament{6},
  187. MutRate: 0.5,
  188. },
  189. err: errors.New("Invalid model"),
  190. },
  191. }
  192. )
  193. for i, tc := range testCases {
  194. var err = tc.pop.speciateEvolveMerge(tc.speciator, tc.model)
  195. if (err == nil) != (tc.err == nil) {
  196. t.Errorf("Wrong error in test case number %d", i)
  197. }
  198. // If there is no error check the individuals are ordered as they were
  199. // at they were initially
  200. if err == nil {
  201. for j, indi := range tc.pop.Individuals {
  202. if indi.Fitness != float64(j) {
  203. t.Errorf("Wrong result in test case number %d", i)
  204. }
  205. }
  206. }
  207. }
  208. }
  209. func TestCallback(t *testing.T) {
  210. var (
  211. counter int
  212. incrementCounter = func(ga *GA) {
  213. counter++
  214. }
  215. )
  216. ga.Callback = incrementCounter
  217. ga.Initialize()
  218. if counter != 1 {
  219. t.Error("Counter was not incremented by the callback at initialization")
  220. }
  221. ga.Enhance()
  222. if counter != 2 {
  223. t.Error("Counter was not incremented by the callback at enhancement")
  224. }
  225. }