예제 #1
0
파일: classic.go 프로젝트: NioTeX/neat
// Compares two genomes and returns their compatibility distance
//
// The number of excess and disjoint genes between a pair of genomes is a natural measure of their
// compatibility distance. The more disjoint two genomes are, the less evolutionary history they
// share, and thus the less compatible they are. Therefore, we can measure the compatibility distance δ
// of different structures in NEAT as a simple linear combination of the number of excess E and
// disjoint D genes, as well as the average weight differences of matching genes W, including disabled genes:
//     see formula in paper
// The coefficients c1, c2,and c3 allow us to adjust the importance of the three factors, and thefactor N,
// the number of genes in the larger genome, normalizes for genome size (N can be set to 1 if both genomes
// are small, i.e., consist of fewer than 20 genes (Stanley, 110)
func (c Classic) Compare(g1, g2 neat.Genome) (float64, error) {

	// Determine N
	n := 1.0
	if len(g1.Conns) > len(g2.Conns) && len(g1.Conns) >= 20 {
		n = float64(len(g1.Conns))
	} else if len(g2.Conns) >= 20 {
		n = float64(len(g2.Conns))
	}

	// Ensure connections are sorted
	_, conns1 := g1.GenesByInnovation()
	_, conns2 := g2.GenesByInnovation()

	// Calculate the components. This assumes both genomes' connections are sorted by their
	// innovation number (which is true if the NEAT library created them)
	var d, e, w, x float64
	i := 0
	j := 0
	for i < len(conns1) || j < len(conns2) {
		switch {
		case i == len(conns1):
			e += 1
			j += 1
		case j == len(conns2):
			e += 1
			i += 1
		default:
			c1 := conns1[i]
			c2 := conns2[j]
			switch {
			case c1.Innovation < c2.Innovation:
				d += 1
				i += 1
			case c1.Innovation > c2.Innovation:
				d += 1
				j += 1
			default: // Same innovation number
				w += math.Abs(c1.Weight - c2.Weight)
				x += 1
				i += 1
				j += 1
			}
		}
	}

	// Return the compatibility distance
	n = 1 // NOTE: The variable N mentioned in the paper does not seem to be used in any implemenation
	δ := c.ExcessCoefficient()*e/n + c.DisjointCoefficient()*d/n
	if x > 0 {
		δ += c.WeightCoefficient() * w / x
	}
	return δ, nil
}