distance_test.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. package gago
  2. import (
  3. "errors"
  4. "testing"
  5. )
  6. func TestDistanceMemoizer(t *testing.T) {
  7. var (
  8. dm = newDistanceMemoizer(l1Distance)
  9. a = Individual{Genome: Vector{1, 1, 1}, ID: "1"}
  10. b = Individual{Genome: Vector{3, 3, 3}, ID: "2"}
  11. c = Individual{Genome: Vector{6, 6, 6}, ID: "3"}
  12. )
  13. // Check the number of calculations is initially 0
  14. if dm.nCalculations != 0 {
  15. t.Error("nCalculations is not initialized to 0")
  16. }
  17. // Check the distance between the 1st and itself
  18. if dm.GetDistance(a, a) != 0 {
  19. t.Error("Wrong calculated distance")
  20. }
  21. // Check the number of calculations is initially 0
  22. if dm.nCalculations != 0 {
  23. t.Error("nCalculations should not have increased")
  24. }
  25. // Check the distance between the 1st and the 2nd individual
  26. if dm.GetDistance(a, b) != 6 {
  27. t.Error("Wrong calculated distance")
  28. }
  29. // Check the number of calculations has increased by 1
  30. if dm.nCalculations != 1 {
  31. t.Error("nCalculations has not increased")
  32. }
  33. // Check the distance between the 2nd and the 1st individual
  34. if dm.GetDistance(b, a) != 6 {
  35. t.Error("Wrong calculated distance")
  36. }
  37. // Check the number of calculations has not increased
  38. if dm.nCalculations != 1 {
  39. t.Error("nCalculations has increased")
  40. }
  41. // Check the distance between the 1st and the 3rd individual
  42. if dm.GetDistance(a, c) != 15 {
  43. t.Error("Wrong calculated distance")
  44. }
  45. // Check the distance between the 1st and the 3rd individual
  46. if dm.GetDistance(b, c) != 9 {
  47. t.Error("Wrong calculated distance")
  48. }
  49. }
  50. func TestSortByDistanceToMedoid(t *testing.T) {
  51. var (
  52. indis = Individuals{
  53. Individual{Genome: Vector{3, 3, 3}, Fitness: 0},
  54. Individual{Genome: Vector{2, 2, 2}, Fitness: 1},
  55. Individual{Genome: Vector{5, 5, 5}, Fitness: 2},
  56. }
  57. dm = newDistanceMemoizer(l1Distance)
  58. )
  59. indis.SortByDistanceToMedoid(dm)
  60. for i := range indis {
  61. if indis[i].Fitness != float64(i) {
  62. t.Error("Individuals were not sorted according to their distance to the medoid")
  63. }
  64. }
  65. }
  66. func TestRebalanceClusters(t *testing.T) {
  67. var testCases = []struct {
  68. clusters []Individuals
  69. dm DistanceMemoizer
  70. minClusterSize int
  71. newClusterSizes []int
  72. err error
  73. }{
  74. {
  75. clusters: []Individuals{
  76. Individuals{
  77. Individual{Genome: Vector{1, 1, 1}, ID: "1"},
  78. Individual{Genome: Vector{1, 1, 1}, ID: "2"},
  79. Individual{Genome: Vector{1, 1, 1}, ID: "3"},
  80. Individual{Genome: Vector{2, 2, 2}, ID: "4"}, // Second furthest away from the cluster
  81. Individual{Genome: Vector{3, 3, 3}, ID: "5"}, // Furthest away from the cluster
  82. },
  83. Individuals{
  84. Individual{Genome: Vector{2, 2, 2}, ID: "6"},
  85. },
  86. Individuals{
  87. Individual{Genome: Vector{3, 3, 3}, ID: "7"},
  88. },
  89. },
  90. dm: newDistanceMemoizer(l1Distance),
  91. minClusterSize: 2,
  92. newClusterSizes: []int{3, 2, 2},
  93. err: nil,
  94. },
  95. {
  96. clusters: []Individuals{
  97. Individuals{
  98. Individual{Genome: Vector{1, 1, 1}, ID: "1"},
  99. Individual{Genome: Vector{1, 1, 1}, ID: "2"},
  100. },
  101. Individuals{},
  102. },
  103. dm: newDistanceMemoizer(l1Distance),
  104. minClusterSize: 1,
  105. newClusterSizes: []int{2, 0},
  106. err: errors.New("Cluster number 2 is empty"),
  107. },
  108. {
  109. clusters: []Individuals{
  110. Individuals{
  111. Individual{Genome: Vector{1, 1, 1}, ID: "1"},
  112. Individual{Genome: Vector{1, 1, 1}, ID: "2"},
  113. },
  114. Individuals{
  115. Individual{Genome: Vector{1, 1, 1}, ID: "3"},
  116. },
  117. },
  118. dm: newDistanceMemoizer(l1Distance),
  119. minClusterSize: 2,
  120. newClusterSizes: []int{2, 0},
  121. err: errors.New("Not enough individuals to rebalance"),
  122. },
  123. }
  124. for i, tc := range testCases {
  125. var err = rebalanceClusters(tc.clusters, tc.dm, tc.minClusterSize)
  126. // Check if the error is nil or not
  127. if (err == nil) != (tc.err == nil) {
  128. t.Errorf("Wrong error in test case number %d", i)
  129. }
  130. // Check new cluster sizes
  131. if err == nil {
  132. for j, cluster := range tc.clusters {
  133. if len(cluster) != tc.newClusterSizes[j] {
  134. t.Errorf("Wrong new cluster size in test case number %d", i)
  135. }
  136. }
  137. }
  138. }
  139. }
  140. // If a cluster is empty then rebalancing is impossible
  141. func TestRebalanceClustersEmptyCluster(t *testing.T) {
  142. var (
  143. clusters = []Individuals{
  144. Individuals{
  145. Individual{Genome: Vector{1, 1, 1}, ID: "1"},
  146. Individual{Genome: Vector{1, 1, 1}, ID: "2"},
  147. Individual{Genome: Vector{1, 1, 1}, ID: "3"},
  148. },
  149. Individuals{},
  150. }
  151. dm = newDistanceMemoizer(l1Distance)
  152. )
  153. var err = rebalanceClusters(clusters, dm, 2)
  154. if err == nil {
  155. t.Error("rebalanceClusters should have returned an error")
  156. }
  157. }
  158. // It's impossible to put 2 Individuals inside each cluster if there are 3
  159. // clusters and 5 individuals in total
  160. func TestRebalanceClustersTooManyMissing(t *testing.T) {
  161. var (
  162. clusters = []Individuals{
  163. Individuals{
  164. Individual{Genome: Vector{1, 1, 1}, ID: "1"},
  165. Individual{Genome: Vector{1, 1, 1}, ID: "2"},
  166. Individual{Genome: Vector{1, 1, 1}, ID: "3"},
  167. },
  168. Individuals{
  169. Individual{Genome: Vector{2, 2, 2}, ID: "6"},
  170. },
  171. Individuals{
  172. Individual{Genome: Vector{3, 3, 3}, ID: "7"},
  173. },
  174. }
  175. dm = newDistanceMemoizer(l1Distance)
  176. )
  177. var err = rebalanceClusters(clusters, dm, 2)
  178. if err == nil {
  179. t.Error("rebalanceClusters should have returned an error")
  180. }
  181. }